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
84 #else /* !HAVE_TERMCAP_H */
85 int tgetent (char *, const char *);
86 int tgetnum (const char *);
87 #endif /* !HAVE_TERMCAP_H */
88 #endif /* !HAVE_LIBTERMCAP */
90 static int set_errors;
91 static int set_messages;
92 static int set_results;
94 static double set_blanks=SYSMIS;
96 static struct fmt_spec set_format={FMT_F,8,2};
98 static struct set_cust_currency set_cc[5];
100 static char *set_journal;
101 static int set_journaling;
103 static int set_listing=1;
105 #if !USE_INTERNAL_PAGER
106 static char *set_pager=0;
107 #endif /* !USE_INTERNAL_PAGER */
109 static unsigned long set_seed;
110 static int seed_flag=0;
112 static int long_view=0;
113 int set_testing_mode=0;
114 static int set_viewlength;
115 static int set_viewwidth;
117 void aux_show_warranty(void);
118 void aux_show_copying(void);
120 static const char *route_to_string(int routing);
121 static void set_routing (int q, int *setting);
123 static int set_ccx (const char *cc_string, struct set_cust_currency * cc,
127 automenu=automenu:on/off;
130 block=string "x==1" "one character long";
131 boxstring=string "x==3 || x==11" "3 or 11 characters long";
132 case=size:upper/uplow;
139 compression=compress:on/off;
140 cpi=integer "x>0" "%s must be greater than 0";
142 decimal=dec:dot/comma;
147 endcmd=string "x==1" "one character long";
148 errorbreak=errbrk:on/off;
149 errors=errors:on/off/terminal/listing/both/none;
151 headers=headers:no/yes/blank;
152 helpwindows=helpwin:on/off;
153 highres=hires:on/off;
154 histogram=string "x==1" "one character long";
160 lowres=lores:auto/on/off;
161 lpi=integer "x>0" "% must be greater than 0";
162 menus=menus:standard/extended;
163 messages=messages:on/off/terminal/listing/both/none;
165 miterate=integer "x>0" "%s must be greater than 0";
166 mnest=integer "x>0" "%s must be greater than 0";
168 mprint=mprint:on/off;
169 mxerrs=integer "x >= 1" "%s must be at least 1";
170 mxloops=integer "x >=1" "%s must be at least 1";
175 printback=prtbck:on/off;
178 ptranslate=ptrans:on/off;
181 runreview=runrev:auto/manual;
183 scompression=scompress:on/off;
185 scripttab=string "x==1" "one character long";
187 tb1=string "x==3 || x==11" "3 or 11 characters long";
189 undefined=undef:warn/nowarn;
194 workspace=integer "x>=1024" "%s must be at least 1 MB";
203 aux_stc_custom_blanks(struct cmd_set *cmd UNUSED)
205 if ( set_blanks == SYSMIS )
208 msg(MM, "%g", set_blanks);
214 aux_stc_custom_color(struct cmd_set *cmd UNUSED)
216 msg (MW, _("%s is obsolete."),"COLOR");
221 aux_stc_custom_listing(struct cmd_set *cmd UNUSED)
224 msg(MM, _("LISTING is ON"));
226 msg(MM, _("LISTING is OFF"));
232 aux_stc_custom_disk(struct cmd_set *cmd UNUSED)
234 return aux_stc_custom_listing(cmd);
238 aux_stc_custom_format(struct cmd_set *cmd UNUSED)
240 msg(MM, fmt_to_string(&set_format));
247 aux_stc_custom_journal(struct cmd_set *cmd UNUSED)
250 msg(MM, set_journal);
252 msg(MM, _("Journalling is off") );
258 aux_stc_custom_length(struct cmd_set *cmd UNUSED)
260 msg(MM, "%d", set_viewlength);
265 aux_stc_custom_log(struct cmd_set *cmd )
267 return aux_stc_custom_journal (cmd);
271 aux_stc_custom_pager(struct cmd_set *cmd UNUSED)
273 #if !USE_INTERNAL_PAGER
278 #else /* USE_INTERNAL_PAGER */
279 msg (MM, "Internal pager.");
280 #endif /* USE_INTERNAL_PAGER */
286 aux_stc_custom_rcolor(struct cmd_set *cmd UNUSED)
288 msg (SW, _("%s is obsolete."),"RCOLOR");
293 aux_stc_custom_results(struct cmd_set *cmd UNUSED)
296 msg(MM, route_to_string(set_results) );
302 aux_stc_custom_seed(struct cmd_set *cmd UNUSED)
304 msg(MM, "%ld",set_seed);
309 aux_stc_custom_viewlength(struct cmd_set *cmd UNUSED)
311 msg(MM, "%d", set_viewlength);
316 aux_stc_custom_viewwidth(struct cmd_set *cmd UNUSED)
318 msg(MM, "%d", set_viewwidth);
323 aux_stc_custom_width(struct cmd_set *cmd UNUSED)
325 msg(MM, "%d", set_viewwidth);
330 aux_stc_custom_workdev(struct cmd_set *cmd UNUSED)
332 msg (SW, _("%s is obsolete."),"WORKDEV");
339 warranty=show_warranty;
340 copying=show_copying.
344 static struct cmd_set cmd;
349 lex_match_id ("SHOW");
351 if (!aux_parse_set (&cmd))
361 lex_match_id ("SET");
363 if (!parse_set (&cmd))
367 set_ccx (cmd.s_cca, &set_cc[0], 'A');
369 set_ccx (cmd.s_ccb, &set_cc[1], 'B');
371 set_ccx (cmd.s_ccc, &set_cc[2], 'C');
373 set_ccx (cmd.s_ccd, &set_cc[3], 'D');
375 set_ccx (cmd.s_cce, &set_cc[4], 'E');
378 set_routing (cmd.errors, &set_errors);
379 if (cmd.sbc_messages)
380 set_routing (cmd.messages, &set_messages);
382 /* PC+ compatible syntax. */
384 outp_enable_device (cmd.scrn == STC_OFF ? 0 : 1, OUTP_DEV_SCREEN);
386 outp_enable_device (cmd.prtr == STC_OFF ? 0 : 1, OUTP_DEV_PRINTER);
388 if (cmd.sbc_automenu )
389 msg (SW, _("%s is obsolete."),"AUTOMENU");
391 msg (SW, _("%s is obsolete."),"BEEP");
393 msg (SW, _("%s is obsolete."),"BLOCK");
394 if (cmd.sbc_boxstring)
395 msg (SW, _("%s is obsolete."),"BOXSTRING");
397 msg (SW, _("%s is obsolete."),"EJECT");
398 if (cmd.sbc_helpwindows )
399 msg (SW, _("%s is obsolete."),"HELPWINDOWS");
400 if (cmd.sbc_histogram)
401 msg (MW, _("%s is obsolete."),"HISTOGRAM");
403 msg (MW, _("%s is obsolete."),"MENUS");
404 if (cmd.sbc_ptranslate )
405 msg (SW, _("%s is obsolete."),"PTRANSLATE");
406 if (cmd.sbc_runreview )
407 msg (SW, _("%s is obsolete."),"RUNREVIEW");
409 msg (SW, _("%s is obsolete."),"XSORT");
410 if (cmd.sbc_mxmemory )
411 msg (SE, _("%s is obsolete."),"MXMEMORY");
412 if (cmd.sbc_scripttab)
413 msg (SE, _("%s is obsolete."),"SCRIPTTAB");
416 msg (SW, _("%s is not yet implemented."),"TBFONTS");
417 if (cmd.sbc_tb1 && cmd.s_tb1)
418 msg (SW, _("%s is not yet implemented."),"TB1");
420 /* Windows compatible syntax. */
422 msg (SW, _("CASE is not implemented and probably won't be. "
423 "If you care, complain about it."));
425 if (cmd.sbc_compression)
427 msg (MW, _("Active file compression is not yet implemented "
428 "(and probably won't be)."));
434 /* Sets custom currency specifier CC having name CC_NAME ('A' through
435 'E') to correspond to the settings in CC_STRING. */
437 set_ccx (const char *cc_string, struct set_cust_currency * cc, int cc_name)
439 if (strlen (cc_string) > 16)
441 msg (SE, _("CC%c: Length of custom currency string `%s' (%d) "
442 "exceeds maximum length of 16."),
443 cc_name, cc_string, strlen (cc_string));
447 /* Determine separators. */
450 int n_commas, n_periods;
452 /* Count the number of commas and periods. There must be exactly
453 three of one or the other. */
454 n_commas = n_periods = 0;
455 for (sp = cc_string; *sp; sp++)
461 if (!((n_commas == 3) ^ (n_periods == 3)))
463 msg (SE, _("CC%c: Custom currency string `%s' does not contain "
464 "exactly three periods or commas (not both)."),
468 else if (n_commas == 3)
480 /* Copy cc_string to cc, changing separators to nulls. */
484 strcpy (cc->buf, cc_string);
485 cp = cc->neg_prefix = cc->buf;
487 while (*cp++ != cc->grouping)
492 while (*cp++ != cc->grouping)
497 while (*cp++ != cc->grouping)
508 route_to_string(int routing)
516 strcpy(s, _("None"));
520 if (routing & SET_ROUTE_DISABLE )
522 strcpy(s, _("Disabled") );
526 if (routing & SET_ROUTE_SCREEN)
527 strcat(s, _("Screen") );
529 if (routing & SET_ROUTE_LISTING)
534 strcat(s, _("Listing") );
537 if (routing & SET_ROUTE_OTHER)
541 strcat(s, _("Other") );
550 /* Sets *SETTING, which is a combination of SET_ROUTE_* bits that
551 indicates what to do with some sort of output, to the value
552 indicated by Q, which is a value provided by the input parser. */
554 set_routing (int q, int *setting)
559 *setting |= SET_ROUTE_DISABLE;
562 *setting &= ~SET_ROUTE_DISABLE;
565 *setting &= ~(SET_ROUTE_LISTING | SET_ROUTE_OTHER);
566 *setting |= SET_ROUTE_SCREEN;
569 *setting &= ~SET_ROUTE_SCREEN;
570 *setting |= SET_ROUTE_LISTING | SET_ROUTE_OTHER;
573 *setting |= SET_ROUTE_SCREEN | SET_ROUTE_LISTING | SET_ROUTE_OTHER;
576 *setting &= ~(SET_ROUTE_SCREEN | SET_ROUTE_LISTING | SET_ROUTE_OTHER);
584 stc_custom_pager (struct cmd_set *cmd UNUSED)
587 #if !USE_INTERNAL_PAGER
588 if (lex_match_id ("OFF"))
596 if (!lex_force_string ())
600 set_pager = xstrdup (ds_value (&tokstr));
604 #else /* USE_INTERNAL_PAGER */
607 msg (SW, "External pagers not supported.");
609 #endif /* USE_INTERNAL_PAGER */
612 /* Parses the BLANKS subcommand, which controls the value that
613 completely blank fields in numeric data imply. X, Wnd: Syntax is
614 SYSMIS or a numeric value; PC+: Syntax is '.', which is equivalent
615 to SYSMIS, or a numeric value. */
617 stc_custom_blanks (struct cmd_set *cmd UNUSED)
620 if ((token == T_ID && lex_id_match ("SYSMIS", tokid))
621 || (token == T_STRING && !strcmp (tokid, ".")))
628 if (!lex_force_num ())
637 stc_custom_length (struct cmd_set *cmd UNUSED)
642 if (lex_match_id ("NONE"))
646 if (!lex_force_int ())
648 if (lex_integer () < 1)
650 msg (SE, _("LENGTH must be at least 1."));
653 page_length = lex_integer ();
657 if ( page_length != -1 )
658 set_viewlength = page_length;
664 stc_custom_results (struct cmd_set *cmd UNUSED)
672 static struct tuple tab[] =
676 {"TERMINAL", STC_TERMINAL},
677 {"LISTING", STC_LISTING},
689 msg (SE, _("Missing identifier in RESULTS subcommand."));
693 for (t = tab; t->s; t++)
694 if (lex_id_match (t->s, tokid))
697 set_routing (t->v, &set_results);
700 msg (SE, _("Unrecognized identifier in RESULTS subcommand."));
705 stc_custom_seed (struct cmd_set *cmd UNUSED)
708 if (lex_match_id ("RANDOM"))
709 set_seed = random_seed();
712 if (!lex_force_num ())
723 stc_custom_width (struct cmd_set *cmd UNUSED)
728 if (lex_match_id ("NARROW"))
730 else if (lex_match_id ("WIDE"))
734 if (!lex_force_int ())
736 if (lex_integer () < 1)
738 msg (SE, _("WIDTH must be at least 1."));
741 page_width = lex_integer ();
745 set_viewwidth = page_width;
749 /* Parses FORMAT subcommand, which consists of a numeric format
752 stc_custom_format (struct cmd_set *cmd UNUSED)
757 if (!parse_format_specifier (&fmt, 0))
759 if ((formats[fmt.type].cat & FCAT_STRING) != 0)
761 msg (SE, _("FORMAT requires numeric output format as an argument. "
762 "Specified format %s is of type string."),
763 fmt_to_string (&fmt));
772 stc_custom_journal (struct cmd_set *cmd UNUSED)
775 if (lex_match_id ("ON"))
777 else if (lex_match_id ("OFF"))
779 if (token == T_STRING)
781 set_journal = xstrdup (ds_value (&tokstr));
787 /* Parses COLOR subcommand. PC+: either ON or OFF or two or three
788 comma-delimited numbers inside parentheses. */
790 stc_custom_color (struct cmd_set *cmd UNUSED)
792 msg (MW, _("%s is obsolete."),"COLOR");
795 if (!lex_match_id ("ON") && !lex_match_id ("YES") && !lex_match_id ("OFF") && !lex_match_id ("NO"))
797 if (!lex_force_match ('('))
799 if (!lex_match ('*'))
801 if (!lex_force_int ())
803 if (lex_integer () < 0 || lex_integer () > 15)
805 msg (SE, _("Text color must be in range 0-15."));
810 if (!lex_force_match (','))
812 if (!lex_match ('*'))
814 if (!lex_force_int ())
816 if (lex_integer () < 0 || lex_integer () > 7)
818 msg (SE, _("Background color must be in range 0-7."));
823 if (lex_match (',') && !lex_match ('*'))
825 if (!lex_force_int ())
827 if (lex_integer () < 0 || lex_integer () > 7)
829 msg (SE, _("Border color must be in range 0-7."));
834 if (!lex_force_match (')'))
841 stc_custom_listing (struct cmd_set *cmd UNUSED)
844 if (lex_match_id ("ON") || lex_match_id ("YES"))
846 else if (lex_match_id ("OFF") || lex_match_id ("NO"))
853 outp_enable_device (set_listing, OUTP_DEV_LISTING);
859 stc_custom_disk (struct cmd_set *cmd UNUSED)
861 return stc_custom_listing (cmd);
865 stc_custom_log (struct cmd_set *cmd UNUSED)
867 return stc_custom_journal (cmd);
871 stc_custom_rcolor (struct cmd_set *cmd UNUSED)
873 msg (SW, _("%s is obsolete."),"RCOLOR");
876 if (!lex_force_match ('('))
879 if (!lex_match ('*'))
881 if (!lex_force_int ())
883 if (lex_integer () < 0 || lex_integer () > 6)
885 msg (SE, _("Lower window color must be between 0 and 6."));
890 if (!lex_force_match (','))
893 if (!lex_match ('*'))
895 if (!lex_force_int ())
897 if (lex_integer () < 0 || lex_integer () > 6)
899 msg (SE, _("Upper window color must be between 0 and 6."));
905 if (lex_match (',') && !lex_match ('*'))
907 if (!lex_force_int ())
909 if (lex_integer () < 0 || lex_integer () > 6)
911 msg (SE, _("Frame color must be between 0 and 6."));
920 stc_custom_viewwidth (struct cmd_set *cmd UNUSED)
924 if ( !lex_force_int() )
927 set_viewwidth = lex_integer();
934 stc_custom_viewlength (struct cmd_set *cmd UNUSED)
936 if (lex_match_id ("MINIMUM"))
938 else if (lex_match_id ("MEDIAN"))
939 set_viewlength = 43; /* This is not correct for VGA displays. */
940 else if (lex_match_id ("MAXIMUM"))
944 if (!lex_force_int ())
947 if (lex_integer () >= (43 + 25) / 2)
952 set_viewlength = lex_integer ();
958 msg (SW, _("%s is not yet implemented."),"VIEWLENGTH");
964 stc_custom_workdev (struct cmd_set *cmd UNUSED)
968 msg (SW, _("%s is obsolete."),"WORKDEV");
971 for (*c = 'A'; *c <= 'Z'; (*c)++)
972 if (token == T_ID && lex_id_match (c, tokid))
977 msg (SE, _("Drive letter expected in WORKDEV subcommand."));
987 static char term_buffer[16384];
990 /* Workable defaults before we determine the real terminal size. */
996 #if __DJGPP__ || __BORLANDC__
1001 set_viewlength = max (ti.screenheight, 25);
1002 set_viewwidth = max (ti.screenwidth, 79);
1004 #elif HAVE_LIBTERMCAP
1009 /* This code stolen from termcap.info, though modified. */
1010 termtype = getenv ("TERM");
1012 msg (FE, _("Specify a terminal type with `setenv TERM <yourtype>'."));
1014 success = tgetent (term_buffer, termtype);
1018 msg (IE, _("Could not access the termcap data base."));
1020 msg (IE, _("Terminal type `%s' is not defined."), termtype);
1024 set_viewlength = tgetnum ("li");
1025 set_viewwidth = tgetnum ("co") - 1;
1032 /* Try the environment variables */
1033 s = getenv("COLUMNS");
1034 if ( s ) set_viewwidth = atoi(s);
1036 s = getenv("LINES");
1037 if ( s ) set_viewlength = atoi(s);
1039 #endif /* !HAVE_LIBTERMCAP */
1043 /* Public functions */
1048 cmd.s_dprompt = xstrdup (_("data> "));
1049 cmd.s_cprompt = xstrdup (" > ");
1050 cmd.s_prompt = xstrdup ("PSPP> ");
1051 cmd.s_endcmd = xstrdup (".");
1053 assert(cmd.safe == 0 );
1061 cmd.headers = STC_YES;
1062 cmd.errbrk = STC_OFF;
1064 cmd.scompress = STC_OFF;
1065 cmd.undef = STC_WARN;
1066 cmd.mprint = STC_ON ;
1067 cmd.prtbck = STC_ON ;
1071 set_journal = xstrdup ("pspp.jnl");
1074 cmd.n_mxwarns = 100;
1077 cmd.n_workspace = 4L * 1024 * 1024;
1080 #if !USE_INTERNAL_PAGER
1084 pager = getenv ("STAT_PAGER");
1085 if (!pager) set_pager = getenv ("PAGER");
1088 set_pager = xstrdup (pager);
1091 set_pager = xstrdup (DEFAULT_PAGER);
1092 #endif /* DEFAULT_PAGER */
1094 #endif /* !USE_INTERNAL_PAGER */
1100 for (i = 0; i < 5; i++)
1102 struct set_cust_currency *cc = &set_cc[i];
1103 strcpy (cc->buf, "-");
1104 cc->neg_prefix = cc->buf;
1105 cc->prefix = &cc->buf[1];
1106 cc->suffix = &cc->buf[1];
1107 cc->neg_suffix = &cc->buf[1];
1116 signal (SIGWINCH,set_viewport);
1122 force_long_view(void)
1131 return !(cmd.safe != STC_ON) ;
1135 /* Set safer mode */
1146 return (cmd.dec == STC_DOT ? '.' : ',');
1153 return (cmd.dec == STC_DOT ? ',' : '.');
1160 return cmd.s_prompt;
1166 return cmd.s_dprompt;
1172 return cmd.s_cprompt;
1179 return (cmd.echo != STC_OFF );
1184 get_errorbreak(void)
1186 return (cmd.errbrk != STC_OFF);
1191 get_scompression(void)
1193 return (cmd.scompress != STC_OFF );
1199 return (cmd.undef != STC_NOWARN);
1205 return cmd.n_mxwarns;
1211 return cmd.n_mxerrs;
1217 return ( cmd.mprint != STC_OFF );
1223 return (cmd.prtbck != STC_OFF );
1229 return cmd.n_mxloops;
1235 return (cmd.null != STC_OFF );
1241 return (cmd.inc != STC_OFF );
1247 return cmd.s_endcmd[0];
1252 get_max_workspace(void)
1254 return cmd.n_workspace;
1269 /* CCA through CCE. */
1270 const struct set_cust_currency *
1277 aux_show_warranty(void)
1279 msg(MM,lack_of_warranty);
1283 aux_show_copying(void)
1290 get_viewlength(void)
1292 return set_viewlength;
1298 return set_viewwidth;
1307 /* Return 1 if the seed has been set since the last time this function
1309 Fill the value pointed to by seed with the seed .
1312 seed_is_set(unsigned long *seed)