/* Parse one Texinfo file and create manpages according to the embedded instructions. */ static void parse_file (const char *fname, FILE *fp, char **section_name, int in_pause) { char *line; int lnr = 0; /* Fixme: The following state variables don't carry over to include files. */ int skip_to_end = 0; /* Used to skip over menu entries. */ int skip_sect_line = 0; /* Skip after @mansect. */ int item_indent = 0; /* How far is the current @item indented. */ /* Helper to define a macro. */ char *macroname = NULL; char *macrovalue = NULL; size_t macrovaluesize = 0; size_t macrovalueused = 0; line = xmalloc (LINESIZE); while (fgets (line, LINESIZE, fp)) { size_t n = strlen (line); int got_line = 0; char *p, *pend; lnr++; if (!n || line[n-1] != '\n') { err ("%s:%d: trailing linefeed missing, line too long or " "embedded Nul character", fname, lnr); break; } line[--n] = 0; /* Kludge to allow indentation of tables. */ for (p=line; *p == ' ' || *p == '\t'; p++) ; if (*p) { if (*p == '@' && !strncmp (p+1, "item", 4)) item_indent = p - line; /* Set a new indent level. */ else if (p - line < item_indent) item_indent = 0; /* Switch off indention. */ if (item_indent) { memmove (line, line+item_indent, n - item_indent + 1); n -= item_indent; } } if (*line == '@') { for (p=line+1, n=1; *p && *p != ' ' && *p != '\t'; p++) n++; while (*p == ' ' || *p == '\t') p++; } else p = line; /* Take action on macro. */ if (macroname) { if (n == 4 && !memcmp (line, "@end", 4) && (line[4]==' '||line[4]=='\t'||!line[4]) && !strncmp (p, "macro", 5) && (p[5]==' '||p[5]=='\t'||!p[5])) { if (macrovalueused) macrovalue[--macrovalueused] = 0; /* Kill the last LF. */ macrovalue[macrovalueused] = 0; /* Terminate macro. */ macrovalue = xrealloc (macrovalue, macrovalueused+1); set_macro (macroname, macrovalue); macrovalue = NULL; free (macroname); macroname = NULL; } else { if (macrovalueused + strlen (line) + 2 >= macrovaluesize) { macrovaluesize += strlen (line) + 256; macrovalue = xrealloc (macrovalue, macrovaluesize); } strcpy (macrovalue+macrovalueused, line); macrovalueused += strlen (line); macrovalue[macrovalueused++] = '\n'; } continue; } if (n >= 5 && !memcmp (line, "@node", 5) && (line[5]==' '||line[5]=='\t'||!line[5])) { /* Completey ignore @node lines. */ continue; } if (skip_sect_line) { skip_sect_line = 0; if (!strncmp (line, "@section", 8) || !strncmp (line, "@subsection", 11) || !strncmp (line, "@chapheading", 12)) continue; } /* We only parse lines we need and ignore the rest. There are a few macros used to control this as well as one @ifset command. Parts we know about are saved away into containers separate for each section. */ /* First process ifset/ifclear commands. */ if (*line == '@') { if (n == 6 && !memcmp (line, "@ifset", 6) && (line[6]==' '||line[6]=='\t')) { for (p=line+7; *p == ' ' || *p == '\t'; p++) ; if (!*p) { err ("%s:%d: name missing after \"@ifset\"", fname, lnr); continue; } for (pend=p; *pend && *pend != ' ' && *pend != '\t'; pend++) ; *pend = 0; /* Ignore rest of the line. */ push_condition (p, 1, fname, lnr); continue; } else if (n == 8 && !memcmp (line, "@ifclear", 8) && (line[8]==' '||line[8]=='\t')) { for (p=line+9; *p == ' ' || *p == '\t'; p++) ; if (!*p) { err ("%s:%d: name missing after \"@ifsclear\"", fname, lnr); continue; } for (pend=p; *pend && *pend != ' ' && *pend != '\t'; pend++) ; *pend = 0; /* Ignore rest of the line. */ push_condition (p, 0, fname, lnr); continue; } else if (n == 4 && !memcmp (line, "@end", 4) && (line[4]==' '||line[4]=='\t') && !strncmp (p, "ifset", 5) && (p[5]==' '||p[5]=='\t'||!p[5])) { pop_condition (1, fname, lnr); continue; } else if (n == 4 && !memcmp (line, "@end", 4) && (line[4]==' '||line[4]=='\t') && !strncmp (p, "ifclear", 7) && (p[7]==' '||p[7]=='\t'||!p[7])) { pop_condition (0, fname, lnr); continue; } } /* Take action on ifset/ifclear. */ if (!cond_is_active) continue; /* Process commands. */ if (*line == '@') { if (skip_to_end && n == 4 && !memcmp (line, "@end", 4) && (line[4]==' '||line[4]=='\t'||!line[4])) { skip_to_end = 0; } else if (cond_in_verbatim) { got_line = 1; } else if (n == 6 && !memcmp (line, "@macro", 6)) { macroname = xstrdup (p); macrovalue = xmalloc ((macrovaluesize = 1024)); macrovalueused = 0; } else if (n == 8 && !memcmp (line, "@manpage", 8)) { free (*section_name); *section_name = NULL; finish_page (); start_page (p); in_pause = 0; } else if (n == 8 && !memcmp (line, "@mansect", 8)) { if (!thepage.name) err ("%s:%d: section outside of a man page", fname, lnr); else { free (*section_name); *section_name = ascii_strupr (xstrdup (p)); in_pause = 0; skip_sect_line = 1; } } else if (n == 9 && !memcmp (line, "@manpause", 9)) { if (!*section_name) err ("%s:%d: pausing outside of a man section", fname, lnr); else if (in_pause) err ("%s:%d: already pausing", fname, lnr); else in_pause = 1; } else if (n == 8 && !memcmp (line, "@mancont", 8)) { if (!*section_name) err ("%s:%d: continue outside of a man section", fname, lnr); else if (!in_pause) err ("%s:%d: continue while not pausing", fname, lnr); else in_pause = 0; } else if (n == 5 && !memcmp (line, "@menu", 5) && (line[5]==' '||line[5]=='\t'||!line[5])) { skip_to_end = 1; } else if (n == 8 && !memcmp (line, "@include", 8) && (line[8]==' '||line[8]=='\t'||!line[8])) { char *incname = xstrdup (p); FILE *incfp = fopen (incname, "r"); if (!incfp && opt_include && *opt_include && *p != '/') { free (incname); incname = xmalloc (strlen (opt_include) + 1 + strlen (p) + 1); strcpy (incname, opt_include); if ( incname[strlen (incname)-1] != '/' ) strcat (incname, "/"); strcat (incname, p); incfp = fopen (incname, "r"); } if (!incfp) err ("can't open include file '%s':%s", incname, strerror (errno)); else { parse_file (incname, incfp, section_name, in_pause); fclose (incfp); } free (incname); } else if (n == 4 && !memcmp (line, "@bye", 4) && (line[4]==' '||line[4]=='\t'||!line[4])) { break; } else if (!skip_to_end) got_line = 1; } else if (!skip_to_end) got_line = 1; if (got_line && cond_in_verbatim) add_content (*section_name, line, 1); else if (got_line && thepage.name && *section_name && !in_pause) add_content (*section_name, line, 0); } if (ferror (fp)) err ("%s:%d: read error: %s", fname, lnr, strerror (errno)); free (macroname); free (macrovalue); free (line); }
const char * odbc_get_cmd_line(char **p_s, int *cond) { while (fgets(line_buf, sizeof(line_buf), parse_file)) { char *p = line_buf; const char *cmd; ++odbc_line_num; cmd = odbc_get_tok(&p); /* skip comments */ if (!cmd || cmd[0] == '#' || cmd[0] == 0 || cmd[0] == '\n') continue; /* conditional statement */ if (!strcmp(cmd, "else")) { int c = pop_condition(); push_condition(c); *cond = c && !*cond; continue; } if (!strcmp(cmd, "endif")) { *cond = pop_condition(); continue; } if (!strcmp(cmd, "if")) { push_condition(*cond); if (*cond) *cond = get_condition(&p); continue; } if (strcmp(cmd, "tds_version_cmp") == 0) { const char *bool_name = odbc_get_tok(&p); const char *cmp = odbc_get_tok(&p); const char *s_ver = odbc_get_tok(&p); int ver = odbc_tds_version(); int expected; int res; unsigned M, m; if (!cmp || !s_ver) odbc_fatal(": missing parameters\n"); if (sscanf(s_ver, "%u.%u", &M, &m) != 2) odbc_fatal(": invalid version %s\n", s_ver); expected = M * 0x100u + m; if (strcmp(cmp, ">") == 0) res = ver > expected; else if (strcmp(cmp, ">=") == 0) res = ver >= expected; else if (strcmp(cmp, "<") == 0) res = ver < expected; else if (strcmp(cmp, "<=") == 0) res = ver <= expected; else if (strcmp(cmp, "==") == 0) res = ver == expected; else if (strcmp(cmp, "!=") == 0) res = ver != expected; else odbc_fatal(": invalid operator %s\n", cmp); if (*cond) odbc_set_bool(bool_name, res); continue; } *p_s = p; return cmd; } return NULL; }