1/*  This file is part of the program psim.
2
3    Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19    */
20
21
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <stdio.h>
25#include <fcntl.h>
26#include <ctype.h>
27
28#include "config.h"
29#include "misc.h"
30#include "lf.h"
31#include "table.h"
32
33#ifdef HAVE_UNISTD_H
34#include <unistd.h>
35#endif
36
37#ifdef HAVE_STDLIB_H
38#include <stdlib.h>
39#endif
40
41typedef struct _open_table open_table;
42struct _open_table {
43  size_t size;
44  char *buffer;
45  char *pos;
46  int line_nr;
47  int nr_fields;
48  int nr_model_fields;
49  char *file_name;
50  open_table *parent;
51  table *root;
52};
53struct _table {
54  open_table *current;
55};
56
57void
58table_push (table *root,
59	    table_include *includes,
60	    const char *file_name,
61	    int nr_fields,
62	    int nr_model_fields)
63
64{
65  int fd;
66  struct stat stat_buf;
67  open_table *file;
68  table_include dummy;
69  table_include *include = &dummy;
70  int nr;
71
72  /* dummy up a search of this directory */
73  dummy.next = includes;
74  dummy.dir = "";
75
76  /* create a file descriptor */
77  file = ZALLOC (open_table);
78  ASSERT(file != NULL);
79  file->nr_fields = nr_fields;
80  file->nr_model_fields = nr_model_fields;
81  file->root = root;
82  file->parent = root->current;
83  root->current = file;
84
85  while (1)
86    {
87      /* save the file name */
88      char *dup_name = NZALLOC (char, strlen (include->dir) + strlen (file_name) + 2);
89      if (dup_name == NULL)
90	{
91	  perror (file_name);
92	  exit (1);
93	}
94      if (include->dir[0] != '\0')
95	{
96	  strcat (dup_name, include->dir);
97	  strcat (dup_name, "/");
98	}
99      strcat (dup_name, file_name);
100      file->file_name = dup_name;
101      /* open the file */
102      fd = open (dup_name, O_RDONLY, 0);
103      if (fd >= 0)
104	break;
105      /* zfree (dup_name); */
106      if (include->next == NULL)
107	{
108	  error ("Problem opening file `%s'\n", file_name);
109	  perror (file_name);
110	  exit (1);
111	}
112      include = include->next;
113  }
114
115  /* determine the size */
116  if (fstat(fd, &stat_buf) < 0) {
117    perror("table_open.fstat");
118    exit(1);
119  }
120  file->size = stat_buf.st_size;
121
122  /* allocate this much memory */
123  file->buffer = (char*)zalloc(file->size+1);
124  if(file->buffer == NULL) {
125    perror("table_open.calloc.file->size+1");
126    exit(1);
127  }
128  file->pos = file->buffer;
129
130  /* read it in */
131#ifdef __CYGWIN32__
132  if ((file->size) && ((nr = read(fd, file->buffer, file->size)) <= 0)) {
133#else
134  if ((nr = read(fd, file->buffer, file->size)) < file->size) {
135#endif
136    perror("table_open.read");
137    exit(1);
138  }
139  file->size = nr;
140  file->buffer[file->size] = '\0';
141
142  /* done */
143  close(fd);
144}
145
146extern table *
147table_open(const char *file_name,
148	   int nr_fields,
149	   int nr_model_fields)
150{
151  table *root;
152
153  /* create a file descriptor */
154  root = ZALLOC (table);
155  if (root == NULL)
156    {
157      perror (file_name);
158      exit (1);
159    }
160
161  table_push (root, NULL, file_name, nr_fields, nr_model_fields);
162  return root;
163}
164
165extern table_entry *
166table_entry_read(table *root)
167{
168  open_table *file = root->current;
169  int field;
170  table_entry *entry;
171
172  /* skip comments/blanks */
173  while(1) {
174    /* end-of-file? */
175    while (*file->pos == '\0')
176      {
177        if (file->parent != NULL)
178          {
179            file = file->parent;
180            root->current = file;
181          }
182        else
183          return NULL;
184      }
185    /* leading white space */
186    while (*file->pos != '\0'
187	   && *file->pos != '\n'
188	   && isspace(*file->pos))
189      file->pos++;
190    /* comment */
191    if (*file->pos == '#') {
192      do {
193	file->pos++;
194      } while (*file->pos != '\0' && *file->pos != '\n');
195    }
196    /* end of line? */
197    if (*file->pos == '\n') {
198      file->pos++;
199      file->line_nr++;
200    }
201    else
202      break;
203  }
204
205  /* create this new entry */
206  entry = (table_entry*)zalloc(sizeof(table_entry)
207			       + (file->nr_fields + 1) * sizeof(char*));
208  ASSERT(entry != NULL);
209  entry->file_name = file->file_name;
210  entry->nr_fields = file->nr_fields;
211
212  /* break the line into its colon delimitered fields */
213  for (field = 0; field < file->nr_fields-1; field++) {
214    entry->fields[field] = file->pos;
215    while(*file->pos && *file->pos != ':' && *file->pos != '\n')
216      file->pos++;
217    if (*file->pos == ':') {
218      *file->pos = '\0';
219      file->pos++;
220    }
221  }
222
223  /* any trailing stuff not the last field */
224  ASSERT(field == file->nr_fields-1);
225  entry->fields[field] = file->pos;
226  while (*file->pos && *file->pos != '\n') {
227    file->pos++;
228  }
229  if (*file->pos == '\n') {
230    *file->pos = '\0';
231    file->pos++;
232  }
233  file->line_nr++;
234
235  /* if following lines begin with a star, add them to the model
236     section.  */
237  while ((file->nr_model_fields > 0) && (*file->pos == '*')) {
238    table_model_entry *model = (table_model_entry*)zalloc(sizeof(table_model_entry)
239							  + (file->nr_model_fields + 1) * sizeof(char*));
240    if (entry->model_last)
241      entry->model_last->next = model;
242    else
243      entry->model_first = model;
244    entry->model_last = model;
245
246    /* break the line into its colon delimitered fields */
247    file->pos++;
248    for (field = 0; field < file->nr_model_fields-1; field++) {
249      model->fields[field] = file->pos;
250      while(*file->pos && *file->pos != ':' && *file->pos != '\n')
251	file->pos++;
252      if (*file->pos == ':') {
253	*file->pos = '\0';
254	file->pos++;
255      }
256    }
257
258    /* any trailing stuff not the last field */
259    ASSERT(field == file->nr_model_fields-1);
260    model->fields[field] = file->pos;
261    while (*file->pos && *file->pos != '\n') {
262      file->pos++;
263    }
264    if (*file->pos == '\n') {
265      *file->pos = '\0';
266      file->pos++;
267    }
268
269    file->line_nr++;
270    model->line_nr = file->line_nr;
271  }
272
273  entry->line_nr = file->line_nr;
274
275  /* if following lines are tab indented, put in the annex */
276  if (*file->pos == '\t') {
277    entry->annex = file->pos;
278    do {
279      do {
280	file->pos++;
281      } while (*file->pos != '\0' && *file->pos != '\n');
282      if (*file->pos == '\n') {
283	char *save_pos = ++file->pos;
284	int extra_lines = 0;
285	file->line_nr++;
286	/* Allow tab indented to have blank lines */
287	while (*save_pos == '\n') {
288	  save_pos++;
289	  extra_lines++;
290	}
291	if (*save_pos == '\t') {
292	  file->pos = save_pos;
293	  file->line_nr += extra_lines;
294	}
295      }
296    } while (*file->pos != '\0' && *file->pos == '\t');
297    if (file->pos[-1] == '\n')
298      file->pos[-1] = '\0';
299  }
300  else
301    entry->annex = NULL;
302
303  /* return it */
304  return entry;
305
306}
307
308
309extern void
310dump_table_entry(table_entry *entry,
311		 int indent)
312{
313  printf("(table_entry*)%p\n", entry);
314
315  if (entry != NULL) {
316    int field;
317    char sep;
318
319    sep = ' ';
320    dumpf(indent, "(fields");
321    for (field = 0; field < entry->nr_fields; field++) {
322      printf("%c%s", sep, entry->fields[field]);
323      sep = ':';
324    }
325    printf(")\n");
326
327    dumpf(indent, "(line_nr %d)\n", entry->line_nr);
328
329    dumpf(indent, "(file_name %s)\n", entry->file_name);
330
331    dumpf(indent, "(annex\n%s\n", entry->annex);
332    dumpf(indent, " )\n");
333
334  }
335}
336
337
338extern void
339table_entry_print_cpp_line_nr(lf *file,
340			      table_entry *entry)
341{
342  lf_print__external_reference(file, entry->line_nr, entry->file_name);
343}
344
345
346