home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2 / DJLSR201.ZIP / src / utils / texi2ps / ifset.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-08  |  7.4 KB  |  262 lines

  1. /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  2. /* texi2ps -- convert texinfo format files into Postscript files.
  3.  
  4.    Author: Eli Zaretskii (eliz@is.elta.co.il)
  5.  
  6.    Copyright (C) 1995 DJ Delorie (dj@delorie.com)
  7.  
  8.    texi2ps is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY.  No author or distributor accepts
  10.    responsibility to anyone for the consequences of using it or for
  11.    whether it serves any particular purpose or works at all, unless he
  12.    says so in writing.  Refer to the GNU General Public License
  13.    for full details.
  14.  
  15.    Everyone is granted permission to copy, modify and redistribute
  16.    texi2ps, but only under the conditions described in the GNU
  17.    General Public License.   A copy of this license is supposed to
  18.    have been given to you along with texi2ps so you can know your
  19.    rights and responsibilities.  It should be in a file named COPYING.
  20.    Among other things, the copyright notice and this notice must be
  21.    preserved on all copies.  */
  22.  
  23. /* Functions to manipulate flags: @set, @clear, @value, @ifset, @ifclear.
  24.  
  25.    The flags are placed into a char array in this form:
  26.  
  27.      "\0name=value\0name=value\0...\0\0"
  28.  
  29.    (yes, like DOS environment variables), where the value may be empty.
  30.    This array grows as needed, if the space isn't large enough after the
  31.    garbage was collected.  To clear a flag, we just overwrite the place
  32.    it was stored with `?' characters.  */
  33.  
  34. #include <stdio.h>
  35. #include <string.h>
  36. #include <stdlib.h>
  37. #include "fileio.h"
  38. #include "screenio.h"
  39.  
  40. /* The table to hold flags which are currently set.  */
  41. static char *flag_table;
  42.  
  43. /* The size of currently allocated table.  */
  44. static size_t flag_table_size;
  45.  
  46. /* The initial size we allocate for the table.  */
  47. #define INITIAL_SIZE    1024
  48.  
  49. /* How much is actually used by the table entries.  */
  50. static size_t used_size;
  51.  
  52. /* Return a pointer to NAME in the table if it is followed by `=',
  53.    or NULL otherwise.  */
  54. static char *
  55. find_flag(char *name)
  56. {
  57.   char *p = flag_table;
  58.   size_t namelen = strlen(name);
  59.  
  60.   if (p == (char *)0)
  61.     return p;
  62.  
  63.   /* Look for "\0name=".  */
  64.   while (*p == '\0' && p[1] != '\0')
  65.     {
  66.       if (strncmp(p + 1, name, namelen) == 0 && p[namelen + 1] == '=')
  67.         return p + namelen + 2;
  68.       p += strlen(p + 1) + 1;
  69.     }
  70.  
  71.   return (char *)0;
  72. }
  73.  
  74. /* Ensure we have enough space to add a new variable, return a pointer to
  75.    first free slot.  */
  76. static char *
  77. alloc_flag(size_t need_bytes)
  78. {
  79.   size_t min_req_size = used_size + need_bytes;
  80.  
  81.   if (flag_table_size == 0)
  82.     {
  83.       /* Initial allocation.  */
  84.       flag_table = (char *)malloc(INITIAL_SIZE);
  85.       flag_table_size = INITIAL_SIZE;
  86.       flag_table[0] = flag_table[1] = '\0';
  87.       used_size = 2;
  88.     }
  89.  
  90.   if (min_req_size > flag_table_size)
  91.     {
  92.       int need_realloc = 0;
  93.       
  94.       /* Not enough free space up front.  Before we reallocate, find
  95.          unused slots and reuse them by unfragmenting the table.
  96.          Unused slots look like this: "\0?????????\0" (the number of
  97.          `?'s depends on the length of the name=value string which
  98.          once occupied that slot).  */
  99.       char *d = flag_table;
  100.       char *s = d + 1;
  101.  
  102.       while (s - flag_table < used_size - 1)
  103.         {
  104.           size_t i = strspn(s, "?");    /* find first char which ISN'T `?' */
  105.  
  106.           if (i && s[i] == '\0')        /* the entire string is `?'s */
  107.             {
  108.               /* This slot is unused.  Compact it.  */
  109.               s += i;
  110.               memmove(d, s, used_size - (s - flag_table));
  111.               used_size -= s - d;
  112.               min_req_size -= s - d;
  113.             }
  114.           else
  115.             /* This slot is used.  Go to next slot.  */
  116.             d = s + i + strlen(s + i);
  117.  
  118.           s = d + 1;
  119.         }
  120.  
  121.       while (flag_table_size < min_req_size)
  122.         {
  123.           need_realloc++;
  124.           flag_table_size *= 2;
  125.         }
  126.  
  127.       if (need_realloc)
  128.         /* What?  1KB isn't enough for them??  Oh, well...  */
  129.         flag_table = (char *)realloc(flag_table, flag_table_size);
  130.     }
  131.  
  132.   if (flag_table == (char *)0)
  133.     {
  134.       fprintf(stderr,
  135.               "Error: too many flags set: memory exhausted at %s\n",
  136.               fileio_where());
  137.       exit (1);
  138.     }
  139.  
  140.   return flag_table + used_size - 1;
  141. }
  142.  
  143. /* --------------------------------------------------------------------- */
  144.     
  145.  
  146. /* Insert a flag and its value into the table.  */
  147. void
  148. set_flag(char *name, char *new_value)
  149. {
  150.   size_t namlen = strlen(name), vallen = strlen(new_value);
  151.   char *current_value = find_flag(name);
  152.   char *new;
  153.  
  154.   if (current_value)
  155.     {
  156.       if (strcmp(current_value, new_value) == 0)
  157.         return;     /* it's already there with the right value */
  158.  
  159.       /* It's there, but with another value.  Strike-out this slot.  */
  160.       memset(current_value - namlen - 1, '?',
  161.              namlen + strlen(current_value) + 1);
  162.     }
  163.   new = alloc_flag(namlen + vallen + 2); /* name, value, `=' and `\0' */
  164.   memcpy(new, name, namlen);
  165.   used_size += namlen - 1;      /* we've overwritten the last `\0' */
  166.   flag_table[used_size] = '=';
  167.   used_size++;
  168.   memcpy(flag_table + used_size, new_value, vallen + 1);
  169.   used_size += vallen + 1;
  170.   flag_table[used_size++] = '\0';
  171. }
  172.  
  173. /* Clear a flag.  */
  174. void
  175. clear_flag(char *name)
  176. {
  177.   size_t namlen = strlen(name);
  178.   char *current = find_flag(name);
  179.  
  180.   if (current)
  181.     memset(current - namlen - 1, '?', namlen + strlen(current) + 1);
  182.  
  183.   /* It's OK to clear a flag which wasn't set. */
  184.   screenio_print("Warning: flag `%s\' wasn\'t set, but is cleared at %s",
  185.                  name, fileio_where());
  186. }
  187.  
  188. /* Return a value of a flag, or an error string if it isn't set.  */
  189.  
  190. static char no_value_fmt[] = "{No value for \"%s\"}";
  191.  
  192. char *
  193. flag_value(char *name)
  194. {
  195.   char *p = find_flag(name);
  196.  
  197.   if (p)
  198.     return strdup(p);
  199.  
  200.   p = (char *)malloc(strlen(name) + sizeof(no_value_fmt) - 2);
  201.   if (p != (char *)0)
  202.     {
  203.       screenio_print("Warning: flag `%s\' wasn\'t set, but its value used at %s",
  204.                      name, fileio_where());
  205.       sprintf(p, no_value_fmt, name);
  206.     }
  207.   return p;
  208. }
  209.  
  210. /* Take a name of a flag out of ARG, move pointer past the name.
  211.    The name is the first word, which may include embedded quoted
  212.    whitespace.  */
  213. char *
  214. take_name(char *arg)
  215. {
  216.   char *p = arg;
  217.   int quote = 0;
  218.  
  219.   while (quote || *p && *p != ' ' && *p != '\t')
  220.     {
  221.       if (quote == 0 && (*p == '"' || *p == '\''))
  222.         quote = *p;
  223.       else if (quote && *p == quote)
  224.         quote = 0;
  225.  
  226.       p++;
  227.     }
  228.  
  229.   return p;
  230. }
  231.  
  232. /* Return non-zero if the flag, which is the first word of
  233.    LINE, is set, and push the rest of line back onto input.  */
  234. int
  235. ifset(char *line)
  236. {
  237.   /* We got an entire line (instead of a single word) becase we
  238.      want to support flag names with embedded quoted whitespace.
  239.      We will push the rest of the line back onto input after we
  240.      get the first word.  */
  241.   char *s = line + strlen(line) - 1;  /* don't push back the '\0' char */
  242.   char *p = take_name(line);
  243.   char *name = (char *)alloca(p - line + 1);
  244.   int   delim;
  245.  
  246.   delim = *p;       /* remember the delimiter */
  247.   *p = '\0';
  248.   strcpy(name, line);
  249.  
  250.   /* Push back the rest of the line.  */
  251.   while (s > p)
  252.     fileio_unget(*s--);
  253.  
  254.   /* Push back the delimiter.  */
  255.   fileio_unget(delim);
  256.  
  257.   if (find_flag(name))
  258.     return 1;
  259.  
  260.   return 0;
  261. }
  262.