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