home *** CD-ROM | disk | FTP | other *** search
- /*
- HEADER: CUG999.08;
- DATE: 5/15/87;
-
- DESCRIPTION: "Text storage and manipulation routines for the GED editor.
- Virtual memory interface";
- KEYWORDS: text storage, memory management, virtual storage, paging;
- SYSTEM: MS-DOS;
- FILENAME: VIRT2.C;
- AUTHORS: G. Nigel Gilbert, James W. Haefner, Mel Tearle, G. Osborn;
- COMPILERS: Microsoft 4.0;
- */
-
- /*
- e/qed/ged/se screen editor
-
- (C) G. Nigel Gilbert, MICROLOGY, 1981
- August-December 1981
-
- Modified: Aug-Dec 1984: BDS-C 'e'(vers 4.6a) to 'qe' (J.W. Haefner)
- March 1985: BDS-C 'qe' to DeSmet-C 'qed' (J.W. Haefner)
- May 1986: converted to ged - Mel Tearle
-
-
- FUNCTIONS: loc, gettext, getline, inject, deltp, puttext,
- readtext, opentext, balloc,
- addhistory, trim
-
- PURPOSE: get and put text lines into and out of storage
-
-
-
-
- The far and huge pointer definitions can be removed by changing
- the preprocessor directives in ged.h
-
-
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include "ged.h"
-
-
- int untrims;
-
-
- /* returns line + move, adjusted to be within text.
- */
- loc(line,move)
- int line, move;
- {
- int y, sav, i;
-
- if(charep) {
- i = move;
- if(i < 0)
- i = -i;
- if (i > 10) {
- charep = 0; /* exit character replace mode if line changes a lot*/
- blankedmess = YES; /* and change the header status indication */
- }
- }
-
- if ( ( y = line+move ) < 1 )
- y = 1;
- if ( y > lastl )
- return lastl;
- else
- return y;
- }
-
-
- /* makes 'line' the current line.
- Lines which appear on the screen cause the virtual memory page containing
- the line to be marked as recently used. The global search operations do
- not call this routine.
- */
- gettext(line, cp)
- int line, cp;
- {
- int i;
- char *getline();
-
- if (altered)
- cerr(80); /* the text buffer was not stored with puttext */
-
- strcpy( text, getline( line ) );
- pad(cp); /* add trailing spaces if cursor beyond end of line */
-
- cline = line;
-
- if (clock < (MAXINT-1) )
- clock++;
- /* don't lower the priority of newpage */
- i = virtslot[ tp[line].page ];
- if (usage[i] < clock)
- usage[i] = clock;
-
-
- text[LLIM-1] = '\0'; /* for diagnostic checks only */
- return;
- }
-
- /* returns small memory model address of text of 'line' and updates
- * page usage. The buffers used by getline and gettext have to be
- * different. The extra text move for gettext has no significant effect
- * on program timing. getline is used for the string search operatios
- * and needs to be fast.
- *
- * getline has to be used with caution because the page pointed to can
- * be swapped out by subsequent activites, invalidating the pointer. That
- * problem does not exist in this version because the line is copied to
- * a local buffer to satisfy the mixed memory model requirements.
- * In this version the pointer is invalidated by a subsequent gettext().
- *
- * Requires that strings not cross 64 k boundaries.
- */
-
- char glbuf[LLIM]; /* this buffer is shared by getline, gethist, & gettext */
-
- char *getline(line)
- int line;
- {
- char FAR *hgetline();
- register char FAR *hptr;
- register char *s;
-
- hptr=hgetline(line);
- s=&glbuf[0];
- /* The following is equivalent to the movesf() call. movesf is in pcio.asm
- * while (*s++ = *hptr++)
- * ;
- */
- movesf(s,hptr);
- return &glbuf[0];
- }
-
- /* used by undo */
- char *gethist(page,offset)
- int page,offset;
- {
- char HUGE *hptr;
- char *s;
- if(virtslot[page] < 0)
- swappin(page);
- hptr = slotaddr[virtslot[page]]+offset;
- s = &glbuf[0];
- while (*s++ = *hptr++)
- ;
- return &glbuf[0];
- }
- /* returns far address of text of 'line'
- * and updates page usage. Requires that 2<<16 % pagesize == 0 to
- * avoid crosssing a 64 k boundary.
- * the huge pointers are recast to far for consistancy and effieciency.
- */
- /*
- char FAR *hgetline(line)
- int line;
- {
- int pg;
- line = loc(line,0);
- pg = tp[line].page;
- if ( virtslot[pg] < 0 )
- swappin(pg);
- return (char FAR *) slotaddr[virtslot[pg]] + tp[line].moffset;
- }
- */
- char FAR *hgetline(line)
- int line;
- {
- int pg;
- int i,j;
-
- line = loc(line,0);
- pg = tp[line].page;
- if ( virtslot[pg] < 0 )
- swappin(pg);
-
- i = tp[line].moffset;
- if(i > 0) {
- j = *((char FAR *) slotaddr[virtslot[pg]] + tp[line].moffset -1);
- if(j != 0)
- cerr(84);
- }
- return (char FAR *) slotaddr[virtslot[pg]] + tp[line].moffset;
- }
-
-
- /* Inserts 'txt' after 'line', moving following pointer array up. Line 1
- * is injected at 0.
- *
- * See also comment in deltp.
- */
- inject(line,txt)
- int line;
- char *txt;
- {
- int l, balloc();
- int i, j, trims;
- char *s;
- char FAR *h;
- long FAR *ht;
- long FAR *hf;
- long int ii;
-
-
- trims = trim(txt);
-
- if (lastl > 16383)
- goto tomany;
-
- ii = (long) (lastl + 1) * sizeof(*tp);
- if ( (ii/PAGESIZE) >= tpslots) {
- /* need another slot to store tp's in */
- if ( tpslots == slotsinmem-2)
- goto tomany;
- if ( usage[tpslots] > 0 )
- swapout(tpslots); /* bump for tp, which can't be swapped out */
- usage[tpslots++] = -1;
- }
-
- addhistory( line+1, line+1, HISTINSERT );
-
- if(line < lastl) {
- ht = (long int FAR *) &tp[lastl+1];
- hf = (long int FAR *) &tp[lastl];
- j = lastl-line;
- for (i = 0; i < j; i++)
- *ht-- = *hf--;
- }
- lastl++;
-
- tp[line+1].moffset = balloc(1+trims); /* increments newpage if necessary */
- tp[line+1].page = newpage;
- h = slotaddr[virtslot[newpage]] + tp[line+1].moffset;
- s = &txt[0];
- while (*h++ = *s++)
- ;
- stale(newpage);
- untrim();
-
- /* keep the default jump location on the same physical line */
- if ( line <= jmpto)
- jmpto++;
- /* keep the marked jump locations on the same physical line */
- if ( line <= linem1)
- linem1++;
- if ( line <= linem2)
- linem2++;
- if ( line <= linem3)
- linem3++;
- /* rember the last change for the jump command. never needs adjustment. */
- lastc = line+1;
-
- return line+1;
-
- tomany:;
- error(" Too many lines for RAM size. Line lost. ");
- return FAIL;
- }
-
-
- /* delete line by shifting pointers
-
- The tp structures must have the same size as a long integer for
- this routine to work. Execution time is excessive for very large
- documents if the shortcut is not used.
- */
- deltp(dline, cnt)
- int dline, cnt;
- {
- int i, j, lastls;
- long FAR *ht;
- long FAR *hf;
-
- lastls = lastl;
- for (i = dline; i < dline+cnt; i++) {
- addhistory( i, dline, HISTDELETE ); /* save for undo */
- lastl--;
- if ( lastl < 1 )
- lastl = 1;
- if (i < jmpto)
- jmpto--;
-
- if (i < linem1)
- linem1--;
- if (i < linem2)
- linem2--;
- if (i < linem3)
- linem3--;
-
- lastc = i;
- }
- ht = (long FAR *) &tp[dline];
- hf = (long FAR *) &tp[dline+cnt];
- j = lastls - dline;
- for (i = 0; i < j; i++)
- *ht++ = *hf++;
-
- return;
- }
-
- /* replaces cline's text if it has been altered. the new text goes to
- * a newly allocated region. the old text remains as is for the undo.
- */
- puttext()
- {
- int balloc();
- char *s;
- char FAR *h;
- int tsize;
-
-
- if (text[LLIM-1] != '\0')
- cerr(81);
-
- if ( altered ) {
- tsize = trim(text); /* string restored before exit */
- if (charn > untrims)
- cerr(82); /* trailing spaces lost */
- addhistory( cline, cline, HISTREPLACE ); /* add for undo */
- altered = NO;
-
- tp[cline].moffset = balloc(1+tsize); /* increments newpage if necessary */
- tp[cline].page = newpage;
- h = slotaddr[virtslot[newpage]] + tp[cline].moffset;
- s = &text[0];
- while (*h++ = *s++)
- ;
- stale(newpage);
- untrim();
- /* remember the last change for the jump command */
- lastc = cline;
- }
- return;
- }
-
- /* mark the disc copy of the page obsolete and recycle the disc slot */
- stale(page)
- int page;
- {
- int i;
-
- i = virtslot[page];
- if ( i < 0 || i >= slotsinmem)
- cerr(83); /* table corrupt */
- if (auxloc[i] < 0) {
- dskslots[1 -auxloc[i]] = 0;
- auxloc[i] = 0;
- }
- return;
- }
-
- /* allocate and return the offset in newpage of a vector size n.
- */
- int balloc(n)
- unsigned n;
- {
-
- if (virtslot[newpage] < 0)
- swappin(newpage);
- if ( allocp + n >= PAGESIZE ) {
-
- /* no room in current newpage; get another.
- */
- usage[virtslot[newpage]] = clock; /* normal priority */
- virtslot[++newpage] = freememslot();
- usage[virtslot[newpage]] = MAXINT; /* highest possible priority for residency */
- allocp = 0;
- }
- allocp += n;
- return allocp-n;
- }
-
- addhistory(is,willbe,type)
- int is, willbe;
- int type;
- {
- if ( !storehist ) return;
-
- history[histptr].histp.page = tp[is].page;
- history[histptr].histp.moffset = tp[is].moffset;
-
- history[histptr].histline = willbe;
- history[histptr].histtype = type;
- history[histptr].histcomm = ncommand;
-
- histptr++;
- if ( histptr == HISTLEN ) histptr = 0;
- if ( histcnt < HISTLEN ) histcnt++;
- return;
- }
-
- /* eliminate trailing blanks and tabs if trail is false */
- /* returns the string length after trimming */
- char *untriml;
- char untrimc;
-
- int trim(string)
- char *string;
- {
- int i, l;
-
- untrims = strlen(string);
- if ( (!trail) && (untrims > 0) ) {
- for ( i = untrims-1; (i >= 0) &&
- ( (string[i]==' ') || (string[i]=='\t') ); i-- )
- ;
- l = ++i;
- }
- else {
- l = untrims;
- }
- untriml = &string[l];
- untrimc = *untriml;
- *untriml = '\0';
- return l;
- }
- /* restore the string to its original state */
- untrim()
- {
- *untriml = untrimc;
- return;
- }
-
-
-
- /* Reads file being edited into virtual memory until 'line' is read, or eof.
- * If eof, sets lastl to number of last line read. File is assumed to be
- * already open.
- *
- * ENDFILE is the ^Z end of file marker. DFAIL is from egetc(), not from the
- * library. These values are internal and do not depend on the compiler used.
- */
- readtext(line)
- int line;
- {
- struct iobuffer *iobuf;
- int nbytes;
- register unsigned char *t;
- register int c;
- static unsigned char *nextp;
- static int nleft;
-
- char txt[LLIM]; /* latest char at txt[LLIM-2], latest '\0' at txt[LLIM-1] */
- char buf[80], *mpt1, *mpt2;
- int i, j, l;
- static unsigned char *tend;
- int once1, once2, once3;
-
- storehist = NO;
- goteof = NO;
- if (line == 1)
- once1 = once2 = once3 = NO;
-
- /* use local variables to speed execution. they are restored after
- * use to insure compatibality with egetc(). these i/o functions are used
- * similarly to the library functions but they are local.
- * (later timing studies show little if any improvement with local variables.)
- */
- iobuf = textbuf;
- nextp = iobuf -> nextp;
- nleft = iobuf -> nleft;
-
- while ( lastl < line && !(goteof) ) {
- t = &txt[0];
- tend = &txt[LLIM-1];
- /* This section needs to be fast for the frequent tests.
- * Each machine instruction adds over a second to the load
- * time for a 500 kb document on a 5 MHz PC.
- */
- do {
-
- skip:;
- /* following same as egetc(). inline to minimize execution time */
-
- if ( nleft-- ) {
- if ( (*t = (charmask & *nextp++) ) > 0x1F) { /* char overlain later if wrong */
- goto agn;
- }
- else {
- --nextp;
- c = *nextp++;
- }
- }
- else if ( (nbytes = read(iobuf -> fdes, iobuf -> buff, NSECTS*SECSIZ)) == -1 ) {
- nleft++;
- c = DFAIL;
- }
- else if ( nbytes == 0 ) {
- nleft++;
- c = ENDFILE;
- }
- else {
- nleft = nbytes ;
- nextp = iobuf -> buff;
- goto skip;
-
- }
- /* the standard EOL is 0x0D 0x0A. */
- if (c == '\r') {
- goto eol;
- }
- else if (c == '\n') {
- goto skip;
- }
- else if (c == '\t') {
- /* Detab. Unconditional here, will be made the default option in later versions. */
- if (!once3) {
- writeline(0,3,"Input is being detabbed. Invoke with -Tn option to change tab.",ATTR2);
- once3 = YES;
- }
- i = tabwidth - ((t - txt) % tabwidth); /* 1 <= i <= tabwidth */
- for (j= 1; j <= i && !(t == (tend)); j++)
- *t++ = ' ';
- t--;
- }
- else if (c == ENDCHAR) {
- goteof = YES;
- goto eol; /* end of file is ^Z */
- }
- else if (c == ENDFILE) {
- goteof = YES; /* end of file given by directory file size */
- goto eol;
- }
- /* Retain control codes if the invocation option -C was specified,
- * otherwise convert them to '?'
- */
- else if ( c >= 0) {
- mpt1 = "File contains ASCII codes below 0x20";
- if (ctrl) {
- *t = c;
- mpt2 = "";
- }
- else {
- *t = '?';
- mpt2 = ". Converted to '?'. Use -C option to retain";
- }
- if (!once1) {
- strcpy(buf,mpt1);
- strcat(buf,mpt2);
- writeline(0,1,buf,ATTR2);
- once1 = YES;
- }
- }
- else {
- error("Disc Error"); /* wait for keystroke then edit whatever is there */
- goteof = YES;
- goto eol;
- }
- agn:;
- }
- while ( !(++t == tend) );
- /* ----------------------------------------*/
- /* A line of maximal length followed by 0D 0A will result in the loop
- * falling through when there is no actual overflow.
- * No character is discarded on a line split,
- * and the handling of this rare case does not slow the loop. This
- * algorithm limits the line length to LLIM-2 in most cases.
- */
-
- if (!once2) {
- sprintf(buf, "Line %d was too long, line(s) split.", line);
- writeline(0,2,buf,ATTR2);
- once2 = YES;
- }
- eol:;
- *t = '\0';
- l = 0;
- if ( !goteof || !(t == &txt[0]) || (line == 1) ) {
- l = inject(lastl,txt);
- }
- if ( l == FAIL ) {
- goteof = YES; /* at line limit */
- }
- else {
- if ( lastl % 100 == 0 ) {
- putlineno(lastl);
- displine = cline; /* no change in text display */
- putallo();
- }
- }
- }
- iobuf -> nextp = nextp;
- iobuf -> nleft = nleft;
-
- storehist = YES;
- blankedmess = YES;
- if (goteof) {
- fclose(textbuf);
- if((once1 || once2 || once3) && (lastl < 5000) )
- wait(1); /* wait so that the err msg can be seen on a fast system */
- }
- return;
- }
-
-
- /* open the file being edited for reading
- */
- opentext(name)
- char *name;
- {
- int fopen1();
- int buf[FILELEN+20];
- strcpy(buf,name);
- if ( fopen1(name, textbuf) == FAIL) {
-
- /* attempt to open with default extension added */
- strcat(buf,".c");
- if ( fopen1(buf, textbuf) == FAIL ) {
- /* try second default */
- strcpy(buf,name);
- strcat(buf,".doc");
- if (fopen1(buf, textbuf) == FAIL ) {
- strcpy(buf," Can't open file ");
- strncat(buf,name,FILELEN-1);
- error1(buf);
- name[0] = '\0';
- lastl = 1;
- return FAIL;
- }
- }
- }
- strcpy(name,buf);
- return YES;
- }