groff before CVS: release 1.06
[s-roff.git] / libdriver / input.cc
blobca0b87117693ddaae3847885a2b88ee6d53a391c
1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING. If not, write to the Free Software
19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21 #include "driver.h"
22 #include "device.h"
24 const char *current_filename;
25 int current_lineno;
26 const char *device = 0;
27 FILE *current_file;
29 int get_char();
30 int get_integer(); // don't read the newline
31 int possibly_get_integer(int *);
32 char *get_string(int is_long = 0);
33 void skip_line();
35 struct environment_list {
36 environment env;
37 environment_list *next;
39 environment_list(const environment &, environment_list *);
42 environment_list::environment_list(const environment &e, environment_list *p)
43 : env(e), next(p)
47 inline int get_char()
49 return getc(current_file);
52 void do_file(const char *filename)
54 int npages = 0;
55 if (filename[0] == '-' && filename[1] == '\0') {
56 current_filename = "<standard input>";
57 current_file = stdin;
59 else {
60 errno = 0;
61 current_file = fopen(filename, "r");
62 if (current_file == 0) {
63 error("can't open `%1'", filename);
64 return;
66 current_filename = filename;
68 environment env;
69 env.vpos = -1;
70 env.hpos = -1;
71 env.fontno = -1;
72 env.height = 0;
73 env.slant = 0;
74 environment_list *env_list = 0;
75 current_lineno = 1;
76 int command;
77 char *s;
78 command = get_char();
79 if (command == EOF)
80 return;
81 if (command != 'x')
82 fatal("the first command must be `x T'");
83 s = get_string();
84 if (s[0] != 'T')
85 fatal("the first command must be `x T'");
86 char *dev = get_string();
87 if (pr == 0) {
88 device = strsave(dev);
89 if (!font::load_desc())
90 fatal("sorry, I can't continue");
92 else {
93 if (device == 0 || strcmp(device, dev) != 0)
94 fatal("all files must use the same device");
96 skip_line();
97 env.size = 10*font::sizescale;
98 command = get_char();
99 if (command != 'x')
100 fatal("the second command must be `x res'");
101 s = get_string();
102 if (s[0] != 'r')
103 fatal("the second command must be `x res'");
104 int n = get_integer();
105 if (n != font::res)
106 fatal("resolution does not match");
107 n = get_integer();
108 if (n != font::hor)
109 fatal("horizontal resolution does not match");
110 n = get_integer();
111 if (n != font::vert)
112 fatal("vertical resolution does not match");
113 skip_line();
114 command = get_char();
115 if (command != 'x')
116 fatal("the third command must be `x init'");
117 s = get_string();
118 if (s[0] != 'i')
119 fatal("the third command must be `x init'");
120 skip_line();
121 if (pr == 0)
122 pr = make_printer();
123 while ((command = get_char()) != EOF) {
124 switch (command) {
125 case 's':
126 env.size = get_integer();
127 if (env.height == env.size)
128 env.height = 0;
129 break;
130 case 'f':
131 env.fontno = get_integer();
132 break;
133 case 'C':
135 if (npages == 0)
136 fatal("`C' command illegal before first `p' command");
137 char *s = get_string();
138 pr->set_special_char(s, &env);
140 break;
141 case 'N':
143 if (npages == 0)
144 fatal("`N' command illegal before first `p' command");
145 pr->set_numbered_char(get_integer(), &env);
147 break;
148 case 'H':
149 env.hpos = get_integer();
150 break;
151 case 'h':
152 env.hpos += get_integer();
153 break;
154 case 'V':
155 env.vpos = get_integer();
156 break;
157 case 'v':
158 env.vpos += get_integer();
159 break;
160 case '0':
161 case '1':
162 case '2':
163 case '3':
164 case '4':
165 case '5':
166 case '6':
167 case '7':
168 case '8':
169 case '9':
171 int c = get_char();
172 if (!isascii(c) || !isdigit(c))
173 fatal("digit expected");
174 env.hpos += (command - '0')*10 + (c - '0');
176 // fall through
177 case 'c':
179 if (npages == 0)
180 fatal("`c' command illegal before first `p' command");
181 int c = get_char();
182 if (c == EOF)
183 fatal("missing argument to `c' command");
184 pr->set_ascii_char(c, &env);
186 break;
187 case 'n':
188 if (npages == 0)
189 fatal("`n' command illegal before first `p' command");
190 pr->end_of_line();
191 (void)get_integer();
192 (void)get_integer();
193 break;
194 case 'w':
195 case ' ':
196 break;
197 case '\n':
198 current_lineno++;
199 break;
200 case 'p':
201 if (npages)
202 pr->end_page();
203 npages++;
204 pr->begin_page(get_integer());
205 env.vpos = 0;
206 break;
207 case '{':
208 env_list = new environment_list(env, env_list);
209 break;
210 case '}':
211 if (!env_list) {
212 fatal("can't pop");
214 else {
215 env = env_list->env;
216 environment_list *tem = env_list;
217 env_list = env_list->next;
218 delete tem;
220 break;
221 case 'u':
223 if (npages == 0)
224 fatal("`u' command illegal before first `p' command");
225 int kern = get_integer();
226 int c = get_char();
227 while (c == ' ')
228 c = get_char();
229 while (c != EOF) {
230 if (c == '\n') {
231 current_lineno++;
232 break;
234 int w;
235 pr->set_ascii_char(c, &env, &w);
236 env.hpos += w + kern;
237 c = get_char();
238 if (c == ' ')
239 break;
242 break;
243 case 't':
245 if (npages == 0)
246 fatal("`t' command illegal before first `p' command");
247 int c;
248 while ((c = get_char()) != EOF && c != ' ') {
249 if (c == '\n') {
250 current_lineno++;
251 break;
253 int w;
254 pr->set_ascii_char(c, &env, &w);
255 env.hpos += w;
258 break;
259 case '#':
260 skip_line();
261 break;
262 case 'D':
264 if (npages == 0)
265 fatal("`D' command illegal before first `p' command");
266 int c;
267 while ((c = get_char()) == ' ')
269 int n;
270 int *p = 0;
271 int szp = 0;
272 for (int np = 0; possibly_get_integer(&n); np++) {
273 if (np >= szp) {
274 if (szp == 0) {
275 szp = 16;
276 p = new int[szp];
278 else {
279 int *oldp = p;
280 p = new int[szp*2];
281 memcpy(p, oldp, szp*sizeof(int));
282 szp *= 2;
283 a_delete oldp;
286 p[np] = n;
288 pr->draw(c, p, np, &env);
289 if (c == 'e') {
290 if (np > 0)
291 env.hpos += p[0];
293 else {
294 for (int i = 0; i < np/2; i++) {
295 env.hpos += p[i*2];
296 env.vpos += p[i*2 + 1];
298 // there might be an odd number of characters
299 if (i*2 < np)
300 env.hpos += p[i*2];
302 a_delete p;
303 skip_line();
305 break;
306 case 'x':
308 char *s = get_string();
309 int suppress_skip = 0;
310 switch (s[0]) {
311 case 'i':
312 error("duplicate `x init' command");
313 break;
314 case 'T':
315 error("duplicate `x T' command");
316 break;
317 case 'r':
318 error("duplicate `x res' command");
319 break;
320 case 'p':
321 break;
322 case 's':
323 break;
324 case 't':
325 break;
326 case 'f':
328 int n = get_integer();
329 char *name = get_string();
330 pr->load_font(n, name);
332 break;
333 case 'H':
334 env.height = get_integer();
335 if (env.height == env.size)
336 env.height = 0;
337 break;
338 case 'S':
339 env.slant = get_integer();
340 break;
341 case 'X':
342 if (npages == 0)
343 fatal("`x X' command illegal before first `p' command");
344 pr->special(get_string(1), &env);
345 suppress_skip = 1;
346 break;
347 default:
348 error("unrecognised x command `%1'", s);
350 if (!suppress_skip)
351 skip_line();
353 break;
354 default:
355 error("unrecognised command code %1", int(command));
356 skip_line();
357 break;
360 if (npages)
361 pr->end_page();
364 int get_integer()
366 int c = get_char();
367 while (c == ' ')
368 c = get_char();
369 int neg = 0;
370 if (c == '-') {
371 neg = 1;
372 c = get_char();
374 if (!isascii(c) || !isdigit(c))
375 fatal("integer expected");
376 int total = 0;
377 do {
378 total = total*10;
379 if (neg)
380 total -= c - '0';
381 else
382 total += c - '0';
383 c = get_char();
384 } while (isascii(c) && isdigit(c));
385 if (c != EOF)
386 ungetc(c, current_file);
387 return total;
390 int possibly_get_integer(int *res)
392 int c = get_char();
393 while (c == ' ')
394 c = get_char();
395 int neg = 0;
396 if (c == '-') {
397 neg = 1;
398 c = get_char();
400 if (!isascii(c) || !isdigit(c)) {
401 if (c != EOF)
402 ungetc(c, current_file);
403 return 0;
405 int total = 0;
406 do {
407 total = total*10;
408 if (neg)
409 total -= c - '0';
410 else
411 total += c - '0';
412 c = get_char();
413 } while (isascii(c) && isdigit(c));
414 if (c != EOF)
415 ungetc(c, current_file);
416 *res = total;
417 return 1;
421 char *get_string(int is_long)
423 static char *buf;
424 static int buf_size;
425 int c = get_char();
426 while (c == ' ')
427 c = get_char();
428 for (int i = 0;; i++) {
429 if (i >= buf_size) {
430 if (buf_size == 0) {
431 buf_size = 16;
432 buf = new char[buf_size];
434 else {
435 char *old_buf = buf;
436 int old_size = buf_size;
437 buf_size *= 2;
438 buf = new char[buf_size];
439 memcpy(buf, old_buf, old_size);
440 a_delete old_buf;
443 if ((!is_long && (c == ' ' || c == '\n')) || c == EOF) {
444 buf[i] = '\0';
445 break;
447 if (is_long && c == '\n') {
448 current_lineno++;
449 c = get_char();
450 if (c == '+')
451 c = '\n';
452 else {
453 buf[i] = '\0';
454 break;
457 buf[i] = c;
458 c = get_char();
460 if (c != EOF)
461 ungetc(c, current_file);
462 return buf;
465 void skip_line()
467 int c;
468 while ((c = get_char()) != EOF)
469 if (c == '\n') {
470 current_lineno++;
471 break;