home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 304_01 / roff52.c < prev    next >
Text File  |  1990-02-14  |  15KB  |  536 lines

  1. /********************************************************/
  2. /*         ROFF5, Version 2.00            */
  3. /*    (c) 1983,4,8,9 by Ernest E. Bergmann        */
  4. /*    730 Seneca Street, Bethlehem, Pa. 18015        */
  5. /*                            */
  6. /* Permission is hereby granted for all commercial and    */
  7. /* non-commercial reproduction and distribution of this    */
  8. /* material provided this notice is included.        */
  9. /********************************************************/
  10. #include <roff5.h>
  11. #if (VERSION!=2) || (subVERSION!=00)
  12. #error ***************This is version 2.00******************
  13. #endif
  14. /************************************************/
  15. /* insert() takes the .DS command line in LINE    */
  16. /* and uses malloc() to make an ENTRY in SLINK    */
  17. /************************************************/
  18. void insert()
  19. {ARGs a; int i;
  20. ENTRY *pe;
  21. char *pc,*pc2,*fnd;
  22. unsigned siz; ENTRY *where;
  23. char buff[128];
  24. pe=(ENTRY *)buff;
  25. pe->link=SLINK.link;
  26. pc=(char *)&(pe->ident);
  27. i = process(&a);
  28. if (i<1) {fprintf(stderr,".ds has no name\n");
  29.       LIN=LINE; LINE[0]='\0';
  30.       return;
  31.      }
  32.  
  33. pc2 = a.arg[1];
  34. transfer(&pc2,&pc,'\0');
  35. pc2 = a.arg[2];
  36. transfer(&pc2,&pc,'\0');
  37. fnd=find2(pe->ident,&SLINK);
  38. if(fnd)
  39.   {fprintf(stderr,"%cWarning: <%s> was defined to be <%s>\n",
  40.         BELL, pe->ident ,fnd);
  41.    fprintf(stderr,"...now it is defined to be <%s>\n",a.arg[2]);
  42.   }
  43. siz = pc - buff;
  44. if (NULL==(where=(ENTRY *)malloc(siz))) exitm("insert(): cannot malloc\n");
  45. SLINK.link = (ENTRY *)memcpy(where,buff,siz);
  46. }
  47. /****************************************/
  48. void showit()    /* displays the list of entries in the string
  49.         substitution table pointed to by SLINK. */
  50. {ENTRY *pe;
  51. char *pc;
  52. fprintf(stderr,"ENTRIES:\n");
  53. pe=SLINK.link;
  54. while(pe)
  55.     {fprintf(stderr,"%u: ",(unsigned)pe);
  56.     pc=(char *)&(pe->ident);
  57.     fprintf(stderr,"<%s>",pc);
  58.     pc += strlen(pc); pc++;
  59.     if(*pc) fprintf(stderr," <%s>\n",pc);
  60.     else fprintf(stderr," <>\n"); /*'C' bug*/
  61.     pe=pe->link;
  62.     }
  63. dashes();
  64. }
  65. /****************************************/
  66. void putback(char c)    /*cf K & P, p256*/
  67. {if(++BINP >= BBSIZ) exitm("Too many characters pushed back\n");
  68. BACKBUF[BINP]=c;
  69. }
  70. /*****************************/
  71. /*filters \r followed by \n; */
  72. /* msb if kgetc(),getc()     */
  73. /*****************************/
  74. int ngetc(FILE *iobuf)    /*cf K & P p256*/
  75. {int c;
  76. if(BINP) c=BACKBUF[BINP];
  77. else {if(KEYBD)     c=kgetc();
  78.       else       c=getc(iobuf);
  79.       if (c=='\n') INPUTlns++;
  80.       if (c== EOF) BACKBUF[BINP=1]=CPMEOF;
  81.       else { c&=0x7f; BACKBUF[BINP=1]=c; }
  82.       }
  83. BINP--;
  84. if (c==CPMEOF) return(EOF);
  85. if (c==EOF)    return(EOF);
  86. if(c=='\r')
  87.     {c=ngetc(iobuf);
  88.      if(c!='\n') {putback(c); return('\r');    }
  89.     }
  90. return(c);
  91. }
  92. /****************************************/
  93. int kgetc()    /*like getc(),from keyboard, line-buffered*/
  94. {int i;
  95. if(!*KPTR)
  96.     {fprintf(stderr,"%c",KEYBD);
  97.     if((gets(KLINE)) == NULL) return EOF;
  98.     i=strlen(KLINE);
  99.     KLINE[i++]='\n';
  100.     KLINE[i]='\0';
  101.     KPTR=KLINE;
  102.     }
  103. return(*(KPTR++));
  104. }
  105. /****************************************/
  106. void pbstr(char s[LSZ])    /*put back string on input;cf K&P,p257*/
  107. {int i;
  108. for(i=strlen(s);i>0;) putback(s[--i]);
  109. }
  110. /*************************************/
  111. unsigned char PatchName[5]=".\376\376\n";
  112. unsigned char PN[3]="\376\376";
  113. /************************************/
  114. void apatch(char *s) /* appends PatchName-- to string s */
  115. {strcat(s,PatchName);
  116.  PN[0]=PatchName[1];
  117.  PN[1]=PatchName[2];
  118.  PatchName[2]--;
  119.  if (PatchName[2]< (unsigned char)'\200')
  120.     {PatchName[2]='\376';PatchName[1]--;}
  121. }
  122. /****************************************/
  123. void showm(int mode)    /*lists macro definitions*/
  124. /*mode 0 is most complete; mode 1 line counts;*/
  125. {ENTRY *pe;
  126. char *pc,c;
  127. if((mode<0)||(mode>1)) mode=1;
  128. fprintf(stderr,"MACROS DEFINED:\n");
  129. pe=MLINK.link;
  130. while(pe)
  131.     {pc = (char *)&(pe->ident);
  132.     if(*pc=='\177')
  133.      {DENTRY *pd=(DENTRY *)pe;
  134.       fprintf(stderr,"[%p diversion]\ dl=%d, dn=%d",(unsigned)pd,/*???*/
  135.                    pd->dl,pd->dn);
  136.       if((pd->dt)>0) fprintf(stderr,", .dt %d %s",
  137.                     pd->dt,pd->dtname);
  138.       fprintf(stderr,"\n\n");
  139.      }
  140.     else
  141.      {fprintf(stderr,"%p  .%s\n",(unsigned)pe,pc);
  142.       pc +=strlen(pc); pc++;
  143.       if(mode)
  144.         {int cnt=0;
  145.          ENTRY *pe2;
  146.          while(NULL!=(c=*(pc++))) if (c=='\n') cnt++;
  147.          while(pe2=pe->link,pc=(char *)pe2->ident,
  148.             (unsigned) *pc >'\177')
  149.             {pe=pe2; if(!pe) break;
  150.              cnt--; pc +=strlen(pc)+1;
  151.              while(NULL!=(c=*(pc++))) if (c=='\n') cnt++;
  152.             }
  153.          fprintf(stderr,"%d lines\n",cnt);
  154.         }
  155.       else fprintf(stderr,"%s\n",pc);
  156.      }
  157.       pe = pe->link;
  158.     }
  159. dashes();
  160. }
  161. /****************************************/
  162. char *macq1(char *line)    /*looks up name to see if it is a macro
  163.             definition.  If it is, returns the
  164.             corresponding string, else returns
  165.             FALSE.
  166.             */
  167. {char c,*pc,wb[LSZ];
  168. pc=wb;
  169. while(class(c=*(line++))==BLACK) *(pc++)=c;
  170. *pc='\0';
  171. return(find2(wb,&MLINK));
  172. }
  173. /****************************************/
  174. char *find2(char *s,ENTRY *LINK)    /*finds or doesn't find s in table
  175.             of substitutions pointed to by link*/
  176. {char *pc;
  177. if(*s=='\0') return(NULL);
  178. while(LINK)
  179.     {if(!strcmp(s,(char *)&(LINK->ident)))
  180.         {pc=(char *)&(LINK->ident);
  181.         pc += strlen(pc);
  182.         pc++;
  183.         return(pc);
  184.         }
  185.     LINK = LINK->link;
  186.     }
  187. return(FALSE);
  188. }
  189. /**********************************************/
  190. ENTRY *find(char *s, ENTRY *LINK)
  191. {if(*s=='\0') return(NULL);
  192.  while (LINK)
  193.     {if(!strcmp(s,(char *)&(LINK->ident))) return(LINK);
  194.      LINK=LINK->link;
  195.     }
  196.  return(NULL);
  197. }
  198. /****************************************/
  199. ENTRY *mpatch(char *name,ENTRY *LINK) /*returns FALSE or ->patched name*/
  200. {ENTRY *found,*foundmore;
  201. char c,*pc;
  202. found=find(name,LINK);
  203. if(!found) return(FALSE);
  204. for(foundmore=found;foundmore;)
  205.     {foundmore = found->link;
  206.      c = *(foundmore->ident);
  207.      if(foundmore &&((unsigned char)c > '\177')) found=found->link;
  208.      else   foundmore = FALSE;
  209.     }
  210. pc = found->ident;
  211. pc += strlen(pc)+1;
  212. apatch(pc);
  213. return(found);
  214. }
  215. /**********************************************/
  216. /* mappend() takes a .DE or .AM and following */
  217. /* lines and places the information in MLIST. */
  218. /* If .de (or .am with no prior definition),  */
  219. /* then new entry at heast of list.  If .am,  */
  220. /* then places entry after prior defintion.   */
  221. /* Now uses malloc() to get space for entries.*/
  222. /* Modified to have space for append and ends */
  223. /* with .;;                      */
  224. /**********************************************/
  225. #define MBUF 1000    /*used to fix the max size of mappend()'s buffer*/
  226. /*************************************/
  227. void mappend(CMD cmd)
  228. {char c, *pc,*pc2;
  229. ENTRY *pe;
  230. unsigned siz; ENTRY *where, *prev, *next, *found;
  231. char C1=';';
  232. char C2=';';
  233. char buff[MBUF+5];
  234. /*pass over command and following white space*/
  235. for(pc=LIN,c=*pc; (c!=' ')&&(c!='\n')&&(c!='\t'); pc++)
  236.     c=*pc;
  237. for(; (c==' ')||(c=='\t'); pc++) c=*pc;
  238. if(c=='\n') {fprintf(stderr,".de or .am is UNnamed\n");
  239.          LIN=LINE; LINE[0]='\0';
  240.          return;
  241.         }
  242. else    {pe=(ENTRY *)buff;
  243.     pe->link = MLINK.link;
  244.     pc2=(char *)&(pe->ident);
  245.     while(class(c)==BLACK)
  246.         {*(pc2++)=c;
  247.         c=*(pc++);
  248.         }
  249.     }
  250. *(pc2++)='\0';
  251. if (cmd==DE) found=FALSE;
  252. else found=mpatch(pe->ident,&MLINK);
  253. if (found) /*then should use patched name, location*/
  254.    {prev = found;
  255.     pe->link = found->link;
  256.     pc2 = (char *)&(pe->ident);
  257.     *(pc2++)=PN[0]; *(pc2++)=PN[1]; *(pc2++)='\0';
  258.     siz = pc2-buff+4;
  259.    }
  260. else prev=&MLINK;
  261. while(fgets3())    /*until EOF or MSDOSEOF*/
  262.     {pc=LIN;
  263.      if((*LIN==COMMAND)&&(LIN[1]==C1)&&(LIN[2]==C2)) break;
  264.      siz += strlen(LIN);
  265.      if (siz>=MBUF) /* then need to start new append */
  266.         {*(pc2++)='\0';
  267.          siz = pc2 - buff + 4;
  268.          apatch(pc2-1);
  269.          if (NULL==(where=(ENTRY *)malloc(siz)))
  270.             exitm("mappend(): cannot malloc\n");
  271.          next=prev->link;
  272.          prev->link = (ENTRY *)memcpy(where,buff,siz);
  273.          prev = prev->link;
  274.          siz = sizeof(ENTRY)+3+strlen(LIN);
  275.          pe->link = next;
  276.          pc2 = (char *)&(pe->ident);
  277.          *(pc2++)=PN[0]; *(pc2++)=PN[1]; *(pc2++)='\0';
  278.         }
  279.     transfer(&pc,&pc2,0);
  280.     *(pc2-1)='\n';
  281.     }
  282. *(pc2++)='\0';
  283. siz = pc2 - buff + 4;
  284. if (NULL==(where=(ENTRY *)malloc(siz))) exitm("mappend(): cannot malloc\n");
  285. prev->link = (ENTRY *)memcpy(where,buff,siz);
  286. }
  287. /**********************************************/
  288. ENTRY *findany(char *s)
  289. {ENTRY *fnd;
  290.  fnd=find(s,&MLINK);if(fnd) return(fnd);
  291.  fnd=find(s,&SLINK);if(fnd) return(fnd);
  292.  return(find(s,&RLINK));
  293. }
  294. /**********************************************/
  295. void rndef()
  296. {ARGs a; ENTRY *pe;
  297.  int identsiz, newsiz, i;
  298.  i = process(&a);
  299.  if(i<2)
  300.     {fprintf(stderr,"2 args needed for .RN\n");
  301.      LIN=LINE; LINE[0]='\0';
  302.      return;
  303.     }
  304.  identsiz=strlen(a.arg[1]);
  305.  newsiz = strlen(a.arg[2]);
  306.  if(identsiz!=newsiz)
  307.     {fprintf(stderr,"replacement name should be same length for .RN\n");
  308.      LIN=LINE; LINE[0]='\0';
  309.      return;
  310.     }
  311.  pe=findany(a.arg[1]);
  312.  if (pe) strcpy( (char *)&(pe->ident), a.arg[2] );
  313.  else fprintf(stderr,"<%s> not found for .RN\n",a.arg[1]);
  314. }
  315. /**********************************/
  316. /* returns NULL if s not found,   */
  317. /* otherwise returns ->ENTRY found*/
  318. /**********************************/
  319. ENTRY *find0(char *s, ENTRY *LINK)
  320. {ENTRY * LINK2;
  321.  if(!LINK) return(NULL);
  322.  if(*s=='\0') return(NULL);
  323.  while(LINK->link)
  324.     {LINK2=LINK->link;
  325.      if(!strcmp(s,(char *)&(LINK2->ident))) return(LINK);
  326.      LINK = LINK2;
  327.     }
  328.  return(NULL);
  329. }
  330. /**********************************************/
  331. ENTRY *find0any(char *s)
  332. {ENTRY *fnd;
  333.  fnd=find0(s,&MLINK);if(fnd) return(fnd);
  334.  fnd=find0(s,&SLINK);if(fnd) return(fnd);
  335.  return(find0(s,&RLINK));
  336. }
  337. /**********************************************/
  338. int RMRPT;    /*global for rm1(),remdef()*/
  339. /****************/
  340. int rm1(char *id) /* removes one definition; returns NULL if not found */
  341. {ENTRY *prev, *curr, *next;
  342.  char c;
  343.  if((*id=='?')&&(id[1]=='\0')) return(RMRPT=TRUE);
  344.  prev = find0any(id);
  345.  if(!prev) return(NULL);
  346.  do {curr = prev->link;
  347.      next = curr->link;
  348.      prev->link=next;
  349.      free(curr);
  350.      c = *(next->ident);
  351.     }
  352.  while(next&&((unsigned char)c >= '\177'));
  353.  return(-1);
  354. }
  355. /**********************************************/
  356. void rmdef()
  357. {int num,i;
  358.  ARGs a;
  359.  RMRPT=FALSE;
  360.  num = process(&a);
  361.  if(num==0)
  362.     {fprintf(stderr,".RM given no args.\n");
  363.      LIN=LINE; LINE[0]='\0';
  364.      return;
  365.     }
  366.  for(i=1;i<=num;i++)
  367.     if(!rm1(a.arg[i]))
  368.         if(RMRPT)
  369.         fprintf(stderr,"<%s> not found for .rm\n",
  370.                     a.arg[i]);
  371. }
  372. /**********************************************/
  373. /* dappend() with divert() and enddiv() takes */
  374. /* a .DI or .DA and following processed lines */
  375. /* and places the information in MLIST.          */
  376. /* If .di (or .da with no prior definition),  */
  377. /* then new entry at head of list.  If .da,   */
  378. /* then places entry after prior definition.  */
  379. /* Now uses malloc() to get space for entries.*/
  380. /* Modified to have space for append and ends */
  381. /* with .;;                      */
  382. /**********************************************/
  383. int DWIDTH=0;    /* max OUTW during current or last diversion */
  384. char DNAME[FNAMSIZ]=""; /*name of current or last diversion*/
  385. char Dbuff[MBUF+5];
  386. unsigned Dsiz;
  387. char *Dpc2;
  388. ENTRY *Dprev,*Dpe;
  389. DENTRY *Dstats; /*init by dappend; updated by enddiv() */
  390. int Di,Di2,Dp1,Dp2,Dp3; /*used to update DWIDTH; cf. strlen4()*/
  391. /**********************************************/
  392. void dappend(CMD cmd)
  393. {char c, *pc;
  394.  ENTRY *found;
  395.  /* similar to start of mappend() */
  396. /*pass over command and following white space*/
  397. for(pc=LIN,c=*pc; (c!=' ')&&(c!='\n')&&(c!='\t'); pc++)
  398.     c=*pc;
  399. for(; (c==' ')||(c=='\t'); pc++) c=*pc;
  400. if(c=='\n')
  401.     if(DIVERTING) {enddiv(); return;}
  402.     else {fprintf(stderr,".de or .am is UNnamed\n");
  403.           LIN=LINE; LINE[0]='\0';
  404.           return;
  405.          }
  406. else   {if(DIVERTING)
  407.         {fprintf(stderr,"Cannot nest diversions; <%s> ignored.\n",
  408.             LIN);
  409.          LIN=LINE; LINE[0]='\0';
  410.          return;
  411.         }
  412.     Dpe=(ENTRY *)Dbuff;
  413.     Dpc2=(char *)&(Dpe->ident);
  414.     while(class(c)==BLACK)
  415.         {*(Dpc2++)=c;
  416.         c=*(pc++);
  417.         }
  418.     }
  419. *(Dpc2++)='\0';
  420. strcpy(DNAME,Dpe->ident);
  421. if (cmd==DI) found=FALSE;
  422. else found=mpatch(Dpe->ident,&MLINK);
  423. if (found) /*then should use patched name, location*/
  424.    {Dprev = found;
  425.     Dpe->link = found->link;
  426.     Dpc2 = (char *)&(Dpe->ident);
  427.     *(Dpc2++)=PN[0]; *(Dpc2++)=PN[1]; *(Dpc2++)='\0';
  428.     Dsiz = Dpc2-Dbuff+4;
  429.     Dstats=found->link;
  430.     DLINES=Dstats->dn;
  431.     DWIDTH=Dstats->dl;
  432.    }
  433. else
  434.    {DENTRY *dentry;
  435.     if (NULL==(dentry=(DENTRY *)malloc(sizeof(DENTRY))))
  436.     exitm("dappend(): cannot malloc\n");
  437.     dentry->ident[0]='\177';dentry->ident[1]='\0';
  438.     dentry->dl=0;
  439.     dentry->dn=0;
  440.     dentry->dt=NO_VAL;
  441.     dentry->dtname[0]='\0';
  442.     dentry->link=MLINK.link;
  443.     MLINK.link=Dstats=dentry;
  444.     Dpe->link = MLINK.link;
  445.     Dprev=&MLINK;
  446.     DLINES=0;
  447.     DWIDTH=0;
  448.     Di=Di2=Dp3=Dp2=Dp1=0;
  449.    }
  450. DIVERTING=TRUE;
  451. }
  452. /**********************************************/
  453. void divert(char *line)
  454. {char *pc,c;
  455.  ENTRY *where,*next;
  456.  pc=line;
  457.  Dsiz += strlen(LIN);
  458.  if (Dsiz>=MBUF) /* then need to start new append */
  459.     {*(Dpc2++)='\0';
  460.      Dsiz = Dpc2 - Dbuff + 4;
  461.      apatch(Dpc2-1);
  462.      if (NULL==(where=(ENTRY *)malloc(Dsiz)))
  463.         exitm("divert(): cannot malloc\n");
  464.      next = Dprev->link;
  465.      Dprev->link = (ENTRY *)memcpy(where,Dbuff,Dsiz);
  466.      Dprev = Dprev->link;
  467.      Dsiz = sizeof(ENTRY)+4+strlen(line);
  468.      Dpe->link = next;
  469.      Dpc2 = (char *)&(Dpe->ident);
  470.      *(Dpc2++)=PN[0]; *(Dpc2++)=PN[1]; *(Dpc2++)='\0';
  471.      Di=Di2=Dp3=Dp2=Dp1=0;
  472.     }
  473. while(*pc)
  474.     {c = *(Dpc2++) = *(pc++);
  475.      if(c=='\n')
  476.         {if(Di2>Di) Di=Di2;
  477.          if(Di>DWIDTH) DWIDTH = Di;
  478.          Di=Di2=Dp3=Dp2=Dp1=0;
  479.         }
  480.      else if((c!=TFVAL[0])&&(c!=CFVAL[0])) Di++;
  481.      else if(c==CFVAL[0])
  482.            {c = *(Dpc2++) = *(pc++);
  483.         if(!c) break;
  484.         switch(c)
  485.         {case 'h':
  486.         case 'H':if(Di>Di2) Di2=Di;
  487.              if(Di) Di--;
  488.             break;
  489.         case '(': Dp1=Di; break;
  490.         case '[': Dp2=Di; break;
  491.         case '{': Dp3=Di; break;
  492.         case ')': if(Di>Di2) Di2=Di; Di=Dp1; break;
  493.         case ']': if(Di>Di2) Di2=Di; Di=Dp2; break;
  494.         case '}': if(Di>Di2) Di2=Di; Di=Dp3; break;
  495.         default : break;
  496.         }}
  497.     }
  498. }
  499. /**********************************************/
  500. void enddiv()
  501. {ENTRY *where;
  502.  *(Dpc2++)='\0';
  503.  Dsiz = Dpc2 - Dbuff + 4;
  504.  if (NULL==(where=(ENTRY *)malloc(Dsiz))) exitm("enddiv(): cannot malloc\n");
  505.  Dprev->link = (ENTRY *)memcpy(where,Dbuff,Dsiz);
  506.  if(Di2>Di) Di=Di2;
  507.  if(Di>DWIDTH) DWIDTH = Di;
  508.  Dstats->dl=DWIDTH;
  509.  Dstats->dn=DLINES;
  510.  DIVERTING=FALSE;
  511. }
  512. /****************************************/
  513. void dtset()
  514. {char c,*lptr;
  515.  int *ip,save;
  516.  if(!DIVERTING)
  517.     {fprintf(stderr,"No current diversion; .dt ignored.\n");
  518.      LIN=LINE; LINE[0]='\0';
  519.      return;
  520.     }
  521.  ip=&(Dstats->dt);
  522.  *ip=get_val2(LIN,&c,&lptr);
  523.  if((*ip==NO_VAL)||(c=='-'))
  524.     {*ip=0;
  525.      Dstats->dtname[0]='\0';
  526.      return;
  527.     }
  528.  save=SENTENCE;
  529.  if(!getwrd(lptr,Dstats->dtname))
  530.     {Dstats->dtname[0]='\0';
  531.      *ip=0;
  532.     }
  533.  SENTENCE=save;
  534.  return;
  535. }
  536.