8d9afd61cf455776a12992a7ae2327d9d96e6cc2
[pspp-builds.git] / src / set.q
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
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.
9
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.
14
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
18    02111-1307, USA. */
19
20 /*
21    Categories of SET subcommands:
22
23    data input: BLANKS, DECIMAL, FORMAT.
24    
25    program input: ENDCMD, NULLINE.
26    
27    interaction: CPROMPT, DPROMPT, ERRORBREAK, MXERRS, MXWARNS, PROMPT.
28    
29    program execution: MEXPAND, MITERATE, MNEST, MPRINT,
30    MXLOOPS, SEED, UNDEFINED.
31
32    data output: CCA...CCE, DECIMAL, FORMAT, RESULTS-p.
33
34    output routing: ECHO, ERRORS, INCLUDE, MESSAGES, PRINTBACK, ERRORS,
35    RESULTS-rw.
36
37    output activation: LISTING (on/off), SCREEN, PRINTER.
38
39    output driver options: HEADERS, MORE, PAGER, VIEWLENGTH, VIEWWIDTH,
40    LISTING (filename).
41
42    logging: LOG, JOURNAL.
43
44    system files: COMP/COMPRESSION, SCOMP/SCOMPRESSION.
45
46    security: SAFER.
47 */
48
49 /*
50    FIXME
51
52    These subcommands remain to be implemented:
53      ECHO, PRINTBACK, INCLUDE
54      MORE, PAGER, VIEWLENGTH, VIEWWIDTH, HEADERS
55
56    These subcommands are not complete:
57      MESSAGES, ERRORS, RESULTS
58      LISTING/DISK, LOG/JOURNAL
59 */     
60    
61 #include <config.h>
62 #include "settings.h"
63 #include "error.h"
64 #include <stdio.h>
65 #include <errno.h>
66 #include <stdlib.h>
67 #include "alloc.h"
68 #include "command.h"
69 #include "lexer.h"
70 #include "error.h"
71 #include "magic.h"
72 #include "log.h"
73 #include "output.h"
74 #include "var.h"
75 #include "format.h"
76 #include "copyleft.h"
77 #include "random.h"
78
79 #include "signal.h"
80
81 #if HAVE_LIBTERMCAP
82 #if HAVE_TERMCAP_H
83 #include <termcap.h>
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 */
89
90 static int set_errors;
91 static int set_messages;
92 static int set_results;
93
94 static double set_blanks=SYSMIS;
95
96 static struct fmt_spec set_format={FMT_F,8,2};
97
98 static struct set_cust_currency set_cc[5];
99   
100 static char *set_journal;
101 static int set_journaling;
102
103 static int set_listing=1;
104
105 #if !USE_INTERNAL_PAGER
106 static char *set_pager=0;
107 #endif /* !USE_INTERNAL_PAGER */
108
109 static unsigned long set_seed;
110 static int seed_flag=0;
111
112 static int long_view=0;
113 int set_testing_mode=0;
114 static int set_viewlength;
115 static int set_viewwidth;
116
117 void aux_show_warranty(void);
118 void aux_show_copying(void);
119
120 static const char *route_to_string(int routing);
121 static void set_routing (int q, int *setting);
122
123 static int set_ccx (const char *cc_string, struct set_cust_currency * cc,
124                     int cc_name);
125 /* (specification)
126    "SET" (stc_):
127      automenu=automenu:on/off;
128      beep=beep:on/off;
129      blanks=custom;
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;
133      cca=string;
134      ccb=string;
135      ccc=string;
136      ccd=string;
137      cce=string;
138      color=custom;
139      compression=compress:on/off;
140      cpi=integer "x>0" "%s must be greater than 0";
141      cprompt=string;
142      decimal=dec:dot/comma;
143      disk=custom;
144      dprompt=string;
145      echo=echo:on/off;
146      eject=eject:on/off;
147      endcmd=string "x==1" "one character long";
148      errorbreak=errbrk:on/off;
149      errors=errors:on/off/terminal/listing/both/none;
150      format=custom;
151      headers=headers:no/yes/blank;
152      helpwindows=helpwin:on/off;
153      highres=hires:on/off;
154      histogram=string "x==1" "one character long";
155      include=inc:on/off;
156      journal=custom;
157      length=custom;
158      listing=custom;
159      log=custom;
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;
164      mexpand=mexp:on/off;
165      miterate=integer "x>0" "%s must be greater than 0";
166      mnest=integer "x>0" "%s must be greater than 0";
167      more=more:on/off;
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";
171      mxmemory=integer;
172      mxwarns=integer;
173      nulline=null:on/off;
174      pager=custom;
175      printback=prtbck:on/off;
176      printer=prtr:on/off;
177      prompt=string;
178      ptranslate=ptrans:on/off;
179      rcolor=custom;
180      results=custom;
181      runreview=runrev:auto/manual;
182      safer=safe:on;
183      scompression=scompress:on/off;
184      screen=scrn:on/off;
185      scripttab=string "x==1" "one character long";
186      seed=custom;
187      tb1=string "x==3 || x==11" "3 or 11 characters long";
188      tbfonts=string;
189      undefined=undef:warn/nowarn;
190      viewlength=custom;
191      viewwidth=custom;
192      width=custom;
193      workdev=custom;
194      workspace=integer "x>=1024" "%s must be at least 1 MB";
195      xsort=xsort:yes/no.
196 */
197
198 /* (declarations) */
199
200 /* (_functions) */
201
202 static int
203 aux_stc_custom_blanks(struct cmd_set *cmd UNUSED)
204 {
205   if ( set_blanks == SYSMIS ) 
206     msg(MM, "SYSMIS");
207   else
208     msg(MM, "%g", set_blanks);
209   return 0;
210 }
211
212
213 static int
214 aux_stc_custom_color(struct cmd_set *cmd UNUSED)
215 {
216   msg (MW, _("%s is obsolete."),"COLOR");
217   return 0;
218 }
219
220 static int
221 aux_stc_custom_listing(struct cmd_set *cmd UNUSED)
222 {
223   if ( set_listing ) 
224     msg(MM, _("LISTING is ON"));
225   else
226     msg(MM, _("LISTING is OFF"));
227
228   return 0;
229 }
230
231 static int
232 aux_stc_custom_disk(struct cmd_set *cmd UNUSED)
233 {
234   return aux_stc_custom_listing(cmd);
235 }
236
237 static int
238 aux_stc_custom_format(struct cmd_set *cmd UNUSED)
239 {
240   msg(MM, fmt_to_string(&set_format));
241   return 0;
242 }
243
244
245
246 static int
247 aux_stc_custom_journal(struct cmd_set *cmd UNUSED)
248 {
249   if (set_journaling) 
250     msg(MM, set_journal);
251   else
252     msg(MM, _("Journalling is off") );
253         
254   return 0;
255 }
256
257 static int
258 aux_stc_custom_length(struct cmd_set *cmd UNUSED)
259 {
260   msg(MM, "%d", set_viewlength);
261   return 0;
262 }
263
264 static int
265 aux_stc_custom_log(struct cmd_set *cmd )
266 {
267   return aux_stc_custom_journal (cmd);
268 }
269
270 static int
271 aux_stc_custom_pager(struct cmd_set *cmd UNUSED)
272 {
273 #if !USE_INTERNAL_PAGER 
274   if ( set_pager ) 
275     msg(MM, set_pager);
276   else
277     msg(MM, "No pager");
278 #else /* USE_INTERNAL_PAGER */
279   msg (MM, "Internal pager.");
280 #endif /* USE_INTERNAL_PAGER */
281
282   return 0;
283 }
284
285 static int
286 aux_stc_custom_rcolor(struct cmd_set *cmd UNUSED)
287 {
288   msg (SW, _("%s is obsolete."),"RCOLOR");
289   return 0;
290 }
291
292 static int
293 aux_stc_custom_results(struct cmd_set *cmd UNUSED)
294 {
295   
296   msg(MM, route_to_string(set_results) );
297
298   return 0;
299 }
300
301 static int
302 aux_stc_custom_seed(struct cmd_set *cmd UNUSED)
303 {
304   msg(MM, "%ld",set_seed);
305   return 0;
306 }
307
308 static int
309 aux_stc_custom_viewlength(struct cmd_set *cmd UNUSED)
310 {
311   msg(MM, "%d", set_viewlength);
312   return 0;
313 }
314
315 static int
316 aux_stc_custom_viewwidth(struct cmd_set *cmd UNUSED)
317 {
318   msg(MM, "%d", set_viewwidth);
319   return 0;
320 }
321
322 static int
323 aux_stc_custom_width(struct cmd_set *cmd UNUSED)
324 {
325   msg(MM, "%d", set_viewwidth);
326   return 0;
327 }
328
329 static int
330 aux_stc_custom_workdev(struct cmd_set *cmd UNUSED)
331 {
332   msg (SW, _("%s is obsolete."),"WORKDEV");
333   return 0;
334 }
335
336
337
338 /* (aux_functions) 
339      warranty=show_warranty;
340      copying=show_copying.
341 */
342
343
344 static struct cmd_set cmd;
345
346 int
347 cmd_show (void)
348 {
349   lex_match_id ("SHOW");
350
351   if (!aux_parse_set (&cmd))
352     return CMD_FAILURE;
353
354   return CMD_SUCCESS;
355 }
356
357 int
358 cmd_set (void)
359 {
360
361   if (!parse_set (&cmd))
362     return CMD_FAILURE;
363
364   if (cmd.sbc_cca)
365     set_ccx (cmd.s_cca, &set_cc[0], 'A');
366   if (cmd.sbc_ccb)
367     set_ccx (cmd.s_ccb, &set_cc[1], 'B');
368   if (cmd.sbc_ccc)
369     set_ccx (cmd.s_ccc, &set_cc[2], 'C');
370   if (cmd.sbc_ccd)
371     set_ccx (cmd.s_ccd, &set_cc[3], 'D');
372   if (cmd.sbc_cce)
373     set_ccx (cmd.s_cce, &set_cc[4], 'E');
374
375   if (cmd.sbc_errors)
376     set_routing (cmd.errors, &set_errors);
377   if (cmd.sbc_messages)
378     set_routing (cmd.messages, &set_messages);
379
380   /* PC+ compatible syntax. */
381   if (cmd.sbc_screen)
382     outp_enable_device (cmd.scrn == STC_OFF ? 0 : 1, OUTP_DEV_SCREEN);
383   if (cmd.sbc_printer)
384     outp_enable_device (cmd.prtr == STC_OFF ? 0 : 1, OUTP_DEV_PRINTER);
385
386   if (cmd.sbc_automenu )
387     msg (SW, _("%s is obsolete."),"AUTOMENU");
388   if (cmd.sbc_beep )
389     msg (SW, _("%s is obsolete."),"BEEP");
390   if (cmd.sbc_block)
391     msg (SW, _("%s is obsolete."),"BLOCK");
392   if (cmd.sbc_boxstring)
393     msg (SW, _("%s is obsolete."),"BOXSTRING");
394   if (cmd.sbc_eject )
395     msg (SW, _("%s is obsolete."),"EJECT");
396   if (cmd.sbc_helpwindows )
397     msg (SW, _("%s is obsolete."),"HELPWINDOWS");
398   if (cmd.sbc_histogram)
399     msg (MW, _("%s is obsolete."),"HISTOGRAM");
400   if (cmd.sbc_menus )
401     msg (MW, _("%s is obsolete."),"MENUS");
402   if (cmd.sbc_ptranslate )
403     msg (SW, _("%s is obsolete."),"PTRANSLATE");
404   if (cmd.sbc_runreview )
405     msg (SW, _("%s is obsolete."),"RUNREVIEW");
406   if (cmd.sbc_xsort )
407     msg (SW, _("%s is obsolete."),"XSORT");
408   if (cmd.sbc_mxmemory )
409     msg (SE, _("%s is obsolete."),"MXMEMORY");
410   if (cmd.sbc_scripttab)
411     msg (SE, _("%s is obsolete."),"SCRIPTTAB");
412
413   if (cmd.sbc_tbfonts)
414     msg (SW, _("%s is not yet implemented."),"TBFONTS");
415   if (cmd.sbc_tb1 && cmd.s_tb1)
416     msg (SW, _("%s is not yet implemented."),"TB1");
417
418   /* Windows compatible syntax. */
419   if (cmd.sbc_case)
420     msg (SW, _("CASE is not implemented and probably won't be.  "
421         "If you care, complain about it."));
422
423   if (cmd.sbc_compression)
424     {
425       msg (MW, _("Active file compression is not yet implemented "
426                  "(and probably won't be)."));
427     }
428
429   return CMD_SUCCESS;
430 }
431
432 /* Sets custom currency specifier CC having name CC_NAME ('A' through
433    'E') to correspond to the settings in CC_STRING. */
434 static int
435 set_ccx (const char *cc_string, struct set_cust_currency * cc, int cc_name)
436 {
437   if (strlen (cc_string) > 16)
438     {
439       msg (SE, _("CC%c: Length of custom currency string `%s' (%d) "
440                  "exceeds maximum length of 16."),
441            cc_name, cc_string, strlen (cc_string));
442       return 0;
443     }
444
445   /* Determine separators. */
446   {
447     const char *sp;
448     int n_commas, n_periods;
449   
450     /* Count the number of commas and periods.  There must be exactly
451        three of one or the other. */
452     n_commas = n_periods = 0;
453     for (sp = cc_string; *sp; sp++)
454       if (*sp == ',')
455         n_commas++;
456       else if (*sp == '.')
457         n_periods++;
458   
459     if (!((n_commas == 3) ^ (n_periods == 3)))
460       {
461         msg (SE, _("CC%c: Custom currency string `%s' does not contain "
462                    "exactly three periods or commas (not both)."),
463              cc_name, cc_string);
464         return 0;
465       }
466     else if (n_commas == 3)
467       {
468         cc->decimal = '.';
469         cc->grouping = ',';
470       }
471     else
472       {
473         cc->decimal = ',';
474         cc->grouping = '.';
475       }
476   }
477   
478   /* Copy cc_string to cc, changing separators to nulls. */
479   {
480     char *cp;
481     
482     strcpy (cc->buf, cc_string);
483     cp = cc->neg_prefix = cc->buf;
484
485     while (*cp++ != cc->grouping)
486       ;
487     cp[-1] = '\0';
488     cc->prefix = cp;
489
490     while (*cp++ != cc->grouping)
491       ;
492     cp[-1] = '\0';
493     cc->suffix = cp;
494
495     while (*cp++ != cc->grouping)
496       ;
497     cp[-1] = '\0';
498     cc->neg_suffix = cp;
499   }
500   
501   return 1;
502 }
503
504
505 const char *
506 route_to_string(int routing)
507 {
508   static char s[255];
509   
510   s[0]='\0';
511
512   if ( routing == 0 )
513     {
514       strcpy(s, _("None"));
515       return s;
516     }
517
518   if (routing & SET_ROUTE_DISABLE ) 
519     {
520     strcpy(s, _("Disabled") );
521     return s;
522     }
523
524   if (routing & SET_ROUTE_SCREEN)
525     strcat(s, _("Screen") );
526   
527   if (routing & SET_ROUTE_LISTING)
528     {
529       if(s[0] != '\0') 
530         strcat(s,", ");
531         
532       strcat(s, _("Listing") );
533     }
534
535   if (routing & SET_ROUTE_OTHER)
536     {
537       if(s[0] != '\0') 
538         strcat(s,", ");
539       strcat(s, _("Other") );
540     }
541  
542     
543   return s;
544   
545     
546 }
547
548 /* Sets *SETTING, which is a combination of SET_ROUTE_* bits that
549    indicates what to do with some sort of output, to the value
550    indicated by Q, which is a value provided by the input parser. */
551 static void
552 set_routing (int q, int *setting)
553 {
554   switch (q)
555     {
556     case STC_OFF:
557       *setting |= SET_ROUTE_DISABLE;
558       break;
559     case STC_ON:
560       *setting &= ~SET_ROUTE_DISABLE;
561       break;
562     case STC_TERMINAL:
563       *setting &= ~(SET_ROUTE_LISTING | SET_ROUTE_OTHER);
564       *setting |= SET_ROUTE_SCREEN;
565       break;
566     case STC_LISTING:
567       *setting &= ~SET_ROUTE_SCREEN;
568       *setting |= SET_ROUTE_LISTING | SET_ROUTE_OTHER;
569       break;
570     case STC_BOTH:
571       *setting |= SET_ROUTE_SCREEN | SET_ROUTE_LISTING | SET_ROUTE_OTHER;
572       break;
573     case STC_NONE:
574       *setting &= ~(SET_ROUTE_SCREEN | SET_ROUTE_LISTING | SET_ROUTE_OTHER);
575       break;
576     default:
577       assert (0);
578     }
579 }
580
581 static int
582 stc_custom_pager (struct cmd_set *cmd UNUSED)
583 {
584   lex_match ('=');
585 #if !USE_INTERNAL_PAGER
586   if (lex_match_id ("OFF"))
587     {
588       if (set_pager)
589         free (set_pager);
590       set_pager = NULL;
591     }
592   else
593     {
594       if (!lex_force_string ())
595         return 0;
596       if (set_pager)
597         free (set_pager);
598       set_pager = xstrdup (ds_value (&tokstr));
599       lex_get ();
600     }
601   return 1;
602 #else /* USE_INTERNAL_PAGER */
603   if (match_id (OFF))
604     return 1;
605   msg (SW, "External pagers not supported.");
606   return 0;
607 #endif /* USE_INTERNAL_PAGER */
608 }
609
610 /* Parses the BLANKS subcommand, which controls the value that
611    completely blank fields in numeric data imply.  X, Wnd: Syntax is
612    SYSMIS or a numeric value; PC+: Syntax is '.', which is equivalent
613    to SYSMIS, or a numeric value. */
614 static int
615 stc_custom_blanks (struct cmd_set *cmd UNUSED)
616 {
617   lex_match ('=');
618   if ((token == T_ID && lex_id_match ("SYSMIS", tokid))
619       || (token == T_STRING && !strcmp (tokid, ".")))
620     {
621       lex_get ();
622       set_blanks = SYSMIS;
623     }
624   else
625     {
626       if (!lex_force_num ())
627         return 0;
628       set_blanks = tokval;
629       lex_get ();
630     }
631   return 1;
632 }
633
634 static int
635 stc_custom_length (struct cmd_set *cmd UNUSED)
636 {
637   int page_length;
638
639   lex_match ('=');
640   if (lex_match_id ("NONE"))
641     page_length = -1;
642   else
643     {
644       if (!lex_force_int ())
645         return 0;
646       if (lex_integer () < 1)
647         {
648           msg (SE, _("LENGTH must be at least 1."));
649           return 0;
650         }
651       page_length = lex_integer ();
652       lex_get ();
653     }
654
655   if ( page_length != -1 ) 
656     set_viewlength = page_length;
657
658   return 1;
659 }
660
661 static int
662 stc_custom_results (struct cmd_set *cmd UNUSED)
663 {
664   struct tuple
665     {   
666       const char *s;    
667       int v;
668     };
669
670   static struct tuple tab[] =
671     {
672       {"ON", STC_ON},
673       {"OFF", STC_OFF},
674       {"TERMINAL", STC_TERMINAL},
675       {"LISTING", STC_LISTING},
676       {"BOTH", STC_BOTH},
677       {"NONE", STC_NONE},
678       {NULL, 0},
679     };
680
681   struct tuple *t;
682
683   lex_match ('=');
684
685   if (token != T_ID)
686     {
687       msg (SE, _("Missing identifier in RESULTS subcommand."));
688       return 0;
689     }
690   
691   for (t = tab; t->s; t++)
692     if (lex_id_match (t->s, tokid))
693       {
694         lex_get ();
695         set_routing (t->v, &set_results);
696         return 1;
697       }
698   msg (SE, _("Unrecognized identifier in RESULTS subcommand."));
699   return 0;
700 }
701
702 static int
703 stc_custom_seed (struct cmd_set *cmd UNUSED)
704 {
705   lex_match ('=');
706   if (lex_match_id ("RANDOM"))
707     set_seed = random_seed();
708   else
709     {
710       if (!lex_force_num ())
711         return 0;
712       set_seed = tokval;
713       lex_get ();
714     }
715   seed_flag = 1;
716
717   return 1;
718 }
719
720 static int
721 stc_custom_width (struct cmd_set *cmd UNUSED)
722 {
723   int page_width;
724
725   lex_match ('=');
726   if (lex_match_id ("NARROW"))
727     page_width = 79;
728   else if (lex_match_id ("WIDE"))
729     page_width = 131;
730   else
731     {
732       if (!lex_force_int ())
733         return 0;
734       if (lex_integer () < 1)
735         {
736           msg (SE, _("WIDTH must be at least 1."));
737           return 0;
738         }
739       page_width = lex_integer ();
740       lex_get ();
741     }
742
743   set_viewwidth = page_width;
744   return 1;
745 }
746
747 /* Parses FORMAT subcommand, which consists of a numeric format
748    specifier. */
749 static int
750 stc_custom_format (struct cmd_set *cmd UNUSED)
751 {
752   struct fmt_spec fmt;
753
754   lex_match ('=');
755   if (!parse_format_specifier (&fmt, 0))
756     return 0;
757   if ((formats[fmt.type].cat & FCAT_STRING) != 0)
758     {
759       msg (SE, _("FORMAT requires numeric output format as an argument.  "
760                  "Specified format %s is of type string."),
761            fmt_to_string (&fmt));
762       return 0;
763     }
764
765   set_format = fmt;
766   return 1;
767 }
768
769 static int
770 stc_custom_journal (struct cmd_set *cmd UNUSED)
771 {
772   lex_match ('=');
773   if (lex_match_id ("ON"))
774     set_journaling = 1;
775   else if (lex_match_id ("OFF"))
776     set_journaling = 0;
777   if (token == T_STRING)
778     {
779       set_journal = xstrdup (ds_value (&tokstr));
780       lex_get ();
781     }
782   return 1;
783 }
784
785 /* Parses COLOR subcommand.  PC+: either ON or OFF or two or three
786    comma-delimited numbers inside parentheses. */
787 static int
788 stc_custom_color (struct cmd_set *cmd UNUSED)
789 {
790   msg (MW, _("%s is obsolete."),"COLOR");
791
792   lex_match ('=');
793   if (!lex_match_id ("ON") && !lex_match_id ("YES") && !lex_match_id ("OFF") && !lex_match_id ("NO"))
794     {
795       if (!lex_force_match ('('))
796         return 0;
797       if (!lex_match ('*'))
798         {
799           if (!lex_force_int ())
800             return 0;
801           if (lex_integer () < 0 || lex_integer () > 15)
802             {
803               msg (SE, _("Text color must be in range 0-15."));
804               return 0;
805             }
806           lex_get ();
807         }
808       if (!lex_force_match (','))
809         return 0;
810       if (!lex_match ('*'))
811         {
812           if (!lex_force_int ())
813             return 0;
814           if (lex_integer () < 0 || lex_integer () > 7)
815             {
816               msg (SE, _("Background color must be in range 0-7."));
817               return 0;
818             }
819           lex_get ();
820         }
821       if (lex_match (',') && !lex_match ('*'))
822         {
823           if (!lex_force_int ())
824             return 0;
825           if (lex_integer () < 0 || lex_integer () > 7)
826             {
827               msg (SE, _("Border color must be in range 0-7."));
828               return 0;
829             }
830           lex_get ();
831         }
832       if (!lex_force_match (')'))
833         return 0;
834     }
835   return 1;
836 }
837
838 static int
839 stc_custom_listing (struct cmd_set *cmd UNUSED)
840 {
841   lex_match ('=');
842   if (lex_match_id ("ON") || lex_match_id ("YES"))
843     set_listing = 1;
844   else if (lex_match_id ("OFF") || lex_match_id ("NO"))
845     set_listing = 0;
846   else
847     {
848       /* FIXME */
849       return 0;
850     }
851   outp_enable_device (set_listing, OUTP_DEV_LISTING);
852
853   return 1;
854 }
855
856 static int
857 stc_custom_disk (struct cmd_set *cmd UNUSED)
858 {
859   return stc_custom_listing (cmd);
860 }
861
862 static int
863 stc_custom_log (struct cmd_set *cmd UNUSED)
864
865   return stc_custom_journal (cmd);
866 }
867
868 static int
869 stc_custom_rcolor (struct cmd_set *cmd UNUSED)
870 {
871   msg (SW, _("%s is obsolete."),"RCOLOR");
872
873   lex_match ('=');
874   if (!lex_force_match ('('))
875     return 0;
876
877   if (!lex_match ('*'))
878     {
879       if (!lex_force_int ())
880         return 0;
881       if (lex_integer () < 0 || lex_integer () > 6)
882         {
883           msg (SE, _("Lower window color must be between 0 and 6."));
884           return 0;
885         }
886       lex_get ();
887     }
888   if (!lex_force_match (','))
889     return 0;
890
891   if (!lex_match ('*'))
892     {
893       if (!lex_force_int ())
894         return 0;
895       if (lex_integer () < 0 || lex_integer () > 6)
896         {
897           msg (SE, _("Upper window color must be between 0 and 6."));
898           return 0;
899         }
900       lex_get ();
901     }
902
903   if (lex_match (',') && !lex_match ('*'))
904     {
905       if (!lex_force_int ())
906         return 0;
907       if (lex_integer () < 0 || lex_integer () > 6)
908         {
909           msg (SE, _("Frame color must be between 0 and 6."));
910           return 0;
911         }
912       lex_get ();
913     }
914   return 1;
915 }
916
917 static int
918 stc_custom_viewwidth (struct cmd_set *cmd UNUSED)
919 {
920   lex_match ('=');
921
922   if ( !lex_force_int() ) 
923     return 0;
924
925   set_viewwidth = lex_integer();
926   lex_get();
927   
928   return 1;
929 }
930
931 static int
932 stc_custom_viewlength (struct cmd_set *cmd UNUSED)
933 {
934   if (lex_match_id ("MINIMUM"))
935     set_viewlength = 25;
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"))
939     set_viewlength = 43;
940   else
941     {
942       if (!lex_force_int ())
943         return 0;
944 #ifdef __MSDOS__
945       if (lex_integer () >= (43 + 25) / 2)
946         set_viewlength = 43;
947       else
948         set_viewlength = 25;
949 #else /* not dos */
950       set_viewlength = lex_integer ();
951 #endif /* not dos */
952       lex_get ();
953     }
954
955 #ifdef __MSDOS__
956   msg (SW, _("%s is not yet implemented."),"VIEWLENGTH");
957 #endif /* dos */
958   return 1;
959 }
960
961 static int
962 stc_custom_workdev (struct cmd_set *cmd UNUSED)
963 {
964   char c[2];
965
966   msg (SW, _("%s is obsolete."),"WORKDEV");
967
968   c[1] = 0;
969   for (*c = 'A'; *c <= 'Z'; (*c)++)
970     if (token == T_ID && lex_id_match (c, tokid))
971       {
972         lex_get ();
973         return 1;
974       }
975   msg (SE, _("Drive letter expected in WORKDEV subcommand."));
976   return 0;
977 }
978
979
980
981 static void 
982 set_viewport(int sig_num UNUSED)
983 {
984 #if HAVE_LIBTERMCAP
985   static char term_buffer[16384];
986 #endif
987
988   set_viewwidth = -1;
989   set_viewlength = -1;
990
991 #if __DJGPP__ || __BORLANDC__
992   {
993     struct text_info ti;
994
995     gettextinfo (&ti);
996     set_viewlength = max (ti.screenheight, 25);
997     set_viewwidth = max (ti.screenwidth, 79);
998   }
999 #elif HAVE_LIBTERMCAP
1000   {
1001     char *termtype;
1002     int success;
1003
1004     /* This code stolen from termcap.info, though modified. */
1005     termtype = getenv ("TERM");
1006     if (!termtype)
1007       msg (FE, _("Specify a terminal type with the TERM environment variable."));
1008
1009     success = tgetent (term_buffer, termtype);
1010     if (success <= 0)
1011       {
1012         if (success < 0)
1013           msg (IE, _("Could not access the termcap data base."));
1014         else
1015           msg (IE, _("Terminal type `%s' is not defined."), termtype);
1016       }
1017     else
1018       {
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 
1021            do (eg Cygwin) .
1022         */
1023         if ( -1 != tgetnum("li")) 
1024           set_viewlength = tgetnum ("li");
1025
1026         if ( -1 != tgetnum("co")) 
1027           set_viewwidth = tgetnum ("co") - 1;
1028       }
1029   }
1030 #endif /* HAVE_LIBTERMCAP */
1031
1032   /* Try the environment variables */
1033   if ( -1 ==  set_viewwidth ) 
1034     { 
1035       char *s = getenv("COLUMNS");
1036       if ( s )  set_viewwidth = atoi(s);
1037     }
1038
1039   if ( -1 ==  set_viewwidth ) 
1040     {
1041       char *s = getenv("LINES");
1042       if ( s )  set_viewlength = atoi(s);
1043     }
1044
1045
1046   /* Last resort.  Use hard coded values */
1047   if ( 0  >  set_viewwidth ) set_viewwidth = 79;
1048   if ( 0  >  set_viewlength ) set_viewlength = 24;
1049
1050 }
1051
1052 /* Public functions */
1053
1054 void
1055 init_settings(void)
1056 {
1057   cmd.s_dprompt = xstrdup (_("data> "));
1058   cmd.s_cprompt = xstrdup ("    > ");  
1059   cmd.s_prompt = xstrdup ("PSPP> ");
1060   cmd.s_endcmd = xstrdup (".");
1061
1062   assert(cmd.safe == 0 );
1063   cmd.safe = STC_OFF;
1064
1065   cmd.dec = STC_DOT;
1066   cmd.n_cpi = 6;
1067   cmd.n_lpi = 10;
1068   cmd.echo = STC_OFF;
1069   cmd.more = STC_ON;
1070   cmd.headers = STC_YES;
1071   cmd.errbrk = STC_OFF;
1072
1073   cmd.scompress = STC_OFF;
1074   cmd.undef = STC_WARN;
1075   cmd.mprint = STC_ON ;
1076   cmd.prtbck = STC_ON ;
1077   cmd.null = STC_ON ;
1078   cmd.inc = STC_ON ;
1079
1080   set_journal = xstrdup ("pspp.jnl");
1081   set_journaling = 1;
1082
1083   cmd.n_mxwarns = 100;
1084   cmd.n_mxerrs = 100;
1085   cmd.n_mxloops = 1;
1086   cmd.n_workspace = 4L * 1024 * 1024;
1087
1088
1089 #if !USE_INTERNAL_PAGER
1090   {
1091     char *pager;
1092
1093     pager = getenv ("STAT_PAGER");
1094     if (!pager)  set_pager = getenv ("PAGER");
1095
1096     if (pager)  
1097       set_pager = xstrdup (pager);
1098 #if DEFAULT_PAGER
1099     else
1100       set_pager = xstrdup (DEFAULT_PAGER);
1101 #endif /* DEFAULT_PAGER */
1102   }
1103 #endif /* !USE_INTERNAL_PAGER */
1104
1105
1106   {
1107     int i;
1108     
1109     for (i = 0; i < 5; i++)
1110       {
1111         struct set_cust_currency *cc = &set_cc[i];
1112         strcpy (cc->buf, "-");
1113         cc->neg_prefix = cc->buf;
1114         cc->prefix = &cc->buf[1];
1115         cc->suffix = &cc->buf[1];
1116         cc->neg_suffix = &cc->buf[1];
1117         cc->decimal = '.';
1118         cc->grouping = ',';
1119       }
1120   }
1121
1122   if ( ! long_view )
1123     {
1124       set_viewport (0);
1125       signal (SIGWINCH, set_viewport);
1126     }
1127
1128 }
1129
1130 void
1131 force_long_view(void)
1132 {
1133   long_view = 1;
1134   set_viewwidth=9999;
1135 }
1136
1137 int 
1138 safer_mode(void)
1139 {
1140   return !(cmd.safe != STC_ON) ;
1141 }
1142
1143
1144 /* Set safer mode */
1145 void
1146 make_safe(void)
1147 {
1148   cmd.safe = STC_ON;
1149 }
1150
1151
1152 char 
1153 get_decimal(void)
1154 {
1155   return (cmd.dec == STC_DOT ? '.' : ',');
1156 }
1157
1158
1159 char
1160 get_grouping(void)
1161 {
1162   return (cmd.dec == STC_DOT ? ',' : '.');
1163 }
1164  
1165
1166 char * 
1167 get_prompt(void)
1168 {
1169   return cmd.s_prompt;
1170 }
1171
1172 char * 
1173 get_dprompt(void)
1174 {
1175   return cmd.s_dprompt;
1176 }
1177
1178 char * 
1179 get_cprompt(void)
1180 {
1181   return cmd.s_cprompt;
1182 }
1183
1184
1185 int
1186 get_echo(void)
1187 {
1188     return (cmd.echo != STC_OFF );
1189 }
1190
1191
1192 int 
1193 get_errorbreak(void)
1194 {
1195   return (cmd.errbrk != STC_OFF);
1196 }
1197
1198
1199 int 
1200 get_scompression(void)
1201 {
1202   return (cmd.scompress != STC_OFF );
1203 }
1204
1205 int
1206 get_undefined(void)
1207 {
1208   return (cmd.undef != STC_NOWARN);
1209 }
1210
1211 int
1212 get_mxwarns(void)
1213 {  
1214   return cmd.n_mxwarns;
1215 }
1216
1217 int
1218 get_mxerrs(void)
1219 {
1220   return cmd.n_mxerrs;
1221 }
1222
1223 int
1224 get_mprint(void)
1225 {
1226   return ( cmd.mprint != STC_OFF );
1227 }
1228
1229 int
1230 get_printback(void)
1231 {
1232   return (cmd.prtbck != STC_OFF );
1233 }
1234
1235 int
1236 get_mxloops(void)
1237 {
1238   return cmd.n_mxloops;
1239 }
1240
1241 int
1242 get_nullline(void)
1243 {
1244   return (cmd.null != STC_OFF );
1245 }
1246
1247 int
1248 get_include(void)
1249 {
1250  return (cmd.inc != STC_OFF );
1251 }
1252
1253 unsigned char
1254 get_endcmd(void)
1255 {
1256   return cmd.s_endcmd[0];
1257 }
1258
1259
1260 size_t
1261 get_max_workspace(void)
1262 {
1263   return cmd.n_workspace;
1264 }
1265
1266 double
1267 get_blanks(void)
1268 {
1269   return set_blanks;
1270 }
1271
1272 struct fmt_spec 
1273 get_format(void)
1274
1275   return set_format;
1276 }
1277
1278 /* CCA through CCE. */
1279 const struct set_cust_currency *
1280 get_cc(int i)
1281 {
1282   return &set_cc[i];
1283 }
1284
1285 void
1286 aux_show_warranty(void)
1287 {
1288   msg(MM,lack_of_warranty);
1289 }
1290
1291 void
1292 aux_show_copying(void)
1293 {
1294   msg(MM,copyleft);
1295 }
1296
1297
1298 int
1299 get_viewlength(void)
1300 {
1301   return set_viewlength;
1302 }
1303
1304 int
1305 get_viewwidth(void)
1306 {
1307   return set_viewwidth;
1308 }
1309
1310 const char *
1311 get_pager(void)
1312 {
1313   return set_pager;
1314 }
1315
1316 /* Return 1 if the seed has been set since the last time this function
1317    was called.
1318    Fill the value pointed to by seed with the seed .
1319 */
1320 int
1321 seed_is_set(unsigned long *seed)
1322 {
1323   int result = 0;
1324
1325   *seed = set_seed ;
1326
1327   if ( seed_flag ) 
1328     result = 1;
1329   
1330   seed_flag = 0;
1331
1332   return result;
1333     
1334 }
1335
1336
1337 static int global_algorithm = ENHANCED;
1338 static int cmd_algorithm = ENHANCED;
1339 static int *algorithm = &global_algorithm;
1340
1341 static int syntax = ENHANCED;
1342
1343 /* Set the algorithm option globally */
1344 void 
1345 set_algorithm(int x)
1346 {
1347   global_algorithm = x;
1348 }
1349
1350 /* Set the algorithm option for this command only */
1351 void 
1352 set_cmd_algorithm(int x)
1353 {
1354   cmd_algorithm = x; 
1355   algorithm = &cmd_algorithm;
1356 }
1357
1358 /* Unset the algorithm option for this command */
1359 void
1360 unset_cmd_algorithm(void)
1361 {
1362   algorithm = &global_algorithm;
1363 }
1364
1365 /* Return the current algorithm setting */
1366 int
1367 get_algorithm(void)
1368 {
1369   return *algorithm;
1370 }
1371
1372 /* Set the syntax option */
1373 void 
1374 set_syntax(int x)
1375 {
1376   syntax = x;
1377 }
1378
1379 /* Get the current syntax setting */
1380 int
1381 get_syntax(void)
1382 {
1383   return syntax;
1384 }
1385
1386
1387 /*
1388    Local Variables:
1389    mode: c
1390    End:
1391 */