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