1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
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
20 /* Device-independent output format. Eventually I intend for all
21 PSPP output to work this way, but adding it as an available
22 format is a first step.
24 Each line in the output is a command. The first character on
25 the line is the command name, and the rest of the line is the
26 command arguments. The commands are described below as Perl
32 S[rc]\d+ table size in rows or columns (optional)
33 H[lrtb]\d+ number of left/right/top/bottom header rows/columns
35 allow column breaks every \3 rows from \1 to \2 exclusive
37 C.* table caption (not yet supported)
38 t(\d+)(-\d+)?,(\d+)(-\d+)?[wn][hb][lcr][tmb]:.*
39 text for cells in rows (\1-\2) inclusive and
40 columns (\3-\4) inclusive,
41 wrappable/nonwrappable, header/body,
42 left/center/right justified, top/middle/bottom
44 l[hv][sdtn](\d+),(\d+)-(\d+)
45 horiz/vert line in single/double/thick/none
46 style, running across columns/rows \2 to \3
47 inclusive at offset \1 from top/left side of
49 b[sdtno]{4}(\d+)-(\d+),(\d+)-(\d+)
50 box across columns \1 to \2 inclusive and rows \3
52 single/double/thick/none/omit style for horiz &
53 vert frame and horiz & vert interior lines
55 add footnote for cell \1, \2
58 v(\d(.\d+)+) insert \1 lines of blank space
61 m[ewmlu]:(.*),(\d+),((\d+)(-\d+)?)?:(.*)
62 error/warning/message/listing/user class message
63 for file \1, line \2, columns \4 to \5, actual
68 Text tokens are free-form, except that they are terminated by
69 commas and new-lines. The following escapes are allowed:
73 \\s non-breaking space
74 \\[0-7]{3} octal escape
76 \\P toggle superscript
78 \\E toggle strong emphasis
79 \\v toggle variable name font
80 \\F toggle file name font
81 \\p toggle fixed-pitch text font (default: proportional)
82 \\n\((\d+)?(\.\d+)?(-?\d+(\.\d+)?+(e-?\d+))?\)
83 number \3 (sysmis if not provided) in \1.\2 format
84 \\f\(([A-Z]*(\d+)?(\.\d+)?)(-?\d+(\.\d+)?+(e-?\d+))?\)
85 number \1 in \4 format
103 #include "filename.h"
110 /* Device-independent output driver extension record. */
111 struct devind_driver_ext
113 /* Internal state. */
114 struct file_ext file; /* Output file. */
115 int sequence_no; /* Sequence number. */
119 devind_open_global (struct outp_class *this UNUSED)
125 devind_close_global (struct outp_class *this UNUSED)
131 devind_preopen_driver (struct outp_driver *this)
133 struct devind_driver_ext *x;
135 assert (this->driver_open == 0);
136 msg (VM (1), _("DEVIND driver initializing as `%s'..."), this->name);
138 this->ext = x = xmalloc (sizeof *x);
140 this->horiz = this->vert = 0;
141 this->width = this->length = 0;
143 this->cp_x = this->cp_y = 0;
145 x->file.filename = NULL;
148 x->file.sequence_no = &x->sequence_no;
149 x->file.param = this;
150 x->file.postopen = NULL;
151 x->file.preclose = NULL;
159 devind_postopen_driver (struct outp_driver *this)
161 struct devind_driver_ext *x = this->ext;
163 assert (this->driver_open == 0);
164 if (NULL == x->file.filename)
165 x->file.filename = xstrdup ("pspp.devind");
167 msg (VM (2), _("%s: Initialization complete."), this->name);
168 this->driver_open = 1;
174 devind_close_driver (struct outp_driver *this)
176 struct devind_driver_ext *x = this->ext;
178 assert (this->driver_open);
179 msg (VM (2), _("%s: Beginning closing..."), this->name);
180 fputs ("q\n", x->file.file);
181 fn_close_ext (&x->file);
182 free (x->file.filename);
184 msg (VM (3), _("%s: Finished closing."), this->name);
185 this->driver_open = 0;
190 /* Generic option types. */
198 /* All the options that the DEVIND driver supports. */
199 static struct outp_option option_tab[] =
202 {"output-file", 1, 0},
206 static struct outp_option_info option_info;
209 devind_option (struct outp_driver *this, const char *key, const struct string *val)
211 struct devind_driver_ext *x = this->ext;
214 cat = outp_match_keyword (key, option_tab, &option_info, &subcat);
218 msg (SE, _("Unknown configuration parameter `%s' for DEVIND device "
222 free (x->file.filename);
223 x->file.filename = xstrdup (ds_c_str (val));
231 devind_open_page (struct outp_driver *this)
233 struct devind_driver_ext *x = this->ext;
235 assert (this->driver_open && this->page_open == 0);
237 if (!fn_open_ext (&x->file))
240 msg (ME, _("DEVIND output driver: %s: %s"), x->file.filename,
245 if (!ferror (x->file.file))
247 return !ferror (x->file.file);
251 devind_close_page (struct outp_driver *this)
253 struct devind_driver_ext *x = this->ext;
255 assert (this->driver_open && this->page_open);
257 return !ferror (x->file.file);
260 static void output_tab_table (struct outp_driver *, struct tab_table *);
263 devind_submit (struct outp_driver *this, struct som_table *s)
265 extern struct som_table_class tab_table_class;
266 struct devind_driver_ext *x = this->ext;
268 assert (this->driver_open && this->page_open);
269 if (x->sequence_no == 0 && !devind_open_page (this))
271 msg (ME, _("Cannot open first page on DEVIND device %s."), this->name);
275 if (s->class == &tab_table_class)
276 output_tab_table (this, s->ext);
281 /* Write string S of length LEN to file F, escaping characters as
282 necessary for DEVIND. */
284 escape_string (FILE *f, char *s, int len)
291 for (bp = cp = s; bp < ep; bp = cp)
293 while (cp < ep && *cp != ',' && *cp != '\n' && *cp)
296 fwrite (bp, 1, cp - bp, f);
314 /* Write table T to THIS output driver. */
316 output_tab_table (struct outp_driver *this, struct tab_table *t)
318 struct devind_driver_ext *x = this->ext;
320 if (t->nr == 1 && t->nc == 1)
322 fputs ("p:", x->file.file);
323 escape_string (x->file.file, ls_c_str (t->cc), ls_length (t->cc));
324 putc ('\n', x->file.file);
330 fprintf (x->file.file, "s\n");
333 fprintf (x->file.file, "Sr%d\n", t->nr);
334 fprintf (x->file.file, "Sc%d\n", t->nc);
338 fprintf (x->file.file, "Hl%d\n", t->l);
340 fprintf (x->file.file, "Hr%d\n", t->r);
342 fprintf (x->file.file, "Ht%d\n", t->t);
344 fprintf (x->file.file, "Hb%d\n", t->b);
347 if (!ls_empty_p (&t->title))
349 putc ('T', x->file.file);
350 escape_string (x->file.file, ls_c_str (&t->title),
351 ls_length (&t->title));
352 putc ('\n', x->file.file);
356 if (t->col_style == TAB_COL_DOWN)
357 fprintf (x->file.file, "B%d-%d/%d\n", t->t, t->nr - t->b, t->col_group);
362 unsigned char *ct = t->ct;
364 for (r = 0; r < t->nr; r++)
368 for (c = 0; c < t->nc; c++, ct++)
370 struct len_string *cc;
371 struct tab_joined_cell *j;
373 if (*ct == TAB_EMPTY)
376 cc = t->cc + c + r * t->nc;
379 j = (struct tab_joined_cell *) ls_c_str (cc);
381 if (c != j->x1 || r != j->y1)
387 putc ('t', x->file.file);
389 fprintf (x->file.file, "%d,%d", r, c);
391 fprintf (x->file.file, "%d-%d,%d-%d",
392 j->y1, j->y2, j->x1, j->x2);
393 putc ((*ct & TAT_NOWRAP) ? 'n' : 'w', x->file.file);
394 putc ((*ct & TAT_TITLE) ? 'h' : 'b', x->file.file);
395 if ((*ct & TAB_ALIGN_MASK) == TAB_RIGHT)
396 putc ('r', x->file.file);
397 else if ((*ct & TAB_ALIGN_MASK) == TAB_LEFT)
398 putc ('l', x->file.file);
400 putc ('c', x->file.file);
401 putc ('t', x->file.file);
402 escape_string (x->file.file, ls_c_str (cc), ls_length (cc));
403 putc ('\n', x->file.file);
408 /* Horizontal lines. */
412 for (r = 0; r <= t->nr; r++)
413 for (c = 0; c < t->nc; c++)
415 int rule = t->rh[c + r * t->nc];
417 fprintf (x->file.file, "lh%c%d,%d-%d\n", "nsdt"[rule], r, c, c);
421 /* Vertical lines. */
425 for (r = 0; r < t->nr; r++)
426 for (c = 0; c <= t->nc; c++)
428 int rule = t->rv[c + r * (t->nc + 1)];
430 fprintf (x->file.file, "lv%c%d,%d-%d\n", "nsdt"[rule], c, r, r);
435 fputs ("e\n", x->file.file);
438 /* DEVIND driver class. */
439 struct outp_class devind_class =
449 devind_preopen_driver,
451 devind_postopen_driver,