[BACK]Return to util.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / texi2mdoc

Diff for /texi2mdoc/util.c between version 1.19 and 1.29

version 1.19, 2015/02/28 13:16:44 version 1.29, 2015/03/07 11:53:21
Line 20 
Line 20 
 #include <assert.h>  #include <assert.h>
 #include <ctype.h>  #include <ctype.h>
 #include <fcntl.h>  #include <fcntl.h>
 #include <getopt.h>  
 #include <libgen.h>  
 #include <limits.h>  #include <limits.h>
 #include <stdarg.h>  #include <stdarg.h>
 #include <stdio.h>  #include <stdio.h>
Line 33 
Line 31 
 #include "extern.h"  #include "extern.h"
   
 /*  /*
    * Table of macros.
    * These ABSOLUTELY MUST BE 2 or three characters long.
    */
   static  const char *const mdocs[] = {
           "Ap",           "Dd",           "Dt",           "Os",
           "Sh",           "Ss",           "Pp",           "D1",
           "Dl",           "Bd",           "Ed",           "Bl",
           "El",           "It",           "Ad",           "An",
           "Ar",           "Cd",           "Cm",           "Dv",
           "Er",           "Ev",           "Ex",           "Fa",
           "Fd",           "Fl",           "Fn",           "Ft",
           "Ic",           "In",           "Li",           "Nd",
           "Nm",           "Op",           "Ot",           "Pa",
           "Rv",           "St",           "Va",           "Vt",
           "Xr",           "%A",           "%B",           "%D",
           "%I",           "%J",           "%N",           "%O",
           "%P",           "%R",           "%T",           "%V",
           "Ac",           "Ao",           "Aq",           "At",
           "Bc",           "Bf",           "Bo",           "Bq",
           "Bsx",          "Bx",           "Db",           "Dc",
           "Do",           "Dq",           "Ec",           "Ef",
           "Em",           "Eo",           "Fx",           "Ms",
           "No",           "Ns",           "Nx",           "Ox",
           "Pc",           "Pf",           "Po",           "Pq",
           "Qc",           "Ql",           "Qo",           "Qq",
           "Re",           "Rs",           "Sc",           "So",
           "Sq",           "Sm",           "Sx",           "Sy",
           "Tn",           "Ux",           "Xc",           "Xo",
           "Fo",           "Fc",           "Oo",           "Oc",
           "Bk",           "Ek",           "Bt",           "Hf",
           "Fr",           "Ud",           "Lb",           "Lp",
           "Lk",           "Mt",           "Brq",          "Bro",
           "Brc",          "%C",           "Es",           "En",
           "Dx",           "%Q",           "br",           "sp",
           "%U",           "Ta",           "ll",           NULL,
           };
   
   /*
  * Unmap the top-most file in the stack of files currently opened (that   * Unmap the top-most file in the stack of files currently opened (that
  * is, nested calls to parsefile()).   * is, nested calls to parsefile()).
  */   */
Line 79  texiexit(struct texi *p)
Line 115  texiexit(struct texi *p)
   
         /* Make sure we're newline-terminated. */          /* Make sure we're newline-terminated. */
         if (p->outcol)          if (p->outcol)
                 putchar('\n');                  fputc('\n', p->outfile);
           if (NULL != p->chapters)
                   teximdocclose(p, 1);
   
         /* Unmap all files. */          /* Unmap all files. */
         while (p->filepos > 0)          while (p->filepos > 0)
