5d9f149072b01c66e02e08cba29f37f7d3aa5628
[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
77 double set_blanks;
78 int set_compression;
79 struct set_cust_currency set_cc[5];
80 int set_cpi;
81 char *set_cprompt;
82 int set_decimal;
83 int set_grouping;
84 char *set_dprompt;
85 int set_echo;
86 int set_endcmd;
87 int set_errorbreak;
88 int set_errors, set_messages, set_results;
89 struct fmt_spec set_format;
90 int set_headers;
91 int set_include;
92 char *set_journal;
93 int set_journaling;
94 int set_lpi;
95 int set_messages;
96 int set_mexpand;
97 int set_miterate;
98 int set_mnest;
99 int set_more;
100 int set_mprint;
101 int set_mxerrs;
102 int set_mxloops;
103 int set_mxwarns;
104 int set_nullline;
105 int set_printback;
106 int set_output = 1;
107 #if !USE_INTERNAL_PAGER
108 char *set_pager;
109 #endif /* !USE_INTERNAL_PAGER */
110 int set_printer;
111 char *set_prompt;
112 char *set_results_file;
113 int set_safer;
114 int set_scompression;
115 int set_screen;
116 long set_seed;
117 int set_seed_used;
118 int set_testing_mode;
119 int set_undefined;
120 int set_viewlength;
121 int set_viewwidth;
122
123 static void set_routing (int q, int *setting);
124 static int set_ccx (const char *cc_string, struct set_cust_currency * cc,
125                     int cc_name);
126
127 /* (specification)
128    "SET" (stc_):
129      automenu=automenu:on/off;
130      beep=beep:on/off;
131      blanks=custom;
132      block=string "x==1" "one character long";
133      boxstring=string "x==3 || x==11" "3 or 11 characters long";
134      case=size:upper/uplow;
135      cca=string;
136      ccb=string;
137      ccc=string;
138      ccd=string;
139      cce=string;
140      color=custom;
141      compression=compress:on/off;
142      cpi=integer;
143      cprompt=string;
144      decimal=dec:dot/_comma;
145      disk=custom;
146      dprompt=string;
147      echo=echo:on/off;
148      eject=eject:on/off;
149      endcmd=string "x==1" "one character long";
150      errorbreak=errbrk:on/off;
151      errors=errors:on/off/terminal/listing/both/none;
152      format=custom;
153      headers=headers:no/yes/blank;
154      helpwindows=helpwin:on/off;
155      highres=hires:on/off;
156      histogram=string "x==1" "one character long";
157      include=inc:on/off;
158      journal=custom;
159      length=custom;
160      listing=custom;
161      log=custom;
162      lowres=lores:auto/on/off;
163      lpi=integer;
164      menus=menus:standard/extended;
165      messages=messages:on/off/terminal/listing/both/none;
166      mexpand=mexp:on/off;
167      miterate=integer;
168      mnest=integer;
169      more=more:on/off;
170      mprint=mprint:on/off;
171      mxerrs=integer;
172      mxloops=integer;
173      mxmemory=integer;
174      mxwarns=integer;
175      nulline=null:on/off;
176      pager=custom;
177      printback=prtbck:on/off;
178      printer=prtr:on/off;
179      prompt=string;
180      ptranslate=ptrans:on/off;
181      rcolor=custom;
182      results=custom;
183      runreview=runrev:auto/manual;
184      safer=safe:on;
185      scompression=scompress:on/off;
186      screen=scrn:on/off;
187      scripttab=string "x==1" "one character long";
188      seed=custom;
189      tb1=string "x==3 || x==11" "3 or 11 characters long";
190      tbfonts=string;
191      undefined=undef:warn/nowarn;
192      viewlength=custom;
193      viewwidth=integer;
194      width=custom;
195      workdev=custom;
196      workspace=integer;
197      xsort=xsort:yes/no.
198 */
199
200 /* (declarations) */
201 /* (functions) */
202
203 int internal_cmd_set (void);
204
205 int
206 cmd_set (void)
207 {
208   struct cmd_set cmd;
209
210   lex_match_id ("SET");
211
212   if (!parse_set (&cmd))
213     return CMD_FAILURE;
214
215   if (cmd.sbc_block)
216     msg (SW, _("%s is obsolete."),"BLOCK");
217
218   if (cmd.sbc_boxstring)
219     msg (SW, _("%s is obsolete."),"BOXSTRING");
220
221   if (cmd.compress != -1)
222     {
223       msg (MW, _("Active file compression is not yet implemented "
224                  "(and probably won't be)."));
225       set_compression = cmd.compress == STC_OFF ? 0 : 1;
226     }
227   if (cmd.scompress != -1)
228     set_scompression = cmd.scompress == STC_OFF ? 0 : 1;
229   if (cmd.n_cpi != NOT_LONG)
230     {
231       if (cmd.n_cpi <= 0)
232         msg (SE, _("CPI must be greater than 0."));
233       else
234         set_cpi = cmd.n_cpi;
235     }
236   if (cmd.sbc_histogram)
237     msg (MW, _("%s is obsolete."),"HISTOGRAM");
238   if (cmd.n_lpi != NOT_LONG)
239     {
240       if (cmd.n_lpi <= 0)
241         msg (SE, _("LPI must be greater than 0."));
242       else
243         set_lpi = cmd.n_lpi;
244     }
245   
246   /* Windows compatible syntax. */
247   if (cmd.sbc_case)
248     msg (SW, _("CASE is not implemented and probably won't be.  If you care, "
249                "complain about it."));
250   if (cmd.sbc_cca)
251     set_ccx (cmd.s_cca, &set_cc[0], 'A');
252   if (cmd.sbc_ccb)
253     set_ccx (cmd.s_ccb, &set_cc[1], 'B');
254   if (cmd.sbc_ccc)
255     set_ccx (cmd.s_ccc, &set_cc[2], 'C');
256   if (cmd.sbc_ccd)
257     set_ccx (cmd.s_ccd, &set_cc[3], 'D');
258   if (cmd.sbc_cce)
259     set_ccx (cmd.s_cce, &set_cc[4], 'E');
260   if (cmd.dec != -1)
261     {
262       set_decimal = cmd.dec == STC_DOT ? '.' : ',';
263       set_grouping = cmd.dec == STC_DOT ? ',' : '.';
264     }
265   if (cmd.errors != -1)
266     set_routing (cmd.errors, &set_errors);
267   if (cmd.headers != -1)
268     set_headers = cmd.headers == STC_NO ? 0 : (cmd.headers == STC_YES ? 1 : 2);
269   if (cmd.messages != -1)
270     set_routing (cmd.messages, &set_messages);
271   if (cmd.mexp != -1)
272     set_mexpand = cmd.mexp == STC_OFF ? 0 : 1;
273   if (cmd.n_miterate != NOT_LONG)
274     {
275       if (cmd.n_miterate > 0)
276         set_miterate = cmd.n_miterate;
277       else
278         msg (SE, _("Value for MITERATE (%ld) must be greater than 0."),
279              cmd.n_miterate);
280     }
281   if (cmd.n_mnest != NOT_LONG)
282     {
283       if (cmd.n_mnest > 0)
284         set_mnest = cmd.n_mnest;
285       else
286         msg (SE, _("Value for MNEST (%ld) must be greater than 0."),
287              cmd.n_mnest);
288     }
289   if (cmd.mprint != -1)
290     set_mprint = cmd.mprint == STC_OFF ? 0 : 1;
291   if (cmd.n_mxerrs != NOT_LONG)
292     {
293       if (set_mxerrs < 1)
294         msg (SE, _("MXERRS must be at least 1."));
295       else
296         set_mxerrs = cmd.n_mxerrs;
297     }
298   if (cmd.n_mxloops != NOT_LONG)
299     {
300       if (set_mxloops < 1)
301         msg (SE, _("MXLOOPS must be at least 1."));
302       else
303         set_mxloops = cmd.n_mxloops;
304     }
305   if (cmd.n_mxmemory != NOT_LONG)
306     msg (SE, _("%s is obsolete."),"MXMEMORY");
307   if (cmd.n_mxwarns != NOT_LONG)
308     set_mxwarns = cmd.n_mxwarns;
309   if (cmd.prtbck != -1)
310     set_printback = cmd.prtbck == STC_OFF ? 0 : 1;
311   if (cmd.s_scripttab)
312     msg (SE, _("%s is obsolete."),"SCRIPTTAB");
313   if (cmd.s_tbfonts)
314     msg (SW, _("%s is not yet implemented."),"TBFONTS");
315   if (cmd.s_tb1)
316     msg (SW, _("%s is not yet implemented."),"TB1");
317   if (cmd.undef != -1)
318     set_undefined = cmd.undef == STC_NOWARN ? 0 : 1;
319   if (cmd.n_workspace != NOT_LONG)
320     msg (SE, _("%s is obsolete."),"WORKSPACE");
321
322   /* PC+ compatible syntax. */
323   if (cmd.scrn != -1)
324     outp_enable_device (cmd.scrn == STC_OFF ? 0 : 1, OUTP_DEV_SCREEN);
325
326   if (cmd.automenu != -1)
327     msg (SW, _("%s is obsolete."),"AUTOMENU");
328   if (cmd.beep != -1)
329     msg (SW, _("%s is obsolete."),"BEEP");
330
331   if (cmd.s_cprompt)
332     {
333       free (set_cprompt);
334       set_cprompt = cmd.s_cprompt;
335       cmd.s_cprompt = NULL;
336     }
337   if (cmd.s_dprompt)
338     {
339       free (set_dprompt);
340       set_dprompt = cmd.s_dprompt;
341       cmd.s_dprompt = NULL;
342     }
343   if (cmd.echo != -1)
344     set_echo = cmd.echo == STC_OFF ? 0 : 1;
345   if (cmd.s_endcmd)
346     set_endcmd = cmd.s_endcmd[0];
347   if (cmd.eject != -1)
348     msg (SW, _("%s is obsolete."),"EJECT");
349   if (cmd.errbrk != -1)
350     set_errorbreak = cmd.errbrk == STC_OFF ? 0 : 1;
351   if (cmd.helpwin != -1)
352     msg (SW, _("%s is obsolete."),"HELPWINDOWS");
353   if (cmd.inc != -1)
354     set_include = cmd.inc == STC_OFF ? 0 : 1;
355   if (cmd.menus != -1)
356     msg (MW, _("%s is obsolete."),"MENUS");
357   if (cmd.null != -1)
358     set_nullline = cmd.null == STC_OFF ? 0 : 1;
359   if (cmd.more != -1)
360     set_more = cmd.more == STC_OFF ? 0 : 1;
361   if (cmd.prtr != -1)
362     outp_enable_device (cmd.prtr == STC_OFF ? 0 : 1, OUTP_DEV_PRINTER);
363   if (cmd.s_prompt)
364     {
365       free (set_prompt);
366       set_prompt = cmd.s_prompt;
367       cmd.s_prompt = NULL;
368     }
369   if (cmd.ptrans != -1)
370     msg (SW, _("%s is obsolete."),"PTRANSLATE");
371   if (cmd.runrev != -1)
372     msg (SW, _("%s is obsolete."),"RUNREVIEW");
373   if (cmd.safe == STC_ON)
374     set_safer = 1;
375   if (cmd.xsort != -1)
376     msg (SW, _("%s is obsolete."),"XSORT");
377
378   free_set (&cmd);
379
380   return CMD_SUCCESS;
381 }
382
383 /* Sets custom currency specifier CC having name CC_NAME ('A' through
384    'E') to correspond to the settings in CC_STRING. */
385 static int
386 set_ccx (const char *cc_string, struct set_cust_currency * cc, int cc_name)
387 {
388   if (strlen (cc_string) > 16)
389     {
390       msg (SE, _("CC%c: Length of custom currency string `%s' (%d) "
391                  "exceeds maximum length of 16."),
392            cc_name, cc_string, strlen (cc_string));
393       return 0;
394     }
395
396   /* Determine separators. */
397   {
398     const char *sp;
399     int n_commas, n_periods;
400   
401     /* Count the number of commas and periods.  There must be exactly
402        three of one or the other. */
403     n_commas = n_periods = 0;
404     for (sp = cc_string; *sp; sp++)
405       if (*sp == ',')
406         n_commas++;
407       else if (*sp == '.')
408         n_periods++;
409   
410     if (!((n_commas == 3) ^ (n_periods == 3)))
411       {
412         msg (SE, _("CC%c: Custom currency string `%s' does not contain "
413                    "exactly three periods or commas (not both)."),
414              cc_name, cc_string);
415         return 0;
416       }
417     else if (n_commas == 3)
418       {
419         cc->decimal = '.';
420         cc->grouping = ',';
421       }
422     else
423       {
424         cc->decimal = ',';
425         cc->grouping = '.';
426       }
427   }
428   
429   /* Copy cc_string to cc, changing separators to nulls. */
430   {
431     char *cp;
432     
433     strcpy (cc->buf, cc_string);
434     cp = cc->neg_prefix = cc->buf;
435
436     while (*cp++ != cc->grouping)
437       ;
438     cp[-1] = '\0';
439     cc->prefix = cp;
440
441     while (*cp++ != cc->grouping)
442       ;
443     cp[-1] = '\0';
444     cc->suffix = cp;
445
446     while (*cp++ != cc->grouping)
447       ;
448     cp[-1] = '\0';
449     cc->neg_suffix = cp;
450   }
451   
452   return 1;
453 }
454
455 /* Sets *SETTING, which is a combination of SET_ROUTE_* bits that
456    indicates what to do with some sort of output, to the value
457    indicated by Q, which is a value provided by the input parser. */
458 static void
459 set_routing (int q, int *setting)
460 {
461   switch (q)
462     {
463     case STC_ON:
464       *setting |= SET_ROUTE_DISABLE;
465       break;
466     case STC_OFF:
467       *setting &= ~SET_ROUTE_DISABLE;
468       break;
469     case STC_TERMINAL:
470       *setting &= ~(SET_ROUTE_LISTING | SET_ROUTE_OTHER);
471       *setting |= SET_ROUTE_SCREEN;
472       break;
473     case STC_LISTING:
474       *setting &= ~SET_ROUTE_SCREEN;
475       *setting |= SET_ROUTE_LISTING | SET_ROUTE_OTHER;
476       break;
477     case STC_BOTH:
478       *setting |= SET_ROUTE_SCREEN | SET_ROUTE_LISTING | SET_ROUTE_OTHER;
479       break;
480     case STC_NONE:
481       *setting &= ~(SET_ROUTE_SCREEN | SET_ROUTE_LISTING | SET_ROUTE_OTHER);
482       break;
483     default:
484       assert (0);
485     }
486 }
487
488 static int
489 stc_custom_pager (struct cmd_set *cmd UNUSED)
490 {
491   lex_match ('=');
492 #if !USE_INTERNAL_PAGER
493   if (lex_match_id ("OFF"))
494     {
495       if (set_pager)
496         free (set_pager);
497       set_pager = NULL;
498     }
499   else
500     {
501       if (!lex_force_string ())
502         return 0;
503       if (set_pager)
504         free (set_pager);
505       set_pager = xstrdup (ds_value (&tokstr));
506       lex_get ();
507     }
508   return 1;
509 #else /* USE_INTERNAL_PAGER */
510   if (match_id (OFF))
511     return 1;
512   msg (SW, "External pagers not supported.");
513   return 0;
514 #endif /* USE_INTERNAL_PAGER */
515 }
516
517 /* Parses the BLANKS subcommand, which controls the value that
518    completely blank fields in numeric data imply.  X, Wnd: Syntax is
519    SYSMIS or a numeric value; PC+: Syntax is '.', which is equivalent
520    to SYSMIS, or a numeric value. */
521 static int
522 stc_custom_blanks (struct cmd_set *cmd UNUSED)
523 {
524   lex_match ('=');
525   if ((token == T_ID && lex_id_match ("SYSMIS", tokid))
526       || (token == T_STRING && !strcmp (tokid, ".")))
527     {
528       lex_get ();
529       set_blanks = SYSMIS;
530     }
531   else
532     {
533       if (!lex_force_num ())
534         return 0;
535       set_blanks = tokval;
536       lex_get ();
537     }
538   return 1;
539 }
540
541 static int
542 stc_custom_length (struct cmd_set *cmd UNUSED)
543 {
544   int page_length;
545
546   lex_match ('=');
547   if (lex_match_id ("NONE"))
548     page_length = -1;
549   else
550     {
551       if (!lex_force_int ())
552         return 0;
553       if (lex_integer () < 1)
554         {
555           msg (SE, _("LENGTH must be at least 1."));
556           return 0;
557         }
558       page_length = lex_integer ();
559       lex_get ();
560     }
561
562   /* FIXME: Set page length. */
563   return 1;
564 }
565
566 static int
567 stc_custom_results (struct cmd_set *cmd UNUSED)
568 {
569   struct tuple
570     {   
571       const char *s;    
572       int v;
573     };
574
575   static struct tuple tab[] =
576     {
577       {"ON", STC_ON},
578       {"OFF", STC_OFF},
579       {"TERMINAL", STC_TERMINAL},
580       {"LISTING", STC_LISTING},
581       {"BOTH", STC_BOTH},
582       {"NONE", STC_NONE},
583       {NULL, 0},
584     };
585
586   struct tuple *t;
587
588   lex_match ('=');
589
590   if (token != T_ID)
591     {
592       msg (SE, _("Missing identifier in RESULTS subcommand."));
593       return 0;
594     }
595   
596   for (t = tab; t->s; t++)
597     if (lex_id_match (t->s, tokid))
598       {
599         lex_get ();
600         set_routing (t->v, &set_results);
601         return 1;
602       }
603   msg (SE, _("Unrecognized identifier in RESULTS subcommand."));
604   return 0;
605 }
606
607 static int
608 stc_custom_seed (struct cmd_set *cmd UNUSED)
609 {
610   lex_match ('=');
611   if (lex_match_id ("RANDOM"))
612     set_seed = NOT_LONG;
613   else
614     {
615       if (!lex_force_num ())
616         return 0;
617       set_seed = tokval;
618       lex_get ();
619     }
620   set_seed_used=1;
621   return 1;
622 }
623
624 static int
625 stc_custom_width (struct cmd_set *cmd UNUSED)
626 {
627   int page_width;
628
629   lex_match ('=');
630   if (lex_match_id ("NARROW"))
631     page_width = 79;
632   else if (lex_match_id ("WIDE"))
633     page_width = 131;
634   else
635     {
636       if (!lex_force_int ())
637         return 0;
638       if (lex_integer () < 1)
639         {
640           msg (SE, _("WIDTH must be at least 1."));
641           return 0;
642         }
643       page_width = lex_integer ();
644       lex_get ();
645     }
646
647   /* FIXME: Set page width. */
648   return 1;
649 }
650
651 /* Parses FORMAT subcommand, which consists of a numeric format
652    specifier. */
653 static int
654 stc_custom_format (struct cmd_set *cmd UNUSED)
655 {
656   struct fmt_spec fmt;
657
658   lex_match ('=');
659   if (!parse_format_specifier (&fmt, 0))
660     return 0;
661   if ((formats[fmt.type].cat & FCAT_STRING) != 0)
662     {
663       msg (SE, _("FORMAT requires numeric output format as an argument.  "
664                  "Specified format %s is of type string."),
665            fmt_to_string (&fmt));
666       return 0;
667     }
668
669   set_format = fmt;
670   return 1;
671 }
672
673 static int
674 stc_custom_journal (struct cmd_set *cmd UNUSED)
675 {
676   lex_match ('=');
677   if (lex_match_id ("ON"))
678     set_journaling = 1;
679   else if (lex_match_id ("OFF"))
680     set_journaling = 0;
681   if (token == T_STRING)
682     {
683       set_journal = xstrdup (ds_value (&tokstr));
684       lex_get ();
685     }
686   return 1;
687 }
688
689 /* Parses COLOR subcommand.  PC+: either ON or OFF or two or three
690    comma-delimited numbers inside parentheses. */
691 static int
692 stc_custom_color (struct cmd_set *cmd UNUSED)
693 {
694   msg (MW, _("%s is obsolete."),"COLOR");
695
696   lex_match ('=');
697   if (!lex_match_id ("ON") && !lex_match_id ("YES") && !lex_match_id ("OFF") && !lex_match_id ("NO"))
698     {
699       if (!lex_force_match ('('))
700         return 0;
701       if (!lex_match ('*'))
702         {
703           if (!lex_force_int ())
704             return 0;
705           if (lex_integer () < 0 || lex_integer () > 15)
706             {
707               msg (SE, _("Text color must be in range 0-15."));
708               return 0;
709             }
710           lex_get ();
711         }
712       if (!lex_force_match (','))
713         return 0;
714       if (!lex_match ('*'))
715         {
716           if (!lex_force_int ())
717             return 0;
718           if (lex_integer () < 0 || lex_integer () > 7)
719             {
720               msg (SE, _("Background color must be in range 0-7."));
721               return 0;
722             }
723           lex_get ();
724         }
725       if (lex_match (',') && !lex_match ('*'))
726         {
727           if (!lex_force_int ())
728             return 0;
729           if (lex_integer () < 0 || lex_integer () > 7)
730             {
731               msg (SE, _("Border color must be in range 0-7."));
732               return 0;
733             }
734           lex_get ();
735         }
736       if (!lex_force_match (')'))
737         return 0;
738     }
739   return 1;
740 }
741
742 static int
743 stc_custom_listing (struct cmd_set *cmd UNUSED)
744 {
745   lex_match ('=');
746   if (lex_match_id ("ON") || lex_match_id ("YES"))
747     outp_enable_device (1, OUTP_DEV_LISTING);
748   else if (lex_match_id ("OFF") || lex_match_id ("NO"))
749     outp_enable_device (0, OUTP_DEV_LISTING);
750   else
751     {
752       /* FIXME */
753     }
754
755   return 0;
756 }
757
758 static int
759 stc_custom_disk (struct cmd_set *cmd UNUSED)
760 {
761   stc_custom_listing (cmd);
762   return 0;
763 }
764
765 static int
766 stc_custom_log (struct cmd_set *cmd UNUSED)
767
768   stc_custom_journal (cmd);
769   return 0;
770 }
771
772 static int
773 stc_custom_rcolor (struct cmd_set *cmd UNUSED)
774 {
775   msg (SW, _("%s is obsolete."),"RCOLOR");
776
777   lex_match ('=');
778   if (!lex_force_match ('('))
779     return 0;
780
781   if (!lex_match ('*'))
782     {
783       if (!lex_force_int ())
784         return 0;
785       if (lex_integer () < 0 || lex_integer () > 6)
786         {
787           msg (SE, _("Lower window color must be between 0 and 6."));
788           return 0;
789         }
790       lex_get ();
791     }
792   if (!lex_force_match (','))
793     return 0;
794
795   if (!lex_match ('*'))
796     {
797       if (!lex_force_int ())
798         return 0;
799       if (lex_integer () < 0 || lex_integer () > 6)
800         {
801           msg (SE, _("Upper window color must be between 0 and 6."));
802           return 0;
803         }
804       lex_get ();
805     }
806
807   if (lex_match (',') && !lex_match ('*'))
808     {
809       if (!lex_force_int ())
810         return 0;
811       if (lex_integer () < 0 || lex_integer () > 6)
812         {
813           msg (SE, _("Frame color must be between 0 and 6."));
814           return 0;
815         }
816       lex_get ();
817     }
818   return 1;
819 }
820
821 static int
822 stc_custom_viewlength (struct cmd_set *cmd UNUSED)
823 {
824   if (lex_match_id ("MINIMUM"))
825     set_viewlength = 25;
826   else if (lex_match_id ("MEDIAN"))
827     set_viewlength = 43;        /* This is not correct for VGA displays. */
828   else if (lex_match_id ("MAXIMUM"))
829     set_viewlength = 43;
830   else
831     {
832       if (!lex_force_int ())
833         return 0;
834 #ifdef __MSDOS__
835       if (lex_integer () >= (43 + 25) / 2)
836         set_viewlength = 43;
837       else
838         set_viewlength = 25;
839 #else /* not dos */
840       set_viewlength = lex_integer ();
841 #endif /* not dos */
842       lex_get ();
843     }
844
845 #ifdef __MSDOS__
846   msg (SW, _("%s is not yet implemented."),"VIEWLENGTH");
847 #endif /* dos */
848   return 1;
849 }
850
851 static int
852 stc_custom_workdev (struct cmd_set *cmd UNUSED)
853 {
854   char c[2];
855
856   msg (SW, _("%s is obsolete."),"WORKDEV");
857
858   c[1] = 0;
859   for (*c = 'A'; *c <= 'Z'; (*c)++)
860     if (token == T_ID && lex_id_match (c, tokid))
861       {
862         lex_get ();
863         return 1;
864       }
865   msg (SE, _("Drive letter expected in WORKDEV subcommand."));
866   return 0;
867 }
868
869 /*
870    Local Variables:
871    mode: c
872    End:
873 */