1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
25 #include "libpspp/assertion.h"
26 #include "libpspp/compiler.h"
27 #include "libpspp/string-map.h"
28 #include "output/ascii.h"
29 #include "output/driver.h"
30 #include "output/tab.h"
31 #include "output/table-item.h"
34 #include "gl/progname.h"
35 #include "gl/xalloc.h"
36 #include "gl/xvasprintf.h"
38 /* --transpose: Transpose the table before outputting? */
41 /* --emphasis: ASCII driver emphasis option. */
42 static char *emphasis
;
44 /* --box: ASCII driver box option. */
47 /* --draw-mode: special ASCII driver test mode. */
50 /* --no-txt: Whether to render to <base>.txt. */
51 static int render_txt
= true;
53 /* --no-stdout: Whether to render to stdout. */
54 static int render_stdout
= true;
56 /* --pdf: Also render PDF output. */
57 static int render_pdf
;
59 /* --csv: Also render CSV output. */
60 static int render_csv
;
62 /* ASCII driver, for ASCII driver test mode. */
63 static struct output_driver
*ascii_driver
;
65 /* -o, --output: Base name for output files. */
66 static const char *output_base
= "render";
68 static const char *parse_options (int argc
, char **argv
);
69 static void usage (void) NO_RETURN
;
70 static struct table
*read_table (FILE *, struct table
**tables
, size_t n_tables
);
71 static void draw (FILE *);
74 main (int argc
, char **argv
)
76 const char *input_file_name
;
79 set_program_name (argv
[0]);
80 output_engine_push ();
81 input_file_name
= parse_options (argc
, argv
);
83 if (!strcmp (input_file_name
, "-"))
87 input
= fopen (input_file_name
, "r");
89 error (1, errno
, "%s: open failed", input_file_name
);
94 struct table
**tables
= NULL
;
95 size_t allocated_tables
= 0;
103 if (n_tables
>= allocated_tables
)
104 tables
= x2nrealloc (tables
, &allocated_tables
, sizeof *tables
);
106 tables
[n_tables
] = read_table (input
, tables
, n_tables
);
115 table
= tables
[n_tables
- 1];
117 table
= table_transpose (table
);
118 table_item_submit (table_item_create (table
, NULL
, NULL
));
127 output_engine_pop ();
133 configure_drivers (int width
, int length
, int min_break
)
135 struct string_map options
, tmp
;
136 struct output_driver
*driver
;
138 string_map_init (&options
);
139 string_map_insert (&options
, "format", "txt");
140 string_map_insert (&options
, "output-file", "-");
141 string_map_insert_nocopy (&options
, xstrdup ("width"),
142 xasprintf ("%d", width
));
143 string_map_insert_nocopy (&options
, xstrdup ("length"),
144 xasprintf ("%d", length
));
147 string_map_insert_nocopy (&options
, xstrdup ("min-hbreak"),
148 xasprintf ("%d", min_break
));
149 string_map_insert_nocopy (&options
, xstrdup ("min-vbreak"),
150 xasprintf ("%d", min_break
));
152 if (emphasis
!= NULL
)
153 string_map_insert (&options
, "emphasis", emphasis
);
155 string_map_insert (&options
, "box", box
);
157 /* Render to stdout. */
160 string_map_clone (&tmp
, &options
);
161 ascii_driver
= driver
= output_driver_create (&tmp
);
164 output_driver_register (driver
);
165 string_map_destroy (&tmp
);
170 string_map_destroy (&options
);
174 /* Render to <base>.txt. */
177 string_map_clear (&options
);
178 string_map_insert_nocopy (&options
, xstrdup ("output-file"),
179 xasprintf ("%s.txt", output_base
));
180 driver
= output_driver_create (&options
);
183 output_driver_register (driver
);
187 /* Render to <base>.pdf. */
190 string_map_clear (&options
);
191 string_map_insert_nocopy (&options
, xstrdup ("output-file"),
192 xasprintf ("%s.pdf", output_base
));
193 string_map_insert (&options
, "top-margin", "0");
194 string_map_insert (&options
, "bottom-margin", "0");
195 string_map_insert (&options
, "left-margin", "0");
196 string_map_insert (&options
, "right-margin", "0");
197 string_map_insert_nocopy (&options
, xstrdup ("paper-size"),
198 xasprintf ("%dx%dpt", width
* 5, length
* 8));
201 string_map_insert_nocopy (&options
, xstrdup ("min-hbreak"),
202 xasprintf ("%d", min_break
* 5));
203 string_map_insert_nocopy (&options
, xstrdup ("min-vbreak"),
204 xasprintf ("%d", min_break
* 8));
206 driver
= output_driver_create (&options
);
209 output_driver_register (driver
);
213 /* Render to <base>.csv. */
216 string_map_clear (&options
);
217 string_map_insert_nocopy (&options
, xstrdup ("output-file"),
218 xasprintf ("%s.csv", output_base
));
219 driver
= output_driver_create (&options
);
222 output_driver_register (driver
);
225 /* Render to <base>.odt. */
226 string_map_replace_nocopy (&options
, xstrdup ("output-file"),
227 xasprintf ("%s.odt", output_base
));
228 driver
= output_driver_create (&options
);
231 output_driver_register (driver
);
233 string_map_destroy (&options
);
237 parse_options (int argc
, char **argv
)
246 OPT_WIDTH
= UCHAR_MAX
+ 1,
253 static const struct option options
[] =
255 {"width", required_argument
, NULL
, OPT_WIDTH
},
256 {"length", required_argument
, NULL
, OPT_LENGTH
},
257 {"min-break", required_argument
, NULL
, OPT_MIN_BREAK
},
258 {"transpose", no_argument
, &transpose
, 1},
259 {"emphasis", required_argument
, NULL
, OPT_EMPHASIS
},
260 {"box", required_argument
, NULL
, OPT_BOX
},
261 {"draw-mode", no_argument
, &draw_mode
, 1},
262 {"no-txt", no_argument
, &render_txt
, 0},
263 {"no-stdout", no_argument
, &render_stdout
, 0},
264 {"pdf", no_argument
, &render_pdf
, 1},
265 {"csv", no_argument
, &render_csv
, 1},
266 {"output", required_argument
, NULL
, 'o'},
267 {"help", no_argument
, NULL
, OPT_HELP
},
271 int c
= getopt_long (argc
, argv
, "o:", options
, NULL
);
278 width
= atoi (optarg
);
282 length
= atoi (optarg
);
286 min_break
= atoi (optarg
);
298 output_base
= optarg
;
317 configure_drivers (width
, length
, min_break
);
319 if (optind
+ 1 != argc
)
320 error (1, 0, "exactly one non-option argument required; "
321 "use --help for help");
328 printf ("%s, to test rendering of PSPP tables\n"
329 "usage: %s [OPTIONS] INPUT\n"
331 " --width=WIDTH set page width in characters\n"
332 " --length=LINE set page length in lines\n",
333 program_name
, program_name
);
338 replace_newlines (char *p
)
342 for (q
= p
; *p
!= '\0'; )
343 if (*p
== '\\' && p
[1] == 'n')
353 static struct table
*
354 read_table (FILE *stream
, struct table
**tables
, size_t n_tables
)
356 struct tab_table
*tab
;
360 int nr
, nc
, hl
, hr
, ht
, hb
;
363 if (fgets (buffer
, sizeof buffer
, stream
) == NULL
364 || (n_input
= sscanf (buffer
, "%d %d %d %d %d %d",
365 &input
[0], &input
[1], &input
[2],
366 &input
[3], &input
[4], &input
[5])) < 2)
367 error (1, 0, "syntax error reading row and column count");
371 hl
= n_input
>= 3 ? input
[2] : 0;
372 hr
= n_input
>= 4 ? input
[3] : 0;
373 ht
= n_input
>= 5 ? input
[4] : 0;
374 hb
= n_input
>= 6 ? input
[5] : 0;
376 tab
= tab_create (nc
, nr
);
377 tab_headers (tab
, hl
, hr
, ht
, hb
);
378 for (r
= 0; r
< nr
; r
++)
379 for (c
= 0; c
< nc
; c
++)
380 if (tab_cell_is_empty (tab
, c
, r
))
388 if (fgets (buffer
, sizeof buffer
, stream
) == NULL
)
389 error (1, 0, "unexpected end of input reading row %d, column %d",
391 new_line
= strchr (buffer
, '\n');
392 if (new_line
!= NULL
)
396 if (sscanf (text
, "%d*%d", &rs
, &cs
) == 2)
398 while (*text
!= ' ' && *text
!= '\0')
410 while (*text
&& strchr ("<>^,@()|", *text
))
414 tab_vline (tab
, TAL_1
, c
, r
, r
+ rs
- 1);
418 tab_vline (tab
, TAL_1
, c
+ cs
, r
, r
+ rs
- 1);
422 tab_hline (tab
, TAL_1
, c
, c
+ cs
- 1, r
);
426 tab_hline (tab
, TAL_1
, c
, c
+ cs
- 1, r
+ rs
);
430 tab_box (tab
, TAL_1
, TAL_1
, -1, -1, c
, r
,
431 c
+ cs
- 1, r
+ rs
- 1);
435 opt
&= ~TAB_ALIGNMENT
;
440 opt
&= ~TAB_ALIGNMENT
;
445 opt
&= ~TAB_ALIGNMENT
;
453 replace_newlines (text
);
455 if (sscanf (text
, "{%u}", &i
) == 1)
460 error (1, 0, "bad table number %u", i
);
461 table
= table_ref (tables
[i
]);
463 text
= strchr (text
, '}') + 1;
468 table
= table_stomp (table
);
472 table
= table_transpose (table
);
476 error (1, 0, "unexpected subtable modifier \"%c\"", *text
);
478 tab_subtable (tab
, c
, r
, c
+ cs
- 1, r
+ rs
- 1, opt
,
479 table_item_create (table
, NULL
, NULL
));
487 for (i
= 0; (content
= strsep (&pos
, "#")) != NULL
; i
++)
489 tab_joint_text (tab
, c
, r
, c
+ cs
- 1, r
+ rs
- 1, opt
,
492 tab_footnote (tab
, c
, r
, "%s", content
);
505 while (fgets (buffer
, sizeof buffer
, stream
))
507 char text
[sizeof buffer
];
513 if (strchr ("#\r\n", buffer
[0]))
516 if (sscanf (buffer
, "%d %d %d %[^\n]", &x
, &y
, &emph
, text
) == 4)
517 ascii_test_write (ascii_driver
, text
, x
, y
, emph
? TAB_EMPH
: 0);
518 else if (sscanf (buffer
, "set-length %d %d", &y
, &length
) == 2)
519 ascii_test_set_length (ascii_driver
, y
, length
);
521 error (1, 0, "line %d has invalid format", line
);