123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636 |
- /* col.c
- * col [ -bfx ]
- */
- #include <stdio.h>
- #include <ctype.h>
- #define ESC '\033'
- /* second chars of escape codes */
- #define HALFDOWN '9'
- #define HALFUP '8'
- #define WHOLEUP '7'
- #define VT '\013' /* alternate form of full reverse lf */
- #define SO '\017' /* turn on alternate char set */
- #define SI '\016' /* turn it off */
- #define CHUNKSIZE 80
- /* globals */
- int backspace, /* can terminal backspace? */
- half, /* ok to do 1/2 forward lf? */
- squeeze, /* turn white-space into tabs */
- col, /* current column */
- whichalf, /* are we on full line or between lines? */
- backs, /* # of backspaces on current line */
- nextchunk, /* next time we need to alloc space for current text */
- altset; /* alternate character set mode */
-
- struct line /* double linked list */
- {
- char *text;
- struct line *up;
- struct line *down;
- int updist; /* one=1/2 lf, two=full lf */
- int downdist;
- } *root,*linit(),*scan();
- char *forward(),*strinsert();
- main(argc,argv)
- int argc;
- char **argv;
- {
- int x;
- char c,*argtmp;
-
- backspace=squeeze=1;
- whichalf=col=half=altset=backs=0;
- /* check args */
- if(argc>=2)
- while(argtmp = *++argv)
- if(**argv=='-')
- while(c = *++*argv)
- switch(c)
- {
- case 'b':
- backspace=0;
- break;
- case 'f':
- half=1;
- break;
- case 'x':
- squeeze=0;
- break;
- default:
- fprintf(stderr,"col: Bad option %c\n"
- ,c);
- exit(1);
-
- }
- else
- {
- fprintf(stderr,"col: Bad arg %s\n",argtmp);
- exit(1);
- }
-
- root=scan(NULL,NULL,NULL); /* All nulls because so far there are
- * no lines */
- printup(root); /* print all lines above + including root */
- if(root)
- printdown(root->down); /* print all lines below root */
- }
- struct line *
- scan(line,above,below)
- register struct line *line,*above,*below;
- {
- int leg,coltmp,eol;
- char *charalloc(),*rightins();
- register char c;
- col -= backs*2; /* get actual cursor pos on screen */
- backs=0;
- if(!line)
- {
- line=linit();
- line->text=charalloc(NULL,CHUNKSIZE);
- line->text[0]=NULL;
- }
- nextchunk=strlen(line->text)%CHUNKSIZE+CHUNKSIZE;
- coltmp=col;
- col=eol=0;
- line->text=forward(line->text,coltmp);
- while(!eol)
- switch(c=getchar())
- {
-
- case EOF:
- if(above)
- {
- above->down=line;
- line->up=above;
- }
- eol=1;
- break;
- case ESC:
- c=getchar(); /* find out what esc sequence is */
- switch(c)
- {
- case HALFDOWN:
- halfdown(line,above,below);
- eol=1;
- break;
- case HALFUP:
- halfup(line,above,below);
- eol=1;
- break;
- case WHOLEUP:
- wholeup(line,above,below);
- eol=1;
- break;
-
- }
- break;
- case '\r':
- col=backs=0;
- break;
- case '\n':
- wholedown(line,above,below);
- break;
- case VT:
- wholeup(line,above,below);
- break;
- case '\t':
- /* convert to spaces */
- do
- line->text=rightins(line->text,' ');
- while((col-backs*2)%8);
- break;
- case '\b':
- if(col)
- {
- col--;
- while(line->text[col]=='\b')
- col=(col<2) ? 0:col-2;
- }
- break;
- case SO:
- altset=1;
- break;
- case SI:
- altset=0;
- break;
- default:
- if(isprint(c))
- line->text=rightins(line->text,c);
- break;
- }
- return(line);
- }
- halfdown(line,above,below)
- register struct line *line,*above,*below;
- {
- whichalf=!whichalf;
- if(above)
- {
- line->updist=above->downdist;
- line->up=above;
- above->down=line;
- }
- if(half)
- {
- line->downdist=1;
- if(below)
- {
- below->up=line;
- if(below->updist==2)
- {
- below->updist=1;
- scan(NULL,line,below);
- }
- else /* below->updist==1 */
- scan(line->down=below,line,
- below->down);
- }
- else
- scan(NULL,line,NULL);
- }
- else
- {
- if(below)
- {
- below->up=line;
- line->down=below;
- if(whichalf)
- scan(below,line,below->down);
- else
- scan(line,above,below);
- }
- else
- {
- if(whichalf)
- scan(NULL,line,NULL);
- else
- scan(line,above,NULL);
- }
- }
- }
- halfup(line,above,below) /* bascially the same as HALFDOWN */
- register struct line *line,*above,*below;
- {
- whichalf=!whichalf;
- if(below)
- {
- line->downdist=below->updist;
- line->down=below;
- below->up=line;
- }
- if(half)
- {
- line->updist=1;
- if(above)
- {
- above->down=line;
- if(above->downdist==2)
- {
- above->downdist=1;
- scan(NULL,above,line);
- }
- else /* above->downdist==1 */
- scan(line->up=above,above->up,line);
- }
- else
- scan(NULL,NULL,line);
- }
- else
- {
- if(above)
- {
- above->down=line;
- line->up=above;
- if(whichalf)
- scan(line,above,below);
- else
- scan(above,above->up,line);
- }
- else
- {
- if(whichalf)
- scan(line,NULL,below);
- else
- scan(NULL,NULL,line);
- }
- }
- }
-
- wholedown(line,above,below)
- register struct line *line,*above,*below;
- {
- col=0; /* go to beginning of line */
- if(above)
- {
- line->updist=above->downdist;
- line->up=above;
- above->down=line;
- }
- if(half)
- {
- if(below)
- {
- line->down=below;
- line->downdist=below->updist;
- below->up=line;
- if(line->downdist==2)
- scan(below,line,below->down);
- else /* line->downdist==1 */
- {
- switch(below->downdist) /* next below*/
- {
-
- case 0: /* nothing down there */
- below->downdist=1;
- scan(NULL,below,NULL);
- break;
- case 1: /* 1/2 line, exactly what we
- * need */
- scan(below->down,below,
- below->down->down);
- break;
- case 2: /* put line between below and
- * below->down */
- below->downdist=1;
- below->down->updist=1;
- scan(NULL,below,below->down);
- break;
-
- }
- }
- }
- else /* create line 2 halves down from 'line' */
- {
-
- line->downdist=2;
- scan(NULL,line,NULL);
- }
- }
- else
- {
- if(below)
- {
- line->down=below;
- below->up=line;
- scan(below,line,below->down);
- }
- else
- scan(NULL,line,NULL);
- }
- }
- wholeup(line,above,below) /* bascially same as WHOLEDOWN */
- register struct line *line,*above,*below;
- {
- if(below)
- {
- line->downdist=below->updist;
- line->down=below;
- below->up=line;
- }
- if(half)
- {
- if(above)
- {
- line->up=above;
- line->updist=above->downdist;
- above->down=line;
- if(line->updist==2)
- scan(above,above->up,line);
- else /* line->updist==1 */
- switch(above->updist) /* next above */
- {
-
- case 0: /* nothing up there */
- above->updist=1;
- scan(NULL,NULL,above);
- break;
- case 1: /* 1/2 line, perfect */
- scan(above->up,above->up->up,
- above);
- break;
- case 2: /* squeeze a line between
- * above->up and above */
- above->updist=1;
- above->up->downdist=1;
- scan(NULL,above->up,above);
- break;
-
- }
- }
- else /* create line 2 halves up from 'line' */
- {
- line->updist=2;
- scan(NULL,NULL,line);
- }
- }
- else
- {
- if(above)
- {
- line->up=above;
- above->down=line;
- scan(above,above->up,line);
- }
- else
- scan(NULL,NULL,line);
- }
- }
- char *
- rightins(s,c) /* choose the right way to insert c into s[col] */
- register char *s,c;
- {
- c=altset ? c|0200 : c&0177; /* use high bit as flag to tell whether or
- * not char is in alt character set */
- if(!s[col])
- {
- if(col+2>=nextchunk)
- s=charalloc(s,nextchunk+=CHUNKSIZE);
- s[col++]=c;
- s[col]=NULL;
- return(s);
- }
- else
- {
- if(s[col]==' ' || !backspace) /* overwrite it */
- s[col]=c;
- else if(c!=' ') /* no use inserting a space */
- {
- ++col;
- s=strinsert(s,col++,'\b');
- s=strinsert(s,col,c);
- backs++;
- }
- return(forward(s,1));
- }
- }
- struct line *
- linit() /* alloc line structure and nullify all members */
- {
- char *malloc();
- struct line *line;
- line=(struct line *)charalloc(NULL,sizeof(struct line));
- line->up=line->down=(struct line *)NULL;
- line->text=(char *)NULL;
- line->updist=line->downdist=0;
- return(line);
- }
- char *
- charalloc(ptr,nbytes) /* if ptr==NULL, allocate new memory, if !=NULL
- * realloc. ; then check for errors */
- char *ptr;
- int nbytes;
- {
- char *malloc(),*realloc();
-
- if(ptr==NULL)
- ptr=malloc(nbytes);
- else
- ptr=realloc(ptr,nbytes);
- if(ptr==NULL)
- error("Can't allocate any more memory");
- return(ptr);
- }
- printup(line) /* recursively print lines above & including 'line' */
- struct line *line;
- {
- if(line) /* exit clause */
- {
- printup(line->up);
- printline(line);
- }
- }
- printdown(line) /* recursively print lines below & including 'line'*/
- struct line *line;
- {
- if(line)
- {
- printline(line);
- printdown(line->down);
- }
- }
- printline(line) /* print line->text and appropriate lf */
- register struct line *line;
- {
- int anytabs,t;
- int pos; /* used for space squeezing */
- register char c;
- register int i,spaces;
- static int inalt=0;
- /* i is used to point to element of line->text being printed out, col is the
- * cursor column
- */
- spaces=0;
- for(i=col=0; c=line->text[i]; i++,col++)
- {
- if(c&0200)
- {
- if(!inalt)
- {
- inalt=1;
- putchar(SO);
- }
- }
- else
- if(inalt)
- {
- inalt=0;
- putchar(SI);
- }
- c &= 0177; /* chop off high bit */
- if(squeeze)
- {
- switch(c)
- {
- case ' ':
- ++spaces;
- break;
- case '\b':
- col--;
- break;
- default:
- if(spaces)
- {
- pos=col-spaces;
- anytabs=t=((col-spaces)%8+spaces)/8;
- while(t--)
- {
- if(pos%8<7) /* make sure tab
- * isn't printed
- * for just one
- * space
- */
- putchar('\t');
- else
- putchar(' ');
- pos=0; /* flag so next time it
- * will always print tab
- */
- }
- if(anytabs)
- spaces=i%8;
- while(spaces--)
- putchar(' ');
- spaces=0;
- }
- break;
- }
- if(c!=' ')
- putchar(c);
- }
- else
- putchar(c);
- }
- if(half)
- switch(line->downdist)
- {
- case 0: /* last line of text */
- if(i>0)
- if(half && whichalf)
- printf("\033\071\r");
- else
- putchar('\n');
- break;
- case 1:
- printf("\033\071\r");
- break;
- case 2:
- putchar('\n');
- break;
- }
- else if(i>0 || line->down!=NULL) /* no \n if last line is blank */
- putchar('\n');
- }
- char *
- strinsert(str,in,c) /* insert c at str[in] */
- register char *str,c;
- int in;
- {
- int foo;
- register char tmp,*ptr;
-
- ptr=str+in;
- while(*ptr)
- {
- tmp = *ptr;
- *ptr++ = c;
- c=tmp;
- }
- if((ptr-str+2)>nextchunk)
- {
- str=charalloc(str,nextchunk+=CHUNKSIZE); /* alloc text space in
- * chunks of CHUNKSIZE, it's
- * faster than one by one
- */
- ptr=str+foo-2;
- }
- *ptr=c;
- *++ptr='\0';
- return(str);
- }
- char *
- forward(s,n) /* move forward n chars in s counting \b as moving back 1 */
- char *s;
- int n;
- {
- register int i;
- for(i=0; i<n || s[col]=='\b'; i++, col++)
- {
- if(!s[col])
- s=strinsert(s,col,' ');
- else if(s[col]=='\b' && i)
- i--;
- }
- return(s);
- }
- error(s,c) /* print error and exit */
- {
- fprintf(stderr,"col: %s %c\n",s,c);
- exit(1);
- }
|