Line 100  texiexit(struct texi *p)
Line 138  texiexit(struct texi *p)
         free(p->dirs);          free(p->dirs);
         free(p->subtitle);          free(p->subtitle);
         free(p->title);          free(p->title);
           free(p->copying);
 }  }
   
 /*  /*
Line 180  texiputchar(struct texi *p, char c)
Line 219  texiputchar(struct texi *p, char c)
         if (p->ign)          if (p->ign)
                 return;                  return;
         if ('.' == c && 0 == p->outcol)          if ('.' == c && 0 == p->outcol)
                 fputs("\\&", stdout);                  fputs("\\&", p->outfile);
         if ('\'' == c && 0 == p->outcol)          if ('\'' == c && 0 == p->outcol)
                 fputs("\\&", stdout);                  fputs("\\&", p->outfile);
   
         putchar(c);          if (p->uppercase)
                   fputc(toupper((unsigned int)c), p->outfile);
           else
                   fputc(c, p->outfile);
         if ('\\' == c)          if ('\\' == c)
                 putchar('e');                  fputc('e', p->outfile);
         p->seenvs = 0;  
         if ('\n' == c) {          if ('\n' == c) {
                 p->outcol = 0;                  p->outcol = 0;
                 p->seenws = 0;                  p->seenws = 0;
Line 207  texiputchars(struct texi *p, const char *s)
Line 248  texiputchars(struct texi *p, const char *s)
         if (p->ign)          if (p->ign)
                 return;                  return;
         if ('.' == *s && 0 == p->outcol)          if ('.' == *s && 0 == p->outcol)
                 fputs("\\&", stdout);                  fputs("\\&", p->outfile);
         if ('\'' == *s && 0 == p->outcol)          if ('\'' == *s && 0 == p->outcol)
                 fputs("\\&", stdout);                  fputs("\\&", p->outfile);
         p->outcol += fputs(s, stdout);          if (p->uppercase)
         p->seenvs = 0;                  for ( ; '\0' != *s; s++)
                           p->outcol += fputc(toupper
                                   ((unsigned int)*s), p->outfile);
           else
                   p->outcol += fputs(s, p->outfile);
 }  }
   
 /*  /*
Line 239  teximacroclose(struct texi *p)
Line 284  teximacroclose(struct texi *p)
                 return;                  return;
   
         if (0 == --p->outmacro) {          if (0 == --p->outmacro) {
                 putchar('\n');                  fputc('\n', p->outfile);
                 p->outcol = p->seenws = 0;                  p->outcol = p->seenws = 0;
         }          }
           p->seenvs = 0;
 }  }
   
 /*  /*
Line 259  teximacroopen(struct texi *p, const char *s)
Line 305  teximacroopen(struct texi *p, const char *s)
                 return;                  return;
   
         if (p->outcol && 0 == p->outmacro) {          if (p->outcol && 0 == p->outmacro) {
                 putchar('\n');                  fputc('\n', p->outfile);
                 p->outcol = 0;                  p->outcol = 0;
         }          }
   
         if (0 == p->outmacro)          if (0 == p->outmacro)
                 putchar('.');                  fputc('.', p->outfile);
         else          else
                 putchar(' ');                  fputc(' ', p->outfile);
   
         if (EOF != (rc = fputs(s, stdout)))          if (EOF != (rc = fputs(s, p->outfile)))
                 p->outcol += rc;                  p->outcol += rc;
   
         putchar(' ');          fputc(' ', p->outfile);
         p->outcol++;          p->outcol++;
         p->outmacro++;          p->outmacro++;
         p->seenws = 0;          p->seenws = 0;
           p->seenvs = 0;
 }  }
   
 /*  /*
Line 293  teximacro(struct texi *p, const char *s)
Line 340  teximacro(struct texi *p, const char *s)
                 texierr(p, "\"%s\" in a literal scope!?", s);                  texierr(p, "\"%s\" in a literal scope!?", s);
   
         if (p->outcol)          if (p->outcol)
                 putchar('\n');                  fputc('\n', p->outfile);
   
         putchar('.');          fputc('.', p->outfile);
         puts(s);          fputs(s, p->outfile);
           fputc('\n', p->outfile);
         p->outcol = p->seenws = 0;          p->outcol = p->seenws = 0;
           p->seenvs = 0;
 }  }
   
 /*  /*
Line 307  void
Line 356  void
 texivspace(struct texi *p)  texivspace(struct texi *p)
 {  {
   
         if (p->seenvs || TEXILIST_TABLE == p->list)          if (TEXILIST_TABLE != p->list)
                 return;                  teximacro(p, "Pp");
         teximacro(p, "Pp");  
         p->seenvs = 1;  
 }  }
   
 /*  /*
Line 361  texipunctuate(struct texi *p, size_t *pos)
Line 408  texipunctuate(struct texi *p, size_t *pos)
                 case ('.'):                  case ('.'):
                 case ('"'):                  case ('"'):
                 case (':'):                  case (':'):
                   case (';'):
                 case ('!'):                  case ('!'):
                 case ('?'):                  case ('?'):
                         continue;                          continue;
Line 400  advancenext(struct texi *p, size_t *pos)
Line 448  advancenext(struct texi *p, size_t *pos)
   
         while (*pos < BUFSZ(p) && ismspace(BUF(p)[*pos])) {          while (*pos < BUFSZ(p) && ismspace(BUF(p)[*pos])) {
                 p->seenws = 1;                  p->seenws = 1;
                 /*  
                  * If it looks like we've printed a double-line, then  
                  * output a paragraph.  
                  * FIXME: this is stupid.  
                  */  
                 if (*pos && '\n' == BUF(p)[*pos] && '\n' == BUF(p)[*pos - 1])  
                         texivspace(p);  
                 advance(p, pos);                  advance(p, pos);
         }          }
         return(*pos);          return(*pos);
