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

Diff for /texi2mdoc/util.c between version 1.6 and 1.7

version 1.6, 2015/02/21 22:01:32 version 1.7, 2015/02/23 11:44:30
Line 46  texifilepop(struct texi *p)
Line 46  texifilepop(struct texi *p)
         munmap(f->map, f->mapsz);          munmap(f->map, f->mapsz);
 }  }
   
   static void
   teximacrofree(struct teximacro *p)
   {
           size_t   i;
   
           for (i = 0; i < p->argsz; i++)
                   free(p->args[i]);
   
           free(p->args);
           free(p->key);
           free(p->value);
   }
   
   static void
   texivaluefree(struct texivalue *p)
   {
   
           free(p->key);
           free(p->value);
   }
   
 /*  /*
  * Unmap all files that we're currently using and free all resources   * Unmap all files that we're currently using and free all resources
  * that we've allocated during the parse.   * that we've allocated during the parse.
Line 64  texiexit(struct texi *p)
Line 85  texiexit(struct texi *p)
         while (p->filepos > 0)          while (p->filepos > 0)
                 texifilepop(p);                  texifilepop(p);
   
           for (i = 0; i < p->macrosz; i++)
                   teximacrofree(&p->macros[i]);
         for (i = 0; i < p->dirsz; i++)          for (i = 0; i < p->dirsz; i++)
                 free(p->dirs[i]);                  free(p->dirs[i]);
   
         for (i = 0; i < p->indexsz; i++)          for (i = 0; i < p->indexsz; i++)
                 free(p->indexs[i]);                  free(p->indexs[i]);
           for (i = 0; i < p->valsz; i++)
                   texivaluefree(&p->vals[i]);
   
         for (i = 0; i < p->valsz; i++) {          free(p->macros);
                 free(p->vals[i].value);  
                 free(p->vals[i].key);  
         }  
   
         free(p->vals);          free(p->vals);
         free(p->indexs);          free(p->indexs);
         free(p->dirs);          free(p->dirs);
Line 380  advanceto(struct texi *p, const char *buf, size_t *pos
Line 400  advanceto(struct texi *p, const char *buf, size_t *pos
                 advance(p, buf, pos);                  advance(p, buf, pos);
 }  }
   
   static void
   texiexecmacro(struct texi *p, struct teximacro *m,
           const char *buf, size_t sz, size_t *pos)
   {
           size_t    valsz, realsz, aasz, asz,
                     ssz, i, j, k, start, end;
           char     *val;
           char    **args;
   
           args = argparse(p, buf, sz, pos, &asz);
           if (asz != m->argsz)
                   texiwarn(p, "invalid macro argument length");
           aasz = asz < m->argsz ? asz : m->argsz;
   
           if (0 == aasz) {
                   parseeof(p, m->value, strlen(m->value));
                   return;
           }
   
           valsz = realsz = strlen(m->value);
           val = strdup(m->value);
   
           for (i = j = 0; i < realsz; i++) {
                   /* Parse blindly til the backslash delimiter. */
                   if ('\\' != m->value[i]) {
                           val[j++] = m->value[i];
                           val[j] = '\0';
                           continue;
                   } else if (i == realsz - 1)
                           texierr(p, "trailing argument name delimiter");
   
                   /* Double-backslash is escaped. */
                   if ('\\' == m->value[i + 1]) {
                           val[j++] = m->value[i++];
                           val[j] = '\0';
                           continue;
                   }
   
                   assert('\\' == m->value[i] && i < realsz - 1);
   
                   /* Parse to terminating delimiter. */
                   /* FIXME: embedded, escaped delimiters? */
                   for (start = end = i + 1; end < realsz; end++)
                           if ('\\' == m->value[end])
                                   break;
                   if (end == realsz)
                           texierr(p, "unterminated argument name");
   
                   for (k = 0; k < aasz; k++) {
                           if ((ssz = strlen(m->args[k])) != (end - start))
                                   continue;
                           if (strncmp(&m->value[start], m->args[k], ssz))
                                   continue;
                           break;
                   }
   
                   /*
                    * Argument didn't exist in argument table.
                    * No need to reallocate here: we just copy the text
                    * directly from the macro value into the buffer.
                    */
                   if (k == aasz) {
                           for ( ; i < end; i++)
                                   val[j++] = m->value[i];
                           assert('\\' == m->value[i]);
                           val[j++] = m->value[i];
                           val[j] = '\0';
                           continue;
                   }
   
                   if (strlen(args[k]) > ssz) {
                           valsz += strlen(args[k]);
                           val = realloc(val, valsz + 1);
                           if (NULL == val)
                                   texiabort(p, NULL);
                   }
   
                   j = strlcat(val, args[k], valsz + 1);
                   i = end;
           }
   
           parseeof(p, val, strlen(val));
   
           for (i = 0; i < asz; i++)
                   free(args[i]);
           free(args);
           free(val);
   }
   
 /*  /*
  * Output a free-form word in the input stream, progressing to the next   * Output a free-form word in the input stream, progressing to the next
  * command or white-space.   * command or white-space.
Line 430  texiword(struct texi *p, const char *buf, 
Line 539  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,  texicmd(struct texi *p, const char *buf, size_t pos,
         size_t pos, size_t sz, size_t *end)          size_t sz, size_t *end, struct teximacro **macro)
 {  {
         size_t   i, len, toksz;          size_t   i, len, toksz;
   
         assert('@' == buf[pos]);          assert('@' == buf[pos]);
   
           if (NULL != macro)
                   *macro = NULL;
   
         if ((*end = pos) == sz)          if ((*end = pos) == sz)
                 return(TEXICMD__MAX);                  return(TEXICMD__MAX);
         else if ((*end = ++pos) == sz)          else if ((*end = ++pos) == sz)
Line 479  texicmd(struct texi *p, const char *buf, 
Line 591  texicmd(struct texi *p, const char *buf, 
                 if (strncmp(&buf[pos], p->indexs[i], toksz))                  if (strncmp(&buf[pos], p->indexs[i], toksz))
                         continue;                          continue;
                 if (0 == strncmp(&buf[pos + toksz], "index", 5))                  if (0 == strncmp(&buf[pos + toksz], "index", 5))
                         return(TEXICMD_INDEX);                          return(TEXICMD_USER_INDEX);
         }          }
   
           for (i = 0; i < p->macrosz; i++) {
                   if (len != strlen(p->macros[i].key))
                           continue;
                   if (strncmp(&buf[pos], p->macros[i].key, len))
                           continue;
                   if (NULL != macro)
                           *macro = &p->macros[i];
                   return(TEXICMD__MAX);
           }
   
         texiwarn(p, "bad command: @%.*s", (int)len, &buf[pos]);          texiwarn(p, "bad command: @%.*s", (int)len, &buf[pos]);
         return(TEXICMD__MAX);          return(TEXICMD__MAX);
 }  }
Line 498  int
Line 620  int
 parsearg(struct texi *p, const char *buf,  parsearg(struct texi *p, const char *buf,
         size_t sz, 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;
   
         while (*pos < sz && ismspace(buf[*pos]))          while (*pos < sz && ismspace(buf[*pos]))
                 advance(p, buf, pos);                  advance(p, buf, pos);
Line 528  parsearg(struct texi *p, const char *buf, 
Line 651  parsearg(struct texi *p, const char *buf, 
                         continue;                          continue;
                 }                  }
   
                 cmd = texicmd(p, buf, *pos, sz, &end);                  cmd = texicmd(p, buf, *pos, sz, &end, &macro);
                 advanceto(p, buf, pos, end);                  advanceto(p, buf, pos, end);
                   if (NULL != macro)
                           texiexecmacro(p, macro, buf, sz, pos);
                 if (TEXICMD__MAX == cmd)                  if (TEXICMD__MAX == cmd)
                         continue;                          continue;
                 if (NULL != texitoks[cmd].fp)                  if (NULL != texitoks[cmd].fp)
Line 545  parsearg(struct texi *p, const char *buf, 
Line 670  parsearg(struct texi *p, const char *buf, 
 void  void
 parsebracket(struct texi *p, const char *buf, size_t sz, size_t *pos)  parsebracket(struct texi *p, const char *buf, size_t sz, size_t *pos)
 {  {
         size_t           end;          size_t            end;
         enum texicmd     cmd;          enum texicmd      cmd;
           struct teximacro *macro;
   
         while (*pos < sz && ismspace(buf[*pos]))          while (*pos < sz && ismspace(buf[*pos]))
                 advance(p, buf, pos);                  advance(p, buf, pos);
Line 572  parsebracket(struct texi *p, const char *buf, size_t s
Line 698  parsebracket(struct texi *p, const char *buf, size_t s
                         continue;                          continue;
                 }                  }
   
                 cmd = texicmd(p, buf, *pos, sz, &end);                  cmd = texicmd(p, buf, *pos, sz, &end, &macro);
                 advanceto(p, buf, pos, end);                  advanceto(p, buf, pos, end);
                   if (NULL != macro)
                           texiexecmacro(p, macro, buf, sz, pos);
                 if (TEXICMD__MAX == cmd)                  if (TEXICMD__MAX == cmd)
                         continue;                          continue;
                 if (NULL != texitoks[cmd].fp)                  if (NULL != texitoks[cmd].fp)
Line 589  parsebracket(struct texi *p, const char *buf, size_t s
Line 717  parsebracket(struct texi *p, const char *buf, size_t s
 void  void
 parseeoln(struct texi *p, const char *buf, size_t sz, size_t *pos)  parseeoln(struct texi *p, const char *buf, size_t sz, size_t *pos)
 {  {
         size_t           end;          size_t            end;
         enum texicmd     cmd;          enum texicmd      cmd;
           struct teximacro *macro;
   
         while (*pos < sz && '\n' != buf[*pos]) {          while (*pos < sz && '\n' != buf[*pos]) {
                 while (*pos < sz && isws(buf[*pos])) {                  while (*pos < sz && isws(buf[*pos])) {
Line 617  parseeoln(struct texi *p, const char *buf, size_t sz, 
Line 746  parseeoln(struct texi *p, const char *buf, size_t sz, 
                         continue;                          continue;
                 }                  }
   
                 cmd = texicmd(p, buf, *pos, sz, &end);                  cmd = texicmd(p, buf, *pos, sz, &end, &macro);
                 advanceto(p, buf, pos, end);                  advanceto(p, buf, pos, end);
                   if (NULL != macro)
                           texiexecmacro(p, macro, buf, sz, pos);
                 if (TEXICMD__MAX == cmd)                  if (TEXICMD__MAX == cmd)
                         continue;                          continue;
                 if (NULL != texitoks[cmd].fp)                  if (NULL != texitoks[cmd].fp)
Line 633  parseeoln(struct texi *p, const char *buf, size_t sz, 
Line 764  parseeoln(struct texi *p, const char *buf, size_t sz, 
 void  void
 parsesingle(struct texi *p, const char *buf, size_t sz, size_t *pos)  parsesingle(struct texi *p, const char *buf, size_t sz, size_t *pos)
 {  {
         size_t           end;          size_t            end;
         enum texicmd     cmd;          enum texicmd      cmd;
           struct teximacro *macro;
   
         if ((*pos = advancenext(p, buf, sz, pos)) >= sz)          if ((*pos = advancenext(p, buf, sz, pos)) >= sz)
                 return;                  return;
Line 657  parsesingle(struct texi *p, const char *buf, size_t sz
Line 789  parsesingle(struct texi *p, const char *buf, size_t sz
                 return;                  return;
         }          }
   
         cmd = texicmd(p, buf, *pos, sz, &end);          cmd = texicmd(p, buf, *pos, sz, &end, &macro);
         advanceto(p, buf, pos, end);          advanceto(p, buf, pos, end);
           if (NULL != macro)
                   texiexecmacro(p, macro, buf, sz, pos);
         if (TEXICMD__MAX == cmd)          if (TEXICMD__MAX == cmd)
                 return;                  return;
         if (NULL != texitoks[cmd].fp)          if (NULL != texitoks[cmd].fp)
Line 713  void
Line 847  void
 parseto(struct texi *p, const char *buf,  parseto(struct texi *p, const char *buf,
         size_t sz, 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;
         size_t           endtoksz;          size_t            endtoksz;
           struct teximacro *macro;
   
         endtoksz = strlen(endtoken);          endtoksz = strlen(endtoken);
         assert(endtoksz > 0);          assert(endtoksz > 0);
Line 739  parseto(struct texi *p, const char *buf, 
Line 874  parseto(struct texi *p, const char *buf, 
                         continue;                          continue;
                 }                  }
   
                 cmd = texicmd(p, buf, *pos, sz, &end);                  cmd = texicmd(p, buf, *pos, sz, &end, &macro);
                 advanceto(p, buf, pos, end);                  advanceto(p, buf, pos, end);
                 if (TEXICMD_END == cmd) {                  if (TEXICMD_END == cmd) {
                         while (*pos < sz && isws(buf[*pos]))                          while (*pos < sz && isws(buf[*pos]))
Line 757  parseto(struct texi *p, const char *buf, 
Line 892  parseto(struct texi *p, const char *buf, 
                                 texiwarn(p, "unexpected \"end\"");                                  texiwarn(p, "unexpected \"end\"");
                         advanceeoln(p, buf, sz, pos, 0);                          advanceeoln(p, buf, sz, pos, 0);
                         continue;                          continue;
                 } else if (TEXICMD__MAX != cmd)                  }
                         if (NULL != texitoks[cmd].fp)                  if (NULL != macro)
                                 (*texitoks[cmd].fp)(p, cmd, buf, sz, pos);                          texiexecmacro(p, macro, buf, sz, pos);
                   if (TEXICMD__MAX == cmd)
                           continue;
                   if (NULL != texitoks[cmd].fp)
                           (*texitoks[cmd].fp)(p, cmd, buf, sz, pos);
         }          }
 }  }
   
Line 952  valueadd(struct texi *p, char *key, char *val)
Line 1091  valueadd(struct texi *p, char *key, char *val)
                 p->vals[p->valsz].value = val;                  p->vals[p->valsz].value = val;
                 p->valsz++;                  p->valsz++;
         }          }
   }
   
   /*
    * Take the arguments to a macro, e.g., @foo{bar, baz, xyzzy} (or the
    * declaration form, @macro foo {arg1, ...}) and textually convert it to
    * an array of arguments of size "argsz".
    * These need to be freed individually and as a whole.
    * NOTE: this will puke on @, or @} macros, which can trick it into
    * stopping argument parsing earlier.
    * Ergo, textual: this doesn't interpret the arguments in any way.
    */
   char **
   argparse(struct texi *p, const char *buf,
           size_t sz, size_t *pos, size_t *argsz)
   {
           char    **args;
           size_t    start, end, stack;
   
           while (*pos < sz && isws(buf[*pos]))
                   advance(p, buf, pos);
   
           args = NULL;
           *argsz = 0;
   
           /* Check for no arguments. */
           if ('{' != buf[*pos])
                   return(args);
   
           /* Parse til the closing '}', putting into the array. */
           advance(p, buf, pos);
           while (*pos < sz) {
                   while (*pos < sz && isws(buf[*pos]))
                           advance(p, buf, pos);
                   start = *pos;
                   stack = 0;
                   while (*pos < sz) {
                           /*
                            * According to the manual, commas within
                            * embedded commands are escaped.
                            * We keep track of embedded-ness in the "stack"
                            * state anyway, so this is free.
                            */
                           if (0 == stack && ',' == buf[*pos])
                                   break;
                           else if (0 == stack && '}' == buf[*pos])
                                   break;
                           else if (0 != stack && '}' == buf[*pos])
                                   stack--;
                           else if ('{' == buf[*pos])
                                   stack++;
                           advance(p, buf, pos);
                   }
                   if (stack)
                           texiwarn(p, "unterminated macro "
                                   "in macro arguments");
                   if ((end = *pos) == sz)
                           break;
                   /* Test for zero-length '{  }'. */
                   if (start == end && '}' == buf[*pos] && 0 == *argsz)
                           break;
                   if (start == end)
                           texierr(p, "zero-length argument");
                   /* FIXME: use reallocarray. */
                   args = realloc
                           (args, sizeof(char *) *
                            (*argsz + 1));
                   if (NULL == args)
                           texiabort(p, NULL);
                   args[*argsz] = malloc(end - start + 1);
                   if (NULL == args[*argsz])
                           texiabort(p, NULL);
                   memcpy(args[*argsz],
                           &buf[start], end - start);
                   args[*argsz][end - start] = '\0';
                   (*argsz)++;
                   if ('}' == buf[*pos])
                           break;
                   advance(p, buf, pos);
           }
   
           if (*pos == sz)
                   texierr(p, "unterminated arguments");
           assert('}' == buf[*pos]);
           advance(p, buf, pos);
           return(args);
 }  }

Legend:
Removed from v.1.6  
changed lines
  Added in v.1.7

CVSweb