home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
- /* texi2ps -- convert texinfo format files into Postscript files.
-
- Author: Eli Zaretskii (eliz@is.elta.co.il)
-
- Copyright (C) 1995 DJ Delorie (dj@delorie.com)
-
- texi2ps is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY. No author or distributor accepts
- responsibility to anyone for the consequences of using it or for
- whether it serves any particular purpose or works at all, unless he
- says so in writing. Refer to the GNU General Public License
- for full details.
-
- Everyone is granted permission to copy, modify and redistribute
- texi2ps, but only under the conditions described in the GNU
- General Public License. A copy of this license is supposed to
- have been given to you along with texi2ps so you can know your
- rights and responsibilities. It should be in a file named COPYING.
- Among other things, the copyright notice and this notice must be
- preserved on all copies. */
-
- /* Functions to manipulate flags: @set, @clear, @value, @ifset, @ifclear.
-
- The flags are placed into a char array in this form:
-
- "\0name=value\0name=value\0...\0\0"
-
- (yes, like DOS environment variables), where the value may be empty.
- This array grows as needed, if the space isn't large enough after the
- garbage was collected. To clear a flag, we just overwrite the place
- it was stored with `?' characters. */
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include "fileio.h"
- #include "screenio.h"
-
- /* The table to hold flags which are currently set. */
- static char *flag_table;
-
- /* The size of currently allocated table. */
- static size_t flag_table_size;
-
- /* The initial size we allocate for the table. */
- #define INITIAL_SIZE 1024
-
- /* How much is actually used by the table entries. */
- static size_t used_size;
-
- /* Return a pointer to NAME in the table if it is followed by `=',
- or NULL otherwise. */
- static char *
- find_flag(char *name)
- {
- char *p = flag_table;
- size_t namelen = strlen(name);
-
- if (p == (char *)0)
- return p;
-
- /* Look for "\0name=". */
- while (*p == '\0' && p[1] != '\0')
- {
- if (strncmp(p + 1, name, namelen) == 0 && p[namelen + 1] == '=')
- return p + namelen + 2;
- p += strlen(p + 1) + 1;
- }
-
- return (char *)0;
- }
-
- /* Ensure we have enough space to add a new variable, return a pointer to
- first free slot. */
- static char *
- alloc_flag(size_t need_bytes)
- {
- size_t min_req_size = used_size + need_bytes;
-
- if (flag_table_size == 0)
- {
- /* Initial allocation. */
- flag_table = (char *)malloc(INITIAL_SIZE);
- flag_table_size = INITIAL_SIZE;
- flag_table[0] = flag_table[1] = '\0';
- used_size = 2;
- }
-
- if (min_req_size > flag_table_size)
- {
- int need_realloc = 0;
-
- /* Not enough free space up front. Before we reallocate, find
- unused slots and reuse them by unfragmenting the table.
- Unused slots look like this: "\0?????????\0" (the number of
- `?'s depends on the length of the name=value string which
- once occupied that slot). */
- char *d = flag_table;
- char *s = d + 1;
-
- while (s - flag_table < used_size - 1)
- {
- size_t i = strspn(s, "?"); /* find first char which ISN'T `?' */
-
- if (i && s[i] == '\0') /* the entire string is `?'s */
- {
- /* This slot is unused. Compact it. */
- s += i;
- memmove(d, s, used_size - (s - flag_table));
- used_size -= s - d;
- min_req_size -= s - d;
- }
- else
- /* This slot is used. Go to next slot. */
- d = s + i + strlen(s + i);
-
- s = d + 1;
- }
-
- while (flag_table_size < min_req_size)
- {
- need_realloc++;
- flag_table_size *= 2;
- }
-
- if (need_realloc)
- /* What? 1KB isn't enough for them?? Oh, well... */
- flag_table = (char *)realloc(flag_table, flag_table_size);
- }
-
- if (flag_table == (char *)0)
- {
- fprintf(stderr,
- "Error: too many flags set: memory exhausted at %s\n",
- fileio_where());
- exit (1);
- }
-
- return flag_table + used_size - 1;
- }
-
- /* --------------------------------------------------------------------- */
-
-
- /* Insert a flag and its value into the table. */
- void
- set_flag(char *name, char *new_value)
- {
- size_t namlen = strlen(name), vallen = strlen(new_value);
- char *current_value = find_flag(name);
- char *new;
-
- if (current_value)
- {
- if (strcmp(current_value, new_value) == 0)
- return; /* it's already there with the right value */
-
- /* It's there, but with another value. Strike-out this slot. */
- memset(current_value - namlen - 1, '?',
- namlen + strlen(current_value) + 1);
- }
- new = alloc_flag(namlen + vallen + 2); /* name, value, `=' and `\0' */
- memcpy(new, name, namlen);
- used_size += namlen - 1; /* we've overwritten the last `\0' */
- flag_table[used_size] = '=';
- used_size++;
- memcpy(flag_table + used_size, new_value, vallen + 1);
- used_size += vallen + 1;
- flag_table[used_size++] = '\0';
- }
-
- /* Clear a flag. */
- void
- clear_flag(char *name)
- {
- size_t namlen = strlen(name);
- char *current = find_flag(name);
-
- if (current)
- memset(current - namlen - 1, '?', namlen + strlen(current) + 1);
-
- /* It's OK to clear a flag which wasn't set. */
- screenio_print("Warning: flag `%s\' wasn\'t set, but is cleared at %s",
- name, fileio_where());
- }
-
- /* Return a value of a flag, or an error string if it isn't set. */
-
- static char no_value_fmt[] = "{No value for \"%s\"}";
-
- char *
- flag_value(char *name)
- {
- char *p = find_flag(name);
-
- if (p)
- return strdup(p);
-
- p = (char *)malloc(strlen(name) + sizeof(no_value_fmt) - 2);
- if (p != (char *)0)
- {
- screenio_print("Warning: flag `%s\' wasn\'t set, but its value used at %s",
- name, fileio_where());
- sprintf(p, no_value_fmt, name);
- }
- return p;
- }
-
- /* Take a name of a flag out of ARG, move pointer past the name.
- The name is the first word, which may include embedded quoted
- whitespace. */
- char *
- take_name(char *arg)
- {
- char *p = arg;
- int quote = 0;
-
- while (quote || *p && *p != ' ' && *p != '\t')
- {
- if (quote == 0 && (*p == '"' || *p == '\''))
- quote = *p;
- else if (quote && *p == quote)
- quote = 0;
-
- p++;
- }
-
- return p;
- }
-
- /* Return non-zero if the flag, which is the first word of
- LINE, is set, and push the rest of line back onto input. */
- int
- ifset(char *line)
- {
- /* We got an entire line (instead of a single word) becase we
- want to support flag names with embedded quoted whitespace.
- We will push the rest of the line back onto input after we
- get the first word. */
- char *s = line + strlen(line) - 1; /* don't push back the '\0' char */
- char *p = take_name(line);
- char *name = (char *)alloca(p - line + 1);
- int delim;
-
- delim = *p; /* remember the delimiter */
- *p = '\0';
- strcpy(name, line);
-
- /* Push back the rest of the line. */
- while (s > p)
- fileio_unget(*s--);
-
- /* Push back the delimiter. */
- fileio_unget(delim);
-
- if (find_flag(name))
- return 1;
-
- return 0;
- }
-