home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 331_01 / store.c < prev    next >
Text File  |  1990-06-12  |  17KB  |  629 lines

  1. /*
  2. HEADER:         CUG999.08;
  3. DATE:           5/15/87;
  4.  
  5. DESCRIPTION:    "Text storage and manipulation routines for the GED editor.
  6.                  Virtual memory interface";
  7. KEYWORDS:       text storage, memory management, virtual storage, paging;
  8. SYSTEM:         MS-DOS;
  9. FILENAME:       VIRT2.C;
  10. AUTHORS:        G. Nigel Gilbert, James W. Haefner, Mel Tearle, G. Osborn;
  11. COMPILERS:      Microsoft 4.0;
  12. */
  13.  
  14. /*
  15.      e/qed/ged/se  screen editor
  16.  
  17.     (C) G. Nigel Gilbert, MICROLOGY, 1981
  18.            August-December 1981
  19.  
  20.     Modified:  Aug-Dec   1984:   BDS-C 'e'(vers 4.6a) to 'qe' (J.W. Haefner)
  21.                March     1985:   BDS-C 'qe' to DeSmet-C 'qed' (J.W. Haefner)
  22.                May       1986:   converted to ged - Mel Tearle
  23.  
  24.  
  25.     FUNCTIONS: loc, gettext, getline, inject, deltp, puttext,
  26.                readtext, opentext, balloc,
  27.                addhistory, trim
  28.  
  29.     PURPOSE:   get and put text lines into and out of storage
  30.  
  31.  
  32.  
  33.  
  34.    The far and huge pointer definitions can be removed by changing
  35.    the preprocessor directives in ged.h
  36.  
  37.  
  38. */
  39.  
  40. #include <stdio.h>
  41. #include <ctype.h>
  42. #include "ged.h"
  43.  
  44.  
  45. int untrims;
  46.  
  47.  
  48. /* returns line + move, adjusted to be within text.
  49.  */
  50. loc(line,move)
  51. int line, move;
  52. {
  53.     int y, sav, i;
  54.  
  55.     if(charep) {
  56.         i = move;
  57.         if(i < 0)
  58.             i = -i;
  59.         if (i > 10) {
  60.             charep = 0;  /* exit character replace mode if line changes a lot*/
  61.             blankedmess = YES;  /* and change the header status indication */
  62.         }
  63.     }
  64.  
  65.     if ( ( y = line+move ) < 1 )
  66.         y = 1;
  67.     if ( y > lastl )
  68.         return lastl;
  69.     else
  70.         return y;
  71. }
  72.  
  73.  
  74. /* makes 'line' the current line.
  75.    Lines which appear on the screen cause the virtual memory page containing
  76.    the line to be marked as recently used.  The global search operations do
  77.    not call this routine.
  78.  */
  79. gettext(line, cp)
  80. int line, cp;
  81. {
  82.     int i;
  83.     char *getline();
  84.  
  85.     if (altered)
  86.         cerr(80);   /* the text buffer was not stored with puttext */
  87.  
  88.     strcpy( text, getline( line ) );
  89.     pad(cp);  /* add trailing spaces if cursor beyond end of line */
  90.  
  91.     cline = line;
  92.  
  93.     if (clock < (MAXINT-1) )
  94.         clock++;
  95. /* don't lower the priority of newpage */
  96.     i = virtslot[ tp[line].page ];
  97.     if (usage[i] < clock)
  98.         usage[i] = clock;
  99.  
  100.  
  101.     text[LLIM-1] = '\0';   /* for diagnostic checks only */
  102.     return;
  103. }
  104.  
  105. /* returns small memory model address of text of 'line' and updates
  106.  * page usage.  The buffers used by getline and gettext have to be
  107.  * different.  The extra text move for gettext has no significant effect
  108.  * on program timing.  getline is used for the string search operatios
  109.  * and needs to be fast.
  110.  *
  111.  * getline has to be used with caution because the page pointed to can
  112.  * be swapped out by subsequent activites, invalidating the pointer.  That
  113.  * problem does not exist in this version because the line is copied to
  114.  * a local buffer to satisfy the mixed memory model requirements.
  115.  * In this version the pointer is invalidated by a subsequent gettext().
  116.  *
  117.  * Requires that strings not cross 64 k boundaries.
  118.  */
  119.  
  120. char glbuf[LLIM];  /* this buffer is shared by getline, gethist, & gettext */
  121.  
  122. char *getline(line)
  123. int line;
  124. {
  125.     char FAR *hgetline();
  126.     register char FAR *hptr;
  127.     register char *s;
  128.  
  129.     hptr=hgetline(line);
  130.     s=&glbuf[0];
  131. /* The following is equivalent to the movesf() call.  movesf is in pcio.asm
  132.  *  while (*s++ = *hptr++)
  133.  *      ;
  134.  */
  135.     movesf(s,hptr);
  136.     return &glbuf[0];
  137. }
  138.  
  139. /* used by undo */
  140. char *gethist(page,offset)
  141. int page,offset;
  142. {
  143.     char HUGE *hptr;
  144.     char *s;
  145.     if(virtslot[page] < 0)
  146.         swappin(page);
  147.     hptr = slotaddr[virtslot[page]]+offset;
  148.     s = &glbuf[0];
  149.     while (*s++ = *hptr++)
  150.         ;
  151.     return &glbuf[0];
  152. }
  153. /* returns far address of text of 'line'
  154.  * and updates page usage.  Requires that 2<<16 % pagesize == 0 to
  155.  * avoid crosssing a 64 k boundary.
  156.  * the huge pointers are recast to far for consistancy and effieciency.
  157.  */
  158. /*
  159. char FAR *hgetline(line)
  160. int line;
  161. {
  162.     int pg;
  163.     line = loc(line,0);
  164.     pg = tp[line].page;
  165.     if ( virtslot[pg] < 0 )
  166.         swappin(pg);
  167.     return  (char FAR *) slotaddr[virtslot[pg]] + tp[line].moffset;
  168. }
  169. */
  170. char FAR *hgetline(line)
  171. int line;
  172. {
  173.     int pg;
  174.     int i,j;
  175.  
  176.     line = loc(line,0);
  177.     pg = tp[line].page;
  178.     if ( virtslot[pg] < 0 )
  179.         swappin(pg);
  180.  
  181.     i =  tp[line].moffset;
  182.     if(i > 0) {
  183.         j = *((char FAR *) slotaddr[virtslot[pg]] + tp[line].moffset -1);
  184.         if(j != 0)
  185.             cerr(84);
  186.     }
  187.     return  (char FAR *) slotaddr[virtslot[pg]] + tp[line].moffset;
  188. }
  189.  
  190.  
  191. /* Inserts 'txt' after 'line', moving following pointer array up.  Line 1
  192.  * is injected at 0.
  193.  *
  194.  * See also comment in deltp.
  195.  */
  196. inject(line,txt)
  197. int  line;
  198. char *txt;
  199. {
  200.     int  l, balloc();
  201.     int i, j, trims;
  202.     char *s;
  203.     char FAR *h;
  204.     long FAR *ht;
  205.     long FAR *hf;
  206.     long int ii;
  207.  
  208.  
  209.     trims = trim(txt);
  210.  
  211.     if (lastl > 16383)
  212.         goto tomany;
  213.  
  214.     ii = (long) (lastl + 1) * sizeof(*tp);
  215.     if ( (ii/PAGESIZE) >= tpslots) {
  216. /* need another slot to store tp's in */
  217.         if ( tpslots == slotsinmem-2)
  218.             goto tomany;
  219.         if ( usage[tpslots] > 0 )
  220.             swapout(tpslots);  /* bump for tp, which can't be swapped out */
  221.         usage[tpslots++] = -1;
  222.     }
  223.  
  224.     addhistory( line+1, line+1, HISTINSERT );
  225.  
  226.     if(line < lastl) {
  227.         ht = (long int FAR *) &tp[lastl+1];
  228.         hf = (long int FAR *) &tp[lastl];
  229.         j = lastl-line;
  230.         for (i = 0; i < j; i++)
  231.             *ht-- = *hf--;
  232.     }
  233.     lastl++;
  234.  
  235.     tp[line+1].moffset = balloc(1+trims);  /* increments newpage if necessary */
  236.     tp[line+1].page = newpage;
  237.     h = slotaddr[virtslot[newpage]] + tp[line+1].moffset;
  238.     s = &txt[0];
  239.     while (*h++ = *s++)
  240.         ;
  241.     stale(newpage);
  242.     untrim();
  243.  
  244. /* keep the default jump location on the same physical line */
  245.     if ( line <= jmpto)
  246.         jmpto++;
  247. /* keep the marked jump locations on the same physical line */
  248.     if ( line <= linem1)
  249.         linem1++;
  250.     if ( line <= linem2)
  251.         linem2++;
  252.     if ( line <= linem3)
  253.         linem3++;
  254. /* rember the last change for the jump command. never needs adjustment. */
  255.     lastc = line+1;
  256.  
  257.     return  line+1;
  258.  
  259. tomany:;
  260.     error(" Too many lines for RAM size.  Line lost. ");
  261.     return  FAIL;
  262. }
  263.  
  264.  
  265. /* delete line by shifting pointers
  266.  
  267.    The tp structures must have the same size as a long integer for
  268.    this routine to work.  Execution time is excessive for very large
  269.    documents if the shortcut is not used.
  270.  */
  271. deltp(dline, cnt)
  272. int dline, cnt;
  273. {
  274.     int i, j, lastls;
  275.     long FAR *ht;
  276.     long FAR *hf;
  277.  
  278.     lastls = lastl;
  279.     for (i = dline; i < dline+cnt; i++) {
  280.         addhistory( i, dline, HISTDELETE );    /* save for undo */
  281.         lastl--;
  282.         if ( lastl < 1 )
  283.             lastl = 1;
  284.         if (i < jmpto)
  285.             jmpto--;
  286.  
  287.         if (i < linem1)
  288.             linem1--;
  289.         if (i < linem2)
  290.             linem2--;
  291.         if (i < linem3)
  292.             linem3--;
  293.  
  294.         lastc = i;
  295.     }
  296.     ht = (long FAR *) &tp[dline];
  297.     hf = (long FAR *) &tp[dline+cnt];
  298.     j = lastls - dline;
  299.     for (i = 0; i < j; i++)
  300.         *ht++ = *hf++;
  301.  
  302.     return;
  303. }
  304.  
  305. /* replaces cline's text if it has been altered.  the new text goes to
  306.  * a newly allocated region.  the old text remains as is for the undo.
  307.  */
  308. puttext()
  309. {
  310.     int balloc();
  311.     char *s;
  312.     char FAR *h;
  313.     int tsize;
  314.  
  315.  
  316.     if (text[LLIM-1] != '\0')
  317.         cerr(81);
  318.  
  319.     if ( altered )  {
  320.         tsize = trim(text);   /* string restored before exit */
  321.         if (charn > untrims)
  322.             cerr(82);         /* trailing spaces lost */
  323.         addhistory( cline, cline, HISTREPLACE );   /* add for undo */
  324.         altered = NO;
  325.  
  326.         tp[cline].moffset = balloc(1+tsize);   /* increments newpage if necessary */
  327.         tp[cline].page = newpage;
  328.         h = slotaddr[virtslot[newpage]] + tp[cline].moffset;
  329.         s = &text[0];
  330.         while (*h++ = *s++)
  331.             ;
  332.         stale(newpage);
  333.         untrim();
  334. /* remember the last change for the jump command */
  335.         lastc = cline;
  336.     }
  337.     return;
  338. }
  339.  
  340. /* mark the disc copy of the page obsolete and recycle the disc slot */
  341. stale(page)
  342. int page;
  343. {
  344.     int i;
  345.  
  346.     i = virtslot[page];
  347.     if ( i < 0 || i >= slotsinmem)
  348.         cerr(83);       /* table corrupt */
  349.     if (auxloc[i] < 0) {
  350.         dskslots[1 -auxloc[i]] = 0;
  351.         auxloc[i] = 0;
  352.     }
  353.     return;
  354. }
  355.  
  356. /* allocate and return the offset in newpage of a vector size n.
  357.  */
  358. int balloc(n)
  359. unsigned n;
  360. {
  361.  
  362.     if (virtslot[newpage] < 0)
  363.         swappin(newpage);
  364.     if ( allocp  + n >= PAGESIZE )  {
  365.  
  366. /* no room in current newpage; get another.
  367.  */
  368.         usage[virtslot[newpage]] = clock;  /* normal priority */
  369.         virtslot[++newpage] = freememslot();
  370.         usage[virtslot[newpage]] = MAXINT;  /* highest possible priority for residency */
  371.         allocp = 0;
  372.     }
  373.     allocp += n;
  374.     return  allocp-n;
  375. }
  376.  
  377. addhistory(is,willbe,type)
  378. int is, willbe;
  379. int type;
  380. {
  381.     if ( !storehist )  return;
  382.  
  383.     history[histptr].histp.page    = tp[is].page;
  384.     history[histptr].histp.moffset = tp[is].moffset;
  385.  
  386.     history[histptr].histline = willbe;
  387.     history[histptr].histtype = type;
  388.     history[histptr].histcomm = ncommand;
  389.  
  390.     histptr++;
  391.     if ( histptr == HISTLEN )  histptr = 0;
  392.     if ( histcnt < HISTLEN )   histcnt++;
  393.     return;
  394. }
  395.  
  396. /* eliminate trailing blanks and tabs if trail is false */
  397. /* returns the string length after trimming */
  398. char *untriml;
  399. char untrimc;
  400.  
  401. int trim(string)
  402. char *string;
  403. {
  404.     int i, l;
  405.  
  406.     untrims = strlen(string);
  407.     if ( (!trail) && (untrims > 0) )  {
  408.         for ( i = untrims-1; (i >= 0)  &&
  409.         ( (string[i]==' ') || (string[i]=='\t') ); i-- )
  410.                 ;
  411.         l = ++i;
  412.     }
  413.     else {
  414.         l = untrims;
  415.     }
  416.     untriml = &string[l];
  417.     untrimc = *untriml;
  418.     *untriml = '\0';
  419.     return l;
  420. }
  421. /* restore the string to its original state */
  422. untrim()
  423. {
  424.     *untriml = untrimc;
  425.     return;
  426. }
  427.  
  428.  
  429.  
  430. /* Reads file being edited into virtual memory until 'line' is read, or eof.
  431.  * If eof, sets lastl to number of last line read.  File is assumed to be
  432.  * already open.
  433.  *
  434.  * ENDFILE is the ^Z end of file marker.  DFAIL is from egetc(), not from the
  435.  * library.  These values are internal and do not depend on the compiler used.
  436.  */
  437. readtext(line)
  438. int line;
  439. {
  440.     struct iobuffer  *iobuf;
  441.     int nbytes;
  442.     register unsigned char *t;
  443.     register int c;
  444.     static unsigned char *nextp;
  445.     static int nleft;
  446.  
  447.     char txt[LLIM]; /* latest char at txt[LLIM-2], latest '\0' at txt[LLIM-1] */
  448.     char buf[80], *mpt1, *mpt2;
  449.     int  i, j, l;
  450.     static unsigned char *tend;
  451.     int once1, once2, once3;
  452.  
  453.     storehist = NO;
  454.     goteof = NO;
  455.     if (line == 1)
  456.         once1 = once2 = once3 = NO;
  457.  
  458. /* use local variables to speed execution.  they are restored after
  459.  * use to insure compatibality with egetc().  these i/o functions are used
  460.  * similarly to the library functions but they are local.
  461.  * (later timing studies show little if any improvement with local variables.)
  462.  */
  463.     iobuf = textbuf;
  464.     nextp = iobuf -> nextp;
  465.     nleft = iobuf -> nleft;
  466.  
  467.     while ( lastl < line && !(goteof) )  {
  468.         t = &txt[0];
  469.         tend = &txt[LLIM-1];
  470. /* This section needs to be fast for the frequent tests.
  471.  * Each machine instruction adds over a second to the load
  472.  * time for a 500 kb document on a 5 MHz PC.
  473.  */
  474.         do {
  475.  
  476. skip:;
  477. /*  following same as egetc().  inline to minimize execution time */
  478.  
  479.             if ( nleft-- ) {
  480.                 if ( (*t = (charmask & *nextp++) ) > 0x1F) {   /* char overlain later if wrong */
  481.                     goto agn;
  482.                 }
  483.                 else {
  484.                     --nextp;
  485.                     c = *nextp++;
  486.                 }
  487.             }
  488.             else if ( (nbytes = read(iobuf -> fdes, iobuf -> buff, NSECTS*SECSIZ)) == -1 )  {
  489.                 nleft++;
  490.                 c = DFAIL;
  491.             }
  492.             else if ( nbytes == 0 )  {
  493.                 nleft++;
  494.                 c = ENDFILE;
  495.             }
  496.             else {
  497.                 nleft = nbytes ;
  498.                 nextp = iobuf -> buff;
  499.                 goto skip;
  500.  
  501.             }
  502. /* the standard EOL is 0x0D 0x0A. */
  503.             if (c == '\r') {
  504.                 goto eol;
  505.             }
  506.             else if (c == '\n') {
  507.                 goto skip;
  508.             }
  509.             else if (c == '\t') {
  510. /* Detab.  Unconditional here, will be made the default option in later versions. */
  511.                 if (!once3) {
  512.                     writeline(0,3,"Input is being detabbed.  Invoke with -Tn option to change tab.",ATTR2);
  513.                     once3 = YES;
  514.                 }
  515.                 i = tabwidth - ((t - txt) % tabwidth);   /* 1 <= i <= tabwidth */
  516.                 for (j= 1; j <= i && !(t == (tend)); j++)
  517.                     *t++ = ' ';
  518.                 t--;
  519.             }
  520.             else if (c == ENDCHAR) {
  521.                 goteof = YES;
  522.                 goto eol;   /* end of file is ^Z */
  523.             }
  524.             else if (c == ENDFILE) {
  525.                 goteof = YES;  /* end of file given by directory file size */
  526.                 goto eol;
  527.             }
  528. /* Retain control codes if the invocation option -C was specified,
  529.  * otherwise convert them to '?'
  530.  */
  531.             else if ( c >= 0) {
  532.                 mpt1 = "File contains ASCII codes below 0x20";
  533.                 if (ctrl) {
  534.                     *t = c;
  535.                     mpt2 = "";
  536.                 }
  537.                 else {
  538.                     *t = '?';
  539.                      mpt2 = ". Converted to '?'. Use -C option to retain";
  540.                 }
  541.                 if (!once1) {
  542.                     strcpy(buf,mpt1);
  543.                     strcat(buf,mpt2);
  544.                     writeline(0,1,buf,ATTR2);
  545.                     once1 = YES;
  546.                 }
  547.             }
  548.             else {
  549.                 error("Disc Error");  /* wait for keystroke then edit whatever is there */
  550.                 goteof = YES;
  551.                 goto eol;
  552.             }
  553. agn:;
  554.         }
  555.         while ( !(++t == tend) );
  556. /* ----------------------------------------*/
  557. /* A line of maximal length followed by 0D 0A will result in the loop
  558.  * falling through when there is no actual overflow.
  559.  * No character is discarded on a line split,
  560.  * and the handling of this rare case does not slow the loop.  This
  561.  * algorithm limits the line length to LLIM-2 in most cases.
  562.  */
  563.  
  564.         if (!once2) {
  565.             sprintf(buf, "Line %d was too long, line(s) split.", line);
  566.             writeline(0,2,buf,ATTR2);
  567.             once2 = YES;
  568.         }
  569. eol:;
  570.         *t = '\0';
  571.         l = 0;
  572.         if ( !goteof || !(t == &txt[0]) || (line == 1) ) {
  573.             l = inject(lastl,txt);
  574.         }
  575.         if ( l == FAIL ) {
  576.             goteof = YES;     /* at line limit */
  577.         }
  578.         else {
  579.             if ( lastl % 100 == 0 ) {
  580.                 putlineno(lastl);
  581.                 displine = cline;  /* no change in text display */
  582.                 putallo();
  583.             }
  584.         }
  585.     }
  586.     iobuf -> nextp = nextp;
  587.     iobuf -> nleft = nleft;
  588.  
  589.     storehist = YES;
  590.     blankedmess = YES;
  591.     if (goteof) {
  592.         fclose(textbuf);
  593.         if((once1 || once2 || once3) && (lastl < 5000) )
  594.             wait(1);  /* wait so that the err msg can be seen on a fast system */
  595.     }
  596.     return;
  597. }
  598.  
  599.  
  600. /* open the file being edited for reading
  601.  */
  602. opentext(name)
  603. char *name;
  604. {
  605.     int fopen1();
  606.     int buf[FILELEN+20];
  607.     strcpy(buf,name);
  608.     if ( fopen1(name, textbuf) == FAIL)  {
  609.  
  610. /* attempt to open with default extension added */
  611.         strcat(buf,".c");
  612.         if ( fopen1(buf, textbuf) == FAIL )  {
  613. /* try second default */
  614.             strcpy(buf,name);
  615.             strcat(buf,".doc");
  616.             if (fopen1(buf, textbuf) == FAIL ) {
  617.                 strcpy(buf," Can't open file ");
  618.                 strncat(buf,name,FILELEN-1);
  619.                 error1(buf);
  620.                 name[0] = '\0';
  621.                 lastl   = 1;
  622.                 return  FAIL;
  623.             }
  624.         }
  625.     }
  626.     strcpy(name,buf);
  627.     return  YES;
  628. }
  629.