Changed DFM from open-at-first-access to explicit-open. Before,
[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 <assert.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   /* Workable defaults before we determine the real terminal size. */
989   set_viewwidth = 79;
990   set_viewlength = 24;
991
992
993
994 #if __DJGPP__ || __BORLANDC__
995   {
996     struct text_info ti;
997
998     gettextinfo (&ti);
999     set_viewlength = max (ti.screenheight, 25);
1000     set_viewwidth = max (ti.screenwidth, 79);
1001   }
1002 #elif HAVE_LIBTERMCAP
1003   {
1004     char *termtype;
1005     int success;
1006
1007     /* This code stolen from termcap.info, though modified. */
1008     termtype = getenv ("TERM");
1009     if (!termtype)
1010       msg (FE, _("Specify a terminal type with `setenv TERM <yourtype>'."));
1011
1012     success = tgetent (term_buffer, termtype);
1013     if (success <= 0)
1014       {
1015         if (success < 0)
1016           msg (IE, _("Could not access the termcap data base."));
1017         else
1018           msg (IE, _("Terminal type `%s' is not defined."), termtype);
1019       }
1020     else
1021       {
1022         set_viewlength = tgetnum ("li");
1023         set_viewwidth = tgetnum ("co") - 1;
1024       }
1025   }
1026 #else
1027   {
1028   char *s;
1029
1030   /* Try the environment variables */
1031   s = getenv("COLUMNS");
1032   if ( s )  set_viewwidth = atoi(s);
1033
1034   s = getenv("LINES");
1035   if ( s )  set_viewlength = atoi(s);
1036   }
1037 #endif /* !HAVE_LIBTERMCAP */
1038
1039 }
1040
1041 /* Public functions */
1042
1043 void
1044 init_settings(void)
1045 {
1046   cmd.s_dprompt = xstrdup (_("data> "));
1047   cmd.s_cprompt = xstrdup ("    > ");  
1048   cmd.s_prompt = xstrdup ("PSPP> ");
1049   cmd.s_endcmd = xstrdup (".");
1050
1051   assert(cmd.safe == 0 );
1052   cmd.safe = STC_OFF;
1053
1054   cmd.dec = STC_DOT;
1055   cmd.n_cpi = 6;
1056   cmd.n_lpi = 10;
1057   cmd.echo = STC_OFF;
1058   cmd.more = STC_ON;
1059   cmd.headers = STC_YES;
1060   cmd.errbrk = STC_OFF;
1061
1062   cmd.scompress = STC_OFF;
1063   cmd.undef = STC_WARN;
1064   cmd.mprint = STC_ON ;
1065   cmd.prtbck = STC_ON ;
1066   cmd.null = STC_ON ;
1067   cmd.inc = STC_ON ;
1068
1069   set_journal = xstrdup ("pspp.jnl");
1070   set_journaling = 1;
1071
1072   cmd.n_mxwarns = 100;
1073   cmd.n_mxerrs = 100;
1074   cmd.n_mxloops = 1;
1075   cmd.n_workspace = 4L * 1024 * 1024;
1076
1077
1078 #if !USE_INTERNAL_PAGER
1079   {
1080     char *pager;
1081
1082     pager = getenv ("STAT_PAGER");
1083     if (!pager)  set_pager = getenv ("PAGER");
1084
1085     if (pager)  
1086       set_pager = xstrdup (pager);
1087 #if DEFAULT_PAGER
1088     else
1089       set_pager = xstrdup (DEFAULT_PAGER);
1090 #endif /* DEFAULT_PAGER */
1091   }
1092 #endif /* !USE_INTERNAL_PAGER */
1093
1094
1095   {
1096     int i;
1097     
1098     for (i = 0; i < 5; i++)
1099       {
1100         struct set_cust_currency *cc = &set_cc[i];
1101         strcpy (cc->buf, "-");
1102         cc->neg_prefix = cc->buf;
1103         cc->prefix = &cc->buf[1];
1104         cc->suffix = &cc->buf[1];
1105         cc->neg_suffix = &cc->buf[1];
1106         cc->decimal = '.';
1107         cc->grouping = ',';
1108       }
1109   }
1110
1111   if ( ! long_view )
1112     {
1113       set_viewport (0);
1114       signal (SIGWINCH, set_viewport);
1115     }
1116
1117 }
1118
1119 void
1120 force_long_view(void)
1121 {
1122   long_view = 1;
1123   set_viewwidth=9999;
1124 }
1125
1126 int 
1127 safer_mode(void)
1128 {
1129   return !(cmd.safe != STC_ON) ;
1130 }
1131
1132
1133 /* Set safer mode */
1134 void
1135 make_safe(void)
1136 {
1137   cmd.safe = STC_ON;
1138 }
1139
1140
1141 char 
1142 get_decimal(void)
1143 {
1144   return (cmd.dec == STC_DOT ? '.' : ',');
1145 }
1146
1147
1148 char
1149 get_grouping(void)
1150 {
1151   return (cmd.dec == STC_DOT ? ',' : '.');
1152 }
1153  
1154
1155 char * 
1156 get_prompt(void)
1157 {
1158   return cmd.s_prompt;
1159 }
1160
1161 char * 
1162 get_dprompt(void)
1163 {
1164   return cmd.s_dprompt;
1165 }
1166
1167 char * 
1168 get_cprompt(void)
1169 {
1170   return cmd.s_cprompt;
1171 }
1172
1173
1174 int
1175 get_echo(void)
1176 {
1177     return (cmd.echo != STC_OFF );
1178 }
1179
1180
1181 int 
1182 get_errorbreak(void)
1183 {
1184   return (cmd.errbrk != STC_OFF);
1185 }
1186
1187
1188 int 
1189 get_scompression(void)
1190 {
1191   return (cmd.scompress != STC_OFF );
1192 }
1193
1194 int
1195 get_undefined(void)
1196 {
1197   return (cmd.undef != STC_NOWARN);
1198 }
1199
1200 int
1201 get_mxwarns(void)
1202 {  
1203   return cmd.n_mxwarns;
1204 }
1205
1206 int
1207 get_mxerrs(void)
1208 {
1209   return cmd.n_mxerrs;
1210 }
1211
1212 int
1213 get_mprint(void)
1214 {
1215   return ( cmd.mprint != STC_OFF );
1216 }
1217
1218 int
1219 get_printback(void)
1220 {
1221   return (cmd.prtbck != STC_OFF );
1222 }
1223
1224 int
1225 get_mxloops(void)
1226 {
1227   return cmd.n_mxloops;
1228 }
1229
1230 int
1231 get_nullline(void)
1232 {
1233   return (cmd.null != STC_OFF );
1234 }
1235
1236 int
1237 get_include(void)
1238 {
1239  return (cmd.inc != STC_OFF );
1240 }
1241
1242 unsigned char
1243 get_endcmd(void)
1244 {
1245   return cmd.s_endcmd[0];
1246 }
1247
1248
1249 size_t
1250 get_max_workspace(void)
1251 {
1252   return cmd.n_workspace;
1253 }
1254
1255 double
1256 get_blanks(void)
1257 {
1258   return set_blanks;
1259 }
1260
1261 struct fmt_spec 
1262 get_format(void)
1263
1264   return set_format;
1265 }
1266
1267 /* CCA through CCE. */
1268 const struct set_cust_currency *
1269 get_cc(int i)
1270 {
1271   return &set_cc[i];
1272 }
1273
1274 void
1275 aux_show_warranty(void)
1276 {
1277   msg(MM,lack_of_warranty);
1278 }
1279
1280 void
1281 aux_show_copying(void)
1282 {
1283   msg(MM,copyleft);
1284 }
1285
1286
1287 int
1288 get_viewlength(void)
1289 {
1290   return set_viewlength;
1291 }
1292
1293 int
1294 get_viewwidth(void)
1295 {
1296   return set_viewwidth;
1297 }
1298
1299 const char *
1300 get_pager(void)
1301 {
1302   return set_pager;
1303 }
1304
1305 /* Return 1 if the seed has been set since the last time this function
1306    was called.
1307    Fill the value pointed to by seed with the seed .
1308 */
1309 int
1310 seed_is_set(unsigned long *seed)
1311 {
1312   int result = 0;
1313
1314   *seed = set_seed ;
1315
1316   if ( seed_flag ) 
1317     result = 1;
1318   
1319   seed_flag = 0;
1320
1321   return result;
1322     
1323 }
1324
1325
1326 /*
1327    Local Variables:
1328    mode: c
1329    End:
1330 */