/* -*- c -*- */
/*
GlossTeX, a tool for the automatic preparation of glossaries.
Copyright (C) 1997 Volkan Yavuz
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Volkan Yavuz,
[email protected]
*/
/* $Id: database.c,v 1.45 1997/12/13 16:06:54 volkan Exp $ */
#include "glosstex.h"
#include "database.h"
#include "error.h"
#include "list.h"
#include "labels.h"
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
enum e_pass {
PASS_1 = 0, PASS_2 = 1
};
static unsigned int lineno = 0;
static void process_file (enum e_pass pass, FILE * infile, char *inname);
static void process_line (enum e_pass pass, char *inname, char *line);
static void write_line (FILE * outfile,
char* inname,
char *list, char *label, char *item, char *longform,
char *line, char *list_mode, char *pageref_mode,
char *page);
static int glo_parse_item (char *line, char *label,
char *item, char *longform, int *ptr);
void
read_databases (void)
{
FILE *dbfile;
enum e_pass pass = PASS_1;
s_node *filename = databases.root;
for (pass = PASS_1; pass <= PASS_2; pass++) {
while (filename != 0) {
if ((dbfile = fopen (filename->ptr, "r")) == NULL) {
error ("database %s", (char *) filename->ptr);
} else {
printlog (PROGRESS, STDOUT, "(%s ", (char *) filename->ptr);
process_file (pass, dbfile, (char *) filename->ptr);
printlog (PROGRESS, STDOUT, ")");
}
filename = filename->next;
}
filename = databases.root;
}
}
static void
process_file (enum e_pass pass, FILE * dbfile, char *inname)
{
enum e_state {
HEADER, BODY
};
int status;
char buf[LINESIZE];
enum e_state state = HEADER;
char *line = 0;
while (fgets (buf, LINESIZE, dbfile) != 0) {
if (buf[strlen (buf) - 1] == '\n')
lineno++;
status = strncmp (buf, "@entry{", 7);
if ((state == HEADER) && (status != 0)) {
; /* ignore heading garbage */
} else {
state = BODY;
if (status == 0) { /* begin new entry */
/* process current entry before starting new entry */
if (line != 0) {
process_line (pass, inname, line);
free (line);
}
line = (char *) malloc (strlen (buf) + 1);
assert (line != 0);
strcpy (line, buf);
if (line[strlen (line) - 1] == '\n')
line[strlen (line) - 1] = ' ';
} else if (strncmp (buf, "%", 1) == 0) {
; /* skip comments */
} else { /* add lines to current entry */
size_t len = strlen (line); /* LINT: null is ok here */
line = (char *) realloc (line, len + strlen (buf) + 1);
assert (line != 0);
strcpy (&line[len], buf);
if (line[strlen (line) - 1] == '\n')
line[strlen (line) - 1] = ' ';
}
}
}
/* process last pending line in file */
if (line != 0) {
process_line (pass, inname, line);
free (line);
}
}
static void
process_line (enum e_pass pass, char *inname, char *line)
{
char label[LINESIZE];
char item[LINESIZE];
char longform[LINESIZE];
size_t index;
int ptr = 0;
s_list_iterator iter;
s_list_iterator iter2;
s_label *node;
s_label *node2;
iter.root = labels.root;
iter.current = labels.root;
iter2.root = labels.root;
iter2.current = labels.root;
if (glo_parse_item (line, label, item, longform, &ptr) != 0) {
printlog (PROGRESS, STDOUT, "x");
printlog (WARNING, LOGFILE, "\n%s:%u parse error: %s",
inname, lineno, line);
count_gdf_parsing++;
return;
}
/* remove all trailing spaces */
index = strlen (&line[ptr]);
index--;
while (line[ptr + index] == ' ') {
line[ptr + index] = '\0';
index--;
}
switch (pass) {
case PASS_1:
/* is there a reference to <label> in any list? */
node = find_label (&iter, FIND_FIRST, label, 0);
if (node != 0) {
/* explicit reference to <label> found
process references to <label> in each <list> */
while (node != 0) {
switch ((enum e_label_flag) node->flag) {
case UNRESOLVED:
write_line (outfile, inname,
node->list, label, item, longform, &line[ptr],
node->list_mode, node->pageref_mode, node->page);
node->flag = RESOLVED;
break;
case RESOLVED:
printlog (PROGRESS, STDOUT, "i");
printlog (INFORMATION, LOGFILE,
"\n%s:%u %s already resolved",
inname, lineno, label);
count_gdf_defined++;
break;
}
node = find_label (&iter, FIND_NEXT, label, 0);
}
}
break;
case PASS_2:
/* now look for wildcard in any list */
node = find_label (&iter, FIND_FIRST, "*", 0);
if (node == 0) {
printlog (PROGRESS, STDOUT, ".");
printlog (DEBUG, LOGFILE, "\n%s:%u %s@%s(%s) not needed",
inname, lineno, label, item, longform);
} else {
/* check for wildcard in every list */
while (node != 0) {
/* wurde <label> in <node->list> schon explicit angefordert? */
if ((node2 =
find_label (&iter2, FIND_FIRST, label, node->list)) == 0) {
write_line (outfile, inname,
node->list, label, item, longform, &line[ptr],
node->list_mode, node->pageref_mode, node->page);
node->flag = RESOLVED;
}
node = find_label (&iter, FIND_NEXT, "*", 0);
}
}
break;
}
}
static void
write_line (FILE * outfile,
char* inname,
char *list, char *label, char *item, char *longform,
char *line, char *list_mode, char *pageref_mode, char *page)
{
fprintf (outfile,
"\\GlossTeXEntry{%s%s@{%s}{%s}{%s}{%s}{%s}{%s}"
"{\\GlossTeXPage{%s}{%s}}|GlossTeXNull}{0}\n",
list, label, label, item, longform, line,
list, list_mode, pageref_mode, page);
printlog (PROGRESS, STDOUT, "o");
printlog (VERBOSE, LOGFILE, "\n%s:%u %s@%s(%s) used *",
inname, lineno, label, item, longform);
count_gdf_success++;
}
/* #module GloScan "2-001"
***********************************************************************
* *
* The software was developed at the Monsanto Company and is provided *
* "as-is". Monsanto Company and the auther disclaim all warranties *
* on the software, including without limitation, all implied warran- *
* ties of merchantabilitiy and fitness. *
* *
* This software does not contain any technical data or information *
* that is proprietary in nature. It may be copied, modified, and *
* distributed on a non-profit basis and with the inclusion of this *
* notice. *
* *
***********************************************************************
*/
/* this has been slightly modified by volkan yavuz 1996/12/18 */
static int
glo_parse_item (char *line, char *label, char *item, char *longform, int *ptr)
{
int i, brace;
char x;
/* Copy the label to the output string. */
i = 0;
brace = 1;
*ptr = 7;
while (1) {
x = line[(*ptr)++];
if (x == '\0')
return 1;
if (x == '{')
if (line[*ptr - 2] != '\\')
brace++;
if (x == '}') {
if (line[*ptr - 2] != '\\')
brace--;
if (brace <= 0)
break;
}
if (x == ',')
break;
label[i++] = x;
}
label[i] = '\0';
/* Find the beginning of the item string. */
while (isspace (line[*ptr]) != 0)
(*ptr)++;
/* Copy the item to the output string. */
i = 0;
while (brace > 0) {
x = line[(*ptr)++];
if (x == '\0')
return 1;
if (x == '{')
if (line[*ptr - 2] != '\\')
brace++;
if (x == '}') {
if (line[*ptr - 2] != '\\')
brace--;
if (brace <= 0)
break;
}
if (x == ',')
break;
item[i++] = x;
}
item[i] = '\0';
/* Check to see if the item is missing. If it is, default to the label. */
if (i == 0)
(void) strcpy (item, label); /* FIXME: lint code error */
while (isspace (line[*ptr]) != 0)
(*ptr)++;
/* Copy the long-form to the output string. */
i = 0;
while (brace > 0) {
x = line[(*ptr)++];
if (x == '\0')
return 1;
if (x == '{')
if (line[*ptr - 2] != '\\')
brace++;
if (x == '}') {
if (line[*ptr - 2] != '\\')
brace--;
if (brace <= 0)
break;
}
longform[i++] = x;
}
longform[i] = '\0';
return 0; /* it's all ok */
}