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
21 Categories of SET subcommands:
23 data input: BLANKS, DECIMAL, FORMAT.
25 program input: ENDCMD, NULLINE.
27 interaction: CPROMPT, DPROMPT, ERRORBREAK, MXERRS, MXWARNS, PROMPT.
29 program execution: MEXPAND, MITERATE, MNEST, MPRINT,
30 MXLOOPS, SEED, UNDEFINED.
32 data output: CCA...CCE, DECIMAL, FORMAT, RESULTS-p.
34 output routing: ECHO, ERRORS, INCLUDE, MESSAGES, PRINTBACK, ERRORS,
37 output activation: LISTING (on/off), SCREEN, PRINTER.
39 output driver options: HEADERS, MORE, PAGER, VIEWLENGTH, VIEWWIDTH,
42 logging: LOG, JOURNAL.
44 system files: COMP/COMPRESSION, SCOMP/SCOMPRESSION.
52 These subcommands remain to be implemented:
53 ECHO, PRINTBACK, INCLUDE
54 MORE, PAGER, VIEWLENGTH, VIEWWIDTH, HEADERS
56 These subcommands are not complete:
57 MESSAGES, ERRORS, RESULTS
58 LISTING/DISK, LOG/JOURNAL
79 struct set_cust_currency set_cc[5];
88 int set_errors, set_messages, set_results;
89 struct fmt_spec set_format;
107 #if !USE_INTERNAL_PAGER
109 #endif /* !USE_INTERNAL_PAGER */
112 char *set_results_file;
114 int set_scompression;
118 int set_testing_mode;
122 size_t set_max_workspace = 4L * 1024 * 1024;
124 static void set_routing (int q, int *setting);
125 static int set_ccx (const char *cc_string, struct set_cust_currency * cc,
130 automenu=automenu:on/off;
133 block=string "x==1" "one character long";
134 boxstring=string "x==3 || x==11" "3 or 11 characters long";
135 case=size:upper/uplow;
142 compression=compress:on/off;
145 decimal=dec:dot/_comma;
150 endcmd=string "x==1" "one character long";
151 errorbreak=errbrk:on/off;
152 errors=errors:on/off/terminal/listing/both/none;
154 headers=headers:no/yes/blank;
155 helpwindows=helpwin:on/off;
156 highres=hires:on/off;
157 histogram=string "x==1" "one character long";
163 lowres=lores:auto/on/off;
165 menus=menus:standard/extended;
166 messages=messages:on/off/terminal/listing/both/none;
171 mprint=mprint:on/off;
178 printback=prtbck:on/off;
181 ptranslate=ptrans:on/off;
184 runreview=runrev:auto/manual;
186 scompression=scompress:on/off;
188 scripttab=string "x==1" "one character long";
190 tb1=string "x==3 || x==11" "3 or 11 characters long";
192 undefined=undef:warn/nowarn;
204 int internal_cmd_set (void);
211 lex_match_id ("SET");
213 if (!parse_set (&cmd))
217 msg (SW, _("%s is obsolete."),"BLOCK");
219 if (cmd.sbc_boxstring)
220 msg (SW, _("%s is obsolete."),"BOXSTRING");
222 if (cmd.compress != -1)
224 msg (MW, _("Active file compression is not yet implemented "
225 "(and probably won't be)."));
226 set_compression = cmd.compress == STC_OFF ? 0 : 1;
228 if (cmd.scompress != -1)
229 set_scompression = cmd.scompress == STC_OFF ? 0 : 1;
230 if (cmd.n_cpi != NOT_LONG)
233 msg (SE, _("CPI must be greater than 0."));
237 if (cmd.sbc_histogram)
238 msg (MW, _("%s is obsolete."),"HISTOGRAM");
239 if (cmd.n_lpi != NOT_LONG)
242 msg (SE, _("LPI must be greater than 0."));
247 /* Windows compatible syntax. */
249 msg (SW, _("CASE is not implemented and probably won't be. If you care, "
250 "complain about it."));
252 set_ccx (cmd.s_cca, &set_cc[0], 'A');
254 set_ccx (cmd.s_ccb, &set_cc[1], 'B');
256 set_ccx (cmd.s_ccc, &set_cc[2], 'C');
258 set_ccx (cmd.s_ccd, &set_cc[3], 'D');
260 set_ccx (cmd.s_cce, &set_cc[4], 'E');
263 set_decimal = cmd.dec == STC_DOT ? '.' : ',';
264 set_grouping = cmd.dec == STC_DOT ? ',' : '.';
266 if (cmd.errors != -1)
267 set_routing (cmd.errors, &set_errors);
268 if (cmd.headers != -1)
269 set_headers = cmd.headers == STC_NO ? 0 : (cmd.headers == STC_YES ? 1 : 2);
270 if (cmd.messages != -1)
271 set_routing (cmd.messages, &set_messages);
273 set_mexpand = cmd.mexp == STC_OFF ? 0 : 1;
274 if (cmd.n_miterate != NOT_LONG)
276 if (cmd.n_miterate > 0)
277 set_miterate = cmd.n_miterate;
279 msg (SE, _("Value for MITERATE (%ld) must be greater than 0."),
282 if (cmd.n_mnest != NOT_LONG)
285 set_mnest = cmd.n_mnest;
287 msg (SE, _("Value for MNEST (%ld) must be greater than 0."),
290 if (cmd.mprint != -1)
291 set_mprint = cmd.mprint == STC_OFF ? 0 : 1;
292 if (cmd.n_mxerrs != NOT_LONG)
295 msg (SE, _("MXERRS must be at least 1."));
297 set_mxerrs = cmd.n_mxerrs;
299 if (cmd.n_mxloops != NOT_LONG)
302 msg (SE, _("MXLOOPS must be at least 1."));
304 set_mxloops = cmd.n_mxloops;
306 if (cmd.n_mxmemory != NOT_LONG)
307 msg (SE, _("%s is obsolete."),"MXMEMORY");
308 if (cmd.n_mxwarns != NOT_LONG)
309 set_mxwarns = cmd.n_mxwarns;
310 if (cmd.prtbck != -1)
311 set_printback = cmd.prtbck == STC_OFF ? 0 : 1;
313 msg (SE, _("%s is obsolete."),"SCRIPTTAB");
315 msg (SW, _("%s is not yet implemented."),"TBFONTS");
317 msg (SW, _("%s is not yet implemented."),"TB1");
319 set_undefined = cmd.undef == STC_NOWARN ? 0 : 1;
320 if (cmd.n_workspace != NOT_LONG)
322 if (cmd.n_workspace < 1024)
323 msg (SE, _("Workspace limit must be at least 1 MB."));
326 if (cmd.n_workspace > (size_t) -1 / 1024)
327 set_max_workspace = -1;
329 set_max_workspace = 1024 * cmd.n_workspace;
333 /* PC+ compatible syntax. */
335 outp_enable_device (cmd.scrn == STC_OFF ? 0 : 1, OUTP_DEV_SCREEN);
337 if (cmd.automenu != -1)
338 msg (SW, _("%s is obsolete."),"AUTOMENU");
340 msg (SW, _("%s is obsolete."),"BEEP");
345 set_cprompt = cmd.s_cprompt;
346 cmd.s_cprompt = NULL;
351 set_dprompt = cmd.s_dprompt;
352 cmd.s_dprompt = NULL;
355 set_echo = cmd.echo == STC_OFF ? 0 : 1;
357 set_endcmd = cmd.s_endcmd[0];
359 msg (SW, _("%s is obsolete."),"EJECT");
360 if (cmd.errbrk != -1)
361 set_errorbreak = cmd.errbrk == STC_OFF ? 0 : 1;
362 if (cmd.helpwin != -1)
363 msg (SW, _("%s is obsolete."),"HELPWINDOWS");
365 set_include = cmd.inc == STC_OFF ? 0 : 1;
367 msg (MW, _("%s is obsolete."),"MENUS");
369 set_nullline = cmd.null == STC_OFF ? 0 : 1;
371 set_more = cmd.more == STC_OFF ? 0 : 1;
373 outp_enable_device (cmd.prtr == STC_OFF ? 0 : 1, OUTP_DEV_PRINTER);
377 set_prompt = cmd.s_prompt;
380 if (cmd.ptrans != -1)
381 msg (SW, _("%s is obsolete."),"PTRANSLATE");
382 if (cmd.runrev != -1)
383 msg (SW, _("%s is obsolete."),"RUNREVIEW");
384 if (cmd.safe == STC_ON)
387 msg (SW, _("%s is obsolete."),"XSORT");
394 /* Sets custom currency specifier CC having name CC_NAME ('A' through
395 'E') to correspond to the settings in CC_STRING. */
397 set_ccx (const char *cc_string, struct set_cust_currency * cc, int cc_name)
399 if (strlen (cc_string) > 16)
401 msg (SE, _("CC%c: Length of custom currency string `%s' (%d) "
402 "exceeds maximum length of 16."),
403 cc_name, cc_string, strlen (cc_string));
407 /* Determine separators. */
410 int n_commas, n_periods;
412 /* Count the number of commas and periods. There must be exactly
413 three of one or the other. */
414 n_commas = n_periods = 0;
415 for (sp = cc_string; *sp; sp++)
421 if (!((n_commas == 3) ^ (n_periods == 3)))
423 msg (SE, _("CC%c: Custom currency string `%s' does not contain "
424 "exactly three periods or commas (not both)."),
428 else if (n_commas == 3)
440 /* Copy cc_string to cc, changing separators to nulls. */
444 strcpy (cc->buf, cc_string);
445 cp = cc->neg_prefix = cc->buf;
447 while (*cp++ != cc->grouping)
452 while (*cp++ != cc->grouping)
457 while (*cp++ != cc->grouping)
466 /* Sets *SETTING, which is a combination of SET_ROUTE_* bits that
467 indicates what to do with some sort of output, to the value
468 indicated by Q, which is a value provided by the input parser. */
470 set_routing (int q, int *setting)
475 *setting |= SET_ROUTE_DISABLE;
478 *setting &= ~SET_ROUTE_DISABLE;
481 *setting &= ~(SET_ROUTE_LISTING | SET_ROUTE_OTHER);
482 *setting |= SET_ROUTE_SCREEN;
485 *setting &= ~SET_ROUTE_SCREEN;
486 *setting |= SET_ROUTE_LISTING | SET_ROUTE_OTHER;
489 *setting |= SET_ROUTE_SCREEN | SET_ROUTE_LISTING | SET_ROUTE_OTHER;
492 *setting &= ~(SET_ROUTE_SCREEN | SET_ROUTE_LISTING | SET_ROUTE_OTHER);
500 stc_custom_pager (struct cmd_set *cmd UNUSED)
503 #if !USE_INTERNAL_PAGER
504 if (lex_match_id ("OFF"))
512 if (!lex_force_string ())
516 set_pager = xstrdup (ds_value (&tokstr));
520 #else /* USE_INTERNAL_PAGER */
523 msg (SW, "External pagers not supported.");
525 #endif /* USE_INTERNAL_PAGER */
528 /* Parses the BLANKS subcommand, which controls the value that
529 completely blank fields in numeric data imply. X, Wnd: Syntax is
530 SYSMIS or a numeric value; PC+: Syntax is '.', which is equivalent
531 to SYSMIS, or a numeric value. */
533 stc_custom_blanks (struct cmd_set *cmd UNUSED)
536 if ((token == T_ID && lex_id_match ("SYSMIS", tokid))
537 || (token == T_STRING && !strcmp (tokid, ".")))
544 if (!lex_force_num ())
553 stc_custom_length (struct cmd_set *cmd UNUSED)
558 if (lex_match_id ("NONE"))
562 if (!lex_force_int ())
564 if (lex_integer () < 1)
566 msg (SE, _("LENGTH must be at least 1."));
569 page_length = lex_integer ();
573 /* FIXME: Set page length. */
578 stc_custom_results (struct cmd_set *cmd UNUSED)
586 static struct tuple tab[] =
590 {"TERMINAL", STC_TERMINAL},
591 {"LISTING", STC_LISTING},
603 msg (SE, _("Missing identifier in RESULTS subcommand."));
607 for (t = tab; t->s; t++)
608 if (lex_id_match (t->s, tokid))
611 set_routing (t->v, &set_results);
614 msg (SE, _("Unrecognized identifier in RESULTS subcommand."));
619 stc_custom_seed (struct cmd_set *cmd UNUSED)
622 if (lex_match_id ("RANDOM"))
626 if (!lex_force_num ())
636 stc_custom_width (struct cmd_set *cmd UNUSED)
641 if (lex_match_id ("NARROW"))
643 else if (lex_match_id ("WIDE"))
647 if (!lex_force_int ())
649 if (lex_integer () < 1)
651 msg (SE, _("WIDTH must be at least 1."));
654 page_width = lex_integer ();
658 /* FIXME: Set page width. */
662 /* Parses FORMAT subcommand, which consists of a numeric format
665 stc_custom_format (struct cmd_set *cmd UNUSED)
670 if (!parse_format_specifier (&fmt, 0))
672 if ((formats[fmt.type].cat & FCAT_STRING) != 0)
674 msg (SE, _("FORMAT requires numeric output format as an argument. "
675 "Specified format %s is of type string."),
676 fmt_to_string (&fmt));
685 stc_custom_journal (struct cmd_set *cmd UNUSED)
688 if (lex_match_id ("ON"))
690 else if (lex_match_id ("OFF"))
692 if (token == T_STRING)
694 set_journal = xstrdup (ds_value (&tokstr));
700 /* Parses COLOR subcommand. PC+: either ON or OFF or two or three
701 comma-delimited numbers inside parentheses. */
703 stc_custom_color (struct cmd_set *cmd UNUSED)
705 msg (MW, _("%s is obsolete."),"COLOR");
708 if (!lex_match_id ("ON") && !lex_match_id ("YES") && !lex_match_id ("OFF") && !lex_match_id ("NO"))
710 if (!lex_force_match ('('))
712 if (!lex_match ('*'))
714 if (!lex_force_int ())
716 if (lex_integer () < 0 || lex_integer () > 15)
718 msg (SE, _("Text color must be in range 0-15."));
723 if (!lex_force_match (','))
725 if (!lex_match ('*'))
727 if (!lex_force_int ())
729 if (lex_integer () < 0 || lex_integer () > 7)
731 msg (SE, _("Background color must be in range 0-7."));
736 if (lex_match (',') && !lex_match ('*'))
738 if (!lex_force_int ())
740 if (lex_integer () < 0 || lex_integer () > 7)
742 msg (SE, _("Border color must be in range 0-7."));
747 if (!lex_force_match (')'))
754 stc_custom_listing (struct cmd_set *cmd UNUSED)
757 if (lex_match_id ("ON") || lex_match_id ("YES"))
758 outp_enable_device (1, OUTP_DEV_LISTING);
759 else if (lex_match_id ("OFF") || lex_match_id ("NO"))
760 outp_enable_device (0, OUTP_DEV_LISTING);
770 stc_custom_disk (struct cmd_set *cmd UNUSED)
772 stc_custom_listing (cmd);
777 stc_custom_log (struct cmd_set *cmd UNUSED)
779 stc_custom_journal (cmd);
784 stc_custom_rcolor (struct cmd_set *cmd UNUSED)
786 msg (SW, _("%s is obsolete."),"RCOLOR");
789 if (!lex_force_match ('('))
792 if (!lex_match ('*'))
794 if (!lex_force_int ())
796 if (lex_integer () < 0 || lex_integer () > 6)
798 msg (SE, _("Lower window color must be between 0 and 6."));
803 if (!lex_force_match (','))
806 if (!lex_match ('*'))
808 if (!lex_force_int ())
810 if (lex_integer () < 0 || lex_integer () > 6)
812 msg (SE, _("Upper window color must be between 0 and 6."));
818 if (lex_match (',') && !lex_match ('*'))
820 if (!lex_force_int ())
822 if (lex_integer () < 0 || lex_integer () > 6)
824 msg (SE, _("Frame color must be between 0 and 6."));
833 stc_custom_viewlength (struct cmd_set *cmd UNUSED)
835 if (lex_match_id ("MINIMUM"))
837 else if (lex_match_id ("MEDIAN"))
838 set_viewlength = 43; /* This is not correct for VGA displays. */
839 else if (lex_match_id ("MAXIMUM"))
843 if (!lex_force_int ())
846 if (lex_integer () >= (43 + 25) / 2)
851 set_viewlength = lex_integer ();
857 msg (SW, _("%s is not yet implemented."),"VIEWLENGTH");
863 stc_custom_workdev (struct cmd_set *cmd UNUSED)
867 msg (SW, _("%s is obsolete."),"WORKDEV");
870 for (*c = 'A'; *c <= 'Z'; (*c)++)
871 if (token == T_ID && lex_id_match (c, tokid))
876 msg (SE, _("Drive letter expected in WORKDEV subcommand."));