/[pspp]/pspp/src/mis-val.c
ViewVC logotype

Diff of /pspp/src/mis-val.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.11 by blp, Sun Jul 31 21:42:46 2005 UTC revision 1.12 by blp, Sun Aug 7 04:39:28 2005 UTC
# Line 21  Line 21 
21  #include "error.h"  #include "error.h"
22  #include <stdlib.h>  #include <stdlib.h>
23  #include "command.h"  #include "command.h"
24    #include "data-in.h"
25  #include "error.h"  #include "error.h"
26  #include "lexer.h"  #include "lexer.h"
27  #include "magic.h"  #include "magic.h"
# Line 32  Line 33 
33    
34  #include "debug-print.h"  #include "debug-print.h"
35    
36  /* Variables on MIS VAL. */  static bool parse_number (double *, const struct fmt_spec *);
 static struct variable **v;  
 static int nv;  
   
 /* Type of the variables on MIS VAL. */  
 static int type;  
   
 /* Width of string variables on MIS VAL. */  
 static size_t width;  
   
 /* Items to fill-in var structs with. */  
 static int miss_type;  
 static union value missing[3];  
   
 static int parse_varnames (void);  
 static int parse_numeric (void);  
 static int parse_alpha (void);  
37    
38  int  int
39  cmd_missing_values (void)  cmd_missing_values (void)
40  {  {
41    int i;    struct variable **v;
42      int nv;
43    
44      int retval = CMD_PART_SUCCESS_MAYBE;
45      bool deferred_errors = false;
46    
47    while (token != '.')    while (token != '.')
48      {      {
49        if (!parse_varnames ())        int i;
50          goto fail;        
51    
52          if (!parse_variables (default_dict, &v, &nv, PV_NONE))
53            goto done;
54    
55        if (token != ')')        if (!lex_match ('('))
56          {          {
57            if ((type == NUMERIC && !parse_numeric ())            lex_error (_("expecting `('"));
58                || (type == ALPHA && !parse_alpha ()))            goto done;
59              goto fail;          }
         }  
       else  
         miss_type = MISSING_NONE;  
   
       if (!lex_match (')'))  
         {  
           msg (SE, _("`)' expected after value specification."));  
           goto fail;  
         }  
60    
61        for (i = 0; i < nv; i++)        for (i = 0; i < nv; i++)
62          {          mv_init (&v[i]->miss, v[i]->width);
63            v[i]->miss_type = miss_type;  
64            memcpy (v[i]->missing, missing, sizeof v[i]->missing);        if (!lex_match (')'))
65          }          {
66              struct missing_values mv;
67    
68              for (i = 0; i < nv; i++)
69                if (v[i]->type != v[0]->type)
70                  {
71                    const struct variable *n = v[0]->type == NUMERIC ? v[0] : v[i];
72                    const struct variable *s = v[0]->type == NUMERIC ? v[i] : v[0];
73                    msg (SE, _("Cannot mix numeric variables (e.g. %s) and "
74                               "string variables (e.g. %s) within a single list."),
75                         n->name, s->name);
76                    goto done;
77                  }
78    
79              if (v[0]->type == NUMERIC)
80                {
81                  mv_init (&mv, 0);
82                  while (!lex_match (')'))
83                    {
84                      double x;
85    
86                      if (lex_match_id ("LO") || lex_match_id ("LOWEST"))
87                        x = LOWEST;
88                      else if (!parse_number (&x, &v[0]->print))
89                        goto done;
90    
91                      if (lex_match_id ("THRU"))
92                        {
93                          double y;
94                          
95                          if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
96                            y = HIGHEST;
97                          else if (!parse_number (&y, &v[0]->print))
98                            goto done;
99    
100                          if (x == LOWEST && y == HIGHEST)
101                            {
102                              msg (SE, _("LO THRU HI is an invalid range."));
103                              deferred_errors = true;
104                            }
105                          else if (!mv_add_num_range (&mv, x, y))
106                            deferred_errors = true;
107                        }
108                      else
109                        {
110                          if (x == LOWEST)
111                            {
112                              msg (SE, _("LO or LOWEST must be part of a range."));
113                              deferred_errors = true;
114                            }
115                          else if (!mv_add_num (&mv, x))
116                            deferred_errors = true;
117                        }
118    
119                      lex_match (',');
120                    }
121                }
122              else
123                {
124                  mv_init (&mv, MAX_SHORT_STRING);
125                  while (!lex_match (')'))
126                    {
127                      if (!lex_force_string ())
128                        {
129                          deferred_errors = true;
130                          break;
131                        }
132    
133                      if (ds_length (&tokstr) > MAX_SHORT_STRING)
134                        {
135                          ds_truncate (&tokstr, MAX_SHORT_STRING);
136                          msg (SE, _("Truncating missing value to short string "
137                                     "length (%d characters)."),
138                               MAX_SHORT_STRING);
139                        }
140                      else
141                        ds_rpad (&tokstr, MAX_SHORT_STRING, ' ');
142    
143                      if (!mv_add_str (&mv, ds_data (&tokstr)))
144                        deferred_errors = true;
145    
146                      lex_get ();
147                      lex_match (',');
148                    }
149                }
150              
151              for (i = 0; i < nv; i++)
152                {
153                  if (!mv_is_resizable (&mv, v[i]->width))
154                    {
155                      msg (SE, _("Missing values provided are too long to assign "
156                                 "to variable of width %d."),
157                           v[i]->width);
158                      deferred_errors = true;
159                    }
160                  else
161                    {
162                      mv_copy (&v[i]->miss, &mv);
163                      mv_resize (&v[i]->miss, v[i]->width);
164                    }
165                }
166            }
167    
168        lex_match ('/');        lex_match ('/');
169        free (v);        free (v);
170          v = NULL;
171      }      }
172      retval = lex_end_of_command ();
173    return lex_end_of_command ();    
174     done:
 fail:  
175    free (v);    free (v);
176    return CMD_PART_SUCCESS_MAYBE;    if (deferred_errors)
177  }      retval = CMD_PART_SUCCESS_MAYBE;
178      return retval;
 static int  
 parse_varnames (void)  
 {  
   int i;  
   
   if (!parse_variables (default_dict, &v, &nv, PV_SAME_TYPE))  
     return 0;  
   if (!lex_match ('('))  
     {  
       msg (SE, _("`(' expected after variable name%s."), nv > 1 ? "s" : "");  
       return 0;  
     }  
   
   type = v[0]->type;  
   if (type == NUMERIC)  
     return 1;  
   
   width = v[0]->width;  
   for (i = 1; i < nv; i++)  
     if (v[i]->type == ALPHA && v[i]->nv != 1)  
       {  
         msg (SE, _("Long string value specified."));  
         return 0;  
       }  
     else if (v[i]->type == ALPHA && (int) width != v[i]->width)  
       {  
         msg (SE, _("Short strings must be of equal width."));  
         return 0;  
       }  
   
   return 1;  
179  }  }
180    
181  /* Number or range? */  static bool
182  enum  parse_number (double *x, const struct fmt_spec *f)
   {  
     MV_NOR_NOTHING,             /* Empty. */  
     MV_NOR_NUMBER,              /* Single number. */  
     MV_NOR_RANGE                /* Range. */  
   };  
   
 /* A single value or a range. */  
 struct num_or_range  
   {  
     int type;                   /* One of NOR_*. */  
     double d[2];                /* d[0]=lower bound or value, d[1]=upper bound. */  
   };  
   
 /* Parses something of the form <num>, or LO[WEST] THRU <num>, or  
    <num> THRU HI[GHEST], or <num> THRU <num>, and sets the appropriate  
    members of NOR.  Returns success. */  
 static int  
 parse_num_or_range (struct num_or_range * nor)  
