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

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

version 1.1, 2015/02/20 09:58:50 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++)
                   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->dirs);          free(p->dirs);
         free(p->subtitle);          free(p->subtitle);
         free(p->title);          free(p->title);
Line 248  void
Line 272  void
 texivspace(struct texi *p)  texivspace(struct texi *p)
 {  {
   
         if (p->seenvs)          if (p->seenvs || TEXILIST_TABLE == p->list)
                 return;                  return;
         teximacro(p, "Pp");          teximacro(p, "Pp");
         p->seenvs = 1;          p->seenvs = 1;
Line 376  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 426  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;          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 452  texicmd(struct texi *p, const char *buf, 
Line 568  texicmd(struct texi *p, const char *buf, 
                 return(TEXICMD__MAX);                  return(TEXICMD__MAX);
         }          }
   
           /* Scan to the end of the possible command name. */
         for (*end = pos; *end < sz && ! ismspace(buf[*end]); (*end)++)          for (*end = pos; *end < sz && ! ismspace(buf[*end]); (*end)++)
                 if ((*end > pos && ('@' == buf[*end] ||                  if ((*end > pos && ('@' == buf[*end] ||
                           '{' == buf[*end] || '}' == buf[*end])))                            '{' == buf[*end] || '}' == buf[*end])))
                         break;                          break;
   
           /* Look for the command. */
         len = *end - pos;          len = *end - 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)
Line 465  texicmd(struct texi *p, const char *buf, 
Line 583  texicmd(struct texi *p, const char *buf, 
                         return(i);                          return(i);
         }          }
   
           /* Look for it in our indices. */
           for (i = 0; i < p->indexsz; i++) {
                   toksz = strlen(p->indexs[i]);
                   if (len != 5 + toksz)
                           continue;
                   if (strncmp(&buf[pos], p->indexs[i], toksz))
                           continue;
                   if (0 == strncmp(&buf[pos + toksz], "index", 5))
                           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 481  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 511  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 528  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 555  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 572  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 600  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 616  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 640  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 667  parselinearg(struct texi *p, const char *buf, size_t s
Line 818  parselinearg(struct texi *p, const char *buf, size_t s
   
         if (*pos < sz && '{' == buf[*pos])          if (*pos < sz && '{' == buf[*pos])
                 parsebracket(p, buf, sz, pos);                  parsebracket(p, buf, sz, pos);
         else if ('\n' != buf[*pos])          else if (*pos < sz && '\n' != buf[*pos])
                 parsesingle(p, buf, sz, pos);                  parsesingle(p, buf, sz, pos);
         else          else
                 return(0);                  return(0);
Line 696  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 722  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 740  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 760  parsefile(struct texi *p, const char *fname, int parse
Line 916  parsefile(struct texi *p, const char *fname, int parse
         struct stat      st;          struct stat      st;
         size_t           i;          size_t           i;
   
         assert(p->filepos < 64);          if (64 == p->filepos)
                   texierr(p, "too many open files");
         f = &p->files[p->filepos];          f = &p->files[p->filepos];
         memset(f, 0, sizeof(struct texifile));          memset(f, 0, sizeof(struct texifile));
   
Line 801  parsefile(struct texi *p, const char *fname, int parse
Line 958  parsefile(struct texi *p, const char *fname, int parse
         texifilepop(p);          texifilepop(p);
 }  }
   
   /*
    * Look up the value to a stored pair's value starting in "buf" from
    * start to end.
    * Return the pointer to the value memory, which can be NULL if the
    * pointer key does not exist.
    * The pointer can point to NULL if the value has been unset.
    */
   static char **
   valuequery(const struct texi *p,
           const char *buf, size_t start, size_t end)
   {
           size_t   i, sz, len;
   
           assert(end >= start);
           /* Ignore zero-length. */
           if (0 == (len = (end - start)))
                   return(NULL);
           for (i = 0; i < p->valsz; i++) {
                   sz = strlen(p->vals[i].key);
                   if (sz != len)
                           continue;
                   if (0 == strncmp(p->vals[i].key, &buf[start], len))
                           return(&p->vals[i].value);
           }
           return(NULL);
   }
   
   /*
    * Parse a key until the end of line, e.g., @clear foo\n, and return the
    * pointer to its value via valuequery().
    */
   static char **
   valuelquery(struct texi *p, const char *buf, size_t sz, size_t *pos)
   {
           size_t    start, end;
           char    **ret;
   
           while (*pos < sz && isws(buf[*pos]))
                   advance(p, buf, pos);
           if (*pos == sz)
                   return(NULL);
           for (start = end = *pos; end < sz; end++)
                   if ('\n' == buf[end])
                           break;
           advanceto(p, buf, pos, end);
           if (*pos < sz) {
                   assert('\n' == buf[*pos]);
                   advance(p, buf, pos);
           }
           if (NULL == (ret = valuequery(p, buf, start, end)))
                   return(NULL);
           return(ret);
   }
   
   void
   valuelclear(struct texi *p, const char *buf, size_t sz, size_t *pos)
   {
           char    **ret;
   
           if (NULL == (ret = valuelquery(p, buf, sz, pos)))
                   return;
           free(*ret);
           *ret = NULL;
   }
   
   const char *
   valuellookup(struct texi *p, const char *buf, size_t sz, size_t *pos)
   {
           char    **ret;
   
           if (NULL == (ret = valuelquery(p, buf, sz, pos)))
                   return(NULL);
           return(*ret);
   }
   
   /*
    * Parse a key from a bracketed string, e.g., @value{foo}, and return
    * the pointer to its value.
    * If the returned pointer is NULL, either there was no string within
    * the brackets (or no brackets), or the value was not found, or the
    * value had previously been unset.
    */
   const char *
   valueblookup(struct texi *p, const char *buf, size_t sz, size_t *pos)
   {
           size_t    start, end;
           char    **ret;
   
           while (*pos < sz && isws(buf[*pos]))
                   advance(p, buf, pos);
           if (*pos == sz || '{' != buf[*pos])
                   return(NULL);
           advance(p, buf, pos);
           for (start = end = *pos; end < sz; end++)
                   if ('}' == buf[end])
                           break;
           advanceto(p, buf, pos, end);
           if (*pos < sz) {
                   assert('}' == buf[*pos]);
                   advance(p, buf, pos);
           }
           if (NULL == (ret = valuequery(p, buf, start, end)))
                   return(NULL);
           return(*ret);
   }
   
   void
   valueadd(struct texi *p, char *key, char *val)
   {
           size_t   i;
   
           assert(NULL != key);
           assert(NULL != val);
   
           for (i = 0; i < p->valsz; i++)
                   if (0 == strcmp(p->vals[i].key, key))
                           break;
   
           if (i < p->valsz) {
                   free(key);
                   free(p->vals[i].value);
                   p->vals[i].value = val;
           } else {
                   /* FIXME: reallocarray() */
                   p->vals = realloc(p->vals,
                           (p->valsz + 1) *
                            sizeof(struct texivalue));
                   if (NULL == p->vals)
                           texiabort(p, NULL);
                   p->vals[p->valsz].key = key;
                   p->vals[p->valsz].value = val;
                   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.1  
changed lines
  Added in v.1.7

CVSweb