|
|
1.1 root 1: /*
2: ** tpr - text formatter
3: ** Ken Yap, June 1981
4: */
5: #include <stdio.h>
6: #include <ctype.h>
7:
8: #define min(a,b) (a<b?a:b)
9: #define max(a,b) (a>b?a:b)
10: #define skipbl(p) {while(*p == ' ' || *p == '\t')p++;}
11: #define skipnbl(p) {while(*p != ' ' && *p != '\t' && *p != '\n')p++;}
12: #define CHARNULL ((char *)NULL)
13: #define NO 0
14: #define YES 1
15: #define COMMAND '.'
16: #define PAGENUM '%'
17: #define HUGE 10000
18: #define MAXIN 132
19: #define MAXOUT 132
20: #define MAXCHARS 14
21: #define MAXMAC 50
22: #define MAXPB 50
23: #define MAXTABS 20
24: #define PAGLEN 66
25: #define PAPERSIZE 65
26: #define M1DEF 3
27: #define M2DEF 1
28: #define M3DEF 1
29: #define M4DEF 3
30: #define PAGEWIDTH 60
31: #define ARABIC 0
32: #define ROMAN 1
33:
34: struct linelink{
35: char *lineptr;
36: struct linelink *lastline;
37: };
38: struct macro{
39: char macnam[3];
40: struct linelink *macend;
41: } macros[MAXMAC];
42: short maccnt = 0; /* counter for current macro */
43: char *pbptr[MAXMAC]; /* pointers to pushed back lines */
44: short pblev = 0; /* indicates level of macro nesting during collection */
45:
46: char outbuf[MAXOUT]; /* lines to be filled collect here */
47: char *outp = outbuf; /* last char position in outbuf; init = 0 */
48: short outw = 0; /* width of text currenty in outbuf; init = 0 */
49: short outwds = 0; /* number of words in outbuf; init = 0 */
50:
51: short curpag = 0;
52: short newpag = 1;
53: short lineno = 0;
54: char blnkhdr[] = "\n";
55: struct envir{
56: short plval;
57: short m1val;
58: short m2val;
59: short m3val;
60: short m4val;
61: short bottom;
62: char *evenhdr,*oddhdr;
63: char *evenftr,*oddftr;
64: char comchr;
65: char tabchr;
66: char ubchr;
67: short fill;
68: short adjust;
69: short numtyp;
70: short lsval;
71: short llval;
72: short inval;
73: short tival;
74: short poval;
75: short ceval;
76: short ulval;
77: short litval;
78: short blval;
79: short skpval;
80: short tabpos[MAXTABS];
81: struct envir *lastenv;
82: };
83: struct envir env = {
84: PAGLEN, M1DEF, M2DEF, M3DEF, M4DEF, (PAGLEN-M3DEF-M4DEF),
85: blnkhdr, blnkhdr,
86: blnkhdr, blnkhdr,
87: '.', '\t', ' ',
88: YES, YES, ARABIC, 1, PAGEWIDTH, 0, 0, 0, 0, 0, 0, 0, 0,
89: { 8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,0 },
90: NULL
91: };
92: struct envir *curenv = NULL;
93: struct cmdents{
94: char cmdname[3];
95: short notredefd;
96: };
97: struct cmdents builtins[] ={
98: { "ad",YES },
99: { "ar",YES },
100: { "bl",YES },
101: { "bp",YES },
102: { "br",YES },
103: { "cc",YES },
104: { "ce",YES },
105: { "de",YES },
106: { "ef",YES },
107: { "eh",YES },
108: { "fi",YES },
109: { "fo",YES },
110: { "he",YES },
111: { "in",YES },
112: { "ix",YES },
113: { "li",YES },
114: { "ll",YES },
115: { "ls",YES },
116: { "m1",YES },
117: { "m2",YES },
118: { "m3",YES },
119: { "m4",YES },
120: { "na",YES },
121: { "ne",YES },
122: { "nf",YES },
123: { "of",YES },
124: { "oh",YES },
125: { "pl",YES },
126: { "po",YES },
127: { "re",YES },
128: { "ro",YES },
129: { "se",YES },
130: { "sk",YES },
131: { "sp",YES },
132: { "ta",YES },
133: { "tc",YES },
134: { "ti",YES },
135: { "ub",YES },
136: { "ul",YES }
137: };
138:
139: enum cmdnum {ADJ, ARA, BLN, BPG, BRE, CMC, CEN, DFN, EFO, EHD, FIL,
140: FOT, HED, IND, INX, LIT, LNL, LNS, M1, M2, M3,
141: M4, NAD, NED, NFL, OFO, OHD, PGL, POF, RNV, ROM, SNV, SKP,
142: SPA, TCL, TCH, TMI, UBC, UDL, MAC, UNKNOWN};
143:
144: short echodir = 0;
145: char *filename = "stdin";
146: short fileline = 0;
147: char *nomem = "Out of dynamic memory\n"; /* canned message */
148:
149: /*
150: ** main
151: */
152: main(argc,argv)
153: short argc;
154: char **argv;{
155: char stdoutbuf[BUFSIZ];
156: FILE *file;
157:
158: for(argc--, argv++; argc > 0 && **argv == '-' && (*argv)[1] != '\0'; argc--, argv++)
159: setoptions(*argv);
160: setbuf(stdout,stdoutbuf);
161: if(argc == 0)
162: tpr(stdin,"stdin");
163: else
164: for( ; argc > 0; argc--, argv++){
165: if(**argv == '-' && (*argv)[1] == '\0')
166: tpr(stdin,"stdin");
167: else{
168: if((file = fopen(*argv,"r")) == NULL){
169: perror(*argv);
170: continue;
171: }
172: tpr(file,*argv);
173: fclose(file);
174: }
175: }
176: if(lineno > 0)
177: spc(HUGE); /* flush last output */
178: fflush(stdout);
179: }
180:
181: setoptions(arg)
182: char *arg;{
183: register char c;
184:
185: while((c = *++arg) != '\0')
186: switch(c){
187: case 'd': /* echo directives */
188: echodir++;
189: break;
190: case 'e': /* divert errors */
191: close(2);
192: if(creat(++arg,0600) < 0){
193: open("/dev/tty",1);
194: perror(arg);
195: exit(1);
196: }
197: return;
198: default:
199: fprintf(stderr,"Usage - see manual (ho, ho)\n");
200: exit(1);
201: }
202: }
203:
204: /*
205: ** tpr - here is the main routine for each file
206: ** the name is passed along so that the 'include' directive
207: ** can call 'tpr' recursively
208: */
209: tpr(file,name)
210: FILE *file;
211: char *name;{
212: register char *savename;
213: register short saveline;
214: char inbuf[MAXIN];
215: char *ngetl();
216:
217: savename = filename; /* save old name */
218: filename = name; /* make new one available for error routine */
219: saveline = fileline; /* and line number */
220: fileline = 0;
221: while(ngetl(inbuf,file) != CHARNULL){
222: ++fileline;
223: if(*inbuf == env.comchr) /* it's a command */
224: cmd(inbuf,file);
225: else /* it's text */
226: text(inbuf);
227: }
228: filename = savename; /* restore name and linenumber */
229: fileline = saveline;
230: }
231:
232: /*
233: ** error - prints filename and linenumber
234: */
235: error(msg,arg)
236: char *msg,*arg;{
237:
238: /*ROB
239: fprintf(stderr,"At line %d in file %s: ",fileline,filename);
240: fprintf(stderr,msg,arg);
241: */
242: }
243:
244: /*
245: ** blnk - space n lines (to new page if necessary, cf spc)
246: */
247: blnk(n)
248: short n;{
249: register short i;
250:
251: linebreak();
252: while(n > 0){
253: if(lineno > env.bottom){
254: pfoot();
255: lineno = 0;
256: }
257: if(lineno == 0)
258: phead();
259: i = min(n,env.bottom + 1 - lineno);
260: skip(i);
261: n -= i;
262: lineno += i;
263: }
264: if(lineno > env.bottom)
265: pfoot();
266: }
267:
268: /*
269: ** linebreak - end current filled line
270: */
271: linebreak(){
272:
273: if(outp != outbuf){
274: *outp++ = '\n';
275: *outp = '\0';
276: put(outbuf);
277: }
278: outp = outbuf;
279: outw = 0;
280: outwds = 0;
281: }
282:
283: /*
284: ** centre - centre a line by setting tival
285: */
286: center(buf)
287: char *buf;{
288: short width();
289:
290: env.tival = max((env.llval + env.tival - width(buf))/2,0);
291: }
292:
293: /*
294: ** cmd - perform formatting command
295: */
296: cmd(buf,file)
297: char *buf;
298: FILE *file;{
299: enum cmdnum comtyp(),ct;
300: register short spval,val;
301: short macnum;
302: char argtyp;
303: short getval(),set();
304: char *gettl();
305:
306: if(echodir)
307: putdir(buf);
308: ct = comtyp(buf,&macnum);
309: val = 0;
310: val = getval(buf,&argtyp);
311: switch(ct){
312: case SPA:
313: spval = set(0,val,argtyp,1,0,HUGE);
314: spc(spval);
315: break;
316: case IND:
317: case INX:
318: if(ct == IND)
319: linebreak();
320: env.inval = set(env.inval,val,argtyp,0,0,env.llval - 1);
321: env.tival = env.inval;
322: break;
323: case TMI:
324: linebreak();
325: env.tival = set(env.tival,val,argtyp,0,0,env.llval);
326: break;
327: case CEN:
328: linebreak();
329: env.ceval = set(env.ceval,val,argtyp,1,0,HUGE);
330: break;
331: case UDL:
332: env.ulval = set(env.ulval,val,argtyp,0,1,HUGE);
333: break;
334: case FIL:
335: linebreak();
336: env.fill = YES;
337: break;
338: case NFL:
339: linebreak();
340: env.fill = NO;
341: break;
342: case BRE:
343: linebreak();
344: break;
345: case BLN:
346: env.blval = set(env.blval,val,argtyp,1,0,HUGE);
347: blnk(env.blval);
348: env.blval = 0;
349: break;
350: case NED:
351: if(val > env.bottom - lineno + 1)
352: spc(HUGE);
353: break;
354: case LNS:
355: env.lsval = set(env.lsval,val,argtyp,1,1,HUGE);
356: break;
357: case LNL:
358: env.llval = set(env.llval,val,argtyp,PAGEWIDTH,env.tival + 1,HUGE);
359: break;
360: case PGL:
361: env.plval = set(env.plval,val,argtyp,PAGLEN,
362: env.m1val + env.m2val + env.m3val + env.m4val + 1,HUGE);
363: env.bottom = env.plval - env.m3val - env.m4val;
364: break;
365: case BPG:
366: if(lineno > 0)
367: spc(HUGE);
368: curpag = set(curpag,val,argtyp,curpag + 1, - HUGE,HUGE);
369: newpag = curpag;
370: break;
371: case HED:
372: env.evenhdr = env.oddhdr = gettl(buf);
373: break;
374: case FOT:
375: env.evenftr = env.oddftr = gettl(buf);
376: break;
377: case EHD:
378: env.evenhdr = gettl(buf);
379: break;
380: case EFO:
381: env.evenftr = gettl(buf);
382: break;
383: case OHD:
384: env.oddhdr = gettl(buf);
385: break;
386: case OFO:
387: env.oddftr = gettl(buf);
388: break;
389: case NAD:
390: env.adjust = NO;
391: break;
392: case ADJ:
393: env.adjust = YES;
394: break;
395: case ROM:
396: env.numtyp = ROMAN;
397: break;
398: case ARA:
399: env.numtyp = ARABIC;
400: break;
401: case LIT:
402: env.litval = set(env.litval,val,argtyp,1,0,HUGE);
403: break;
404: case M1:
405: env.m1val = set(env.m1val,val,argtyp,M1DEF,
406: 0,env.plval - (env.m2val + env.m3val + env.m4val + 1));
407: break;
408: case M2:
409: env.m2val = set(env.m2val,val,argtyp,M2DEF,
410: 0,env.plval - (env.m1val + env.m3val + env.m4val + 1));
411: break;
412: case M3:
413: env.m3val = set(env.m3val,val,argtyp,M3DEF,
414: 0,env.plval - (env.m1val + env.m2val + env.m4val + 1));
415: env.bottom = env.plval - env.m3val - env.m4val;
416: break;
417: case M4:
418: env.m4val = set(env.m4val,val,argtyp,M4DEF,
419: 0,env.plval - (env.m1val + env.m2val + env.m3val + 1));
420: env.bottom = env.plval - env.m3val - env.m4val;
421: break;
422: case CMC:
423: if(argtyp != '\n')
424: env.comchr = argtyp;
425: else
426: env.comchr = COMMAND;
427: break;
428: case POF:
429: env.poval = set(env.poval,val,argtyp,0,0,PAPERSIZE);
430: break;
431: case SKP:
432: env.skpval = set(env.skpval,val,argtyp,1,0,HUGE);
433: break;
434: case DFN:
435: getmac(buf,file);
436: break;
437: case TCH:
438: if(argtyp != '\n')
439: env.tabchr = argtyp;
440: else
441: env.tabchr = '\t';
442: break;
443: case TCL:
444: tabcol(buf);
445: break;
446: case UBC:
447: if(argtyp != '\n')
448: env.ubchr = argtyp;
449: else
450: env.ubchr = ' ';
451: break;
452: case RNV:
453: if(val <= 0)
454: val = 1;
455: resenv(val);
456: break;
457: case SNV:
458: savenv();
459: break;
460: case MAC:
461: expand(macnum);
462: break;
463: case UNKNOWN:
464: error("Unrecognised directive:\n%s",buf);
465: return;
466: }
467: }
468:
469: /*
470: ** comtyp - decode command type
471: */
472: enum cmdnum comtyp(buf,macnum)
473: char *buf;
474: short *macnum;{
475: register char a,b;
476: register struct cmdents *p;
477: register char *q;
478: register short l,h,m;
479:
480: a = buf[1];
481: b = buf[2];
482: for(l = 0, h = (sizeof(builtins)/sizeof(builtins[0])) - 1; l <= h; ){
483: p = &builtins[m = (l + h) / 2];
484: if(a < p->cmdname[0] || a <= p->cmdname[0] && b < p->cmdname[1])
485: h = m - 1;
486: else if(a > p->cmdname[0] || a <= p->cmdname[0] && b > p->cmdname[1])
487: l = m + 1;
488: else
489: break;
490: }
491: if(l <= h && p->notredefd)
492: return((enum cmdnum)m);
493: for(l = maccnt - 1; l >= 0; l--){
494: q = macros[l].macnam;
495: if(a == *q++ && b == *q){
496: *macnum = l;
497: return(MAC);
498: }
499: }
500: return(UNKNOWN);
501: }
502:
503: /*
504: ** expand - pushback macro definition onto input
505: */
506: expand(macnum)
507: short macnum;{
508: register struct linelink *lp;
509:
510: for(lp = macros[macnum].macend; lp != NULL; lp = lp->lastline){
511: if(pblev > MAXPB){
512: error("Not enough pushback space\n",CHARNULL);
513: break; /* to catch stack overflow */
514: }
515: pbptr[pblev] = lp->lineptr;
516: pblev++;
517: }
518: }
519:
520: /*
521: ** getmac - collect macro
522: */
523: getmac(buf,file)
524: char *buf;
525: FILE *file;{
526: register char *p;
527: register struct macro *mp;
528: register struct linelink *lp;
529: register short dotlev;
530: enum cmdnum ct;
531: short macnum;
532: char line[MAXIN];
533: enum cmdnum comtyp();
534: char *strcpy();
535: char *malloc();
536:
537: skipnbl(buf);
538: skipbl(buf);
539: if(*buf == '\n'){
540: error("Missing macro name\n",CHARNULL);
541: return;
542: }
543: if(maccnt >= MAXMAC){
544: error("Too many macro definitions",CHARNULL);
545: return;
546: }
547: mp = ¯os[maccnt];
548: p = mp->macnam;
549: if((ct = comtyp(buf - 1,&macnum)) != UNKNOWN && ct != MAC)
550: builtins[(int)ct].notredefd = NO;
551: *p++ = *buf++; /* record name */
552: *p++ = *buf++;
553: *p = '\0';
554: mp->macend = NULL;
555: dotlev = 1;
556: do{
557: if((p = ngetl(line,file)) == CHARNULL)
558: break; /* unexpected EOF */
559: ++fileline;
560: if(*p++ == env.comchr){
561: if(*p == '.')
562: dotlev--;
563: else if(comtyp(line,&macnum) == DFN)
564: dotlev++; /* included .de */
565: }
566: if(dotlev > 0){
567: if((lp = (struct linelink *)malloc((unsigned)sizeof(*mp->macend))) == NULL){
568: error(nomem,CHARNULL);
569: break;
570: }
571: lp->lastline = mp->macend;
572: mp->macend = lp;
573: if((lp->lineptr = malloc((unsigned)(strlen(line) + 1))) == NULL){
574: error(nomem,CHARNULL);
575: break;
576: }
577: strcpy(lp->lineptr,line);
578: }
579: }while(dotlev > 0);
580: maccnt++;
581: }
582:
583: /*
584: ** getseg - puts out part of header
585: */
586: char *getseg(buf,copy,copyend,term,pageno)
587: char *buf,*copy,*copyend,term;
588: short pageno;{
589: register short i;
590: register char *p;
591: short itorom();
592:
593: p = buf;
594: for( ;copy != copyend && *p != term && *p != '\0' && *p != '\n'; p++){
595: if(*p == PAGENUM){
596: if(env.numtyp == ARABIC){
597: sprintf(copy, "%d", pageno);
598: i=strlen(copy);
599: }
600: else
601: i = itorom(pageno,copy,min(MAXCHARS,(short)(copyend - copy)));
602: copy += i;
603: }
604: else
605: *copy++ = *p;
606: }
607: if(*p == term)
608: p++;
609: *copy = '\0';
610: return(p);
611: }
612:
613: /*
614: ** gettl - copy title from buf to ttl
615: */
616: char *gettl(buf)
617: char *buf;{
618: register char *p,*q;
619: char *strcpy();
620: char *malloc();
621:
622: p = buf;
623: skipnbl(p);
624: skipbl(p); /* find argument */
625: if((q = malloc((unsigned)(strlen(p) + 1))) == NULL){
626: error(nomem,CHARNULL);
627: return(q);
628: }
629: strcpy(q,p);
630: return(q);
631: }
632:
633: /*
634: ** getval - evaluate optional numeric argument
635: */
636: short getval(buf,argtyp)
637: char *buf;
638: char *argtyp;{
639: int atoi();
640:
641: skipnbl(buf);
642: skipbl(buf); /* find argument */
643: *argtyp = *buf;
644: if(!isdigit(*buf))
645: buf++;
646: return(atoi(buf));
647: }
648:
649: /*
650: ** getwrd - get a non - blank word from instr(i) to out, increment i
651: */
652: char *getwrd(instr,out)
653: char *instr,*out;{
654: register char c;
655: register char *p,*q;
656:
657: p = instr;
658: q = out;
659: while((*p == ' ' || *p == '\t') && *p != env.tabchr)
660: p++;
661: instr = p;
662: if(*p == env.tabchr)
663: *q++ = *p;
664: else{
665: while((c = *p) != '\0' && c != ' ' && c != '\t'
666: && c != '\n' && c != env.tabchr){
667: *q++ = *p++;
668: }
669: }
670: *q = '\0';
671: return(p == instr ? NULL : p);
672: }
673:
674: /*
675: ** itorom - converts integer to roman numerals
676: */
677: short itorom(num,str,flen)
678: char *str;
679: short num,flen;{
680: register short i,j;
681: char *p;
682: static short romval[] = { 1000,500,100,50,10,5,1,0 };
683: static short reltab[] = { 2,1,2,1,2,1,1,0 };
684: static char romlet[] = "mdclxvi0";
685:
686: p = str;
687: if(num < 0 && flen > 1){
688: num = -num;
689: *p++ = '-';
690: }
691: for(i = 0; num > 0; i++){
692: while(num >= romval[i]){
693: num -= romval[i];
694: *p++ = romlet[i];
695: }
696: j = i + reltab[i];
697: if(num >= (romval[i] - romval[j])){
698: num -= (romval[i] - romval[j]);
699: *p++ = romlet[j];
700: *p++ = romlet[i];
701: }
702: }
703: *p = '\0';
704: return((short)(p - str));
705: }
706:
707: /*
708: ** leadbl - delete leading blanks, set tival
709: */
710: leadbl(buf)
711: char *buf;{
712: register char *p;
713:
714: linebreak();
715: p = buf;
716: skipnbl(buf);
717: if(*buf != '\n')
718: env.tival = (buf - p);
719: while(*buf != '\0') /* move line to left */
720: *p++ = *buf++;
721: *p = '\0';
722: }
723:
724: /*
725: ** nextab - returns position of next tab stop
726: */
727: short nextab(pos)
728: short pos;{
729: register short i,k;
730:
731: for(i = 0; i < MAXTABS; i++){
732: if(env.tabpos[i] == 0)
733: break;
734: if(env.tabpos[i] > pos){
735: k = env.tabpos[i];
736: return(k);
737: }
738: }
739: k = pos + 1;
740: return(k);
741: }
742:
743: /*
744: ** ngetl - gets line from input or pushback buffer
745: */
746: char *ngetl(buf,file)
747: char *buf;
748: FILE *file;{
749: char *fgets();
750: char *strcpy();
751:
752: if(pblev <= 0)
753: return(fgets(buf,MAXIN,file));
754: else{
755: pblev--;
756: strcpy(buf,pbptr[pblev]);
757: }
758: return(buf);
759: }
760:
761: /*
762: ** pfoot - put out page footer
763: */
764: pfoot(){
765:
766: skip(env.m3val);
767: if(env.m4val > 0){
768: puttl(curpag % 2 ? env.oddftr : env.evenftr, curpag);
769: skip(env.m4val - 1);
770: }
771: }
772:
773: /*
774: ** phead - put out page header
775: */
776: phead(){
777:
778: curpag = newpag;
779: newpag++;
780: if(env.m1val > 0){
781: skip(env.m1val - 1);
782: puttl(curpag % 2 ? env.oddhdr : env.evenhdr, curpag);
783: }
784: skip(env.m2val);
785: lineno = env.m1val + env.m2val + 1;
786: }
787:
788: /*
789: ** put - put out line with proper spacing and indenting
790: */
791: put(buf)
792: char *buf;{
793: short nextab();
794: register char c;
795: register short col,i;
796:
797: if(lineno == 0 || lineno > env.bottom)
798: phead();
799: for(i = (env.tival + env.poval); i--; )
800: putchar(' ');
801: col = env.tival;
802: env.tival = env.inval;
803: for(; (c = *buf) != '\0'; buf++){
804: if(c == env.ubchr)
805: c = ' '; /* put blanks instead of blank replacement */
806: if(c == env.tabchr){
807: i = nextab(col); /* nextab wants last used column */
808: for(; col < i; col++)
809: putchar(' ');
810: continue;
811: }
812: else if(c == '\b')
813: col--;
814: else
815: col++;
816: putchar(c);
817: }
818: skip(min(env.lsval - 1,env.bottom - lineno));
819: lineno += env.lsval;
820: if(lineno > env.bottom){
821: pfoot();
822: if(env.skpval > 0)
823: skpage(env.skpval);
824: env.skpval = 0;
825: }
826: }
827:
828: /*
829: ** putdir - output a directive
830: */
831: putdir(buf)
832: char *buf;{
833:
834: fprintf(stderr,"%.10s",buf); /* first 10 chars */
835: }
836:
837: /*
838: ** puttl - put out title line with optional page number
839: */
840: puttl(buf,pageno)
841: char *buf;
842: short pageno;{
843: char copy[MAXOUT],term;
844: char *getseg();
845: register char *p;
846: register short i,col,newcol;
847:
848: for(i = env.poval; i--; )
849: putchar(' ');
850: term = *buf;
851: if(term == '\n'){
852: putchar('\n');
853: return;
854: }
855: col = 1;
856: p = buf + 1;
857: p = getseg(p,copy,©[MAXOUT],term,pageno);
858: printf("%s", copy);
859: col += strlen(copy);
860: buf = p;
861: p = getseg(p,copy,©[MAXOUT],term,pageno);
862: newcol = (env.llval - strlen(copy))/2 + 1; /* start of centre */
863: for(; col < newcol; col++)
864: putchar(' ');
865: printf("%s", copy);
866: col += strlen(copy);
867: p = getseg(p,copy,©[MAXOUT],term,pageno);
868: newcol = env.llval - strlen(copy) + 1; /* start of right */
869: for(; col < newcol; col++)
870: putchar(' ');
871: printf("%s",copy);
872: putchar('\n');
873: }
874:
875: /*
876: ** putwrd - put a word in outbuf; includes margin justification
877: */
878: putwrd(wrdbuf)
879: char *wrdbuf;{
880: char *strcpy();
881: register short l,w,lnval,nextra;
882: short width(), nextab();
883: int strlen();
884:
885: lnval = env.llval - env.tival;
886: if(*wrdbuf == env.tabchr){
887: outw = nextab(outw + env.tival) - env.tival;
888: /* because outw floats from the indent */
889: /* and nextab is absolute */
890: if(outp != outbuf && outw > lnval){
891: linebreak();
892: outw = nextab(outw + env.tival) - env.tival;
893: }
894: *++outp = env.tabchr;
895: outwds = 0; /* adjust from next word */
896: }
897: else{
898: w = width(wrdbuf);
899: l = strlen(wrdbuf);
900: if(outp != outbuf && (outw + w > lnval || /* too big */
901: (char *)(outp + l) >= &outbuf[MAXOUT])){
902: --outp; /* we put in a blank earlier */
903: if(env.adjust == YES){
904: nextra = lnval - outw + 1;
905: spread(outp,nextra,outwds);
906: outp += nextra;
907: }
908: linebreak(); /* flush previous line */
909: }
910: strcpy(outp,wrdbuf);
911: outp += l;
912: *outp++ = ' '; /* blank between words */
913: outw += w + 1; /* 1 for blank */
914: outwds++;
915: }
916: }
917:
918: /*
919: ** resenv - restore environment n levels back
920: */
921: resenv(n)
922: short n;{
923: register struct envir *ep,*tp;
924:
925: linebreak(); /* to flush any latent output */
926: for(ep = curenv; ep != NULL && --n > 0; free(tp))
927: ep = (tp = ep)->lastenv;
928: if(ep != NULL){
929: env = *ep;
930: curenv = ep->lastenv;
931: free(ep);
932: }
933: }
934:
935: /*
936: ** savenv - keep environment for later restoration
937: */
938: savenv(){
939: register struct envir *ep;
940:
941: if((ep = (struct envir *)malloc((unsigned)sizeof(env))) == NULL){
942: error(nomem,CHARNULL);
943: return;
944: }
945: *ep = env; /* structure copy */
946: ep->lastenv = curenv;
947: curenv = ep;
948: }
949:
950: /*
951: ** set - set parameter and check range
952: */
953: short set(param,val,argtyp,defval,minval,maxval)
954: short param,val,defval,minval,maxval;
955: char argtyp;{
956:
957: switch(argtyp){
958: case '\n':
959: param = defval;
960: break;
961: case '+':
962: param = param + val;
963: break;
964: case '-':
965: param = param - val;
966: break;
967: default:
968: param = val;
969: }
970: param = min(param,maxval);
971: param = max(param,minval);
972: return(param);
973: }
974:
975: /*
976: ** skip - output n blank lines
977: */
978: skip(n)
979: short n;{
980:
981: while(n-- > 0)
982: putchar('\n');
983: }
984:
985: /*
986: ** skpage - skip n pages
987: */
988: skpage(n)
989: short n;{
990:
991: while(n-- > 0){
992: phead();
993: skip(env.bottom + 1 - lineno);
994: lineno = env.bottom + 1;
995: pfoot();
996: }
997: }
998:
999: /*
1000: ** spc - space n lines or to bottom of page (cf blnk)
1001: */
1002: spc(n)
1003: short n;{
1004:
1005: linebreak();
1006: if(lineno > env.bottom)
1007: return;
1008: if(lineno == 0)
1009: phead();
1010: skip(min(n,env.bottom + 1 - lineno));
1011: lineno += n;
1012: if(lineno > env.bottom){
1013: pfoot();
1014: if(env.skpval > 0)
1015: skpage(env.skpval);
1016: env.skpval = 0;
1017: }
1018: }
1019:
1020: /*
1021: ** spread - spread words to justify right margin
1022: */
1023: spread(ptr,nextra,nwrds)
1024: char *ptr;
1025: short nextra,nwrds;{
1026: register char *p,*q;
1027: register short nb,nholes;
1028: static short dir = 0;
1029:
1030: if(nextra <= 0 || nwrds <= 1)
1031: return;
1032: dir = !dir; /* reverse previous direction */
1033: nholes = nwrds - 1;
1034: p = ptr - 1;
1035: q = ptr + nextra;
1036: *q-- = '\0';
1037: while(p < q){
1038: if((*q = *p) == ' '){
1039: nb = dir ? (nextra - 1) / nholes + 1 :
1040: nextra / nholes;
1041: nextra -= nb;
1042: nholes--;
1043: while(nb-- > 0){
1044: *--q = ' ';
1045: }
1046: }
1047: p--;
1048: q--;
1049: }
1050: }
1051:
1052: /*
1053: ** tabcol - enters pseudotab stops, checking validity
1054: */
1055: tabcol(buf)
1056: char *buf;{
1057: int atoi();
1058: register short tp,incr,val;
1059:
1060: for(tp = 0; tp < MAXTABS - 1; tp++){
1061: skipnbl(buf);
1062: skipbl(buf);
1063: if(*buf == '\n')
1064: break; /* end of list */
1065: incr = *buf++ == '+' ? YES : NO;
1066: val = atoi(buf);
1067: if(incr == YES && tp > 1) /* relative tab */
1068: val = env.tabpos[tp - 1] + val;
1069: env.tabpos[tp] = val;
1070: if(val < 0 || (tp > 1 && val < env.tabpos[tp - 1]))
1071: tp--;
1072: }
1073: env.tabpos[tp] = 0; /* end of list */
1074: }
1075:
1076: /*
1077: ** text - process text lines
1078: */
1079: text(inbuf)
1080: char *inbuf;{
1081: register char *p;
1082: char wrdbuf[MAXIN];
1083: char *getwrd();
1084:
1085: if(env.litval > 0){
1086: put(inbuf);
1087: env.litval--;
1088: return;
1089: }
1090: if(*inbuf == ' ' || *inbuf == '\n')
1091: leadbl(inbuf); /* move left, set tival */
1092: if(env.ulval > 0){ /* underlining */
1093: underl(inbuf,wrdbuf,&wrdbuf[MAXIN]);
1094: env.ulval--;
1095: }
1096: if(env.ceval > 0){ /* centering */
1097: center(inbuf);
1098: put(inbuf);
1099: env.ceval--;
1100: }
1101: else if(*inbuf == '\n') /* all blank line */
1102: put(inbuf);
1103: else if(env.fill == NO) /* unfilled text */
1104: put(inbuf);
1105: else
1106: for(p = inbuf; (p = getwrd(p,wrdbuf)) != NULL;)
1107: putwrd(wrdbuf);
1108: }
1109:
1110: /*
1111: ** underl - underline a line
1112: */
1113: underl(buf,tbuf,tend)
1114: char *buf,*tbuf,*tend;{
1115: register char c;
1116: register char *p,*q;
1117: char *strcpy();
1118:
1119: p = buf;
1120: q = tbuf;
1121: while(*p != '\n' && q < tend){
1122: if(isalnum(c = *p++)){
1123: *q++ = '_';
1124: *q++ = '\b';
1125: }
1126: *q++ = c;
1127: }
1128: *q++ = '\n';
1129: *q = '\0';
1130: strcpy(buf,tbuf); /* copy it back to buf */
1131: }
1132:
1133: /*
1134: ** width - compute width of character string
1135: */
1136: short width(buf)
1137: char *buf;{
1138: register short i;
1139: register char c;
1140:
1141: for(i = 0; (c = *buf) != '\0'; buf++){
1142: if(c == '\b')
1143: i--;
1144: else if(c != '\n')
1145: i++;
1146: }
1147: return(i);
1148: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.