183  {  {
184    if (lex_match_id ("LO") || lex_match_id ("LOWEST"))    if (lex_is_number ())
185      {      {
186        nor->type = MV_NOR_RANGE;        *x = lex_number ();
       if (!lex_force_match_id ("THRU"))  
         return 0;  
       if (!lex_force_num ())  
         return 0;  
       nor->d[0] = LOWEST;  
       nor->d[1] = tokval;  
     }  
   else if (lex_is_number ())  
     {  
       nor->d[0] = tokval;  
187        lex_get ();        lex_get ();
188          return true;
       if (lex_match_id ("THRU"))  
         {  
           nor->type = MV_NOR_RANGE;  
           if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))  
             nor->d[1] = HIGHEST;  
           else  
             {  
               if (!lex_force_num ())  
                 return 0;  
               nor->d[1] = tokval;  
               lex_get ();  
   
               if (nor->d[0] > nor->d[1])  
                 {  
                   msg (SE, _("Range %g THRU %g is not valid because %g is "  
                              "greater than %g."),  
                        nor->d[0], nor->d[1], nor->d[0], nor->d[1]);  
                   return 0;  
                 }  
             }  
         }  
       else  
         nor->type = MV_NOR_NUMBER;  
     }  
   else  
     return -1;  
   
   return 1;  
 }  
   
 /* Parses a set of numeric missing values and stores them into  
    `missing[]' and `miss_type' global variables. */  
 static int  
 parse_numeric (void)  
 {  
   struct num_or_range set[3];  
   int r;  
   
   set[1].type = set[2].type = MV_NOR_NOTHING;  
   
   /* Get first number or range. */  
   r = parse_num_or_range (&set[0]);  
   if (r < 1)  
     {  
       if (r == -1)  
         msg (SE, _("Number or range expected."));  
       return 0;  
     }  
   
   /* Get second and third optional number or range. */  
   lex_match (',');  
   r = parse_num_or_range (&set[1]);  
   if (r == 1)  
     {  
       lex_match (',');  
       r = parse_num_or_range (&set[2]);  
     }  
   if (r == 0)  
     return 0;  
   
   /* Force range, if present, into set[0]. */  
   if (set[1].type == MV_NOR_RANGE)  
     {  
       struct num_or_range t = set[1];  
       set[1] = set[0];  
       set[0] = t;  
     }  
   if (set[2].type == MV_NOR_RANGE)  
     {  
       struct num_or_range t = set[2];  
       set[2] = set[0];  
       set[0] = t;  
     }  
     
   /* Ensure there's not more than one range, or one range  
      plus one value. */  
   if (set[1].type == MV_NOR_RANGE || set[2].type == MV_NOR_RANGE)  
     {  
       msg (SE, _("At most one range can exist in the missing values "  
                  "for any one variable."));  
       return 0;  
189      }      }
190    if (set[0].type == MV_NOR_RANGE && set[2].type != MV_NOR_NOTHING)    else if (token == T_STRING)
191      {      {
192        msg (SE, _("At most one individual value can be missing along "        struct data_in di;
193                   "with one range."));        union value v;
194        return 0;        di.s = ds_data (&tokstr);
195      }        di.e = ds_end (&tokstr);
196          di.v = &v;
197    /* Set missing[] from set[]. */        di.flags = 0;
198    if (set[0].type == MV_NOR_RANGE)        di.f1 = 1;
199      {        di.f2 = ds_length (&tokstr);
200        int x = 0;        di.format = *f;
201          data_in (&di);
       if (set[0].d[0] == LOWEST)  
         {  
           miss_type = MISSING_LOW;  
           missing[x++].f = set[0].d[1];  
         }  
       else if (set[0].d[1] == HIGHEST)  
         {  
           miss_type = MISSING_HIGH;  
           missing[x++].f = set[0].d[0];  
         }  
       else  
         {  
           miss_type = MISSING_RANGE;  
           missing[x++].f = set[0].d[0];  
           missing[x++].f = set[0].d[1];  
         }  
   
       if (set[1].type == MV_NOR_NUMBER)  
         {  
           miss_type += 3;  
           missing[x].f = set[1].d[0];  
         }  
     }  
   else  
     {  
       if (set[0].type == MV_NOR_NUMBER)  
         {  
           miss_type = MISSING_1;  
           missing[0].f = set[0].d[0];  
         }  
       if (set[1].type == MV_NOR_NUMBER)  
         {  
           miss_type = MISSING_2;  
           missing[1].f = set[1].d[0];  
         }  
       if (set[2].type == MV_NOR_NUMBER)  
         {  
           miss_type = MISSING_3;  
           missing[2].f = set[2].d[0];  
         }  
     }  
   
   return 1;  
 }  
   
 static int  
 parse_alpha (void)  
 {  
   for (miss_type = 0; token == T_STRING && miss_type < 3; miss_type++)  
     {  
       if (ds_length (&tokstr) != width)  
         {  
           msg (SE, _("String is not of proper length."));  
           return 0;  
         }  
       strncpy (missing[miss_type].s, ds_c_str (&tokstr), MAX_SHORT_STRING);  
202        lex_get ();        lex_get ();
203        lex_match (',');        *x = v.f;
204          return true;
205      }      }
206    if (miss_type < 1)    else
207      {      {
208        msg (SE, _("String expected."));        lex_error (_("expecting number or data string"));
209        return 0;        return false;
210      }      }
   
   return 1;  
211  }  }
212    
 /* Copy the missing values from variable SRC to variable DEST. */  
 void  
 copy_missing_values (struct variable *dest, const struct variable *src)  
 {  
   static const int n_values[MISSING_COUNT] =  
     {  
       0, 1, 2, 3, 2, 1, 1, 3, 2, 2,  
     };  
       
   assert (dest->width == src->width);  
   assert (src->miss_type >= 0 && src->miss_type < MISSING_COUNT);  
     
   {  
     int i;  
   
     dest->miss_type = src->miss_type;  
     for (i = 0; i < n_values[src->miss_type]; i++)  
       if (src->type == NUMERIC)  
         dest->missing[i].f = src->missing[i].f;  
       else  
         memcpy (dest->missing[i].s, src->missing[i].s, src->width);  
   }  
 }  

Legend:
Removed from v.1.11  
changed lines
  Added in v.1.12

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26