Sat Dec 27 16:16:49 2003 Ben Pfaff <blp@gnu.org>
[pspp-builds.git] / src / val-labs.c
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 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include "alloc.h"
24 #include "command.h"
25 #include "error.h"
26 #include "hash.h"
27 #include "lexer.h"
28 #include "str.h"
29 #include "value-labels.h"
30 #include "var.h"
31 \f
32 /* Declarations. */
33
34 #include "debug-print.h"
35
36 /* Variable list. */
37 static struct variable **v;
38
39 /* Number of variables. */
40 static int nv;
41
42 static int do_value_labels (int);
43 static int verify_val_labs (int erase);
44 static int get_label (void);
45
46 #if DEBUGGING
47 static void debug_print (void);
48 #endif
49 \f
50 /* Stubs. */
51
52 static void
53 init (void)
54 {
55   v = NULL;
56 }
57
58 static void
59 done (void)
60 {
61   free (v);
62 }
63
64 int
65 cmd_value_labels (void)
66 {
67   int code;
68   init ();
69   lex_match_id ("VALUE");
70   lex_match_id ("LABELS");
71   code = do_value_labels (1);
72   done ();
73   return code;
74 }
75
76 int
77 cmd_add_value_labels (void)
78 {
79   int code;
80   lex_match_id ("ADD");
81   lex_match_id ("VALUE");
82   lex_match_id ("LABELS");
83   code = do_value_labels (0);
84   done ();
85   return code;
86 }
87 \f
88 /* Do it. */
89
90 static int
91 do_value_labels (int erase)
92 {
93   lex_match ('/');
94   
95   while (token != '.')
96     {
97       parse_variables (default_dict, &v, &nv, PV_SAME_TYPE);
98       if (!verify_val_labs (erase))
99         return CMD_PART_SUCCESS_MAYBE;
100       while (token != '/' && token != '.')
101         if (!get_label ())
102           return CMD_PART_SUCCESS_MAYBE;
103
104       if (token != '/')
105         break;
106       lex_get ();
107
108       free (v);
109       v = NULL;
110     }
111
112   if (token != '.')
113     {
114       lex_error (NULL);
115       return CMD_TRAILING_GARBAGE;
116     }
117
118 #if 0 && DEBUGGING
119   debug_print ();
120 #endif
121   return CMD_SUCCESS;
122 }
123
124 static int
125 verify_val_labs (int erase)
126 {
127   int i;
128
129   if (!nv)
130     return 1;
131
132   for (i = 0; i < nv; i++)
133     {
134       struct variable *vp = v[i];
135
136       if (vp->type == ALPHA && vp->width > 8)
137         {
138           msg (SE, _("It is not possible to assign value labels to long "
139                      "string variables such as %s."), vp->name);
140           return 0;
141         }
142
143       if (erase)
144         val_labs_clear (vp->val_labs);
145     }
146   return 1;
147 }
148
149 /* Parse all the labels for a particular set of variables and add the
150    specified labels to those variables. */
151 static int
152 get_label (void)
153 {
154   int i;
155
156   /* Make sure there's some variables. */
157   if (!nv)
158     {
159       if (token != T_STRING && token != T_NUM)
160         return 0;
161       lex_get ();
162       return 1;
163     }
164
165   /* Parse all the labels and add them to the variables. */
166   do
167     {
168       union value value;
169       char *label;
170
171       /* Set value. */
172       if (v[0]->type == ALPHA)
173         {
174           if (token != T_STRING)
175             {
176               msg (SE, _("String expected for value."));
177               return 0;
178             }
179           st_bare_pad_copy (value.s, ds_value (&tokstr), MAX_SHORT_STRING);
180         }
181       else
182         {
183           if (token != T_NUM)
184             {
185               msg (SE, _("Number expected for value."));
186               return 0;
187             }
188           if (!lex_integer_p ())
189             msg (SW, _("Value label `%g' is not integer."), tokval);
190           value.f = tokval;
191         }
192
193       /* Set label. */
194       lex_get ();
195       if (!lex_force_string ())
196         return 0;
197       if (ds_length (&tokstr) > 60)
198         {
199           msg (SW, _("Truncating value label to 60 characters."));
200           ds_truncate (&tokstr, 60);
201         }
202       label = ds_value (&tokstr);
203
204       for (i = 0; i < nv; i++)
205         val_labs_replace (v[i]->val_labs, value, label);
206
207       lex_get ();
208     }
209   while (token != '/' && token != '.');
210
211   return 1;
212 }
213
214 #if 0 && DEBUGGING
215 static void
216 debug_print ()
217 {
218   int i;
219
220   puts (_("Value labels:"));
221   for (i = 0; i < nvar; i++)
222     {
223       struct hsh_iterator i;
224       struct value_label *val;
225
226       printf ("  %s\n", var[i]->name);
227       if (var[i]->val_lab) 
228         {
229           for (val = hsh_first (var[i]->val_lab, &i); val != NULL;
230                val = hsh_next (var[i]->val_lab, &i))
231             if (var[i]->type == NUMERIC)
232               printf ("    %g:  `%s'\n", val->v.f, val->s);
233             else
234               printf ("    `%.8s':  `%s'\n", val->v.s, val->s); 
235         }
236       else
237         printf (_("    (no value labels)\n"));
238     }
239 }
240 #endif /* DEBUGGING */