Implemented the SHOW command and massaged the SET command to fit
[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   lex_match_id ("SET");
362
363   if (!parse_set (&cmd))
364     return CMD_FAILURE;
365
366   if (cmd.sbc_cca)
367     set_ccx (cmd.s_cca, &set_cc[0], 'A');
368   if (cmd.sbc_ccb)
369     set_ccx (cmd.s_ccb, &set_cc[1], 'B');
370   if (cmd.sbc_ccc)
371     set_ccx (cmd.s_ccc, &set_cc[2], 'C');
372   if (cmd.sbc_ccd)
373     set_ccx (cmd.s_ccd, &set_cc[3], 'D');
374   if (cmd.sbc_cce)
375     set_ccx (cmd.s_cce, &set_cc[4], 'E');
376
377   if (cmd.sbc_errors)
378     set_routing (cmd.errors, &set_errors);
379   if (cmd.sbc_messages)
380     set_routing (cmd.messages, &set_messages);
381
382   /* PC+ compatible syntax. */
383   if (cmd.sbc_screen)
384     outp_enable_device (cmd.scrn == STC_OFF ? 0 : 1, OUTP_DEV_SCREEN);
385   if (cmd.sbc_printer)
386     outp_enable_device (cmd.prtr == STC_OFF ? 0 : 1, OUTP_DEV_PRINTER);
387
388   if (cmd.sbc_automenu )
389     msg (SW, _("%s is obsolete."),"AUTOMENU");
390   if (cmd.sbc_beep )
391     msg (SW, _("%s is obsolete."),"BEEP");
392   if (cmd.sbc_block)
393     msg (SW, _("%s is obsolete."),"BLOCK");
394   if (cmd.sbc_boxstring)
395     msg (SW, _("%s is obsolete."),"BOXSTRING");
396   if (cmd.sbc_eject )
397     msg (SW, _("%s is obsolete."),"EJECT");
398   if (cmd.sbc_helpwindows )
399     msg (SW, _("%s is obsolete."),"HELPWINDOWS");
400   if (cmd.sbc_histogram)
401     msg (MW, _("%s is obsolete."),"HISTOGRAM");
402   if (cmd.sbc_menus )
403     msg (MW, _("%s is obsolete."),"MENUS");
404   if (cmd.sbc_ptranslate )
405     msg (SW, _("%s is obsolete."),"PTRANSLATE");
406   if (cmd.sbc_runreview )
407     msg (SW, _("%s is obsolete."),"RUNREVIEW");
408   if (cmd.sbc_xsort )
409     msg (SW, _("%s is obsolete."),"XSORT");
410   if (cmd.sbc_mxmemory )
411     msg (SE, _("%s is obsolete."),"MXMEMORY");
412   if (cmd.sbc_scripttab)
413     msg (SE, _("%s is obsolete."),"SCRIPTTAB");
414
415   if (cmd.sbc_tbfonts)
416     msg (SW, _("%s is not yet implemented."),"TBFONTS");
417   if (cmd.sbc_tb1 && cmd.s_tb1)
418     msg (SW, _("%s is not yet implemented."),"TB1");
419
420   /* Windows compatible syntax. */
421   if (cmd.sbc_case)
422     msg (SW, _("CASE is not implemented and probably won't be.  "
423         "If you care, complain about it."));
424
425   if (cmd.sbc_compression)
426     {
427       msg (MW, _("Active file compression is not yet implemented "
428                  "(and probably won't be)."));
429     }
430
431   return CMD_SUCCESS;
432 }
433
434 /* Sets custom currency specifier CC having name CC_NAME ('A' through
435    'E') to correspond to the settings in CC_STRING. */
436 static int
437 set_ccx (const char *cc_string, struct set_cust_currency * cc, int cc_name)
438 {
439   if (strlen (cc_string) > 16)
440     {
441       msg (SE, _("CC%c: Length of custom currency string `%s' (%d) "
442                  "exceeds maximum length of 16."),
443            cc_name, cc_string, strlen (cc_string));
444       return 0;
445     }
446
447   /* Determine separators. */
448   {
449     const char *sp;
450     int n_commas, n_periods;
451   
452     /* Count the number of commas and periods.  There must be exactly
453        three of one or the other. */
454     n_commas = n_periods = 0;
455     for (sp = cc_string; *sp; sp++)
456       if (*sp == ',')
457         n_commas++;
458       else if (*sp == '.')
459         n_periods++;
460   
461     if (!((n_commas == 3) ^ (n_periods == 3)))
462       {
463         msg (SE, _("CC%c: Custom currency string `%s' does not contain "
464                    "exactly three periods or commas (not both)."),
465              cc_name, cc_string);
466         return 0;
467       }
468     else if (n_commas == 3)
469       {
470         cc->decimal = '.';
471         cc->grouping = ',';
472       }
473     else
474       {
475         cc->decimal = ',';
476         cc->grouping = '.';
477       }
478   }
479   
480   /* Copy cc_string to cc, changing separators to nulls. */
481   {
482     char *cp;
483     
484     strcpy (cc->buf, cc_string);
485     cp = cc->neg_prefix = cc->buf;
486
487     while (*cp++ != cc->grouping)
488       ;
489     cp[-1] = '\0';
490     cc->prefix = cp;
491
492     while (*cp++ != cc->grouping)
493       ;
494     cp[-1] = '\0';
495     cc->suffix = cp;
496
497     while (*cp++ != cc->grouping)
498       ;
499     cp[-1] = '\0';
500     cc->neg_suffix = cp;
501   }
502   
503   return 1;
504 }
505
506
507 const char *
508 route_to_string(int routing)
509 {
510   static char s[255];
511   
512   s[0]='\0';
513
514   if ( routing == 0 )
515     {
516       strcpy(s, _("None"));
517       return s;
518     }
519
520   if (routing & SET_ROUTE_DISABLE ) 
521     {
522     strcpy(s, _("Disabled") );
523     return s;
524     }
525
526   if (routing & SET_ROUTE_SCREEN)
527     strcat(s, _("Screen") );
528   
529   if (routing & SET_ROUTE_LISTING)
530     {
531       if(s[0] != '\0') 
532         strcat(s,", ");
533         
534       strcat(s, _("Listing") );
535     }
536
537   if (routing & SET_ROUTE_OTHER)
538     {
539       if(s[0] != '\0') 
540         strcat(s,", ");
541       strcat(s, _("Other") );
542     }
543  
544     
545   return s;
546   
547     
548 }
549
550 /* Sets *SETTING, which is a combination of SET_ROUTE_* bits that
551    indicates what to do with some sort of output, to the value
552    indicated by Q, which is a value provided by the input parser. */
553 static void
554 set_routing (int q, int *setting)
555 {
556   switch (q)
557     {
558     case STC_OFF:
559       *setting |= SET_ROUTE_DISABLE;
560       break;
561     case STC_ON:
562       *setting &= ~SET_ROUTE_DISABLE;
563       break;
564     case STC_TERMINAL:
565       *setting &= ~(SET_ROUTE_LISTING | SET_ROUTE_OTHER);
566       *setting |= SET_ROUTE_SCREEN;
567       break;
568     case STC_LISTING:
569       *setting &= ~SET_ROUTE_SCREEN;
570       *setting |= SET_ROUTE_LISTING | SET_ROUTE_OTHER;
571       break;
572     case STC_BOTH:
573       *setting |= SET_ROUTE_SCREEN | SET_ROUTE_LISTING | SET_ROUTE_OTHER;
574       break;
575     case STC_NONE:
576       *setting &= ~(SET_ROUTE_SCREEN | SET_ROUTE_LISTING | SET_ROUTE_OTHER);
577       break;
578     default:
579       assert (0);
580     }
581 }
582
583 static int
584 stc_custom_pager (struct cmd_set *cmd UNUSED)
585 {
586   lex_match ('=');
587 #if !USE_INTERNAL_PAGER
588   if (lex_match_id ("OFF"))
589     {
590       if (set_pager)
591         free (set_pager);
592       set_pager = NULL;
593     }
594   else
595     {
596       if (!lex_force_string ())
597         return 0;
598       if (set_pager)
599         free (set_pager);
600       set_pager = xstrdup (ds_value (&tokstr));
601       lex_get ();
602     }
603   return 1;
604 #else /* USE_INTERNAL_PAGER */
605   if (match_id (OFF))
606     return 1;
607   msg (SW, "External pagers not supported.");
608   return 0;
609 #endif /* USE_INTERNAL_PAGER */
610 }
611
612 /* Parses the BLANKS subcommand, which controls the value that
613    completely blank fields in numeric data imply.  X, Wnd: Syntax is
614    SYSMIS or a numeric value; PC+: Syntax is '.', which is equivalent
615    to SYSMIS, or a numeric value. */
616 static int
617 stc_custom_blanks (struct cmd_set *cmd UNUSED)
618 {
619   lex_match ('=');
620   if ((token == T_ID && lex_id_match ("SYSMIS", tokid))
621       || (token == T_STRING && !strcmp (tokid, ".")))
622     {
623       lex_get ();
624       set_blanks = SYSMIS;
625     }
626   else
627     {
628       if (!lex_force_num ())
629         return 0;
630       set_blanks = tokval;
631       lex_get ();
632     }
633   return 1;
634 }
635
636 static int
637 stc_custom_length (struct cmd_set *cmd UNUSED)
638 {
639   int page_length;
640
641   lex_match ('=');
642   if (lex_match_id ("NONE"))
643     page_length = -1;
644   else
645     {
646       if (!lex_force_int ())
647         return 0;
648       if (lex_integer () < 1)
649         {
650           msg (SE, _("LENGTH must be at least 1."));
651           return 0;
652         }
653       page_length = lex_integer ();
654       lex_get ();
655     }
656
657   if ( page_length != -1 ) 
658     set_viewlength = page_length;
659
660   return 1;
661 }
662
663 static int
664 stc_custom_results (struct cmd_set *cmd UNUSED)
665 {
666   struct tuple
667     {   
668       const char *s;    
669       int v;
670     };
671
672   static struct tuple tab[] =
673     {
674       {"ON", STC_ON},
675       {"OFF", STC_OFF},
676       {"TERMINAL", STC_TERMINAL},
677       {"LISTING", STC_LISTING},
678       {"BOTH", STC_BOTH},
679       {"NONE", STC_NONE},
680       {NULL, 0},
681     };
682
683   struct tuple *t;
684
685   lex_match ('=');
686
687   if (token != T_ID)
688     {
689       msg (SE, _("Missing identifier in RESULTS subcommand."));
690       return 0;
691     }
692   
693   for (t = tab; t->s; t++)
694     if (lex_id_match (t->s, tokid))
695       {
696         lex_get ();
697         set_routing (t->v, &set_results);
698         return 1;
699       }
700   msg (SE, _("Unrecognized identifier in RESULTS subcommand."));
701   return 0;
702 }
703
704 static int
705 stc_custom_seed (struct cmd_set *cmd UNUSED)
706 {
707   lex_match ('=');
708   if (lex_match_id ("RANDOM"))
709     set_seed = random_seed();
710   else
711     {
712       if (!lex_force_num ())
713         return 0;
714       set_seed = tokval;
715       lex_get ();
716     }
717   seed_flag = 1;
718
719   return 1;
720 }
721
722 static int
723 stc_custom_width (struct cmd_set *cmd UNUSED)
724 {
725   int page_width;
726
727   lex_match ('=');
728   if (lex_match_id ("NARROW"))
729     page_width = 79;
730   else if (lex_match_id ("WIDE"))
731     page_width = 131;
732   else
733     {
734       if (!lex_force_int ())
735         return 0;
736       if (lex_integer () < 1)
737         {
738           msg (SE, _("WIDTH must be at least 1."));
739           return 0;
740         }
741       page_width = lex_integer ();
742       lex_get ();
743     }
744
745   set_viewwidth = page_width;
746   return 1;
747 }
748
749 /* Parses FORMAT subcommand, which consists of a numeric format
750    specifier. */
751 static int
752 stc_custom_format (struct cmd_set *cmd UNUSED)
753 {
754   struct fmt_spec fmt;
755
756   lex_match ('=');
757   if (!parse_format_specifier (&fmt, 0))
758     return 0;
759   if ((formats[fmt.type].cat & FCAT_STRING) != 0)
760     {
761       msg (SE, _("FORMAT requires numeric output format as an argument.  "
762                  "Specified format %s is of type string."),
763            fmt_to_string (&fmt));
764       return 0;
765     }
766
767   set_format = fmt;
768   return 1;
769 }
770
771 static int
772 stc_custom_journal (struct cmd_set *cmd UNUSED)
773 {
774   lex_match ('=');
775   if (lex_match_id ("ON"))
776     set_journaling = 1;
777   else if (lex_match_id ("OFF"))
778     set_journaling = 0;
779   if (token == T_STRING)
780     {
781       set_journal = xstrdup (ds_value (&tokstr));
782       lex_get ();
783     }
784   return 1;
785 }
786
787 /* Parses COLOR subcommand.  PC+: either ON or OFF or two or three
788    comma-delimited numbers inside parentheses. */
789 static int
790 stc_custom_color (struct cmd_set *cmd UNUSED)
791 {
792   msg (MW, _("%s is obsolete."),"COLOR");
793
794   lex_match ('=');
795   if (!lex_match_id ("ON") && !lex_match_id ("YES") && !lex_match_id ("OFF") && !lex_match_id ("NO"))
796     {
797       if (!lex_force_match ('('))
798         return 0;
799       if (!lex_match ('*'))
800         {
801           if (!lex_force_int ())
802             return 0;
803           if (lex_integer () < 0 || lex_integer () > 15)
804             {
805               msg (SE, _("Text color must be in range 0-15."));
806               return 0;
807             }
808           lex_get ();
809         }
810       if (!lex_force_match (','))
811         return 0;
812       if (!lex_match ('*'))
813         {
814           if (!lex_force_int ())
815             return 0;
816           if (lex_integer () < 0 || lex_integer () > 7)
817             {
818               msg (SE, _("Background color must be in range 0-7."));
819               return 0;
820             }
821           lex_get ();
822         }
823       if (lex_match (',') && !lex_match ('*'))
824         {
825           if (!lex_force_int ())
826             return 0;
827           if (lex_integer () < 0 || lex_integer () > 7)
828             {
829               msg (SE, _("Border color must be in range 0-7."));
830               return 0;
831             }
832           lex_get ();
833         }
834       if (!lex_force_match (')'))
835         return 0;
836     }
837   return 1;
838 }
839
840 static int
841 stc_custom_listing (struct cmd_set *cmd UNUSED)
842 {
843   lex_match ('=');
844   if (lex_match_id ("ON") || lex_match_id ("YES"))
845     set_listing = 1;
846   else if (lex_match_id ("OFF") || lex_match_id ("NO"))
847     set_listing = 0;
848   else
849     {
850       /* FIXME */
851       return 0;
852     }
853   outp_enable_device (set_listing, OUTP_DEV_LISTING);
854
855   return 1;
856 }
857
858 static int
859 stc_custom_disk (struct cmd_set *cmd UNUSED)
860 {
861   return stc_custom_listing (cmd);
862 }
863
864 static int
865 stc_custom_log (struct cmd_set *cmd UNUSED)
866
867   return stc_custom_journal (cmd);
868 }
869
870 static int
871 stc_custom_rcolor (struct cmd_set *cmd UNUSED)
872 {
873   msg (SW, _("%s is obsolete."),"RCOLOR");
874
875   lex_match ('=');
876   if (!lex_force_match ('('))
877     return 0;
878
879   if (!lex_match ('*'))
880     {
881       if (!lex_force_int ())
882         return 0;
883       if (lex_integer () < 0 || lex_integer () > 6)
884         {
885           msg (SE, _("Lower window color must be between 0 and 6."));
886           return 0;
887         }
888       lex_get ();
889     }
890   if (!lex_force_match (','))
891     return 0;
892
893   if (!lex_match ('*'))
894     {
895       if (!lex_force_int ())
896         return 0;
897       if (lex_integer () < 0 || lex_integer () > 6)
898         {
899           msg (SE, _("Upper window color must be between 0 and 6."));
900           return 0;
901         }
902       lex_get ();
903     }
904
905   if (lex_match (',') && !lex_match ('*'))
906     {
907       if (!lex_force_int ())
908         return 0;
909       if (lex_integer () < 0 || lex_integer () > 6)
910         {
911           msg (SE, _("Frame color must be between 0 and 6."));
912           return 0;
913         }
914       lex_get ();
915     }
916   return 1;
917 }
918
919 static int
920 stc_custom_viewwidth (struct cmd_set *cmd UNUSED)
921 {
922   lex_match ('=');
923
924   if ( !lex_force_int() ) 
925     return 0;
926
927   set_viewwidth = lex_integer();
928   lex_get();
929   
930   return 1;
931 }
932
933 static int
934 stc_custom_viewlength (struct cmd_set *cmd UNUSED)
935 {
936   if (lex_match_id ("MINIMUM"))
937     set_viewlength = 25;
938   else if (lex_match_id ("MEDIAN"))
939     set_viewlength = 43;        /* This is not correct for VGA displays. */
940   else if (lex_match_id ("MAXIMUM"))
941     set_viewlength = 43;
942   else
943     {
944       if (!lex_force_int ())
945         return 0;
946 #ifdef __MSDOS__
947       if (lex_integer () >= (43 + 25) / 2)
948         set_viewlength = 43;
949       else
950         set_viewlength = 25;
951 #else /* not dos */
952       set_viewlength = lex_integer ();
953 #endif /* not dos */
954       lex_get ();
955     }
956
957 #ifdef __MSDOS__
958   msg (SW, _("%s is not yet implemented."),"VIEWLENGTH");
959 #endif /* dos */
960   return 1;
961 }
962
963 static int
964 stc_custom_workdev (struct cmd_set *cmd UNUSED)
965 {
966   char c[2];
967
968   msg (SW, _("%s is obsolete."),"WORKDEV");
969
970   c[1] = 0;
971   for (*c = 'A'; *c <= 'Z'; (*c)++)
972     if (token == T_ID && lex_id_match (c, tokid))
973       {
974         lex_get ();
975         return 1;
976       }
977   msg (SE, _("Drive letter expected in WORKDEV subcommand."));
978   return 0;
979 }
980
981
982
983 static void 
984 set_viewport(void)
985 {
986 #if HAVE_LIBTERMCAP
987   static char term_buffer[16384];
988 #endif
989
990   /* Workable defaults before we determine the real terminal size. */
991   set_viewwidth = 79;
992   set_viewlength = 24;
993
994
995
996 #if __DJGPP__ || __BORLANDC__
997   {
998     struct text_info ti;
999
1000     gettextinfo (&ti);
1001     set_viewlength = max (ti.screenheight, 25);
1002     set_viewwidth = max (ti.screenwidth, 79);
1003   }
1004 #elif HAVE_LIBTERMCAP
1005   {
1006     char *termtype;
1007     int success;
1008
1009     /* This code stolen from termcap.info, though modified. */
1010     termtype = getenv ("TERM");
1011     if (!termtype)
1012       msg (FE, _("Specify a terminal type with `setenv TERM <yourtype>'."));
1013
1014     success = tgetent (term_buffer, termtype);
1015     if (success <= 0)
1016       {
1017         if (success < 0)
1018           msg (IE, _("Could not access the termcap data base."));
1019         else
1020           msg (IE, _("Terminal type `%s' is not defined."), termtype);
1021       }
1022     else
1023       {
1024         set_viewlength = tgetnum ("li");
1025         set_viewwidth = tgetnum ("co") - 1;
1026       }
1027   }
1028 #else
1029   {
1030   char *s;
1031
1032   /* Try the environment variables */
1033   s = getenv("COLUMNS");
1034   if ( s )  set_viewwidth = atoi(s);
1035
1036   s = getenv("LINES");
1037   if ( s )  set_viewlength = atoi(s);
1038   }
1039 #endif /* !HAVE_LIBTERMCAP */
1040
1041 }
1042
1043 /* Public functions */
1044
1045 void
1046 init_settings(void)
1047 {
1048   cmd.s_dprompt = xstrdup (_("data> "));
1049   cmd.s_cprompt = xstrdup ("    > ");  
1050   cmd.s_prompt = xstrdup ("PSPP> ");
1051   cmd.s_endcmd = xstrdup (".");
1052
1053   assert(cmd.safe == 0 );
1054   cmd.safe = STC_OFF;
1055
1056   cmd.dec = STC_DOT;
1057   cmd.n_cpi = 6;
1058   cmd.n_lpi = 10;
1059   cmd.echo = STC_OFF;
1060   cmd.more = STC_ON;
1061   cmd.headers = STC_YES;
1062   cmd.errbrk = STC_OFF;
1063
1064   cmd.scompress = STC_OFF;
1065   cmd.undef = STC_WARN;
1066   cmd.mprint = STC_ON ;
1067   cmd.prtbck = STC_ON ;
1068   cmd.null = STC_ON ;
1069   cmd.inc = STC_ON ;
1070
1071   set_journal = xstrdup ("pspp.jnl");
1072   set_journaling = 1;
1073
1074   cmd.n_mxwarns = 100;
1075   cmd.n_mxerrs = 100;
1076   cmd.n_mxloops = 1;
1077   cmd.n_workspace = 4L * 1024 * 1024;
1078
1079
1080 #if !USE_INTERNAL_PAGER
1081   {
1082     char *pager;
1083
1084     pager = getenv ("STAT_PAGER");
1085     if (!pager)  set_pager = getenv ("PAGER");
1086
1087     if (pager)  
1088       set_pager = xstrdup (pager);
1089 #if DEFAULT_PAGER
1090     else
1091       set_pager = xstrdup (DEFAULT_PAGER);
1092 #endif /* DEFAULT_PAGER */
1093   }
1094 #endif /* !USE_INTERNAL_PAGER */
1095
1096
1097   {
1098     int i;
1099     
1100     for (i = 0; i < 5; i++)
1101       {
1102         struct set_cust_currency *cc = &set_cc[i];
1103         strcpy (cc->buf, "-");
1104         cc->neg_prefix = cc->buf;
1105         cc->prefix = &cc->buf[1];
1106         cc->suffix = &cc->buf[1];
1107         cc->neg_suffix = &cc->buf[1];
1108         cc->decimal = '.';
1109         cc->grouping = ',';
1110       }
1111   }
1112
1113   if ( ! long_view )
1114     {
1115       set_viewport();
1116       signal (SIGWINCH,set_viewport);
1117     }
1118
1119 }
1120
1121 void
1122 force_long_view(void)
1123 {
1124   long_view = 1;
1125   set_viewwidth=9999;
1126 }
1127
1128 int 
1129 safer_mode(void)
1130 {
1131   return !(cmd.safe != STC_ON) ;
1132 }
1133
1134
1135 /* Set safer mode */
1136 void
1137 make_safe(void)
1138 {
1139   cmd.safe = STC_ON;
1140 }
1141
1142
1143 char 
1144 get_decimal(void)
1145 {
1146   return (cmd.dec == STC_DOT ? '.' : ',');
1147 }
1148
1149
1150 char
1151 get_grouping(void)
1152 {
1153   return (cmd.dec == STC_DOT ? ',' : '.');
1154 }
1155  
1156
1157 char * 
1158 get_prompt(void)
1159 {
1160   return cmd.s_prompt;
1161 }
1162
1163 char * 
1164 get_dprompt(void)
1165 {
1166   return cmd.s_dprompt;
1167 }
1168
1169 char * 
1170 get_cprompt(void)
1171 {
1172   return cmd.s_cprompt;
1173 }
1174
1175
1176 int
1177 get_echo(void)
1178 {
1179     return (cmd.echo != STC_OFF );
1180 }
1181
1182
1183 int 
1184 get_errorbreak(void)
1185 {
1186   return (cmd.errbrk != STC_OFF);
1187 }
1188
1189
1190 int 
1191 get_scompression(void)
1192 {
1193   return (cmd.scompress != STC_OFF );
1194 }
1195
1196 int
1197 get_undefined(void)
1198 {
1199   return (cmd.undef != STC_NOWARN);
1200 }
1201
1202 int
1203 get_mxwarns(void)
1204 {  
1205   return cmd.n_mxwarns;
1206 }
1207
1208 int
1209 get_mxerrs(void)
1210 {
1211   return cmd.n_mxerrs;
1212 }
1213
1214 int
1215 get_mprint(void)
1216 {
1217   return ( cmd.mprint != STC_OFF );
1218 }
1219
1220 int
1221 get_printback(void)
1222 {
1223   return (cmd.prtbck != STC_OFF );
1224 }
1225
1226 int
1227 get_mxloops(void)
1228 {
1229   return cmd.n_mxloops;
1230 }
1231
1232 int
1233 get_nullline(void)
1234 {
1235   return (cmd.null != STC_OFF );
1236 }
1237
1238 int
1239 get_include(void)
1240 {
1241  return (cmd.inc != STC_OFF );
1242 }
1243
1244 unsigned char
1245 get_endcmd(void)
1246 {
1247   return cmd.s_endcmd[0];
1248 }
1249
1250
1251 size_t
1252 get_max_workspace(void)
1253 {
1254   return cmd.n_workspace;
1255 }
1256
1257 double
1258 get_blanks(void)
1259 {
1260   return set_blanks;
1261 }
1262
1263 struct fmt_spec 
1264 get_format(void)
1265
1266   return set_format;
1267 }
1268
1269 /* CCA through CCE. */
1270 const struct set_cust_currency *
1271 get_cc(int i)
1272 {
1273   return &set_cc[i];
1274 }
1275
1276 void
1277 aux_show_warranty(void)
1278 {
1279   msg(MM,lack_of_warranty);
1280 }
1281
1282 void
1283 aux_show_copying(void)
1284 {
1285   msg(MM,copyleft);
1286 }
1287
1288
1289 int
1290 get_viewlength(void)
1291 {
1292   return set_viewlength;
1293 }
1294
1295 int
1296 get_viewwidth(void)
1297 {
1298   return set_viewwidth;
1299 }
1300
1301 const char *
1302 get_pager(void)
1303 {
1304   return set_pager;
1305 }
1306
1307 /* Return 1 if the seed has been set since the last time this function
1308    was called.
1309    Fill the value pointed to by seed with the seed .
1310 */
1311 int
1312 seed_is_set(unsigned long *seed)
1313 {
1314   int result = 0;
1315
1316   *seed = set_seed ;
1317
1318   if ( seed_flag ) 
1319     result = 1;
1320   
1321   seed_flag = 0;
1322
1323   return result;
1324     
1325 }
1326
1327
1328 /*
1329    Local Variables:
1330    mode: c
1331    End:
1332 */