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 int tgetflag (const char *);
88 #endif /* !HAVE_TERMCAP_H */
89 #endif /* !HAVE_LIBTERMCAP */
91 static int set_errors;
92 static int set_messages;
93 static int set_results;
95 static double set_blanks=SYSMIS;
97 static struct fmt_spec set_format={FMT_F,8,2};
99 static struct set_cust_currency set_cc[5];
101 static char *set_journal;
102 static int set_journaling;
104 static int set_listing=1;
106 #if !USE_INTERNAL_PAGER
107 static char *set_pager=0;
108 #endif /* !USE_INTERNAL_PAGER */
110 static unsigned long set_seed;
111 static int seed_flag=0;
113 static int long_view=0;
114 int set_testing_mode=0;
115 static int set_viewlength;
116 static int set_viewwidth;
118 void aux_show_warranty(void);
119 void aux_show_copying(void);
121 static const char *route_to_string(int routing);
122 static void set_routing (int q, int *setting);
124 static int set_ccx (const char *cc_string, struct set_cust_currency * cc,
128 automenu=automenu:on/off;
131 block=string "x==1" "one character long";
132 boxstring=string "x==3 || x==11" "3 or 11 characters long";
133 case=size:upper/uplow;
140 compression=compress:on/off;
141 cpi=integer "x>0" "%s must be greater than 0";
143 decimal=dec:dot/comma;
148 endcmd=string "x==1" "one character long";
149 errorbreak=errbrk:on/off;
150 errors=errors:on/off/terminal/listing/both/none;
152 headers=headers:no/yes/blank;
153 helpwindows=helpwin:on/off;
154 highres=hires:on/off;
155 histogram=string "x==1" "one character long";
161 lowres=lores:auto/on/off;
162 lpi=integer "x>0" "% must be greater than 0";
163 menus=menus:standard/extended;
164 messages=messages:on/off/terminal/listing/both/none;
166 miterate=integer "x>0" "%s must be greater than 0";
167 mnest=integer "x>0" "%s must be greater than 0";
169 mprint=mprint:on/off;
170 mxerrs=integer "x >= 1" "%s must be at least 1";
171 mxloops=integer "x >=1" "%s must be at least 1";
176 printback=prtbck:on/off;
179 ptranslate=ptrans:on/off;
182 runreview=runrev:auto/manual;
184 scompression=scompress:on/off;
186 scripttab=string "x==1" "one character long";
188 tb1=string "x==3 || x==11" "3 or 11 characters long";
190 undefined=undef:warn/nowarn;
195 workspace=integer "x>=1024" "%s must be at least 1 MB";
204 aux_stc_custom_blanks(struct cmd_set *cmd UNUSED)
206 if ( set_blanks == SYSMIS )
209 msg(MM, "%g", set_blanks);
215 aux_stc_custom_color(struct cmd_set *cmd UNUSED)
217 msg (MW, _("%s is obsolete."),"COLOR");
222 aux_stc_custom_listing(struct cmd_set *cmd UNUSED)
225 msg(MM, _("LISTING is ON"));
227 msg(MM, _("LISTING is OFF"));
233 aux_stc_custom_disk(struct cmd_set *cmd UNUSED)
235 return aux_stc_custom_listing(cmd);
239 aux_stc_custom_format(struct cmd_set *cmd UNUSED)
241 msg(MM, fmt_to_string(&set_format));
248 aux_stc_custom_journal(struct cmd_set *cmd UNUSED)
251 msg(MM, set_journal);
253 msg(MM, _("Journalling is off") );
259 aux_stc_custom_length(struct cmd_set *cmd UNUSED)
261 msg(MM, "%d", set_viewlength);
266 aux_stc_custom_log(struct cmd_set *cmd )
268 return aux_stc_custom_journal (cmd);
272 aux_stc_custom_pager(struct cmd_set *cmd UNUSED)
274 #if !USE_INTERNAL_PAGER
279 #else /* USE_INTERNAL_PAGER */
280 msg (MM, "Internal pager.");
281 #endif /* USE_INTERNAL_PAGER */
287 aux_stc_custom_rcolor(struct cmd_set *cmd UNUSED)
289 msg (SW, _("%s is obsolete."),"RCOLOR");
294 aux_stc_custom_results(struct cmd_set *cmd UNUSED)
297 msg(MM, route_to_string(set_results) );
303 aux_stc_custom_seed(struct cmd_set *cmd UNUSED)
305 msg(MM, "%ld",set_seed);
310 aux_stc_custom_viewlength(struct cmd_set *cmd UNUSED)
312 msg(MM, "%d", set_viewlength);
317 aux_stc_custom_viewwidth(struct cmd_set *cmd UNUSED)
319 msg(MM, "%d", set_viewwidth);
324 aux_stc_custom_width(struct cmd_set *cmd UNUSED)
326 msg(MM, "%d", set_viewwidth);
331 aux_stc_custom_workdev(struct cmd_set *cmd UNUSED)
333 msg (SW, _("%s is obsolete."),"WORKDEV");
340 warranty=show_warranty;
341 copying=show_copying.
345 static struct cmd_set cmd;
350 lex_match_id ("SHOW");
352 if (!aux_parse_set (&cmd))
362 if (!parse_set (&cmd))
366 set_ccx (cmd.s_cca, &set_cc[0], 'A');
368 set_ccx (cmd.s_ccb, &set_cc[1], 'B');
370 set_ccx (cmd.s_ccc, &set_cc[2], 'C');
372 set_ccx (cmd.s_ccd, &set_cc[3], 'D');
374 set_ccx (cmd.s_cce, &set_cc[4], 'E');
377 set_routing (cmd.errors, &set_errors);
378 if (cmd.sbc_messages)
379 set_routing (cmd.messages, &set_messages);
381 /* PC+ compatible syntax. */
383 outp_enable_device (cmd.scrn == STC_OFF ? 0 : 1, OUTP_DEV_SCREEN);
385 outp_enable_device (cmd.prtr == STC_OFF ? 0 : 1, OUTP_DEV_PRINTER);
387 if (cmd.sbc_automenu )
388 msg (SW, _("%s is obsolete."),"AUTOMENU");
390 msg (SW, _("%s is obsolete."),"BEEP");
392 msg (SW, _("%s is obsolete."),"BLOCK");
393 if (cmd.sbc_boxstring)
394 msg (SW, _("%s is obsolete."),"BOXSTRING");
396 msg (SW, _("%s is obsolete."),"EJECT");
397 if (cmd.sbc_helpwindows )
398 msg (SW, _("%s is obsolete."),"HELPWINDOWS");
399 if (cmd.sbc_histogram)
400 msg (MW, _("%s is obsolete."),"HISTOGRAM");
402 msg (MW, _("%s is obsolete."),"MENUS");
403 if (cmd.sbc_ptranslate )
404 msg (SW, _("%s is obsolete."),"PTRANSLATE");
405 if (cmd.sbc_runreview )
406 msg (SW, _("%s is obsolete."),"RUNREVIEW");
408 msg (SW, _("%s is obsolete."),"XSORT");
409 if (cmd.sbc_mxmemory )
410 msg (SE, _("%s is obsolete."),"MXMEMORY");
411 if (cmd.sbc_scripttab)
412 msg (SE, _("%s is obsolete."),"SCRIPTTAB");
415 msg (SW, _("%s is not yet implemented."),"TBFONTS");
416 if (cmd.sbc_tb1 && cmd.s_tb1)
417 msg (SW, _("%s is not yet implemented."),"TB1");
419 /* Windows compatible syntax. */
421 msg (SW, _("CASE is not implemented and probably won't be. "
422 "If you care, complain about it."));
424 if (cmd.sbc_compression)
426 msg (MW, _("Active file compression is not yet implemented "
427 "(and probably won't be)."));
433 /* Sets custom currency specifier CC having name CC_NAME ('A' through
434 'E') to correspond to the settings in CC_STRING. */
436 set_ccx (const char *cc_string, struct set_cust_currency * cc, int cc_name)
438 if (strlen (cc_string) > 16)
440 msg (SE, _("CC%c: Length of custom currency string `%s' (%d) "
441 "exceeds maximum length of 16."),
442 cc_name, cc_string, strlen (cc_string));
446 /* Determine separators. */
449 int n_commas, n_periods;
451 /* Count the number of commas and periods. There must be exactly
452 three of one or the other. */
453 n_commas = n_periods = 0;
454 for (sp = cc_string; *sp; sp++)
460 if (!((n_commas == 3) ^ (n_periods == 3)))
462 msg (SE, _("CC%c: Custom currency string `%s' does not contain "
463 "exactly three periods or commas (not both)."),
467 else if (n_commas == 3)
479 /* Copy cc_string to cc, changing separators to nulls. */
483 strcpy (cc->buf, cc_string);
484 cp = cc->neg_prefix = cc->buf;
486 while (*cp++ != cc->grouping)
491 while (*cp++ != cc->grouping)
496 while (*cp++ != cc->grouping)
507 route_to_string(int routing)
515 strcpy(s, _("None"));
519 if (routing & SET_ROUTE_DISABLE )
521 strcpy(s, _("Disabled") );
525 if (routing & SET_ROUTE_SCREEN)
526 strcat(s, _("Screen") );
528 if (routing & SET_ROUTE_LISTING)
533 strcat(s, _("Listing") );
536 if (routing & SET_ROUTE_OTHER)
540 strcat(s, _("Other") );
549 /* Sets *SETTING, which is a combination of SET_ROUTE_* bits that
550 indicates what to do with some sort of output, to the value
551 indicated by Q, which is a value provided by the input parser. */
553 set_routing (int q, int *setting)
558 *setting |= SET_ROUTE_DISABLE;
561 *setting &= ~SET_ROUTE_DISABLE;
564 *setting &= ~(SET_ROUTE_LISTING | SET_ROUTE_OTHER);
565 *setting |= SET_ROUTE_SCREEN;
568 *setting &= ~SET_ROUTE_SCREEN;
569 *setting |= SET_ROUTE_LISTING | SET_ROUTE_OTHER;
572 *setting |= SET_ROUTE_SCREEN | SET_ROUTE_LISTING | SET_ROUTE_OTHER;
575 *setting &= ~(SET_ROUTE_SCREEN | SET_ROUTE_LISTING | SET_ROUTE_OTHER);
583 stc_custom_pager (struct cmd_set *cmd UNUSED)
586 #if !USE_INTERNAL_PAGER
587 if (lex_match_id ("OFF"))
595 if (!lex_force_string ())
599 set_pager = xstrdup (ds_value (&tokstr));
603 #else /* USE_INTERNAL_PAGER */
606 msg (SW, "External pagers not supported.");
608 #endif /* USE_INTERNAL_PAGER */
611 /* Parses the BLANKS subcommand, which controls the value that
612 completely blank fields in numeric data imply. X, Wnd: Syntax is
613 SYSMIS or a numeric value; PC+: Syntax is '.', which is equivalent
614 to SYSMIS, or a numeric value. */
616 stc_custom_blanks (struct cmd_set *cmd UNUSED)
619 if ((token == T_ID && lex_id_match ("SYSMIS", tokid))
620 || (token == T_STRING && !strcmp (tokid, ".")))
627 if (!lex_force_num ())
636 stc_custom_length (struct cmd_set *cmd UNUSED)
641 if (lex_match_id ("NONE"))
645 if (!lex_force_int ())
647 if (lex_integer () < 1)
649 msg (SE, _("LENGTH must be at least 1."));
652 page_length = lex_integer ();
656 if ( page_length != -1 )
657 set_viewlength = page_length;
663 stc_custom_results (struct cmd_set *cmd UNUSED)
671 static struct tuple tab[] =
675 {"TERMINAL", STC_TERMINAL},
676 {"LISTING", STC_LISTING},
688 msg (SE, _("Missing identifier in RESULTS subcommand."));
692 for (t = tab; t->s; t++)
693 if (lex_id_match (t->s, tokid))
696 set_routing (t->v, &set_results);
699 msg (SE, _("Unrecognized identifier in RESULTS subcommand."));
704 stc_custom_seed (struct cmd_set *cmd UNUSED)
707 if (lex_match_id ("RANDOM"))
708 set_seed = random_seed();
711 if (!lex_force_num ())
722 stc_custom_width (struct cmd_set *cmd UNUSED)
727 if (lex_match_id ("NARROW"))
729 else if (lex_match_id ("WIDE"))
733 if (!lex_force_int ())
735 if (lex_integer () < 1)
737 msg (SE, _("WIDTH must be at least 1."));
740 page_width = lex_integer ();
744 set_viewwidth = page_width;
748 /* Parses FORMAT subcommand, which consists of a numeric format
751 stc_custom_format (struct cmd_set *cmd UNUSED)
756 if (!parse_format_specifier (&fmt, 0))
758 if ((formats[fmt.type].cat & FCAT_STRING) != 0)
760 msg (SE, _("FORMAT requires numeric output format as an argument. "
761 "Specified format %s is of type string."),
762 fmt_to_string (&fmt));
771 stc_custom_journal (struct cmd_set *cmd UNUSED)
774 if (lex_match_id ("ON"))
776 else if (lex_match_id ("OFF"))
778 if (token == T_STRING)
780 set_journal = xstrdup (ds_value (&tokstr));
786 /* Parses COLOR subcommand. PC+: either ON or OFF or two or three
787 comma-delimited numbers inside parentheses. */
789 stc_custom_color (struct cmd_set *cmd UNUSED)
791 msg (MW, _("%s is obsolete."),"COLOR");
794 if (!lex_match_id ("ON") && !lex_match_id ("YES") && !lex_match_id ("OFF") && !lex_match_id ("NO"))
796 if (!lex_force_match ('('))
798 if (!lex_match ('*'))
800 if (!lex_force_int ())
802 if (lex_integer () < 0 || lex_integer () > 15)
804 msg (SE, _("Text color must be in range 0-15."));
809 if (!lex_force_match (','))
811 if (!lex_match ('*'))
813 if (!lex_force_int ())
815 if (lex_integer () < 0 || lex_integer () > 7)
817 msg (SE, _("Background color must be in range 0-7."));
822 if (lex_match (',') && !lex_match ('*'))
824 if (!lex_force_int ())
826 if (lex_integer () < 0 || lex_integer () > 7)
828 msg (SE, _("Border color must be in range 0-7."));
833 if (!lex_force_match (')'))
840 stc_custom_listing (struct cmd_set *cmd UNUSED)
843 if (lex_match_id ("ON") || lex_match_id ("YES"))
845 else if (lex_match_id ("OFF") || lex_match_id ("NO"))
852 outp_enable_device (set_listing, OUTP_DEV_LISTING);
858 stc_custom_disk (struct cmd_set *cmd UNUSED)
860 return stc_custom_listing (cmd);
864 stc_custom_log (struct cmd_set *cmd UNUSED)
866 return stc_custom_journal (cmd);
870 stc_custom_rcolor (struct cmd_set *cmd UNUSED)
872 msg (SW, _("%s is obsolete."),"RCOLOR");
875 if (!lex_force_match ('('))
878 if (!lex_match ('*'))
880 if (!lex_force_int ())
882 if (lex_integer () < 0 || lex_integer () > 6)
884 msg (SE, _("Lower window color must be between 0 and 6."));
889 if (!lex_force_match (','))
892 if (!lex_match ('*'))
894 if (!lex_force_int ())
896 if (lex_integer () < 0 || lex_integer () > 6)
898 msg (SE, _("Upper window color must be between 0 and 6."));
904 if (lex_match (',') && !lex_match ('*'))
906 if (!lex_force_int ())
908 if (lex_integer () < 0 || lex_integer () > 6)
910 msg (SE, _("Frame color must be between 0 and 6."));
919 stc_custom_viewwidth (struct cmd_set *cmd UNUSED)
923 if ( !lex_force_int() )
926 set_viewwidth = lex_integer();
933 stc_custom_viewlength (struct cmd_set *cmd UNUSED)
935 if (lex_match_id ("MINIMUM"))
937 else if (lex_match_id ("MEDIAN"))
938 set_viewlength = 43; /* This is not correct for VGA displays. */
939 else if (lex_match_id ("MAXIMUM"))
943 if (!lex_force_int ())
946 if (lex_integer () >= (43 + 25) / 2)
951 set_viewlength = lex_integer ();
957 msg (SW, _("%s is not yet implemented."),"VIEWLENGTH");
963 stc_custom_workdev (struct cmd_set *cmd UNUSED)
967 msg (SW, _("%s is obsolete."),"WORKDEV");
970 for (*c = 'A'; *c <= 'Z'; (*c)++)
971 if (token == T_ID && lex_id_match (c, tokid))
976 msg (SE, _("Drive letter expected in WORKDEV subcommand."));
983 set_viewport(int sig_num UNUSED)
986 static char term_buffer[16384];
992 #if __DJGPP__ || __BORLANDC__
997 set_viewlength = max (ti.screenheight, 25);
998 set_viewwidth = max (ti.screenwidth, 79);
1000 #elif HAVE_LIBTERMCAP
1005 /* This code stolen from termcap.info, though modified. */
1006 termtype = getenv ("TERM");
1008 msg (FE, _("Specify a terminal type with the TERM environment variable."));
1010 success = tgetent (term_buffer, termtype);
1014 msg (IE, _("Could not access the termcap data base."));
1016 msg (IE, _("Terminal type `%s' is not defined."), termtype);
1020 /* NOTE: Do not rely upon tgetnum returning -1 if the value is
1021 not available. It's supposed to do it, but not all platforms
1024 if ( tgetflag("li"))
1025 set_viewlength = tgetnum ("li");
1027 if ( tgetflag("co"))
1028 set_viewwidth = tgetnum ("co") - 1;
1031 #endif /* HAVE_LIBTERMCAP */
1033 /* Try the environment variables */
1034 if ( -1 == set_viewwidth )
1036 char *s = getenv("COLUMNS");
1037 if ( s ) set_viewwidth = atoi(s);
1040 if ( -1 == set_viewwidth )
1042 char *s = getenv("LINES");
1043 if ( s ) set_viewlength = atoi(s);
1047 /* Last resort. Use hard coded values */
1048 if ( 0 > set_viewwidth ) set_viewwidth = 79;
1049 if ( 0 > set_viewlength ) set_viewlength = 24;
1053 /* Public functions */
1058 cmd.s_dprompt = xstrdup (_("data> "));
1059 cmd.s_cprompt = xstrdup (" > ");
1060 cmd.s_prompt = xstrdup ("PSPP> ");
1061 cmd.s_endcmd = xstrdup (".");
1063 assert(cmd.safe == 0 );
1071 cmd.headers = STC_YES;
1072 cmd.errbrk = STC_OFF;
1074 cmd.scompress = STC_OFF;
1075 cmd.undef = STC_WARN;
1076 cmd.mprint = STC_ON ;
1077 cmd.prtbck = STC_ON ;
1081 set_journal = xstrdup ("pspp.jnl");
1084 cmd.n_mxwarns = 100;
1087 cmd.n_workspace = 4L * 1024 * 1024;
1090 #if !USE_INTERNAL_PAGER
1094 pager = getenv ("STAT_PAGER");
1095 if (!pager) set_pager = getenv ("PAGER");
1098 set_pager = xstrdup (pager);
1101 set_pager = xstrdup (DEFAULT_PAGER);
1102 #endif /* DEFAULT_PAGER */
1104 #endif /* !USE_INTERNAL_PAGER */
1110 for (i = 0; i < 5; i++)
1112 struct set_cust_currency *cc = &set_cc[i];
1113 strcpy (cc->buf, "-");
1114 cc->neg_prefix = cc->buf;
1115 cc->prefix = &cc->buf[1];
1116 cc->suffix = &cc->buf[1];
1117 cc->neg_suffix = &cc->buf[1];
1126 signal (SIGWINCH, set_viewport);
1132 force_long_view(void)
1141 return !(cmd.safe != STC_ON) ;
1145 /* Set safer mode */
1156 return (cmd.dec == STC_DOT ? '.' : ',');
1163 return (cmd.dec == STC_DOT ? ',' : '.');
1170 return cmd.s_prompt;
1176 return cmd.s_dprompt;
1182 return cmd.s_cprompt;
1189 return (cmd.echo != STC_OFF );
1194 get_errorbreak(void)
1196 return (cmd.errbrk != STC_OFF);
1201 get_scompression(void)
1203 return (cmd.scompress != STC_OFF );
1209 return (cmd.undef != STC_NOWARN);
1215 return cmd.n_mxwarns;
1221 return cmd.n_mxerrs;
1227 return ( cmd.mprint != STC_OFF );
1233 return (cmd.prtbck != STC_OFF );
1239 return cmd.n_mxloops;
1245 return (cmd.null != STC_OFF );
1251 return (cmd.inc != STC_OFF );
1257 return cmd.s_endcmd[0];
1262 get_max_workspace(void)
1264 return cmd.n_workspace;
1279 /* CCA through CCE. */
1280 const struct set_cust_currency *
1287 aux_show_warranty(void)
1289 msg(MM,lack_of_warranty);
1293 aux_show_copying(void)
1300 get_viewlength(void)
1302 return set_viewlength;
1308 return set_viewwidth;
1317 /* Return 1 if the seed has been set since the last time this function
1319 Fill the value pointed to by seed with the seed .
1322 seed_is_set(unsigned long *seed)