1 /* Last non-groff version: hdb.c  1.8 (Berkeley) 84/10/20
2 *
3 * Copyright -C- 1982 Barry S. Roitblat
4 *
5 * This file contains database routines for the hard copy programs of the
6 * gremlin picture editor.
7 */
8
9#include "gprint.h"
10#include <stdlib.h>
11#include <string.h>
12#include <ctype.h>
13
14#include "errarg.h"
15#include "error.h"
16
17#define MAXSTRING 128
18#define MAXSTRING_S "127"
19
20/* imports from main.cpp */
21
22extern int linenum;		/* current line number in input file */
23extern char gremlinfile[];	/* name of file currently reading */
24extern int SUNFILE;		/* TRUE if SUN gremlin file */
25extern int compatibility_flag;	/* TRUE if in compatibility mode */
26extern void savebounds(double x, double y);
27
28/* imports from hpoint.cpp */
29
30extern POINT *PTInit();
31extern POINT *PTMakePoint(double x, double y, POINT ** pplist);
32
33
34int DBGetType(register char *s);
35
36
37/*
38 * This routine returns a pointer to an initialized database element which
39 * would be the only element in an empty list.
40 */
41ELT *
42DBInit()
43{
44  return ((ELT *) NULL);
45}				/* end DBInit */
46
47
48/*
49 * This routine creates a new element with the specified attributes and
50 * links it into database.
51 */
52ELT *
53DBCreateElt(int type,
54	    POINT * pointlist,
55	    int brush,
56	    int size,
57	    char *text,
58	    ELT **db)
59{
60  register ELT *temp;
61
62  temp = (ELT *) malloc(sizeof(ELT));
63  temp->nextelt = *db;
64  temp->type = type;
65  temp->ptlist = pointlist;
66  temp->brushf = brush;
67  temp->size = size;
68  temp->textpt = text;
69  *db = temp;
70  return (temp);
71}				/* end CreateElt */
72
73
74/*
75 * This routine reads the specified file into a database and returns a
76 * pointer to that database.
77 */
78ELT *
79DBRead(register FILE *file)
80{
81  register int i;
82  register int done;		/* flag for input exhausted */
83  register double nx;		/* x holder so x is not set before orienting */
84  int type;			/* element type */
85  ELT *elist;			/* pointer to the file's elements */
86  POINT *plist;			/* pointer for reading in points */
87  char string[MAXSTRING], *txt;
88  double x, y;			/* x and y are read in point coords */
89  int len, brush, size;
90  int lastpoint;
91
92  SUNFILE = FALSE;
93  elist = DBInit();
94  (void) fscanf(file, "%" MAXSTRING_S "s%*[^\n]\n", string);
95  if (strcmp(string, "gremlinfile")) {
96    if (strcmp(string, "sungremlinfile")) {
97      error("`%1' is not a gremlin file", gremlinfile);
98      return (elist);
99    }
100    SUNFILE = TRUE;
101  }
102
103  (void) fscanf(file, "%d%lf%lf\n", &size, &x, &y);
104  /* ignore orientation and file positioning point */
105
106  done = FALSE;
107  while (!done) {
108    /* if (fscanf(file,"%" MAXSTRING_S "s\n", string) == EOF) */
109    /* I changed the scanf format because the element */
110    /* can have two words (e.g. CURVE SPLINE)         */
111    if (fscanf(file, "\n%" MAXSTRING_S "[^\n]%*[^\n]\n", string) == EOF) {
112      error("`%1', error in file format", gremlinfile);
113      return (elist);
114    }
115
116    type = DBGetType(string);	/* interpret element type */
117    if (type < 0) {		/* no more data */
118      done = TRUE;
119    } else {
120#ifdef UW_FASTSCAN
121      (void) xscanf(file, &x, &y);		/* always one point */
122#else
123      (void) fscanf(file, "%lf%lf\n", &x, &y);	/* always one point */
124#endif	/* UW_FASTSCAN */
125      plist = PTInit();		/* NULL point list */
126
127      /*
128       * Files created on the SUN have point lists terminated by a line
129       * containing only an asterik ('*').  Files created on the AED have
130       * point lists terminated by the coordinate pair (-1.00 -1.00).
131       */
132      if (TEXT(type)) {		/* read only first point for TEXT elements */
133	nx = xorn(x, y);
134	y = yorn(x, y);
135	(void) PTMakePoint(nx, y, &plist);
136	savebounds(nx, y);
137
138#ifdef UW_FASTSCAN
139	while (xscanf(file, &x, &y));
140#else
141	lastpoint = FALSE;
142	do {
143	  fgets(string, MAXSTRING, file);
144	  if (string[0] == '*') {	/* SUN gremlin file */
145	    lastpoint = TRUE;
146	  } else {
147	    (void) sscanf(string, "%lf%lf", &x, &y);
148	    if ((x == -1.00 && y == -1.00) && (!SUNFILE))
149	      lastpoint = TRUE;
150	    else {
151	      if (compatibility_flag)
152		savebounds(xorn(x, y), yorn(x, y));
153	    }
154	  }
155	} while (!lastpoint);
156#endif	/* UW_FASTSCAN */
157      } else {			/* not TEXT element */
158#ifdef UW_FASTSCAN
159	do {
160	  nx = xorn(x, y);
161	  y = yorn(x, y);
162	  (void) PTMakePoint(nx, y, &plist);
163	  savebounds(nx, y);
164	} while (xscanf(file, &x, &y));
165#else
166	lastpoint = FALSE;
167	while (!lastpoint) {
168	  nx = xorn(x, y);
169	  y = yorn(x, y);
170	  (void) PTMakePoint(nx, y, &plist);
171	  savebounds(nx, y);
172
173	  fgets(string, MAXSTRING, file);
174	  if (string[0] == '*') {	/* SUN gremlin file */
175	    lastpoint = TRUE;
176	  } else {
177	    (void) sscanf(string, "%lf%lf", &x, &y);
178	    if ((x == -1.00 && y == -1.00) && (!SUNFILE))
179	      lastpoint = TRUE;
180	  }
181	}
182#endif	/* UW_FASTSCAN */
183      }
184      (void) fscanf(file, "%d%d\n", &brush, &size);
185      (void) fscanf(file, "%d", &len);	/* text length */
186      (void) getc(file);		/* eat blank */
187      txt = (char *) malloc((unsigned) len + 1);
188      for (i = 0; i < len; ++i) {	/* read text */
189        int c = getc(file);
190        if (c == EOF)
191          break;
192	txt[i] = c;
193      }
194      txt[len] = '\0';
195      (void) DBCreateElt(type, plist, brush, size, txt, &elist);
196    }				/* end else */
197  } /* end while not done */ ;
198  return (elist);
199}				/* end DBRead */
200
201
202/*
203 * Interpret element type in string s.
204 * Old file format consisted of integer element types.
205 * New file format has literal names for element types.
206 */
207int
208DBGetType(register char *s)
209{
210  if (isdigit(s[0]) || (s[0] == '-'))	/* old element format or EOF */
211    return (atoi(s));
212
213  switch (s[0]) {
214  case 'P':
215    return (POLYGON);
216  case 'V':
217    return (VECTOR);
218  case 'A':
219    return (ARC);
220  case 'C':
221    if (s[1] == 'U') {
222      if (s[5] == '\n')
223	return (CURVE);
224      switch (s[7]) {
225      case 'S':
226	return(BSPLINE);
227      case 'E':
228	fprintf(stderr,
229		"Warning: Bezier Curves will be printed as B-Splines\n");
230	return(BSPLINE);
231      default:
232	return(CURVE);
233      }
234    }
235    switch (s[4]) {
236    case 'L':
237      return (CENTLEFT);
238    case 'C':
239      return (CENTCENT);
240    case 'R':
241      return (CENTRIGHT);
242    default:
243      fatal("unknown element type");
244    }
245  case 'B':
246    switch (s[3]) {
247    case 'L':
248      return (BOTLEFT);
249    case 'C':
250      return (BOTCENT);
251    case 'R':
252      return (BOTRIGHT);
253    default:
254      fatal("unknown element type");
255    }
256  case 'T':
257    switch (s[3]) {
258    case 'L':
259      return (TOPLEFT);
260    case 'C':
261      return (TOPCENT);
262    case 'R':
263      return (TOPRIGHT);
264    default:
265      fatal("unknown element type");
266    }
267  default:
268    fatal("unknown element type");
269  }
270
271  return 0;				/* never reached */
272}
273
274#ifdef UW_FASTSCAN
275/*
276 * Optimization hack added by solomon@crys.wisc.edu, 12/2/86.
277 * A huge fraction of the time was spent reading floating point numbers from
278 * the input file, but the numbers always have the format 'ddd.dd'.  Thus
279 * the following special-purpose version of fscanf.
280 *
281 * xscanf(f,xp,yp) does roughly what fscanf(f,"%f%f",xp,yp) does except:
282 *   -the next piece of input must be of the form
283 *      <space>* <digit>*'.'<digit>* <space>* <digit>*'.'<digit>*
284 *   -xscanf eats the character following the second number
285 *   -xscanf returns 0 for "end-of-data" indication, 1 otherwise, where
286 *    end-of-data is signalled by a '*' [in which case the rest of the
287 *    line is gobbled], or by '-1.00 -1.00' [but only if !SUNFILE].
288 */
289int
290xscanf(FILE *f,
291       double *xp,
292       double *yp)
293{
294  register int c, i, j, m, frac;
295  int iscale = 1, jscale = 1;	/* x = i/scale, y=j/jscale */
296
297  while ((c = getc(f)) == ' ');
298  if (c == '*') {
299    while ((c = getc(f)) != '\n');
300    return 0;
301  }
302  i = m = frac = 0;
303  while (isdigit(c) || c == '.' || c == '-') {
304    if (c == '-') {
305      m++;
306      c = getc(f);
307      continue;
308    }
309    if (c == '.')
310      frac = 1;
311    else {
312      if (frac)
313	iscale *= 10;
314      i = 10 * i + c - '0';
315    }
316    c = getc(f);
317  }
318  if (m)
319    i = -i;
320  *xp = (double) i / (double) iscale;
321
322  while ((c = getc(f)) == ' ');
323  j = m = frac = 0;
324  while (isdigit(c) || c == '.' || c == '-') {
325    if (c == '-') {
326      m++;
327      c = getc(f);
328      continue;
329    }
330    if (c == '.')
331      frac = 1;
332    else {
333      if (frac)
334	jscale *= 10;
335      j = 10 * j + c - '0';
336    }
337    c = getc(f);
338  }
339  if (m)
340    j = -j;
341  *yp = (double) j / (double) jscale;
342  return (SUNFILE || i != -iscale || j != -jscale);
343}
344#endif	/* UW_FASTSCAN */
345
346/* EOF */
347