Update all #include directives to the currently preferred style.
[pspp-builds.git] / src / language / data-io / placement-parser.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2006, 2010, 2011 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "language/data-io/placement-parser.h"
20
21 #include <assert.h>
22
23 #include "data/format.h"
24 #include "language/lexer/format-parser.h"
25 #include "language/lexer/lexer.h"
26 #include "libpspp/message.h"
27 #include "libpspp/pool.h"
28 #include "libpspp/str.h"
29
30 #include "gl/xalloc.h"
31 #include "gl/xsize.h"
32
33 #include "gettext.h"
34 #define _(msgid) gettext (msgid)
35
36 /* Extensions to the format specifiers used only for
37    placement. */
38 enum
39   {
40     PRS_TYPE_T = SCHAR_MAX - 3, /* Tab to absolute column. */
41     PRS_TYPE_X,                 /* Skip columns. */
42     PRS_TYPE_NEW_REC            /* Next record. */
43   };
44
45 static bool fixed_parse_columns (struct lexer *, struct pool *, size_t var_cnt, bool for_input,
46                                  struct fmt_spec **, size_t *);
47 static bool fixed_parse_fortran (struct lexer *l, struct pool *, bool for_input,
48                                  struct fmt_spec **, size_t *);
49
50 /* Parses Fortran-like or column-based specifications for placing
51    variable data in fixed positions in columns and rows, that is,
52    formats like those parsed by DATA LIST or PRINT.  Returns true
53    only if successful.
54
55    If successful, formats for VAR_CNT variables are stored in
56    *FORMATS, and the number of formats required is stored in
57    *FORMAT_CNT.  *FORMAT_CNT may be greater than VAR_CNT because
58    of T, X, and / "formats", but success guarantees that exactly
59    VAR_CNT variables will be placed by the output formats.  The
60    caller should call execute_placement_format to process those
61    "formats" in interpreting the output.
62
63    Uses POOL for allocation.  When the caller is finished
64    interpreting *FORMATS, POOL may be destroyed. */
65 bool
66 parse_var_placements (struct lexer *lexer, struct pool *pool, size_t var_cnt, bool for_input,
67                       struct fmt_spec **formats, size_t *format_cnt)
68 {
69   assert (var_cnt > 0);
70   if (lex_is_number (lexer))
71     return fixed_parse_columns (lexer, pool, var_cnt, for_input, formats, format_cnt);
72   else if (lex_match (lexer, T_LPAREN))
73     {
74       size_t assignment_cnt;
75       size_t i;
76
77       if (!fixed_parse_fortran (lexer, pool, for_input, formats, format_cnt))
78         return false;
79
80       assignment_cnt = 0;
81       for (i = 0; i < *format_cnt; i++)
82         assignment_cnt += (*formats)[i].type < FMT_NUMBER_OF_FORMATS;
83
84       if (assignment_cnt != var_cnt)
85         {
86           msg (SE, _("Number of variables specified (%zu) "
87                      "differs from number of variable formats (%zu)."),
88                var_cnt, assignment_cnt);
89           return false;
90         }
91
92       return true;
93     }
94   else
95     {
96       msg (SE, _("SPSS-like or Fortran-like format "
97                  "specification expected after variable names."));
98       return false;
99     }
100 }
101
102 /* Implements parse_var_placements for column-based formats. */
103 static bool
104 fixed_parse_columns (struct lexer *lexer, struct pool *pool, size_t var_cnt, bool for_input,
105                      struct fmt_spec **formats, size_t *format_cnt)
106 {
107   struct fmt_spec format;
108   int fc, lc;
109   size_t i;
110
111   if ( !parse_column_range (lexer, 1, &fc, &lc, NULL) )
112     return false;
113
114   /* Divide columns evenly. */
115   format.w = (lc - fc + 1) / var_cnt;
116   if ((lc - fc + 1) % var_cnt)
117     {
118       msg (SE, _("The %d columns %d-%d "
119                  "can't be evenly divided into %zu fields."),
120            lc - fc + 1, fc, lc, var_cnt);
121       return false;
122     }
123
124   /* Format specifier. */
125   if (lex_match (lexer, T_LPAREN))
126     {
127       /* Get format type. */
128       if (lex_token (lexer) == T_ID)
129         {
130           if (!parse_format_specifier_name (lexer, &format.type))
131             return false;
132           lex_match (lexer, T_COMMA);
133         }
134       else
135         format.type = FMT_F;
136
137       /* Get decimal places. */
138       if (lex_is_integer (lexer))
139         {
140           format.d = lex_integer (lexer);
141           lex_get (lexer);
142         }
143       else
144         format.d = 0;
145
146       if (!lex_force_match (lexer, T_RPAREN))
147         return false;
148     }
149   else
150     {
151       format.type = FMT_F;
152       format.d = 0;
153     }
154   if (!fmt_check (&format, for_input))
155     return false;
156
157   *formats = pool_nalloc (pool, var_cnt + 1, sizeof **formats);
158   *format_cnt = var_cnt + 1;
159   (*formats)[0].type = PRS_TYPE_T;
160   (*formats)[0].w = fc;
161   for (i = 1; i <= var_cnt; i++)
162     (*formats)[i] = format;
163   return true;
164 }
165
166 /* Implements parse_var_placements for Fortran-like formats. */
167 static bool
168 fixed_parse_fortran (struct lexer *lexer, struct pool *pool, bool for_input,
169                      struct fmt_spec **formats, size_t *format_cnt)
170 {
171   size_t formats_allocated = 0;
172   size_t formats_used = 0;
173
174   *formats = NULL;
175   while (!lex_match (lexer, T_RPAREN))
176     {
177       struct fmt_spec f;
178       struct fmt_spec *new_formats;
179       size_t new_format_cnt;
180       size_t count;
181       size_t formats_needed;
182
183       /* Parse count. */
184       if (lex_is_integer (lexer))
185         {
186           count = lex_integer (lexer);
187           lex_get (lexer);
188         }
189       else
190         count = 1;
191
192       /* Parse format specifier. */
193       if (lex_match (lexer, T_LPAREN))
194         {
195           /* Call ourselves recursively to handle parentheses. */
196           if (!fixed_parse_fortran (lexer, pool, for_input,
197                                     &new_formats, &new_format_cnt))
198             return false;
199         }
200       else
201         {
202           new_formats = &f;
203           new_format_cnt = 1;
204           if (lex_match (lexer, T_SLASH))
205             f.type = PRS_TYPE_NEW_REC;
206           else
207             {
208               char type[FMT_TYPE_LEN_MAX + 1];
209
210               if (!parse_abstract_format_specifier (lexer, type, &f.w, &f.d))
211                 return false;
212
213               if (!strcasecmp (type, "T"))
214                 f.type = PRS_TYPE_T;
215               else if (!strcasecmp (type, "X"))
216                 {
217                   f.type = PRS_TYPE_X;
218                   f.w = count;
219                   count = 1;
220                 }
221               else
222                 {
223                   if (!fmt_from_name (type, &f.type))
224                     {
225                       msg (SE, _("Unknown format type `%s'."), type);
226                       return false;
227                     }
228                   if (!fmt_check (&f, for_input))
229                     return false;
230                 }
231             }
232         }
233
234       /* Add COUNT copies of the NEW_FORMAT_CNT formats in
235          NEW_FORMATS to FORMATS. */
236       if (new_format_cnt != 0
237           && size_overflow_p (xtimes (xsum (formats_used,
238                                             xtimes (count, new_format_cnt)),
239                                       sizeof *formats)))
240         xalloc_die ();
241       formats_needed = count * new_format_cnt;
242       if (formats_used + formats_needed > formats_allocated)
243         {
244           formats_allocated = formats_used + formats_needed;
245           *formats = pool_2nrealloc (pool, *formats, &formats_allocated,
246                                      sizeof **formats);
247         }
248       for (; count > 0; count--)
249         {
250           memcpy (&(*formats)[formats_used], new_formats,
251                   sizeof **formats * new_format_cnt);
252           formats_used += new_format_cnt;
253         }
254
255       lex_match (lexer, T_COMMA);
256     }
257
258   *format_cnt = formats_used;
259   return true;
260 }
261
262 /* Checks whether FORMAT represents one of the special "formats"
263    for T, X, or /.  If so, updates *RECORD or *COLUMN (or both)
264    as appropriate, and returns true.  Otherwise, returns false
265    without any side effects. */
266 bool
267 execute_placement_format (const struct fmt_spec *format,
268                           int *record, int *column)
269 {
270   switch (format->type)
271     {
272     case PRS_TYPE_X:
273       *column += format->w;
274       return true;
275
276     case PRS_TYPE_T:
277       *column = format->w;
278       return true;
279
280     case PRS_TYPE_NEW_REC:
281       (*record)++;
282       *column = 1;
283       return true;
284
285     default:
286       assert (format->type < FMT_NUMBER_OF_FORMATS);
287       return false;
288     }
289 }
290
291 /* Parses a BASE-based column using LEXER.  Returns true and
292    stores a 1-based column number into *COLUMN if successful,
293    otherwise emits an error message and returns false. */
294 static bool
295 parse_column (int value, int base, int *column)
296 {
297   assert (base == 0 || base == 1);
298   *column = value - base + 1;
299   if (*column < 1)
300     {
301       if (base == 1)
302         msg (SE, _("Column positions for fields must be positive."));
303       else
304         msg (SE, _("Column positions for fields must not be negative."));
305       return false;
306     }
307   return true;
308 }
309
310 /* Parse a column or a range of columns, specified as a single
311    integer or two integers delimited by a dash.  Stores the range
312    in *FIRST_COLUMN and *LAST_COLUMN.  (If only a single integer
313    is given, it is stored in both.)  If RANGE_SPECIFIED is
314    non-null, then *RANGE_SPECIFIED is set to true if the syntax
315    contained a dash, false otherwise.  Returns true if
316    successful, false if the syntax was invalid or the values
317    specified did not make sense.
318
319    If BASE is 0, zero-based column numbers are parsed; if BASE is
320    1, 1-based column numbers are parsed.  Regardless of BASE, the
321    values stored in *FIRST_COLUMN and *LAST_COLUMN are
322    1-based. */
323 bool
324 parse_column_range (struct lexer *lexer, int base,
325                     int *first_column, int *last_column,
326                     bool *range_specified)
327 {
328   /* First column. */
329   if (!lex_force_int (lexer)
330       || !parse_column (lex_integer (lexer), base, first_column))
331     return false;
332   lex_get (lexer);
333
334   /* Last column. */
335   if (lex_is_integer (lexer) && lex_integer (lexer) < 0)
336     {
337       if (!parse_column (-lex_integer (lexer), base, last_column))
338         return false;
339       lex_get (lexer);
340
341       if (*last_column < *first_column)
342         {
343           msg (SE, _("The ending column for a field must be "
344                      "greater than the starting column."));
345           return false;
346         }
347
348       if (range_specified)
349         *range_specified = true;
350     }
351   else
352     {
353       *last_column = *first_column;
354       if (range_specified)
355         *range_specified = false;
356     }
357
358   return true;
359 }
360
361 /* Parses a (possibly empty) sequence of slashes, each of which
362    may be followed by an integer.  A slash on its own increases
363    *RECORD by 1 and sets *COLUMN to 1.  A slash followed by an
364    integer sets *RECORD to the integer, as long as that increases
365    *RECORD, and sets *COLUMN to 1.
366
367    Returns true if successful, false on syntax error. */
368 bool
369 parse_record_placement (struct lexer *lexer, int *record, int *column)
370 {
371   while (lex_match (lexer, T_SLASH))
372     {
373       if (lex_is_integer (lexer))
374         {
375           if (lex_integer (lexer) <= *record)
376             {
377               msg (SE, _("The record number specified, %ld, is at or "
378                          "before the previous record, %d.  Data "
379                          "fields must be listed in order of "
380                          "increasing record number."),
381                    lex_integer (lexer), *record);
382               return false;
383             }
384           *record = lex_integer (lexer);
385           lex_get (lexer);
386         }
387       else
388         (*record)++;
389       *column = 1;
390     }
391   assert (*record >= 1);
392
393   return true;
394 }