|
|
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.