Line 414  advancenext(struct texi *p, size_t *pos)
Line 455  advancenext(struct texi *p, size_t *pos)
   
 /*  /*
  * Advance to the EOLN in the input stream.   * Advance to the EOLN in the input stream.
  * NOTE: THIS SHOULD NOT BE CALLED ON BLANK TEXT, as it will read up to   * This will skip over '@' markers in an effort to ignore escaped
  * the @\n.   * newlines.
  */   */
 size_t  size_t
 advanceeoln(struct texi *p, size_t *pos, int consumenl)  advanceeoln(struct texi *p, size_t *pos, int consumenl)
 {  {
   
         while (*pos < BUFSZ(p) && '\n' != BUF(p)[*pos])          while (*pos < BUFSZ(p) && '\n' != BUF(p)[*pos]) {
                   if ('@' == BUF(p)[*pos])
                           advance(p, pos);
                 advance(p, pos);                  advance(p, pos);
           }
         if (*pos < BUFSZ(p) && consumenl)          if (*pos < BUFSZ(p) && consumenl)
                 advance(p, pos);                  advance(p, pos);
         return(*pos);          return(*pos);
Line 451  texiexecmacro(struct texi *p, struct teximacro *m, siz
Line 495  texiexecmacro(struct texi *p, struct teximacro *m, siz
         const char       *cp;          const char       *cp;
   
         /* Disregard empty macros. */          /* Disregard empty macros. */
         if (0 == (valsz = realsz = strlen(m->value)))          if (0 == (valsz = realsz = strlen(m->value))) {
                   args = argparse(p, pos, &asz, m->argsz);
                   for (i = 0; i < asz; i++)
                           free(args[i]);
                   free(args);
                 return;                  return;
           }
   
         /*          /*
          * This is important: it protect us from macros that invoke more           * This is important: it protect us from macros that invoke more
Line 462  texiexecmacro(struct texi *p, struct teximacro *m, siz
Line 511  texiexecmacro(struct texi *p, struct teximacro *m, siz
          * The "sv" value was initialised at the start of the macro.           * The "sv" value was initialised at the start of the macro.
          */           */
         if (sv > 0)          if (sv > 0)
                 if (++p->files[p->filepos].depth > 64)                  if (++p->files[p->filepos - 1].depth > 64)
                         texierr(p, "maximium recursive depth");                          texierr(p, "maximium recursive depth");
   
         args = argparse(p, pos, &asz, m->argsz);          args = argparse(p, pos, &asz, m->argsz);
Line 471  texiexecmacro(struct texi *p, struct teximacro *m, siz
Line 520  texiexecmacro(struct texi *p, struct teximacro *m, siz
         aasz = asz < m->argsz ? asz : m->argsz;          aasz = asz < m->argsz ? asz : m->argsz;
   
         if (0 == aasz) {          if (0 == aasz) {
                 texisplice(p, m->value, valsz, pos);                  texisplice(p, m->value, valsz, *pos);
                 return;                  return;
         }          }
   
Line 534  texiexecmacro(struct texi *p, struct teximacro *m, siz
Line 583  texiexecmacro(struct texi *p, struct teximacro *m, siz
                 i = end;                  i = end;
         }          }
   
         texisplice(p, val, strlen(val), pos);          texisplice(p, val, strlen(val), *pos);
   
         for (i = 0; i < asz; i++)          for (i = 0; i < asz; i++)
                 free(args[i]);                  free(args[i]);
Line 550  texiexecmacro(struct texi *p, struct teximacro *m, siz
Line 599  texiexecmacro(struct texi *p, struct teximacro *m, siz
 static void  static void
 parseword(struct texi *p, size_t *pos, char extra)  parseword(struct texi *p, size_t *pos, char extra)
 {  {
           size_t           i, end, len;
           int              c;
   
           /*
            * If a prior word had a terminating double-newline, then begin
            * this text block with a `Pp'.
            * We don't do this if we're in a literal context (we'll print
            * out the newlines themselves) nor in a `TS' table.
            */
           if (p->seenvs && 0 == p->literal && TEXILIST_TABLE != p->list)
                   teximacro(p, "Pp");
   
           p->seenvs = 0;
   
           /*
            * Some line control: if we (non-macro, non-literal) already
            * have more than 72 characters written to the screen, then
            * output a newline before getting started.
            */
         if (p->seenws && 0 == p->outmacro &&          if (p->seenws && 0 == p->outmacro &&
                  p->outcol > 72 && 0 == p->literal)                   p->outcol > 72 && 0 == p->literal)
                 texiputchar(p, '\n');                  texiputchar(p, '\n');
         /* FIXME: abstract this: we use it elsewhere. */  
           /* Usual padding in the case of seen whitespace. */
         if (p->seenws && p->outcol && 0 == p->literal)          if (p->seenws && p->outcol && 0 == p->literal)
                 texiputchar(p, ' ');                  texiputchar(p, ' ');
   
         p->seenws = 0;          p->seenws = 0;
   
           /*
            * If we're in a macro line, we might want to print text that
            * happens to be the same as an mdoc(7) macro.
            * Obviously, we need to escape these words.
            */
           if (p->outmacro) {
                   end = *pos;
                   /* Read ahead to get the word length. */
                   while (end < BUFSZ(p) && ! ismspace(BUF(p)[end])) {
                           switch ((c = BUF(p)[end])) {
                           case ('@'):
                           case ('}'):
                           case ('{'):
                                   break;
                           default:
                                   if ('\0' != extra && extra == c)
                                           break;
                                   end++;
                                   continue;
                           }
                           break;
                   }
                   len = end - *pos;
                   /* See if we have a match. */
                   for (i = 0; NULL != mdocs[i]; i++) {
                           /* All macros are 2 or three letters. */
                           if (len < 2 || len > 3)
                                   continue;
                           /* Check the macro word length. */
                           if ('\0' == mdocs[i][2] && 2 != len)
                                   continue;
                           else if ('\0' == mdocs[i][3] && 3 != len)
                                   continue;
                           if (strncmp(mdocs[i], &BUF(p)[*pos], len))
                                   continue;
                           texiputchars(p, "\\&");
                           break;
                   }
           }
   
         while (*pos < BUFSZ(p) && ! ismspace(BUF(p)[*pos])) {          while (*pos < BUFSZ(p) && ! ismspace(BUF(p)[*pos])) {
                 switch (BUF(p)[*pos]) {                  switch (BUF(p)[*pos]) {
                 case ('@'):                  case ('@'):
Line 569  parseword(struct texi *p, size_t *pos, char extra)
Line 677  parseword(struct texi *p, size_t *pos, char extra)
                 }                  }
                 if ('\0' != extra && BUF(p)[*pos] == extra)                  if ('\0' != extra && BUF(p)[*pos] == extra)
                         return;                          return;
                 if (*pos < BUFSZ(p) - 1 &&  
                   if (p->literal) {
                           texiputchar(p, BUF(p)[*pos]);
                           advance(p, pos);
                           continue;
                   }
   
                   if (*pos < BUFSZ(p) - 2 &&
                            '-' == BUF(p)[*pos] &&
                            '-' == BUF(p)[*pos + 1] &&
                            '-' == BUF(p)[*pos + 2]) {
                           texiputchars(p, "\\(em");
                           advance(p, pos);
                           advance(p, pos);
                   } else if (*pos < BUFSZ(p) - 1 &&
                            '-' == BUF(p)[*pos] &&
                            '-' == BUF(p)[*pos + 1]) {
                           texiputchars(p, "\\(en");
                           advance(p, pos);
                   } else if (*pos < BUFSZ(p) - 1 &&
                          '`' == BUF(p)[*pos] &&                           '`' == BUF(p)[*pos] &&
                          '`' == BUF(p)[*pos + 1]) {                           '`' == BUF(p)[*pos + 1]) {
                         texiputchars(p, "\\(lq");                          texiputchars(p, "\\(lq");
Line 581  parseword(struct texi *p, size_t *pos, char extra)
Line 708  parseword(struct texi *p, size_t *pos, char extra)
                         advance(p, pos);                          advance(p, pos);
                 } else                  } else
                         texiputchar(p, BUF(p)[*pos]);                          texiputchar(p, BUF(p)[*pos]);
   
                 advance(p, pos);                  advance(p, pos);
         }          }
   
           if (*pos + 1 < BUFSZ(p) &&
                   '\n' == BUF(p)[*pos] &&
                   '\n' == BUF(p)[*pos + 1])
                   p->seenvs = 1;
   
           /*
            * New sentence, new line:if we (non-macro, non-literal) see a
            * period at the end of the last printed word, then open a
            * newline.
            */
           if (0 == p->literal && 0 == p->outmacro &&
                   *pos < BUFSZ(p) && '.' == BUF(p)[*pos - 1])
                   texiputchar(p, '\n');
 }  }
   
 /*  /*
Line 606  texicmd(const struct texi *p, size_t pos, size_t *end,
Line 748  texicmd(const struct texi *p, size_t pos, size_t *end,
                 return(TEXICMD__MAX);                  return(TEXICMD__MAX);
   
         /* Alphabetic commands are special. */          /* Alphabetic commands are special. */
         if ( ! isalpha((unsigned char)BUF(p)[pos])) {          if ( ! isalpha((unsigned int)BUF(p)[pos])) {
                 if ((*end = pos + 1) == BUFSZ(p))                  if ((*end = pos + 1) == BUFSZ(p))
                         return(TEXICMD__MAX);                          return(TEXICMD__MAX);
                 for (i = 0; i < TEXICMD__MAX; i++) {                  for (i = 0; i < TEXICMD__MAX; i++) {
Line 926  parseeof(struct texi *p)
Line 1068  parseeof(struct texi *p)
 }  }
   
 void  void
 texisplice(struct texi *p, const char *buf, size_t sz, size_t *pos)  texisplice(struct texi *p, const char *buf, size_t sz, size_t pos)
 {  {
         char            *cp;          char            *cp;
         struct texifile *f;          struct texifile *f;
Line 943  texisplice(struct texi *p, const char *buf, size_t sz,
Line 1085  texisplice(struct texi *p, const char *buf, size_t sz,
         }          }
   
         f->insplice += sz;          f->insplice += sz;
         memmove(f->map + *pos + sz, f->map + *pos, f->mapsz - *pos);          memmove(f->map + pos + sz, f->map + pos, f->mapsz - pos);
         memcpy(f->map + *pos, buf, sz);          memcpy(f->map + pos, buf, sz);
         f->mapsz += sz;          f->mapsz += sz;
 }  }
   
Line 1348  argparse(struct texi *p, size_t *pos, size_t *argsz, s
Line 1490  argparse(struct texi *p, size_t *pos, size_t *argsz, s
         advance(p, pos);          advance(p, pos);
         return(args);          return(args);
 }  }
   
   /*
    * If we're printing chapters, then do some naviation here and then
    * close our outfile.
    * I want to call this the SEE ALSO section, but that's not really what
    * it is: we'll refer to the "initial" (top) node and the next and
    * previous chapters.
    */
   void
   teximdocclose(struct texi *p, int last)
   {
           char     buf[PATH_MAX];
   
           if (NULL == p->chapters || 0 == p->chapnum)
                   return;
   
           teximacro(p, "Sh INFO NAVIGATION");
   
           /* Print a reference to the "top" node. */
           if (p->chapnum > 1) {
                   texiputchars(p, "Top node,");
                   snprintf(buf, sizeof(buf), "node1 7");
                   teximacroopen(p, "Xr ");
                   texiputchars(p, buf);
                   texiputchars(p, " ;");
                   teximacroclose(p);
           }
   
           /* Print a reference to the previous node. */
           if (p->chapnum > 2) {
                   texiputchars(p, "previous node,");
                   snprintf(buf, sizeof(buf),
                           "node%zu 7", p->chapnum - 1);
                   teximacroopen(p, "Xr ");
                   texiputchars(p, buf);
                   if ( ! last)
                           texiputchars(p, " ;");
                   teximacroclose(p);
           }
   
           /* Print a reference to the next node. */
           if ( ! last) {
                   if (1 == p->chapnum)
                           texiputchars(p, "Next node,");
                   else
                           texiputchars(p, "next node,");
                   snprintf(buf, sizeof(buf),
                           "node%zu 7", p->chapnum + 1);
                   teximacroopen(p, "Xr ");
                   texiputchars(p, buf);
                   teximacroclose(p);
           }
   
           fclose(p->outfile);
   }
   
   /*
    * Open a mdoc(7) context.
    * If we're printing chapters, then open the outfile here, too.
    * Otherwise just print the mdoc(7) prologue.
    */
   void
   teximdocopen(struct texi *p, size_t *pos)
   {
           const char      *cp;
           time_t           t;
           char             date[32];
           char             fname[PATH_MAX];
   
           if (NULL != p->chapters) {
                   snprintf(fname, sizeof(fname), "%s/node%zu.7",
                           p->chapters, ++p->chapnum);
                   p->outfile = fopen(fname, "w");
                   if (NULL == p->outfile)
                           texiabort(p, fname);
           }
   
           /*
            * Here we print our standard mdoc(7) prologue.
            * We use the title set with @settitle for the `Nd' description
            * and the source document filename (the first one as invoked on
            * the command line) for the title.
            * The date is set to the current date.
            */
           t = time(NULL);
           strftime(date, sizeof(date), "%F", localtime(&t));
   
           teximacroopen(p, "Dd");
           texiputchars(p, date);
           teximacroclose(p);
           teximacroopen(p, "Dt");
           for (cp = p->title; '\0' != *cp; cp++)
                   texiputchar(p, toupper((unsigned int)*cp));
           texiputchars(p, " 7");
           teximacroclose(p);
           teximacro(p, "Os");
           teximacro(p, "Sh NAME");
           teximacroopen(p, "Nm");
           for (cp = p->title; '\0' != *cp; cp++)
                   texiputchar(p, *cp);
           teximacroclose(p);
           teximacroopen(p, "Nd");
           /*
            * The subtitle `Nd' can consist of arbitrary macros, so paste
            * it and parse to the end of the line.
            */
           if (NULL != p->subtitle) {
                   texisplice(p, p->subtitle, strlen(p->subtitle), *pos);
                   parseeoln(p, pos);
           } else
                   texiputchars(p, "Unknown description");
           teximacroclose(p);
   }
   

Legend:
Removed from v.1.19  
changed lines
  Added in v.1.29

CVSweb