Line data Source code
1 : /* Last non-groff version: hdb.c 1.8 (Berkeley) 84/10/20
2 : *
3 : * Originally written by Barry Roitblat, 1982.
4 : * Adapted to GNU troff by Daniel Senderowicz 99/12/29.
5 : * Modified 2000-2024 by the Free Software Foundation, Inc.
6 : *
7 : * This file contains no AT&T code and is in the public domain.
8 : *
9 : * This file contains database routines for the hard copy programs of
10 : * the gremlin picture editor.
11 : */
12 :
13 : #ifdef HAVE_CONFIG_H
14 : #include <config.h>
15 : #endif
16 :
17 : #include <ctype.h> // isdigit()
18 : #include <stdio.h> // FILE, feof(), fgets(), getc()
19 : #include <stdlib.h> // atoi()
20 : #include <string.h> // strcmp()
21 :
22 : #include "errarg.h"
23 : #include "error.h"
24 : #include "gprint.h"
25 :
26 : #define MAXSTRING 128
27 : #define MAXSTRING_S "127"
28 :
29 : /* imports from main.cpp */
30 :
31 : extern char gremlinfile[]; /* name of file currently reading */
32 : extern int SUNFILE; /* TRUE if SUN gremlin file */
33 : extern int compatibility_flag; /* TRUE if in compatibility mode */
34 : extern void *grnmalloc(size_t size, const char *what);
35 : extern void savebounds(double x, double y);
36 :
37 : /* imports from hpoint.cpp */
38 :
39 : extern POINT *PTInit();
40 : extern POINT *PTMakePoint(double x, double y, POINT ** pplist);
41 :
42 :
43 : int DBGetType(char *s);
44 :
45 : static long lineno = 0; /* line number of gremlin file */
46 :
47 : /*
48 : * This routine returns a pointer to an initialized database element
49 : * which would be the only element in an empty list.
50 : */
51 : ELT *
52 1 : DBInit()
53 : {
54 1 : return ((ELT *) NULL);
55 : } /* end DBInit */
56 :
57 :
58 : /*
59 : * This routine creates a new element with the specified attributes and
60 : * links it into database.
61 : */
62 : ELT *
63 414 : DBCreateElt(int type,
64 : POINT * pointlist,
65 : int brush,
66 : int size,
67 : char *text,
68 : ELT **db)
69 : {
70 414 : ELT *temp = 0;
71 :
72 414 : temp = (ELT *) grnmalloc(sizeof(ELT), "picture element");
73 414 : temp->nextelt = *db;
74 414 : temp->type = type;
75 414 : temp->ptlist = pointlist;
76 414 : temp->brushf = brush;
77 414 : temp->size = size;
78 414 : temp->textpt = text;
79 414 : *db = temp;
80 414 : return (temp);
81 : } /* end CreateElt */
82 :
83 :
84 : /*
85 : * This routine reads the specified file into a database and returns a
86 : * pointer to that database.
87 : */
88 : ELT *
89 1 : DBRead(FILE *file)
90 : {
91 : int i;
92 : int done; /* flag for input exhausted */
93 : double nx; /* x holder so x is not set before orienting */
94 : int type; /* element type */
95 : ELT *elist; /* pointer to the file's elements */
96 : POINT *plist; /* pointer for reading in points */
97 : char string[MAXSTRING], *txt;
98 : double x, y; /* x and y are read in point coords */
99 : int len, brush, size;
100 : int lastpoint;
101 :
102 1 : SUNFILE = FALSE;
103 1 : elist = DBInit();
104 1 : int nitems = fscanf(file, "%" MAXSTRING_S "s%*[^\n]\n", string);
105 1 : if (nitems != 1) {
106 0 : error_with_file_and_line(gremlinfile, lineno,
107 : "malformed input; giving up on this"
108 : " picture");
109 0 : return (elist);
110 : }
111 1 : lineno++;
112 1 : if (strcmp(string, "gremlinfile")) {
113 1 : if (strcmp(string, "sungremlinfile")) {
114 0 : error_with_file_and_line(gremlinfile, lineno,
115 : "not a gremlin file; giving up on this"
116 : " picture");
117 0 : return (elist);
118 : }
119 1 : SUNFILE = TRUE;
120 : }
121 :
122 1 : nitems = fscanf(file, "%d%lf%lf\n", &size, &x, &y);
123 1 : if (nitems != 3) {
124 0 : error_with_file_and_line(gremlinfile, lineno,
125 : "malformed input; giving up on this"
126 : " picture");
127 0 : return (elist);
128 : }
129 1 : lineno++;
130 : /* ignore orientation and file positioning point */
131 :
132 1 : done = FALSE;
133 416 : while (!done) {
134 : /* if (fscanf(file,"%" MAXSTRING_S "s\n", string) == EOF) */
135 : /* I changed the scanf format because the element */
136 : /* can have two words (e.g. CURVE SPLINE) */
137 415 : if (fscanf(file, "\n%"
138 : MAXSTRING_S
139 415 : "[^\n]%*[^\n]\n", string) == EOF) {
140 0 : lineno++;
141 0 : error_with_file_and_line(gremlinfile, lineno, "error in format;"
142 : " giving up on this picture");
143 0 : return (elist);
144 : }
145 415 : lineno++;
146 :
147 415 : type = DBGetType(string); /* interpret element type */
148 415 : if (type < 0) { /* no more data */
149 1 : done = TRUE;
150 : } else {
151 : /* always one point */
152 : #ifdef UW_FASTSCAN
153 : (void) xscanf(file, &x, &y);
154 : #else
155 414 : nitems = fscanf(file, "%lf%lf\n", &x, &y);
156 414 : if (nitems != 2) {
157 0 : error_with_file_and_line(gremlinfile, lineno,
158 : "malformed input; giving up on this"
159 : " picture");
160 0 : return (elist);
161 : }
162 414 : lineno++;
163 : #endif /* UW_FASTSCAN */
164 414 : plist = PTInit(); /* NULL point list */
165 :
166 : /*
167 : * Files created on the SUN have point lists terminated by a line
168 : * containing only an asterisk ('*'). Files created on the AED
169 : * have point lists terminated by the coordinate pair (-1.00
170 : * -1.00).
171 : */
172 414 : if (TEXT(type)) { /* read only first point for TEXT elements */
173 94 : nx = xorn(x, y);
174 94 : y = yorn(x, y);
175 94 : (void) PTMakePoint(nx, y, &plist);
176 94 : savebounds(nx, y);
177 :
178 : #ifdef UW_FASTSCAN
179 : while (xscanf(file, &x, &y));
180 : #else
181 94 : lastpoint = FALSE;
182 282 : do {
183 376 : char *cp = fgets(string, MAXSTRING, file);
184 376 : if (0 /* nullptr */ == cp) {
185 0 : error_with_file_and_line(gremlinfile, lineno,
186 : "premature end-of-file or error"
187 : " reading input; giving up on this"
188 : " picture");
189 0 : return(elist);
190 : }
191 376 : lineno++;
192 376 : if (string[0] == '*') { /* SUN gremlin file */
193 94 : lastpoint = TRUE;
194 : } else {
195 282 : if (!sscanf(string, "%lf%lf", &x, &y)) {
196 0 : error_with_file_and_line(gremlinfile, lineno,
197 : "expected coordinate pair, got"
198 : " '%1'; giving up on this"
199 0 : " picture", string);
200 0 : return(elist);
201 : }
202 282 : if ((x == -1.00 && y == -1.00) && (!SUNFILE))
203 0 : lastpoint = TRUE;
204 : else {
205 282 : if (compatibility_flag)
206 0 : savebounds(xorn(x, y), yorn(x, y));
207 : }
208 : }
209 376 : } while (!lastpoint);
210 : #endif /* UW_FASTSCAN */
211 : } else { /* not TEXT element */
212 : #ifdef UW_FASTSCAN
213 : do {
214 : nx = xorn(x, y);
215 : y = yorn(x, y);
216 : (void) PTMakePoint(nx, y, &plist);
217 : savebounds(nx, y);
218 : } while (xscanf(file, &x, &y));
219 : #else
220 320 : lastpoint = FALSE;
221 1535 : while (!lastpoint) {
222 1215 : nx = xorn(x, y);
223 1215 : y = yorn(x, y);
224 1215 : (void) PTMakePoint(nx, y, &plist);
225 1215 : savebounds(nx, y);
226 :
227 1215 : char *cp = fgets(string, MAXSTRING, file);
228 1215 : if (0 /* nullptr */ == cp) {
229 0 : error_with_file_and_line(gremlinfile, lineno,
230 : "premature end-of-file or error"
231 : " reading input; giving up on this"
232 : " picture");
233 0 : return(elist);
234 : }
235 1215 : lineno++;
236 1215 : if (string[0] == '*') { /* SUN gremlin file */
237 320 : lastpoint = TRUE;
238 : } else {
239 895 : (void) sscanf(string, "%lf%lf", &x, &y);
240 895 : if ((x == -1.00 && y == -1.00) && (!SUNFILE))
241 0 : lastpoint = TRUE;
242 : }
243 : }
244 : #endif /* UW_FASTSCAN */
245 : }
246 414 : nitems = fscanf(file, "%d%d\n", &brush, &size);
247 414 : if (nitems != 2) {
248 0 : error_with_file_and_line(gremlinfile, lineno,
249 : "malformed input; giving up on this"
250 : " picture");
251 0 : return (elist);
252 : }
253 414 : lineno++;
254 414 : nitems = fscanf(file, "%d", &len); /* text length */
255 414 : if (nitems != 1) {
256 0 : error_with_file_and_line(gremlinfile, lineno,
257 : "malformed input; giving up on this"
258 : " picture");
259 0 : return (elist);
260 : }
261 414 : (void) getc(file); /* eat blank */
262 414 : lineno++; /* advance line counter early */
263 414 : if (len < 0) {
264 0 : error_with_file_and_line(gremlinfile, lineno,
265 : "length claimed for text is nonsense:"
266 : " '%1'; giving up on this picture",
267 0 : len);
268 0 : return (elist);
269 : }
270 414 : txt = (char *) grnmalloc((unsigned) len + 1, "element text");
271 1033 : for (i = 0; i < len; ++i) { /* read text */
272 619 : int c = getc(file);
273 619 : if (c == EOF)
274 0 : break;
275 619 : txt[i] = c;
276 : }
277 414 : if (feof(file)) {
278 0 : error_with_file_and_line(gremlinfile, lineno,
279 : "end of file while reading text of"
280 : " length %1; giving up on this"
281 0 : " picture", len);
282 0 : return (elist);
283 : }
284 414 : txt[len] = '\0';
285 414 : (void) DBCreateElt(type, plist, brush, size, txt, &elist);
286 : } /* end else */
287 : } /* end while not done */ ;
288 1 : return (elist);
289 : } /* end DBRead */
290 :
291 :
292 : /*
293 : * Interpret element type in string s.
294 : * Old file format consisted of integer element types.
295 : * New file format has literal names for element types.
296 : */
297 : int
298 415 : DBGetType(char *s)
299 : {
300 415 : if (isdigit(s[0]) || (s[0] == '-')) /* old element format or EOF */
301 1 : return (atoi(s));
302 :
303 414 : switch (s[0]) {
304 36 : case 'P':
305 36 : return (POLYGON);
306 181 : case 'V':
307 181 : return (VECTOR);
308 99 : case 'A':
309 99 : return (ARC);
310 52 : case 'C':
311 52 : if (s[1] == 'U') {
312 4 : if (s[5] == '\n')
313 0 : return (CURVE);
314 4 : switch (s[7]) {
315 4 : case 'S':
316 4 : return(BSPLINE);
317 0 : case 'E':
318 0 : warning_with_file_and_line(gremlinfile, lineno,
319 : "using B-spline for Bezier curve");
320 0 : return(BSPLINE);
321 0 : default:
322 0 : return(CURVE);
323 : }
324 : }
325 48 : switch (s[4]) {
326 17 : case 'L':
327 17 : return (CENTLEFT);
328 2 : case 'C':
329 2 : return (CENTCENT);
330 29 : case 'R':
331 29 : return (CENTRIGHT);
332 0 : default:
333 0 : error_with_file_and_line(gremlinfile, lineno,
334 0 : "unknown element type '%1'", s);
335 0 : return -1;
336 : }
337 29 : case 'B':
338 29 : switch (s[3]) {
339 3 : case 'L':
340 3 : return (BOTLEFT);
341 10 : case 'C':
342 10 : return (BOTCENT);
343 16 : case 'R':
344 16 : return (BOTRIGHT);
345 0 : default:
346 0 : error_with_file_and_line(gremlinfile, lineno,
347 0 : "unknown element type '%1'", s);
348 0 : return -1;
349 : }
350 17 : case 'T':
351 17 : switch (s[3]) {
352 2 : case 'L':
353 2 : return (TOPLEFT);
354 9 : case 'C':
355 9 : return (TOPCENT);
356 6 : case 'R':
357 6 : return (TOPRIGHT);
358 0 : default:
359 0 : error_with_file_and_line(gremlinfile, lineno,
360 0 : "unknown element type '%1'", s);
361 0 : return -1;
362 : }
363 0 : default:
364 0 : error_with_file_and_line(gremlinfile, lineno,
365 0 : "unknown element type '%1'", s);
366 0 : return -1;
367 : }
368 : }
369 :
370 : #ifdef UW_FASTSCAN
371 : /*
372 : * Optimization hack added by solomon@crys.wisc.edu, 12/2/86.
373 : * A huge fraction of the time was spent reading floating point numbers
374 : * from the input file, but the numbers always have the format 'ddd.dd'.
375 : * Thus the following special-purpose version of fscanf.
376 : *
377 : * xscanf(f,xp,yp) does roughly what fscanf(f,"%f%f",xp,yp) does except:
378 : * -the next piece of input must be of the form
379 : * <space>* <digit>*'.'<digit>* <space>* <digit>*'.'<digit>*
380 : * -xscanf eats the character following the second number
381 : * -xscanf returns 0 for "end-of-data" indication, 1 otherwise, where
382 : * end-of-data is signalled by a '*' [in which case the rest of the
383 : * line is gobbled], or by '-1.00 -1.00' [but only if !SUNFILE].
384 : */
385 : int
386 : xscanf(FILE *f,
387 : double *xp,
388 : double *yp)
389 : {
390 : int c, i, j, m, frac;
391 : int iscale = 1, jscale = 1; /* x = i/scale, y=j/jscale */
392 :
393 : while ((c = getc(f)) == ' ');
394 : if (c == '*') {
395 : while ((c = getc(f)) != '\n');
396 : return 0;
397 : }
398 : i = m = frac = 0;
399 : while (isdigit(c) || c == '.' || c == '-') {
400 : if (c == '-') {
401 : m++;
402 : c = getc(f);
403 : continue;
404 : }
405 : if (c == '.')
406 : frac = 1;
407 : else {
408 : if (frac)
409 : iscale *= 10;
410 : i = 10 * i + c - '0';
411 : }
412 : c = getc(f);
413 : }
414 : if (m)
415 : i = -i;
416 : *xp = (double) i / (double) iscale;
417 :
418 : while ((c = getc(f)) == ' ');
419 : j = m = frac = 0;
420 : while (isdigit(c) || c == '.' || c == '-') {
421 : if (c == '-') {
422 : m++;
423 : c = getc(f);
424 : continue;
425 : }
426 : if (c == '.')
427 : frac = 1;
428 : else {
429 : if (frac)
430 : jscale *= 10;
431 : j = 10 * j + c - '0';
432 : }
433 : c = getc(f);
434 : }
435 : if (m)
436 : j = -j;
437 : *yp = (double) j / (double) jscale;
438 : return (SUNFILE || i != -iscale || j != -jscale);
439 : }
440 : #endif /* UW_FASTSCAN */
441 :
442 : // Local Variables:
443 : // fill-column: 72
444 : // mode: C++
445 : // End:
446 : // vim: set cindent noexpandtab shiftwidth=2 textwidth=72:
|