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 */
111 static int long_view=0;
112 int set_testing_mode=0;
113 static int set_viewlength;
114 static int set_viewwidth;
116 void aux_show_warranty(void);
117 void aux_show_copying(void);
119 static const char *route_to_string(int routing);
120 static void set_routing (int q, int *setting);
122 static int set_ccx (const char *cc_string, struct set_cust_currency * cc,
124 static void set_rng (unsigned long);
125 static unsigned long random_seed (void);
129 automenu=automenu:on/off;
132 block=string "x==1" "one character long";
133 boxstring=string "x==3 || x==11" "3 or 11 characters long";
134 case=size:upper/uplow;
141 compression=compress:on/off;
142 cpi=integer "x>0" "%s must be greater than 0";
144 decimal=dec:dot/comma;
149 endcmd=string "x==1" "one character long";
150 errorbreak=errbrk:on/off;
151 errors=errors:on/off/terminal/listing/both/none;
153 headers=headers:no/yes/blank;
154 helpwindows=helpwin:on/off;
155 highres=hires:on/off;
156 histogram=string "x==1" "one character long";
162 lowres=lores:auto/on/off;
163 lpi=integer "x>0" "%s must be greater than 0";
164 menus=menus:standard/extended;
165 messages=messages:on/off/terminal/listing/both/none;
167 miterate=integer "x>0" "%s must be greater than 0";
168 mnest=integer "x>0" "%s must be greater than 0";
170 mprint=mprint:on/off;
171 mxerrs=integer "x >= 1" "%s must be at least 1";
172 mxloops=integer "x >=1" "%s must be at least 1";
177 printback=prtbck:on/off;
180 ptranslate=ptrans:on/off;
183 runreview=runrev:auto/manual;
185 scompression=scompress:on/off;
187 scripttab=string "x==1" "one character long";
189 tb1=string "x==3 || x==11" "3 or 11 characters long";
191 undefined=undef:warn/nowarn;
196 workspace=integer "x>=1024" "%s must be at least 1 MB";
205 aux_stc_custom_blanks(struct cmd_set *cmd UNUSED)
207 if ( set_blanks == SYSMIS )
210 msg(MM, "%g", set_blanks);
216 aux_stc_custom_color(struct cmd_set *cmd UNUSED)
218 msg (MW, _("%s is obsolete."),"COLOR");
223 aux_stc_custom_listing(struct cmd_set *cmd UNUSED)
226 msg(MM, _("LISTING is ON"));
228 msg(MM, _("LISTING is OFF"));
234 aux_stc_custom_disk(struct cmd_set *cmd UNUSED)
236 return aux_stc_custom_listing(cmd);
240 aux_stc_custom_format(struct cmd_set *cmd UNUSED)
242 msg(MM, fmt_to_string(&set_format));
249 aux_stc_custom_journal(struct cmd_set *cmd UNUSED)
252 msg(MM, set_journal);
254 msg(MM, _("Journalling is off") );
260 aux_stc_custom_length(struct cmd_set *cmd UNUSED)
262 msg(MM, "%d", set_viewlength);
267 aux_stc_custom_log(struct cmd_set *cmd )
269 return aux_stc_custom_journal (cmd);
273 aux_stc_custom_pager(struct cmd_set *cmd UNUSED)
275 #if !USE_INTERNAL_PAGER
280 #else /* USE_INTERNAL_PAGER */
281 msg (MM, "Internal pager.");
282 #endif /* USE_INTERNAL_PAGER */
288 aux_stc_custom_rcolor(struct cmd_set *cmd UNUSED)
290 msg (SW, _("%s is obsolete."),"RCOLOR");
295 aux_stc_custom_results(struct cmd_set *cmd UNUSED)
298 msg(MM, route_to_string(set_results) );
304 aux_stc_custom_seed(struct cmd_set *cmd UNUSED)
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_c_str (&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_rng (random_seed ());
711 if (!lex_force_num ())
721 stc_custom_width (struct cmd_set *cmd UNUSED)
726 if (lex_match_id ("NARROW"))
728 else if (lex_match_id ("WIDE"))
732 if (!lex_force_int ())
734 if (lex_integer () < 1)
736 msg (SE, _("WIDTH must be at least 1."));
739 page_width = lex_integer ();
743 set_viewwidth = page_width;
747 /* Parses FORMAT subcommand, which consists of a numeric format
750 stc_custom_format (struct cmd_set *cmd UNUSED)
755 if (!parse_format_specifier (&fmt, 0))
757 if ((formats[fmt.type].cat & FCAT_STRING) != 0)
759 msg (SE, _("FORMAT requires numeric output format as an argument. "
760 "Specified format %s is of type string."),
761 fmt_to_string (&fmt));
770 stc_custom_journal (struct cmd_set *cmd UNUSED)
773 if (lex_match_id ("ON"))
775 else if (lex_match_id ("OFF"))
777 if (token == T_STRING)
779 set_journal = xstrdup (ds_c_str (&tokstr));
785 /* Parses COLOR subcommand. PC+: either ON or OFF or two or three
786 comma-delimited numbers inside parentheses. */
788 stc_custom_color (struct cmd_set *cmd UNUSED)
790 msg (MW, _("%s is obsolete."),"COLOR");
793 if (!lex_match_id ("ON") && !lex_match_id ("YES") && !lex_match_id ("OFF") && !lex_match_id ("NO"))
795 if (!lex_force_match ('('))
797 if (!lex_match ('*'))
799 if (!lex_force_int ())
801 if (lex_integer () < 0 || lex_integer () > 15)
803 msg (SE, _("Text color must be in range 0-15."));
808 if (!lex_force_match (','))
810 if (!lex_match ('*'))
812 if (!lex_force_int ())
814 if (lex_integer () < 0 || lex_integer () > 7)
816 msg (SE, _("Background color must be in range 0-7."));
821 if (lex_match (',') && !lex_match ('*'))
823 if (!lex_force_int ())
825 if (lex_integer () < 0 || lex_integer () > 7)
827 msg (SE, _("Border color must be in range 0-7."));
832 if (!lex_force_match (')'))
839 stc_custom_listing (struct cmd_set *cmd UNUSED)
842 if (lex_match_id ("ON") || lex_match_id ("YES"))
844 else if (lex_match_id ("OFF") || lex_match_id ("NO"))
851 outp_enable_device (set_listing, OUTP_DEV_LISTING);
857 stc_custom_disk (struct cmd_set *cmd UNUSED)
859 return stc_custom_listing (cmd);
863 stc_custom_log (struct cmd_set *cmd UNUSED)
865 return stc_custom_journal (cmd);
869 stc_custom_rcolor (struct cmd_set *cmd UNUSED)
871 msg (SW, _("%s is obsolete."),"RCOLOR");
874 if (!lex_force_match ('('))
877 if (!lex_match ('*'))
879 if (!lex_force_int ())
881 if (lex_integer () < 0 || lex_integer () > 6)
883 msg (SE, _("Lower window color must be between 0 and 6."));
888 if (!lex_force_match (','))
891 if (!lex_match ('*'))
893 if (!lex_force_int ())
895 if (lex_integer () < 0 || lex_integer () > 6)
897 msg (SE, _("Upper window color must be between 0 and 6."));
903 if (lex_match (',') && !lex_match ('*'))
905 if (!lex_force_int ())
907 if (lex_integer () < 0 || lex_integer () > 6)
909 msg (SE, _("Frame color must be between 0 and 6."));
918 stc_custom_viewwidth (struct cmd_set *cmd UNUSED)
922 if ( !lex_force_int() )
925 set_viewwidth = lex_integer();
932 stc_custom_viewlength (struct cmd_set *cmd UNUSED)
934 if (lex_match_id ("MINIMUM"))
936 else if (lex_match_id ("MEDIAN"))
937 set_viewlength = 43; /* This is not correct for VGA displays. */
938 else if (lex_match_id ("MAXIMUM"))
942 if (!lex_force_int ())
945 if (lex_integer () >= (43 + 25) / 2)
950 set_viewlength = lex_integer ();
956 msg (SW, _("%s is not yet implemented."),"VIEWLENGTH");
962 stc_custom_workdev (struct cmd_set *cmd UNUSED)
966 msg (SW, _("%s is obsolete."),"WORKDEV");
969 for (*c = 'A'; *c <= 'Z'; (*c)++)
970 if (token == T_ID && lex_id_match (c, tokid))
975 msg (SE, _("Drive letter expected in WORKDEV subcommand."));
982 set_viewport(int sig_num UNUSED)
985 static char term_buffer[16384];
991 #if __DJGPP__ || __BORLANDC__
996 set_viewlength = max (ti.screenheight, 25);
997 set_viewwidth = max (ti.screenwidth, 79);
999 #elif HAVE_LIBTERMCAP
1004 /* This code stolen from termcap.info, though modified. */
1005 termtype = getenv ("TERM");
1007 msg (FE, _("Specify a terminal type with the TERM environment variable."));
1009 success = tgetent (term_buffer, termtype);
1013 msg (IE, _("Could not access the termcap data base."));
1015 msg (IE, _("Terminal type `%s' is not defined."), termtype);
1019 /* NOTE: Do not rely upon tgetnum returning -1 if the value is
1020 not available. It's supposed to do it, but not all platforms
1023 if ( -1 != tgetnum("li"))
1024 set_viewlength = tgetnum ("li");
1026 if ( -1 != tgetnum("co"))
1027 set_viewwidth = tgetnum ("co") - 1;
1030 #endif /* HAVE_LIBTERMCAP */
1032 /* Try the environment variables */
1033 if ( -1 == set_viewwidth )
1035 char *s = getenv("COLUMNS");
1036 if ( s ) set_viewwidth = atoi(s);
1039 if ( -1 == set_viewwidth )
1041 char *s = getenv("LINES");
1042 if ( s ) set_viewlength = atoi(s);
1046 /* Last resort. Use hard coded values */
1047 if ( 0 > set_viewwidth ) set_viewwidth = 79;
1048 if ( 0 > set_viewlength ) set_viewlength = 24;
1052 /* Public functions */
1062 free(cmd.s_cprompt);
1063 free(cmd.s_dprompt);
1071 cmd.s_dprompt = xstrdup (_("data> "));
1072 cmd.s_cprompt = xstrdup (" > ");
1073 cmd.s_prompt = xstrdup ("PSPP> ");
1074 cmd.s_endcmd = xstrdup (".");
1076 assert(cmd.safe == 0 );
1084 cmd.headers = STC_YES;
1085 cmd.errbrk = STC_OFF;
1087 cmd.scompress = STC_OFF;
1088 cmd.undef = STC_WARN;
1089 cmd.mprint = STC_ON ;
1090 cmd.prtbck = STC_ON ;
1094 set_journal = xstrdup ("pspp.jnl");
1097 cmd.n_mxwarns[0] = 100;
1098 cmd.n_mxerrs[0] = 100;
1099 cmd.n_mxloops[0] = 1;
1100 cmd.n_workspace[0] = 4L * 1024 * 1024;
1103 #if !USE_INTERNAL_PAGER
1107 pager = getenv ("STAT_PAGER");
1108 if (!pager) set_pager = getenv ("PAGER");
1111 set_pager = xstrdup (pager);
1114 set_pager = xstrdup (DEFAULT_PAGER);
1115 #endif /* DEFAULT_PAGER */
1117 #endif /* !USE_INTERNAL_PAGER */
1123 for (i = 0; i < 5; i++)
1125 struct set_cust_currency *cc = &set_cc[i];
1126 strcpy (cc->buf, "-");
1127 cc->neg_prefix = cc->buf;
1128 cc->prefix = &cc->buf[1];
1129 cc->suffix = &cc->buf[1];
1130 cc->neg_suffix = &cc->buf[1];
1139 signal (SIGWINCH, set_viewport);
1145 force_long_view(void)
1154 return !(cmd.safe != STC_ON) ;
1158 /* Set safer mode */
1169 return (cmd.dec == STC_DOT ? '.' : ',');
1176 return (cmd.dec == STC_DOT ? ',' : '.');
1183 return cmd.s_prompt;
1189 return cmd.s_dprompt;
1195 return cmd.s_cprompt;
1202 return (cmd.echo != STC_OFF );
1207 get_errorbreak(void)
1209 return (cmd.errbrk != STC_OFF);
1214 get_scompression(void)
1216 return (cmd.scompress != STC_OFF );
1222 return (cmd.undef != STC_NOWARN);
1228 return cmd.n_mxwarns[0];
1234 return cmd.n_mxerrs[0];
1240 return ( cmd.mprint != STC_OFF );
1246 return (cmd.prtbck != STC_OFF );
1252 return cmd.n_mxloops[0];
1258 return (cmd.null != STC_OFF );
1264 return (cmd.inc != STC_OFF );
1270 return cmd.s_endcmd[0];
1275 get_max_workspace(void)
1277 return cmd.n_workspace[0];
1292 /* CCA through CCE. */
1293 const struct set_cust_currency *
1300 aux_show_warranty(void)
1302 msg(MM,lack_of_warranty);
1306 aux_show_copying(void)
1313 get_viewlength(void)
1315 return set_viewlength;
1321 return set_viewwidth;
1334 set_rng (random_seed ());
1339 set_rng (unsigned long seed)
1341 rng = gsl_rng_alloc (gsl_rng_mt19937);
1344 gsl_rng_set (rng, seed);
1347 static unsigned long
1353 static int global_algorithm = ENHANCED;
1354 static int cmd_algorithm = ENHANCED;
1355 static int *algorithm = &global_algorithm;
1357 static int syntax = ENHANCED;
1359 /* Set the algorithm option globally */
1361 set_algorithm(int x)
1363 global_algorithm = x;
1366 /* Set the algorithm option for this command only */
1368 set_cmd_algorithm(int x)
1371 algorithm = &cmd_algorithm;
1374 /* Unset the algorithm option for this command */
1376 unset_cmd_algorithm(void)
1378 algorithm = &global_algorithm;
1381 /* Return the current algorithm setting */
1388 /* Set the syntax option */
1395 /* Get the current syntax setting */