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., 51 Franklin Street, Fifth Floor, 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"
111 #define _(msgid) gettext (msgid)
113 /* Device-independent output driver extension record. */
114 struct devind_driver_ext
116 /* Internal state. */
117 struct file_ext file; /* Output file. */
118 int sequence_no; /* Sequence number. */
122 devind_open_global (struct outp_class *this UNUSED)
128 devind_close_global (struct outp_class *this UNUSED)
134 devind_preopen_driver (struct outp_driver *this)
136 struct devind_driver_ext *x;
138 assert (this->driver_open == 0);
139 msg (VM (1), _("DEVIND driver initializing as `%s'..."), this->name);
141 this->ext = x = xmalloc (sizeof *x);
143 this->horiz = this->vert = 0;
144 this->width = this->length = 0;
146 this->cp_x = this->cp_y = 0;
148 x->file.filename = NULL;
151 x->file.sequence_no = &x->sequence_no;
152 x->file.param = this;
153 x->file.postopen = NULL;
154 x->file.preclose = NULL;
162 devind_postopen_driver (struct outp_driver *this)
164 struct devind_driver_ext *x = this->ext;
166 assert (this->driver_open == 0);
167 if (NULL == x->file.filename)
168 x->file.filename = xstrdup ("pspp.devind");
170 msg (VM (2), _("%s: Initialization complete."), this->name);
171 this->driver_open = 1;
177 devind_close_driver (struct outp_driver *this)
179 struct devind_driver_ext *x = this->ext;
181 assert (this->driver_open);
182 msg (VM (2), _("%s: Beginning closing..."), this->name);
183 fputs ("q\n", x->file.file);
184 fn_close_ext (&x->file);
185 free (x->file.filename);
187 msg (VM (3), _("%s: Finished closing."), this->name);
188 this->driver_open = 0;
193 /* Generic option types. */
201 /* All the options that the DEVIND driver supports. */
202 static struct outp_option option_tab[] =
205 {"output-file", 1, 0},
209 static struct outp_option_info option_info;
212 devind_option (struct outp_driver *this, const char *key, const struct string *val)
214 struct devind_driver_ext *x = this->ext;
217 cat = outp_match_keyword (key, option_tab, &option_info, &subcat);
221 msg (SE, _("Unknown configuration parameter `%s' for DEVIND device "
225 free (x->file.filename);
226 x->file.filename = xstrdup (ds_c_str (val));
234 devind_open_page (struct outp_driver *this)
236 struct devind_driver_ext *x = this->ext;
238 assert (this->driver_open && this->page_open == 0);
240 if (!fn_open_ext (&x->file))
243 msg (ME, _("DEVIND output driver: %s: %s"), x->file.filename,
248 if (!ferror (x->file.file))
250 return !ferror (x->file.file);
254 devind_close_page (struct outp_driver *this)
256 struct devind_driver_ext *x = this->ext;
258 assert (this->driver_open && this->page_open);
260 return !ferror (x->file.file);
263 static void output_tab_table (struct outp_driver *, struct tab_table *);
266 devind_submit (struct outp_driver *this, struct som_entity *s)
268 extern struct som_table_class tab_table_class;
269 struct devind_driver_ext *x = this->ext;
271 assert (this->driver_open && this->page_open);
272 if (x->sequence_no == 0 && !devind_open_page (this))
274 msg (ME, _("Cannot open first page on DEVIND device %s."), this->name);
278 assert (s->class == &tab_table_class);
280 if ( s->type == SOM_TABLE )
281 output_tab_table (this, s->ext);
284 /* Write string S of length LEN to file F, escaping characters as
285 necessary for DEVIND. */
287 escape_string (FILE *f, char *s, int len)
294 for (bp = cp = s; bp < ep; bp = cp)
296 while (cp < ep && *cp != ',' && *cp != '\n' && *cp)
299 fwrite (bp, 1, cp - bp, f);
317 /* Write table T to THIS output driver. */
319 output_tab_table (struct outp_driver *this, struct tab_table *t)
321 struct devind_driver_ext *x = this->ext;
323 if (t->nr == 1 && t->nc == 1)
325 fputs ("p:", x->file.file);
326 escape_string (x->file.file, ls_c_str (t->cc), ls_length (t->cc));
327 putc ('\n', x->file.file);
333 fprintf (x->file.file, "s\n");
336 fprintf (x->file.file, "Sr%d\n", t->nr);
337 fprintf (x->file.file, "Sc%d\n", t->nc);
341 fprintf (x->file.file, "Hl%d\n", t->l);
343 fprintf (x->file.file, "Hr%d\n", t->r);
345 fprintf (x->file.file, "Ht%d\n", t->t);
347 fprintf (x->file.file, "Hb%d\n", t->b);
350 if (!ls_empty_p (&t->title))
352 putc ('T', x->file.file);
353 escape_string (x->file.file, ls_c_str (&t->title),
354 ls_length (&t->title));
355 putc ('\n', x->file.file);
359 if (t->col_style == TAB_COL_DOWN)
360 fprintf (x->file.file, "B%d-%d/%d\n", t->t, t->nr - t->b, t->col_group);
365 unsigned char *ct = t->ct;
367 for (r = 0; r < t->nr; r++)
371 for (c = 0; c < t->nc; c++, ct++)
373 struct fixed_string *cc;
374 struct tab_joined_cell *j;
376 if (*ct == TAB_EMPTY)
379 cc = t->cc + c + r * t->nc;
382 j = (struct tab_joined_cell *) ls_c_str (cc);
384 if (c != j->x1 || r != j->y1)
390 putc ('t', x->file.file);
392 fprintf (x->file.file, "%d,%d", r, c);
394 fprintf (x->file.file, "%d-%d,%d-%d",
395 j->y1, j->y2, j->x1, j->x2);
396 putc ((*ct & TAT_NOWRAP) ? 'n' : 'w', x->file.file);
397 putc ((*ct & TAT_TITLE) ? 'h' : 'b', x->file.file);
398 if ((*ct & TAB_ALIGN_MASK) == TAB_RIGHT)
399 putc ('r', x->file.file);
400 else if ((*ct & TAB_ALIGN_MASK) == TAB_LEFT)
401 putc ('l', x->file.file);
403 putc ('c', x->file.file);
404 putc ('t', x->file.file);
405 escape_string (x->file.file, ls_c_str (cc), ls_length (cc));
406 putc ('\n', x->file.file);
411 /* Horizontal lines. */
415 for (r = 0; r <= t->nr; r++)
416 for (c = 0; c < t->nc; c++)
418 int rule = t->rh[c + r * t->nc];
420 fprintf (x->file.file, "lh%c%d,%d-%d\n", "nsdt"[rule], r, c, c);
424 /* Vertical lines. */
428 for (r = 0; r < t->nr; r++)
429 for (c = 0; c <= t->nc; c++)
431 int rule = t->rv[c + r * (t->nc + 1)];
433 fprintf (x->file.file, "lv%c%d,%d-%d\n", "nsdt"[rule], c, r, r);
438 fputs ("e\n", x->file.file);
441 /* DEVIND driver class. */
442 struct outp_class devind_class =
452 devind_preopen_driver,
454 devind_postopen_driver,