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

Diff for /texi2mdoc/util.c between version 1.13 and 1.14

version 1.13, 2015/02/24 14:35:40 version 1.14, 2015/02/25 14:37:17
Line 43  texifilepop(struct texi *p)
Line 43  texifilepop(struct texi *p)
   
         assert(p->filepos > 0);          assert(p->filepos > 0);
         f = &p->files[--p->filepos];          f = &p->files[--p->filepos];
         if (TEXISRC_FILE == f->type)          free(f->map);
                 munmap(f->map, f->mapsz);  
         else  
                 free(f->map);  
 }  }
   
 static void  static void
Line 206  texiputchars(struct texi *p, const char *s)
Line 203  texiputchars(struct texi *p, const char *s)
 /*  /*
  * This puts all characters onto the output stream but makes sure to   * This puts all characters onto the output stream but makes sure to
  * escape mdoc(7) slashes.   * escape mdoc(7) slashes.
    * FIXME: useless.
  */   */
 void  void
 texiputbuf(struct texi *p, const char *buf, size_t start, size_t end)  texiputbuf(struct texi *p, size_t start, size_t end)
 {  {
   
         for ( ; start < end; start++) {          for ( ; start < end; start++)
                 texiputchar(p, buf[start]);                  texiputchar(p, BUF(p)[start]);
                 if ('\\' == buf[start])  
                         texiputchar(p, 'e');  
         }  
 }  }
   
 /*  /*
Line 309  texivspace(struct texi *p)
Line 304  texivspace(struct texi *p)
  * in the current input file.   * in the current input file.
  */   */
 void  void
 advance(struct texi *p, const char *buf, size_t *pos)  advance(struct texi *p, size_t *pos)
 {  {
   
         if ('\n' == buf[*pos]) {          if ('\n' == BUF(p)[*pos]) {
                 p->files[p->filepos - 1].line++;                  p->files[p->filepos - 1].line++;
                 p->files[p->filepos - 1].col = 0;                  p->files[p->filepos - 1].col = 0;
         } else          } else
Line 329  advance(struct texi *p, const char *buf, size_t *pos)
Line 324  advance(struct texi *p, const char *buf, size_t *pos)
  * appropriately flush-left punctuation alongside the macro.   * appropriately flush-left punctuation alongside the macro.
  */   */
 void  void
 texipunctuate(struct texi *p, const char *buf, size_t sz, size_t *pos)  texipunctuate(struct texi *p, size_t *pos)
 {  {
         size_t   start, end;          size_t   start, end;
   
         if (1 != p->outmacro)          if (1 != p->outmacro)
                 return;                  return;
   
         for (start = end = *pos; end < sz; end++) {          for (start = end = *pos; end < BUFSZ(p); end++) {
                 switch (buf[end]) {                  switch (BUF(p)[end]) {
                 case (','):                  case (','):
                 case (')'):                  case (')'):
                 case ('.'):                  case ('.'):
Line 353  texipunctuate(struct texi *p, const char *buf, size_t 
Line 348  texipunctuate(struct texi *p, const char *buf, size_t 
         }          }
         if (end == *pos)          if (end == *pos)
                 return;                  return;
         if (end + 1 == sz || ' ' == buf[end] || '\n' == buf[end]) {          if (end + 1 == BUFSZ(p) || ' ' == BUF(p)[end] ||
                   '\n' == BUF(p)[end]) {
                 for ( ; start < end; start++) {                  for ( ; start < end; start++) {
                         texiputchar(p, ' ');                          texiputchar(p, ' ');
                         texiputchar(p, buf[start]);                          texiputchar(p, BUF(p)[start]);
                         advance(p, buf, pos);                          advance(p, pos);
                 }                  }
         }          }
 }  }
Line 368  texipunctuate(struct texi *p, const char *buf, size_t 
Line 364  texipunctuate(struct texi *p, const char *buf, size_t 
  * doing so.   * doing so.
  */   */
 static size_t  static size_t
 advancenext(struct texi *p, const char *buf, size_t sz, size_t *pos)  advancenext(struct texi *p, size_t *pos)
 {  {
   
         if (p->literal) {          if (p->literal) {
                 while (*pos < sz && ismspace(buf[*pos])) {                  while (*pos < BUFSZ(p) && ismspace(BUF(p)[*pos])) {
                         texiputchar(p, buf[*pos]);                          texiputchar(p, BUF(p)[*pos]);
                         advance(p, buf, pos);                          advance(p, pos);
                 }                  }
                 return(*pos);                  return(*pos);
         }          }
   
         while (*pos < sz && ismspace(buf[*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                   * If it looks like we've printed a double-line, then
                  * output a paragraph.                   * output a paragraph.
                  * FIXME: this is stupid.                   * FIXME: this is stupid.
                  */                   */
                 if (*pos && '\n' == buf[*pos] && '\n' == buf[*pos - 1])                  if (*pos && '\n' == BUF(p)[*pos] && '\n' == BUF(p)[*pos - 1])
                         texivspace(p);                          texivspace(p);
                 advance(p, buf, pos);                  advance(p, pos);
         }          }
         return(*pos);          return(*pos);
 }  }
Line 399  advancenext(struct texi *p, const char *buf, size_t sz
Line 395  advancenext(struct texi *p, const char *buf, size_t sz
  * the @\n.   * the @\n.
  */   */
 size_t  size_t
 advanceeoln(struct texi *p, const char *buf,  advanceeoln(struct texi *p, size_t *pos, int consumenl)
         size_t sz, size_t *pos, int consumenl)  
 {  {
   
         while (*pos < sz && '\n' != buf[*pos])          while (*pos < BUFSZ(p) && '\n' != BUF(p)[*pos])
                 advance(p, buf, pos);                  advance(p, pos);
         if (*pos < sz && consumenl)          if (*pos < BUFSZ(p) && consumenl)
                 advance(p, buf, pos);                  advance(p, pos);
         return(*pos);          return(*pos);
 }  }
   
Line 415  advanceeoln(struct texi *p, const char *buf, 
Line 410  advanceeoln(struct texi *p, const char *buf, 
  * current buffer greater than or equal to the current position.   * current buffer greater than or equal to the current position.
  */   */
 void  void
 advanceto(struct texi *p, const char *buf, size_t *pos, size_t end)  advanceto(struct texi *p, size_t *pos, size_t end)
 {  {
   
         assert(*pos <= end);          assert(*pos <= end);
         while (*pos < end)          while (*pos < end)
                 advance(p, buf, pos);                  advance(p, pos);
 }  }
   
 static void  static void
 texiexecmacro(struct texi *p, struct teximacro *m,  texiexecmacro(struct texi *p, struct teximacro *m, size_t *pos)
         const char *buf, size_t sz, size_t *pos)  
 {  {
         size_t            valsz, realsz, aasz, asz,          size_t            valsz, realsz, aasz, asz,
                            ssz, i, j, k, start, end;                             ssz, i, j, k, start, end;
Line 433  texiexecmacro(struct texi *p, struct teximacro *m,
Line 427  texiexecmacro(struct texi *p, struct teximacro *m,
         char            **args;          char            **args;
         const char       *cp;          const char       *cp;
   
         args = argparse(p, buf, sz, pos, &asz, m->argsz);          args = argparse(p, pos, &asz, m->argsz);
         if (asz != m->argsz)          if (asz != m->argsz)
                 texiwarn(p, "invalid macro argument length");                  texiwarn(p, "invalid macro argument length");
         aasz = asz < m->argsz ? asz : m->argsz;          aasz = asz < m->argsz ? asz : m->argsz;
   
         if (0 == aasz) {          if (0 == aasz) {
                 parsemembuf(p, m->value, strlen(m->value));                  texisplice(p, m->value, strlen(m->value), pos);
                 return;                  return;
         }          }
   
Line 482  texiexecmacro(struct texi *p, struct teximacro *m,
Line 476  texiexecmacro(struct texi *p, struct teximacro *m,
   
                 /*                  /*
                  * Argument didn't exist in argument table.                   * Argument didn't exist in argument table.
                  * No need to reallocate here: we just copy the text                   * Just ignore it.
                  * directly from the macro value into the buffer.  
                  */                   */
                 if (k == aasz) {                  if (k == aasz) {
                         for ( ; i < end; i++)                          i = end;
                                 val[j++] = m->value[i];  
                         assert('\\' == m->value[i]);  
                         val[j++] = m->value[i];  
                         val[j] = '\0';  
                         continue;                          continue;
                 }                  }
   
Line 508  texiexecmacro(struct texi *p, struct teximacro *m,
Line 497  texiexecmacro(struct texi *p, struct teximacro *m,
                 i = end;                  i = end;
         }          }
   
         parsemembuf(p, val, strlen(val));          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 522  texiexecmacro(struct texi *p, struct teximacro *m,
Line 511  texiexecmacro(struct texi *p, struct teximacro *m,
  * This also will advance the input stream.   * This also will advance the input stream.
  */   */
 static void  static void
 texiword(struct texi *p, const char *buf,  parseword(struct texi *p, size_t *pos, char extra)
         size_t sz, size_t *pos, char extra)  
 {  {
   
         if (p->seenws && 0 == p->outmacro &&          if (p->seenws && 0 == p->outmacro &&
Line 535  texiword(struct texi *p, const char *buf, 
Line 523  texiword(struct texi *p, const char *buf, 
   
         p->seenws = 0;          p->seenws = 0;
   
         while (*pos < sz && ! ismspace(buf[*pos])) {          while (*pos < BUFSZ(p) && ! ismspace(BUF(p)[*pos])) {
                 switch (buf[*pos]) {                  switch (BUF(p)[*pos]) {
                 case ('@'):                  case ('@'):
                 case ('}'):                  case ('}'):
                 case ('{'):                  case ('{'):
                         return;                          return;
                 }                  }
                 if ('\0' != extra && buf[*pos] == extra)                  if ('\0' != extra && BUF(p)[*pos] == extra)
                         return;                          return;
                 if (*pos < sz - 1 &&                  if (*pos < BUFSZ(p) - 1 &&
                          '`' == buf[*pos] &&                           '`' == BUF(p)[*pos] &&
                          '`' == buf[*pos + 1]) {                           '`' == BUF(p)[*pos + 1]) {
                         texiputchars(p, "\\(lq");                          texiputchars(p, "\\(lq");
                         advance(p, buf, pos);                          advance(p, pos);
                 } else if (*pos < sz - 1 &&                  } else if (*pos < BUFSZ(p) - 1 &&
                          '\'' == buf[*pos] &&                           '\'' == BUF(p)[*pos] &&
                          '\'' == buf[*pos + 1]) {                           '\'' == BUF(p)[*pos + 1]) {
                         texiputchars(p, "\\(rq");                          texiputchars(p, "\\(rq");
                         advance(p, buf, pos);                          advance(p, pos);
                 } else                  } else
                         texiputchar(p, buf[*pos]);                          texiputchar(p, BUF(p)[*pos]);
                 advance(p, buf, pos);                  advance(p, pos);
         }          }
 }  }
   
Line 566  texiword(struct texi *p, const char *buf, 
Line 554  texiword(struct texi *p, const char *buf, 
  * index after the command name.   * index after the command name.
  */   */
 enum texicmd  enum texicmd
 texicmd(struct texi *p, const char *buf, size_t pos,  texicmd(struct texi *p, size_t pos, size_t *end, struct teximacro **macro)
         size_t sz, size_t *end, struct teximacro **macro)  
 {  {
         size_t   i, len, toksz;          size_t   i, len, toksz;
   
         assert('@' == buf[pos]);          assert('@' == BUF(p)[pos]);
   
         if (NULL != macro)          if (NULL != macro)
                 *macro = NULL;                  *macro = NULL;
   
         if ((*end = pos) == sz)          if ((*end = pos) == BUFSZ(p))
                 return(TEXICMD__MAX);                  return(TEXICMD__MAX);
         else if ((*end = ++pos) == sz)          else if ((*end = ++pos) == BUFSZ(p))
                 return(TEXICMD__MAX);                  return(TEXICMD__MAX);
   
         /* Alphabetic commands are special. */          /* Alphabetic commands are special. */
         if ( ! isalpha(buf[pos])) {          if ( ! isalpha(BUF(p)[pos])) {
                 if ((*end = pos + 1) == sz)                  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++) {
                         if (1 != texitoks[i].len)                          if (1 != texitoks[i].len)
                                 continue;                                  continue;
                         if (0 == strncmp(texitoks[i].tok, &buf[pos], 1))                          if (0 == strncmp(texitoks[i].tok, &BUF(p)[pos], 1))
                                 return(i);                                  return(i);
                 }                  }
                 texiwarn(p, "bad command: @%c", buf[pos]);                  texiwarn(p, "bad command: @%c", BUF(p)[pos]);
                 return(TEXICMD__MAX);                  return(TEXICMD__MAX);
         }          }
   
         /* Scan to the end of the possible command name. */          /* Scan to the end of the possible command name. */
         for (*end = pos; *end < sz && ! ismspace(buf[*end]); (*end)++)          for (*end = pos; *end < BUFSZ(p) && ! ismspace(BUF(p)[*end]); (*end)++)
                 if ((*end > pos && ('@' == buf[*end] ||                  if ((*end > pos && ('@' == BUF(p)[*end] ||
                           '{' == buf[*end] || '}' == buf[*end])))                            '{' == BUF(p)[*end] || '}' == BUF(p)[*end])))
                         break;                          break;
   
         /* Look for the command. */          /* Look for the command. */
Line 606  texicmd(struct texi *p, const char *buf, size_t pos, 
Line 593  texicmd(struct texi *p, const char *buf, size_t pos, 
         for (i = 0; i < TEXICMD__MAX; i++) {          for (i = 0; i < TEXICMD__MAX; i++) {
                 if (len != texitoks[i].len)                  if (len != texitoks[i].len)
                         continue;                          continue;
                 if (0 == strncmp(texitoks[i].tok, &buf[pos], len))                  if (0 == strncmp(texitoks[i].tok, &BUF(p)[pos], len))
                         return(i);                          return(i);
         }          }
   
Line 615  texicmd(struct texi *p, const char *buf, size_t pos, 
Line 602  texicmd(struct texi *p, const char *buf, size_t pos, 
                 toksz = strlen(p->indexs[i]);                  toksz = strlen(p->indexs[i]);
                 if (len != 5 + toksz)                  if (len != 5 + toksz)
                         continue;                          continue;
                 if (strncmp(&buf[pos], p->indexs[i], toksz))                  if (strncmp(&BUF(p)[pos], p->indexs[i], toksz))
                         continue;                          continue;
                 if (0 == strncmp(&buf[pos + toksz], "index", 5))                  if (0 == strncmp(&BUF(p)[pos + toksz], "index", 5))
                         return(TEXICMD_USER_INDEX);                          return(TEXICMD_USER_INDEX);
         }          }
   
         for (i = 0; i < p->macrosz; i++) {          for (i = 0; i < p->macrosz; i++) {
                 if (len != strlen(p->macros[i].key))                  if (len != strlen(p->macros[i].key))
                         continue;                          continue;
                 if (strncmp(&buf[pos], p->macros[i].key, len))                  if (strncmp(&BUF(p)[pos], p->macros[i].key, len))
                         continue;                          continue;
                 if (NULL != macro)                  if (NULL != macro)
                         *macro = &p->macros[i];                          *macro = &p->macros[i];
                 return(TEXICMD__MAX);                  return(TEXICMD__MAX);
         }          }
   
         texiwarn(p, "bad command: @%.*s", (int)len, &buf[pos]);          texiwarn(p, "bad command: @%.*s", (int)len, &BUF(p)[pos]);
         return(TEXICMD__MAX);          return(TEXICMD__MAX);
 }  }
   
Line 644  texicmd(struct texi *p, const char *buf, size_t pos, 
Line 631  texicmd(struct texi *p, const char *buf, size_t pos, 
  * bracket for the zeroth parse.   * bracket for the zeroth parse.
  */   */
 int  int
 parsearg(struct texi *p, const char *buf,  parsearg(struct texi *p, size_t *pos, size_t num)
         size_t sz, size_t *pos, size_t num)  
 {  {
         size_t            end;          size_t            end;
         enum texicmd      cmd;          enum texicmd      cmd;
         struct teximacro *macro;          struct teximacro *macro;
   
         while (*pos < sz && ismspace(buf[*pos]))          while (*pos < BUFSZ(p) && ismspace(BUF(p)[*pos]))
                 advance(p, buf, pos);                  advance(p, pos);
         if (*pos == sz || (0 == num && '{' != buf[*pos]))          if (*pos == BUFSZ(p) || (0 == num && '{' != BUF(p)[*pos]))
                 return(0);                  return(0);
         if (0 == num)          if (0 == num)
                 advance(p, buf, pos);                  advance(p, pos);
   
         while ((*pos = advancenext(p, buf, sz, pos)) < sz) {          while ((*pos = advancenext(p, pos)) < BUFSZ(p)) {
                 switch (buf[*pos]) {                  switch (BUF(p)[*pos]) {
                 case (','):                  case (','):
                         advance(p, buf, pos);                          advance(p, pos);
                         return(1);                          return(1);
                 case ('}'):                  case ('}'):
                         advance(p, buf, pos);                          advance(p, pos);
                         return(0);                          return(0);
                 case ('{'):                  case ('{'):
                         if (0 == p->ign)                          if (0 == p->ign)
                                 texiwarn(p, "unexpected \"{\"");                                  texiwarn(p, "unexpected \"{\"");
                         advance(p, buf, pos);                          advance(p, pos);
                         continue;                          continue;
                 case ('@'):                  case ('@'):
                         break;                          break;
                 default:                  default:
                         texiword(p, buf, sz, pos, ',');                          parseword(p, pos, ',');
                         continue;                          continue;
                 }                  }
   
                 cmd = texicmd(p, buf, *pos, sz, &end, &macro);                  cmd = texicmd(p, *pos, &end, &macro);
                 advanceto(p, buf, pos, end);                  advanceto(p, pos, end);
                 if (NULL != macro)                  if (NULL != macro)
                         texiexecmacro(p, macro, buf, sz, pos);                          texiexecmacro(p, macro, pos);
                 if (TEXICMD__MAX == cmd)                  if (TEXICMD__MAX == cmd)
                         continue;                          continue;
                 if (NULL != texitoks[cmd].fp)                  if (NULL != texitoks[cmd].fp)
                         (*texitoks[cmd].fp)(p, cmd, buf, sz, pos);                          (*texitoks[cmd].fp)(p, cmd, pos);
         }          }
         return(0);          return(0);
 }  }
Line 695  parsearg(struct texi *p, const char *buf, 
Line 681  parsearg(struct texi *p, const char *buf, 
  * This will stop in the event of EOF or if we're not at a bracket.   * This will stop in the event of EOF or if we're not at a bracket.
  */   */
 void  void
 parsebracket(struct texi *p, const char *buf, size_t sz, size_t *pos)  parsebracket(struct texi *p, size_t *pos)
 {  {
         size_t            end;          size_t            end;
         enum texicmd      cmd;          enum texicmd      cmd;
         struct teximacro *macro;          struct teximacro *macro;
   
         while (*pos < sz && ismspace(buf[*pos]))          while (*pos < BUFSZ(p) && ismspace(BUF(p)[*pos]))
                 advance(p, buf, pos);                  advance(p, pos);
   
         if (*pos == sz || '{' != buf[*pos])          if (*pos == BUFSZ(p) || '{' != BUF(p)[*pos])
                 return;                  return;
         advance(p, buf, pos);          advance(p, pos);
   
         while ((*pos = advancenext(p, buf, sz, pos)) < sz) {          while ((*pos = advancenext(p, pos)) < BUFSZ(p)) {
                 switch (buf[*pos]) {                  switch (BUF(p)[*pos]) {
                 case ('}'):                  case ('}'):
                         advance(p, buf, pos);                          advance(p, pos);
                         return;                          return;
                 case ('{'):                  case ('{'):
                         if (0 == p->ign)                          if (0 == p->ign)
                                 texiwarn(p, "unexpected \"{\"");                                  texiwarn(p, "unexpected \"{\"");
                         advance(p, buf, pos);                          advance(p, pos);
                         continue;                          continue;
                 case ('@'):                  case ('@'):
                         break;                          break;
                 default:                  default:
                         texiword(p, buf, sz, pos, '\0');                          parseword(p, pos, '\0');
                         continue;                          continue;
                 }                  }
   
                 cmd = texicmd(p, buf, *pos, sz, &end, &macro);                  cmd = texicmd(p, *pos, &end, &macro);
                 advanceto(p, buf, pos, end);                  advanceto(p, pos, end);
                 if (NULL != macro)                  if (NULL != macro)
                         texiexecmacro(p, macro, buf, sz, pos);                          texiexecmacro(p, macro, pos);
                 if (TEXICMD__MAX == cmd)                  if (TEXICMD__MAX == cmd)
                         continue;                          continue;
                 if (NULL != texitoks[cmd].fp)                  if (NULL != texitoks[cmd].fp)
                         (*texitoks[cmd].fp)(p, cmd, buf, sz, pos);                          (*texitoks[cmd].fp)(p, cmd, pos);
         }          }
 }  }
   
Line 742  parsebracket(struct texi *p, const char *buf, size_t s
Line 728  parsebracket(struct texi *p, const char *buf, size_t s
  * the way.   * the way.
  */   */
 void  void
 parseeoln(struct texi *p, const char *buf, size_t sz, size_t *pos)  parseeoln(struct texi *p, size_t *pos)
 {  {
         size_t            end;          size_t            end;
         enum texicmd      cmd;          enum texicmd      cmd;
         struct teximacro *macro;          struct teximacro *macro;
   
         while (*pos < sz && '\n' != buf[*pos]) {          while (*pos < BUFSZ(p) && '\n' != BUF(p)[*pos]) {
                 while (*pos < sz && isws(buf[*pos])) {                  while (*pos < BUFSZ(p) && isws(BUF(p)[*pos])) {
                         p->seenws = 1;                          p->seenws = 1;
                         if (p->literal)                          if (p->literal)
                                 texiputchar(p, buf[*pos]);                                  texiputchar(p, BUF(p)[*pos]);
                         advance(p, buf, pos);                          advance(p, pos);
                 }                  }
                 switch (buf[*pos]) {                  switch (BUF(p)[*pos]) {
                 case ('}'):                  case ('}'):
                         if (0 == p->ign)                          if (0 == p->ign)
                                 texiwarn(p, "unexpected \"}\"");                                  texiwarn(p, "unexpected \"}\"");
                         advance(p, buf, pos);                          advance(p, pos);
                         continue;                          continue;
                 case ('{'):                  case ('{'):
                         if (0 == p->ign)                          if (0 == p->ign)
                                 texiwarn(p, "unexpected \"{\"");                                  texiwarn(p, "unexpected \"{\"");
                         advance(p, buf, pos);                          advance(p, pos);
                         continue;                          continue;
                 case ('@'):                  case ('@'):
                         break;                          break;
                 default:                  default:
                         texiword(p, buf, sz, pos, '\0');                          parseword(p, pos, '\0');
                         continue;                          continue;
                 }                  }
   
                 cmd = texicmd(p, buf, *pos, sz, &end, &macro);                  cmd = texicmd(p, *pos, &end, &macro);
                 advanceto(p, buf, pos, end);                  advanceto(p, pos, end);
                 if (NULL != macro)                  if (NULL != macro)
                         texiexecmacro(p, macro, buf, sz, pos);                          texiexecmacro(p, macro, pos);
                 if (TEXICMD__MAX == cmd)                  if (TEXICMD__MAX == cmd)
                         continue;                          continue;
                 if (NULL != texitoks[cmd].fp)                  if (NULL != texitoks[cmd].fp)
                         (*texitoks[cmd].fp)(p, cmd, buf, sz, pos);                          (*texitoks[cmd].fp)(p, cmd, pos);
         }          }
   
           if (*pos < BUFSZ(p) && '\n' == BUF(p)[*pos])
                   advance(p, pos);
 }  }
   
 /*  /*
  * Parse a single word or command.   * Parse a single word or command.
  * This will return immediately at the EOF.   * This will return immediately at the EOF.
  */   */
 void  static void
 parsesingle(struct texi *p, const char *buf, size_t sz, size_t *pos)  parsesingle(struct texi *p, size_t *pos)
 {  {
         size_t            end;          size_t            end;
         enum texicmd      cmd;          enum texicmd      cmd;
         struct teximacro *macro;          struct teximacro *macro;
   
         if ((*pos = advancenext(p, buf, sz, pos)) >= sz)          if ((*pos = advancenext(p, pos)) >= BUFSZ(p))
                 return;                  return;
   
         switch (buf[*pos]) {          switch (BUF(p)[*pos]) {
         case ('}'):          case ('}'):
                 if (0 == p->ign)                  if (0 == p->ign)
                         texiwarn(p, "unexpected \"}\"");                          texiwarn(p, "unexpected \"}\"");
                 advance(p, buf, pos);                  advance(p, pos);
                 return;                  return;
         case ('{'):          case ('{'):
                 if (0 == p->ign)                  if (0 == p->ign)
                         texiwarn(p, "unexpected \"{\"");                          texiwarn(p, "unexpected \"{\"");
                 advance(p, buf, pos);                  advance(p, pos);
                 return;                  return;
         case ('@'):          case ('@'):
                 break;                  break;
         default:          default:
                 texiword(p, buf, sz, pos, '\0');                  parseword(p, pos, '\0');
                 return;                  return;
         }          }
   
         cmd = texicmd(p, buf, *pos, sz, &end, &macro);          cmd = texicmd(p, *pos, &end, &macro);
         advanceto(p, buf, pos, end);          advanceto(p, pos, end);
         if (NULL != macro)          if (NULL != macro)
                 texiexecmacro(p, macro, buf, sz, pos);                  texiexecmacro(p, macro, pos);
         if (TEXICMD__MAX == cmd)          if (TEXICMD__MAX == cmd)
                 return;                  return;
         if (NULL != texitoks[cmd].fp)          if (NULL != texitoks[cmd].fp)
                 (*texitoks[cmd].fp)(p, cmd, buf, sz, pos);                  (*texitoks[cmd].fp)(p, cmd, pos);
 }  }
   
 /*  /*
Line 835  parsesingle(struct texi *p, const char *buf, size_t sz
Line 824  parsesingle(struct texi *p, const char *buf, size_t sz
  * line or 1 otherwise.   * line or 1 otherwise.
  */   */
 int  int
 parselinearg(struct texi *p, const char *buf, size_t sz, size_t *pos)  parselinearg(struct texi *p, size_t *pos)
 {  {
   
         while (*pos < sz && isws(buf[*pos])) {          while (*pos < BUFSZ(p) && isws(BUF(p)[*pos])) {
                 p->seenws = 1;                  p->seenws = 1;
                 advance(p, buf, pos);                  advance(p, pos);
         }          }
   
         if (*pos < sz && '{' == buf[*pos])          if (*pos < BUFSZ(p) && '{' == BUF(p)[*pos])
                 parsebracket(p, buf, sz, pos);                  parsebracket(p, pos);
         else if (*pos < sz && '\n' != buf[*pos])          else if (*pos < BUFSZ(p) && '\n' != BUF(p)[*pos])
                 parsesingle(p, buf, sz, pos);                  parsesingle(p, pos);
         else          else
                 return(0);                  return(0);
   
Line 856  parselinearg(struct texi *p, const char *buf, size_t s
Line 845  parselinearg(struct texi *p, const char *buf, size_t s
 /*  /*
  * Parse til the end of the buffer.   * Parse til the end of the buffer.
  */   */
 void  static void
 parseeof(struct texi *p, const char *buf, size_t sz)  parseeof(struct texi *p)
 {  {
         size_t   pos;          size_t   pos;
   
         for (pos = 0; pos < sz; )          for (pos = 0; pos < BUFSZ(p); )
                 parsesingle(p, buf, sz, &pos);                  parsesingle(p, &pos);
 }  }
   
 /*  
  * This is like parseeof() except that it's to be invoked on memory  
  * buffers while parsing a larger scope.  
  * This is useful for parsing macro sequences.  
  * The line, column, and name of the calling file context are saved, the  
  * column and line reset, then all of these restored after parse.  
  */  
 void  void
 parsemembuf(struct texi *p, const char *buf, size_t sz)  texisplice(struct texi *p, const char *buf, size_t sz, size_t *pos)
 {  {
         size_t           svln, svcol;          char            *cp;
         const char      *svname;          struct texifile *f;
   
         svln = p->files[p->filepos - 1].line;          assert(p->filepos > 0);
         svcol = p->files[p->filepos - 1].col;          f = &p->files[p->filepos - 1];
         svname = p->files[p->filepos - 1].name;  
   
         p->files[p->filepos - 1].line = 0;          if (f->mapsz + sz > f->mapmaxsz) {
         p->files[p->filepos - 1].col = 0;                  f->mapmaxsz = f->mapsz + sz + 1024;
         p->files[p->filepos - 1].name = "<macro buffer>";                  cp = realloc(f->map, f->mapmaxsz);
                   if (NULL == cp)
                           texiabort(p, NULL);
                   f->map = cp;
           }
   
         parseeof(p, buf, sz);          memmove(f->map + *pos + sz, f->map + *pos, f->mapsz - *pos);
           memcpy(f->map + *pos, buf, sz);
         p->files[p->filepos - 1].line = svln;          f->mapsz += sz;
         p->files[p->filepos - 1].col = svcol;  
         p->files[p->filepos - 1].name = svname;  
 }  }
   
 /*  /*
Line 899  parsemembuf(struct texi *p, const char *buf, size_t sz
Line 882  parsemembuf(struct texi *p, const char *buf, size_t sz
  * This will return immediately at EOF.   * This will return immediately at EOF.
  */   */
 void  void
 parseto(struct texi *p, const char *buf,  parseto(struct texi *p, size_t *pos, const char *endtoken)
         size_t sz, size_t *pos, const char *endtoken)  
 {  {
         size_t            end;          size_t            end;
         enum texicmd      cmd;          enum texicmd      cmd;
Line 910  parseto(struct texi *p, const char *buf, 
Line 892  parseto(struct texi *p, const char *buf, 
         endtoksz = strlen(endtoken);          endtoksz = strlen(endtoken);
         assert(endtoksz > 0);          assert(endtoksz > 0);
   
         while ((*pos = advancenext(p, buf, sz, pos)) < sz) {          while ((*pos = advancenext(p, pos)) < BUFSZ(p)) {
                 switch (buf[*pos]) {                  switch (BUF(p)[*pos]) {
                 case ('}'):                  case ('}'):
                         if (0 == p->ign)                          if (0 == p->ign)
                                 texiwarn(p, "unexpected \"}\"");                                  texiwarn(p, "unexpected \"}\"");
                         advance(p, buf, pos);                          advance(p, pos);
                         continue;                          continue;
                 case ('{'):                  case ('{'):
                         if (0 == p->ign)                          if (0 == p->ign)
                                 texiwarn(p, "unexpected \"{\"");                                  texiwarn(p, "unexpected \"{\"");
                         advance(p, buf, pos);                          advance(p, pos);
                         continue;                          continue;
                 case ('@'):                  case ('@'):
                         break;                          break;
                 default:                  default:
                         texiword(p, buf, sz, pos, '\0');                          parseword(p, pos, '\0');
                         continue;                          continue;
                 }                  }
   
                 cmd = texicmd(p, buf, *pos, sz, &end, &macro);                  cmd = texicmd(p, *pos, &end, &macro);
                 advanceto(p, buf, pos, end);                  advanceto(p, pos, end);
                 if (TEXICMD_END == cmd) {                  if (TEXICMD_END == cmd) {
                         while (*pos < sz && isws(buf[*pos]))                          while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
                                 advance(p, buf, pos);                                  advance(p, pos);
                         /*                          /*
                          * FIXME: check the full word, not just its                           * FIXME: check the full word, not just its
                          * initial substring!                           * initial substring!
                          */                           */
                         if (sz - *pos >= endtoksz && 0 == strncmp                          if (BUFSZ(p) - *pos >= endtoksz && 0 == strncmp
                                  (&buf[*pos], endtoken, endtoksz)) {                                   (&BUF(p)[*pos], endtoken, endtoksz)) {
                                 advanceeoln(p, buf, sz, pos, 0);                                  advanceeoln(p, pos, 0);
                                 break;                                  break;
                         }                          }
                         if (0 == p->ign)                          if (0 == p->ign)
                                 texiwarn(p, "unexpected \"end\"");                                  texiwarn(p, "unexpected \"end\"");
                         advanceeoln(p, buf, sz, pos, 0);                          advanceeoln(p, pos, 0);
                         continue;                          continue;
                 }                  }
                 if (NULL != macro)                  if (NULL != macro)
                         texiexecmacro(p, macro, buf, sz, pos);                          texiexecmacro(p, macro, pos);
                 if (TEXICMD__MAX == cmd)                  if (TEXICMD__MAX == cmd)
                         continue;                          continue;
                 if (NULL != texitoks[cmd].fp)                  if (NULL != texitoks[cmd].fp)
                         (*texitoks[cmd].fp)(p, cmd, buf, sz, pos);                          (*texitoks[cmd].fp)(p, cmd, pos);
         }          }
 }  }
   
Line 965  void
Line 947  void
 parsestdin(struct texi *p)  parsestdin(struct texi *p)
 {  {
         struct texifile *f;          struct texifile *f;
         size_t           off;  
         ssize_t          ssz;          ssize_t          ssz;
   
         assert(0 == p->filepos);          assert(0 == p->filepos);
Line 975  parsestdin(struct texi *p)
Line 956  parsestdin(struct texi *p)
         f->type = TEXISRC_STDIN;          f->type = TEXISRC_STDIN;
         f->name = "<stdin>";          f->name = "<stdin>";
   
         for (off = 0; ; off += (size_t)ssz) {          for (f->mapsz = 0; ; f->mapsz += (size_t)ssz) {
                 if (off == f->mapsz) {                  if (f->mapsz == f->mapmaxsz) {
                         if (f->mapsz == (1U << 31))                          if (f->mapmaxsz == (1U << 31))
                                 texierr(p, "stdin buffer too long");                                  texierr(p, "stdin buffer too long");
                         f->mapsz = f->mapsz > 65536 / 2 ?                          f->mapmaxsz = f->mapmaxsz > 65536 / 2 ?
                                 2 * f->mapsz : 65536;                                  2 * f->mapmaxsz : 65536;
                         f->map = realloc(f->map, f->mapsz);                          f->map = realloc(f->map, f->mapmaxsz);
                         if (NULL == f->map)                          if (NULL == f->map)
                                 texiabort(p, NULL);                                  texiabort(p, NULL);
                 }                  }
                 ssz = read(STDIN_FILENO,                  ssz = read(STDIN_FILENO, f->map +
                         f->map + (int)off, f->mapsz - off);                          (int)f->mapsz, f->mapmaxsz - f->mapsz);
                 if (0 == ssz)                  if (0 == ssz)
                         break;                          break;
                 else if (-1 == ssz)                  else if (-1 == ssz)
Line 994  parsestdin(struct texi *p)
Line 975  parsestdin(struct texi *p)
         }          }
   
         p->filepos++;          p->filepos++;
         parseeof(p, f->map, off);          parseeof(p);
         texifilepop(p);          texifilepop(p);
 }  }
   
Line 1011  parsefile(struct texi *p, const char *fname, int parse
Line 992  parsefile(struct texi *p, const char *fname, int parse
         int              fd;          int              fd;
         struct stat      st;          struct stat      st;
         size_t           i;          size_t           i;
           char            *map;
   
         if (64 == p->filepos)          if (64 == p->filepos)
                 texierr(p, "too many open files");                  texierr(p, "too many open files");
Line 1026  parsefile(struct texi *p, const char *fname, int parse
Line 1008  parsefile(struct texi *p, const char *fname, int parse
                 texiabort(p, fname);                  texiabort(p, fname);
         }          }
   
         f->mapsz = st.st_size;          f->mapsz = f->mapmaxsz = st.st_size;
         f->map = mmap(NULL, f->mapsz,          map = mmap(NULL, f->mapsz,
                 PROT_READ, MAP_SHARED, fd, 0);                  PROT_READ, MAP_SHARED, fd, 0);
         close(fd);          close(fd);
   
         if (MAP_FAILED == f->map)          if (MAP_FAILED == map)
                 texiabort(p, fname);                  texiabort(p, fname);
   
         p->filepos++;  
         if ( ! parse) {          if ( ! parse) {
                 for (i = 0; i < f->mapsz; i++)                  for (i = 0; i < f->mapsz; i++)
                         texiputchar(p, f->map[i]);                          texiputchar(p, map[i]);
                 if (p->outcol)                  if (p->outcol)
                         texiputchar(p, '\n');                          texiputchar(p, '\n');
         } else                  munmap(map, f->mapsz);
                 parseeof(p, f->map, f->mapsz);                  return;
           }
   
           p->filepos++;
           f->map = malloc(f->mapsz);
           memcpy(f->map, map, f->mapsz);
           munmap(map, f->mapsz);
           parseeof(p);
         texifilepop(p);          texifilepop(p);
 }  }
   
Line 1053  parsefile(struct texi *p, const char *fname, int parse
Line 1041  parsefile(struct texi *p, const char *fname, int parse
  * The pointer can point to NULL if the value has been unset.   * The pointer can point to NULL if the value has been unset.
  */   */
 static char **  static char **
 valuequery(const struct texi *p,  valuequery(const struct texi *p, size_t start, size_t end)
         const char *buf, size_t start, size_t end)  
 {  {
         size_t   i, sz, len;          size_t   i, sz, len;
   
Line 1066  valuequery(const struct texi *p, 
Line 1053  valuequery(const struct texi *p, 
                 sz = strlen(p->vals[i].key);                  sz = strlen(p->vals[i].key);
                 if (sz != len)                  if (sz != len)
                         continue;                          continue;
                 if (0 == strncmp(p->vals[i].key, &buf[start], len))                  if (0 == strncmp(p->vals[i].key, &BUF(p)[start], len))
                         return(&p->vals[i].value);                          return(&p->vals[i].value);
         }          }
         return(NULL);          return(NULL);
Line 1077  valuequery(const struct texi *p, 
Line 1064  valuequery(const struct texi *p, 
  * pointer to its value via valuequery().   * pointer to its value via valuequery().
  */   */
 static char **  static char **
 valuelquery(struct texi *p, const char *buf, size_t sz, size_t *pos)  valuelquery(struct texi *p, size_t *pos)
 {  {
         size_t    start, end;          size_t    start, end;
         char    **ret;          char    **ret;
   
         while (*pos < sz && isws(buf[*pos]))          while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
                 advance(p, buf, pos);                  advance(p, pos);
         if (*pos == sz)          if (*pos == BUFSZ(p))
                 return(NULL);                  return(NULL);
         for (start = end = *pos; end < sz; end++)          for (start = end = *pos; end < BUFSZ(p); end++)
                 if ('\n' == buf[end])                  if ('\n' == BUF(p)[end])
                         break;                          break;
         advanceto(p, buf, pos, end);          advanceto(p, pos, end);
         if (*pos < sz) {          if (*pos < BUFSZ(p)) {
                 assert('\n' == buf[*pos]);                  assert('\n' == BUF(p)[*pos]);
                 advance(p, buf, pos);                  advance(p, pos);
         }          }
         if (NULL == (ret = valuequery(p, buf, start, end)))          if (NULL == (ret = valuequery(p, start, end)))
                 return(NULL);                  return(NULL);
         return(ret);          return(ret);
 }  }
   
 void  void
 valuelclear(struct texi *p, const char *buf, size_t sz, size_t *pos)  valuelclear(struct texi *p, size_t *pos)
 {  {
         char    **ret;          char    **ret;
   
         if (NULL == (ret = valuelquery(p, buf, sz, pos)))          if (NULL == (ret = valuelquery(p, pos)))
                 return;                  return;
         free(*ret);          free(*ret);
         *ret = NULL;          *ret = NULL;
 }  }
   
 const char *  const char *
 valuellookup(struct texi *p, const char *buf, size_t sz, size_t *pos)  valuellookup(struct texi *p, size_t *pos)
 {  {
         char    **ret;          char    **ret;
   
         if (NULL == (ret = valuelquery(p, buf, sz, pos)))          if (NULL == (ret = valuelquery(p, pos)))
                 return(NULL);                  return(NULL);
         return(*ret);          return(*ret);
 }  }
Line 1128  valuellookup(struct texi *p, const char *buf, size_t s
Line 1115  valuellookup(struct texi *p, const char *buf, size_t s
  * value had previously been unset.   * value had previously been unset.
  */   */
 const char *  const char *
 valueblookup(struct texi *p, const char *buf, size_t sz, size_t *pos)  valueblookup(struct texi *p, size_t *pos)
 {  {
         size_t    start, end;          size_t    start, end;
         char    **ret;          char    **ret;
   
         while (*pos < sz && isws(buf[*pos]))          while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
                 advance(p, buf, pos);                  advance(p, pos);
         if (*pos == sz || '{' != buf[*pos])          if (*pos == BUFSZ(p) || '{' != BUF(p)[*pos])
                 return(NULL);                  return(NULL);
         advance(p, buf, pos);          advance(p, pos);
         for (start = end = *pos; end < sz; end++)          for (start = end = *pos; end < BUFSZ(p); end++)
                 if ('}' == buf[end])                  if ('}' == BUF(p)[end])
                         break;                          break;
         advanceto(p, buf, pos, end);          advanceto(p, pos, end);
         if (*pos < sz) {          if (*pos < BUFSZ(p)) {
                 assert('}' == buf[*pos]);                  assert('}' == BUF(p)[*pos]);
                 advance(p, buf, pos);                  advance(p, pos);
         }          }
         if (NULL == (ret = valuequery(p, buf, start, end)))          if (NULL == (ret = valuequery(p, start, end)))
                 return(NULL);                  return(NULL);
         return(*ret);          return(*ret);
 }  }
Line 1190  valueadd(struct texi *p, char *key, char *val)
Line 1177  valueadd(struct texi *p, char *key, char *val)
  * Ergo, textual: this doesn't interpret the arguments in any way.   * Ergo, textual: this doesn't interpret the arguments in any way.
  */   */
 char **  char **
 argparse(struct texi *p, const char *buf,  argparse(struct texi *p, size_t *pos, size_t *argsz, size_t hint)
         size_t sz, size_t *pos, size_t *argsz, size_t hint)  
 {  {
         char    **args;          char    **args;
         size_t    start, end, stack;          size_t    start, end, stack;
   
         while (*pos < sz && isws(buf[*pos]))          while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
                 advance(p, buf, pos);                  advance(p, pos);
   
         args = NULL;          args = NULL;
         *argsz = 0;          *argsz = 0;
   
         if ('{' != buf[*pos] && hint) {          if ('{' != BUF(p)[*pos] && hint) {
                 /*                  /*
                  * Special case: if we encounter an unbracketed argument                   * Special case: if we encounter an unbracketed argument
                  * and we're being invoked with non-zero arguments                   * and we're being invoked with non-zero arguments
Line 1214  argparse(struct texi *p, const char *buf, 
Line 1200  argparse(struct texi *p, const char *buf, 
                 if (NULL == args)                  if (NULL == args)
                         texiabort(p, NULL);                          texiabort(p, NULL);
                 start = *pos;                  start = *pos;
                 while (*pos < sz) {                  while (*pos < BUFSZ(p)) {
                         if ('\n' == buf[*pos])                          if ('\n' == BUF(p)[*pos])
                                 break;                                  break;
                         advance(p, buf, pos);                          advance(p, pos);
                 }                  }
                 args[0] = malloc(*pos - start + 1);                  args[0] = malloc(*pos - start + 1);
                 memcpy(args[0], &buf[start], *pos - start);                  memcpy(args[0], &BUF(p)[start], *pos - start);
                 args[0][*pos - start] = '\0';                  args[0][*pos - start] = '\0';
                 if (*pos < sz && '\n' == buf[*pos])                  if (*pos < BUFSZ(p) && '\n' == BUF(p)[*pos])
                         advance(p, buf, pos);                          advance(p, pos);
                 return(args);                  return(args);
         } else if ('{' != buf[*pos])          } else if ('{' != BUF(p)[*pos])
                 return(args);                  return(args);
   
         /* Parse til the closing '}', putting into the array. */          /* Parse til the closing '}', putting into the array. */
         advance(p, buf, pos);          advance(p, pos);
         while (*pos < sz) {          while (*pos < BUFSZ(p)) {
                 while (*pos < sz && isws(buf[*pos]))                  while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
                         advance(p, buf, pos);                          advance(p, pos);
                 start = *pos;                  start = *pos;
                 stack = 0;                  stack = 0;
                 while (*pos < sz) {                  while (*pos < BUFSZ(p)) {
                         /*                          /*
                          * According to the manual, commas within                           * According to the manual, commas within
                          * embedded commands are escaped.                           * embedded commands are escaped.
                          * We keep track of embedded-ness in the "stack"                           * We keep track of embedded-ness in the "stack"
                          * state anyway, so this is free.                           * state anyway, so this is free.
                          */                           */
                         if (',' == buf[*pos] && 0 == stack && 1 != hint)                          if (',' == BUF(p)[*pos] && 0 == stack && 1 != hint)
                                 break;                                  break;
                         else if (0 == stack && '}' == buf[*pos])                          else if (0 == stack && '}' == BUF(p)[*pos])
                                 break;                                  break;
                         else if (0 != stack && '}' == buf[*pos])                          else if (0 != stack && '}' == BUF(p)[*pos])
                                 stack--;                                  stack--;
                         else if ('{' == buf[*pos])                          else if ('{' == BUF(p)[*pos])
                                 stack++;                                  stack++;
                         advance(p, buf, pos);                          advance(p, pos);
                 }                  }
                 if (stack)                  if (stack)
                         texiwarn(p, "unterminated macro "                          texiwarn(p, "unterminated macro "
                                 "in macro arguments");                                  "in macro arguments");
                 if ((end = *pos) == sz)                  if ((end = *pos) == BUFSZ(p))
                         break;                          break;
                 /* Test for zero-length '{  }'. */                  /* Test for zero-length '{  }'. */
                 if (start == end && '}' == buf[*pos] && 0 == *argsz)                  if (start == end && '}' == BUF(p)[*pos] && 0 == *argsz)
                         break;                          break;
                 /* FIXME: use reallocarray. */                  /* FIXME: use reallocarray. */
                 args = realloc                  args = realloc
Line 1270  argparse(struct texi *p, const char *buf, 
Line 1256  argparse(struct texi *p, const char *buf, 
                 if (NULL == args[*argsz])                  if (NULL == args[*argsz])
                         texiabort(p, NULL);                          texiabort(p, NULL);
                 memcpy(args[*argsz],                  memcpy(args[*argsz],
                         &buf[start], end - start);                          &BUF(p)[start], end - start);
                 args[*argsz][end - start] = '\0';                  args[*argsz][end - start] = '\0';
                 (*argsz)++;                  (*argsz)++;
                 if ('}' == buf[*pos])                  if ('}' == BUF(p)[*pos])
                         break;                          break;
                 advance(p, buf, pos);                  advance(p, pos);
         }          }
   
         if (*pos == sz)          if (*pos == BUFSZ(p))
                 texierr(p, "unterminated arguments");                  texierr(p, "unterminated arguments");
         assert('}' == buf[*pos]);          assert('}' == BUF(p)[*pos]);
         advance(p, buf, pos);          advance(p, pos);
         return(args);          return(args);
 }  }

Legend:
Removed from v.1.13  
changed lines
  Added in v.1.14

CVSweb