c789a16b52e5c22da4d2b8b28dcc46a38e718d5a
[pspp] / src / language / data-io / placement-parser.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2006, 2010, 2011, 2012 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/c-strcase.h"
31 #include "gl/xalloc.h"
32 #include "gl/xsize.h"
33
34 #include "gettext.h"
35 #define _(msgid) gettext (msgid)
36
37 /* Extensions to the format specifiers used only for
38    placement. */
39 enum
40   {
41     PRS_TYPE_T = SCHAR_MAX - 3, /* Tab to absolute column. */
42     PRS_TYPE_X,                 /* Skip columns. */
43     PRS_TYPE_NEW_REC            /* Next record. */
44   };
45
46 static bool fixed_parse_columns (struct lexer *, struct pool *, size_t n_vars,
47                                  enum fmt_use, struct fmt_spec **, size_t *);
48 static bool fixed_parse_fortran (struct lexer *l, struct pool *, enum fmt_use,
49                                  struct fmt_spec **, size_t *);
50
51 /* Parses Fortran-like or column-based specifications for placing
52    variable data in fixed positions in columns and rows, that is,
53    formats like those parsed by DATA LIST or PRINT.  Returns true
54    only if successful.
55
56    The formats parsed are either input or output formats, according
57    to USE.
58
59    If USE is FMT_FOR_INPUT, then T, X, and / "formats" are parsed,
60    in addition to regular formats.  If USE is FMT_FOR_OUTPUT, then
61    T and X "formats" are parsed but not /.
62
63    If successful, formats for N_VARS variables are stored in
64    *FORMATS, and the number of formats required is stored in
65    *FORMAT_CNT.  *FORMAT_CNT may be greater than N_VARS because
66    of T, X, and / "formats", but success guarantees that exactly
67    N_VARS variables will be placed by the output formats.  The
68    caller should call execute_placement_format to process those
69    "formats" in interpreting the output.
70
71    Uses POOL for allocation.  When the caller is finished
72    interpreting *FORMATS, POOL may be destroyed. */
73 bool
74 parse_var_placements (struct lexer *lexer, struct pool *pool, size_t n_vars,
75                       enum fmt_use use,
76                       struct fmt_spec **formats, size_t *n_formats)
77 {
78   assert (n_vars > 0);
79   if (lex_is_number (lexer))
80     return fixed_parse_columns (lexer, pool, n_vars, use,
81                                 formats, n_formats);
82   else if (lex_match (lexer, T_LPAREN))
83     {
84       size_t n_assignments;
85       size_t i;
86
87       if (!fixed_parse_fortran (lexer, pool, use, formats, n_formats))
88         return false;
89
90       n_assignments = 0;
91       for (i = 0; i < *n_formats; i++)
92         n_assignments += (*formats)[i].type < FMT_NUMBER_OF_FORMATS;
93
94       if (n_assignments != n_vars)
95         {
96           msg (SE, _("Number of variables specified (%zu) "
97                      "differs from number of variable formats (%zu)."),
98                n_vars, n_assignments);
99           return false;
100         }
101
102       return true;
103     }
104   else
105     {
106       lex_error (lexer, _("SPSS-like or Fortran-like format "
107                           "specification expected after variable names."));
108       return false;
109     }
110 }
111
112 /* Implements parse_var_placements for column-based formats. */
113 static bool
114 fixed_parse_columns (struct lexer *lexer, struct pool *pool, size_t n_vars,
115                      enum fmt_use use,
116                      struct fmt_spec **formats, size_t *n_formats)
117 {
118   int start_ofs = lex_ofs (lexer);
119
120   int fc, lc;
121   if (!parse_column_range (lexer, 1, &fc, &lc, NULL))
122     return false;
123
124   /* Divide columns evenly. */
125   int w = (lc - fc + 1) / n_vars;
126   if ((lc - fc + 1) % n_vars)
127     {
128       msg (SE, _("The %d columns %d-%d "
129                  "can't be evenly divided into %zu fields."),
130            lc - fc + 1, fc, lc, n_vars);
131       return false;
132     }
133
134   /* Format specifier. */
135   enum fmt_type type;
136   int d;
137   if (lex_match (lexer, T_LPAREN))
138     {
139       /* Get format type. */
140       if (lex_token (lexer) == T_ID)
141         {
142           if (!parse_format_specifier_name (lexer, &type))
143             return false;
144           lex_match (lexer, T_COMMA);
145         }
146       else
147         type = FMT_F;
148
149       /* Get decimal places. */
150       if (lex_is_integer (lexer))
151         {
152           d = lex_integer (lexer);
153           lex_get (lexer);
154         }
155       else
156         d = 0;
157
158       if (!lex_force_match (lexer, T_RPAREN))
159         return false;
160     }
161   else
162     {
163       type = FMT_F;
164       d = 0;
165     }
166   int end_ofs = lex_ofs (lexer) - 1;
167
168   struct fmt_spec format = { .type = type, .w = w, .d = d };
169   char *error = fmt_check__ (&format, use);
170   if (error)
171     {
172       lex_ofs_error (lexer, start_ofs, end_ofs, "%s", error);
173       free (error);
174       return false;
175     }
176
177   *formats = pool_nalloc (pool, n_vars + 1, sizeof **formats);
178   *n_formats = n_vars + 1;
179   (*formats)[0].type = (enum fmt_type) PRS_TYPE_T;
180   (*formats)[0].w = fc;
181   for (size_t i = 1; i <= n_vars; i++)
182     (*formats)[i] = format;
183   return true;
184 }
185
186 /* Implements parse_var_placements for Fortran-like formats. */
187 static bool
188 fixed_parse_fortran (struct lexer *lexer, struct pool *pool, enum fmt_use use,
189                      struct fmt_spec **formats, size_t *n_formats)
190 {
191   size_t formats_allocated = 0;
192   size_t formats_used = 0;
193
194   *formats = NULL;
195   while (!lex_match (lexer, T_RPAREN))
196     {
197       struct fmt_spec f;
198       struct fmt_spec *new_formats;
199       size_t n_new_formats;
200       size_t count;
201       size_t formats_needed;
202
203       /* Parse count. */
204       if (lex_is_integer (lexer))
205         {
206           count = lex_integer (lexer);
207           lex_get (lexer);
208         }
209       else
210         count = 1;
211
212       /* Parse format specifier. */
213       if (lex_match (lexer, T_LPAREN))
214         {
215           /* Call ourselves recursively to handle parentheses. */
216           if (!fixed_parse_fortran (lexer, pool, use,
217                                     &new_formats, &n_new_formats))
218             return false;
219         }
220       else
221         {
222           new_formats = &f;
223           n_new_formats = 1;
224           if (use == FMT_FOR_INPUT && lex_match (lexer, T_SLASH))
225             f.type = (enum fmt_type) PRS_TYPE_NEW_REC;
226           else
227             {
228               int ofs = lex_ofs (lexer);
229               char type[FMT_TYPE_LEN_MAX + 1];
230               if (!parse_abstract_format_specifier (lexer, type, &f.w, &f.d))
231                 return false;
232
233               if (!c_strcasecmp (type, "T"))
234                 f.type = (enum fmt_type) PRS_TYPE_T;
235               else if (!c_strcasecmp (type, "X"))
236                 {
237                   f.type = (enum fmt_type) PRS_TYPE_X;
238                   f.w = count;
239                   count = 1;
240                 }
241               else
242                 {
243                   if (!fmt_from_name (type, &f.type))
244                     {
245                       lex_ofs_error (lexer, ofs, ofs,
246                                      _("Unknown format type `%s'."), type);
247                       return false;
248                     }
249                   char *error = fmt_check__ (&f, use);
250                   if (error)
251                     {
252                       lex_ofs_error (lexer, ofs, ofs, "%s", error);
253                       free (error);
254                       return false;
255                     }
256                 }
257             }
258         }
259
260       /* Add COUNT copies of the NEW_FORMAT_CNT formats in
261          NEW_FORMATS to FORMATS. */
262       if (n_new_formats != 0
263           && size_overflow_p (xtimes (xsum (formats_used,
264                                             xtimes (count, n_new_formats)),
265                                       sizeof *formats)))
266         xalloc_die ();
267       formats_needed = count * n_new_formats;
268       if (formats_used + formats_needed > formats_allocated)
269         {
270           formats_allocated = formats_used + formats_needed;
271           *formats = pool_2nrealloc (pool, *formats, &formats_allocated,
272                                      sizeof **formats);
273         }
274       for (; count > 0; count--)
275         {
276           memcpy (&(*formats)[formats_used], new_formats,
277                   sizeof **formats * n_new_formats);
278           formats_used += n_new_formats;
279         }
280
281       lex_match (lexer, T_COMMA);
282     }
283
284   *n_formats = formats_used;
285   return true;
286 }
287
288 /* Checks whether FORMAT represents one of the special "formats"
289    for T, X, or /.  If so, updates *RECORD or *COLUMN (or both)
290    as appropriate, and returns true.  Otherwise, returns false
291    without any side effects. */
292 bool
293 execute_placement_format (const struct fmt_spec *format,
294                           int *record, int *column)
295 {
296   switch ((int) format->type)
297     {
298     case PRS_TYPE_X:
299       *column += format->w;
300       return true;
301
302     case PRS_TYPE_T:
303       *column = format->w;
304       return true;
305
306     case PRS_TYPE_NEW_REC:
307       (*record)++;
308       *column = 1;
309       return true;
310
311     default:
312       assert (format->type < FMT_NUMBER_OF_FORMATS);
313       return false;
314     }
315 }
316
317 static bool
318 parse_column__ (struct lexer *lexer, bool negative, int base, int *column)
319 {
320   assert (base == 0 || base == 1);
321
322   if (!lex_force_int (lexer))
323     return false;
324   long int value = lex_integer (lexer);
325   if (negative)
326     value = -value;
327   lex_get (lexer);
328
329   *column = value - base + 1;
330   if (*column < 1)
331     {
332       if (base == 1)
333         lex_next_error (lexer, -1, -1,
334                         _("Column positions for fields must be positive."));
335       else
336         lex_next_error (lexer, -1, -1,
337                         _("Column positions for fields must not be negative."));
338       return false;
339     }
340   return true;
341 }
342
343 /* Parses a BASE-based column using LEXER.  Returns true and
344    stores a 1-based column number into *COLUMN if successful,
345    otherwise emits an error message and returns false.
346
347    If BASE is 0, zero-based column numbers are parsed; if BASE is
348    1, 1-based column numbers are parsed.  Regardless of BASE, the
349    values stored in *FIRST_COLUMN and *LAST_COLUMN are
350    1-based. */
351 bool
352 parse_column (struct lexer *lexer, int base, int *column)
353 {
354   return parse_column__ (lexer, false, base, column);
355 }
356
357 /* Parse a column or a range of columns, specified as a single
358    integer or two integers delimited by a dash.  Stores the range
359    in *FIRST_COLUMN and *LAST_COLUMN.  (If only a single integer
360    is given, it is stored in both.)  If RANGE_SPECIFIED is
361    non-null, then *RANGE_SPECIFIED is set to true if the syntax
362    contained a dash, false otherwise.  Returns true if
363    successful, false if the syntax was invalid or the values
364    specified did not make sense.
365
366    If BASE is 0, zero-based column numbers are parsed; if BASE is
367    1, 1-based column numbers are parsed.  Regardless of BASE, the
368    values stored in *FIRST_COLUMN and *LAST_COLUMN are
369    1-based. */
370 bool
371 parse_column_range (struct lexer *lexer, int base,
372                     int *first_column, int *last_column,
373                     bool *range_specified)
374 {
375   int start_ofs = lex_ofs (lexer);
376
377   /* First column. */
378   if (!parse_column__ (lexer, false, base, first_column))
379     return false;
380
381   /* Last column. */
382   if (lex_is_integer (lexer) && lex_integer (lexer) < 0)
383     {
384       if (!parse_column__ (lexer, true, base, last_column))
385         return false;
386
387       if (*last_column < *first_column)
388         {
389           lex_ofs_error (lexer, start_ofs, lex_ofs (lexer) - 1,
390                          _("The ending column for a field must be "
391                            "greater than the starting column."));
392           return false;
393         }
394
395       if (range_specified)
396         *range_specified = true;
397     }
398   else
399     {
400       *last_column = *first_column;
401       if (range_specified)
402         *range_specified = false;
403     }
404
405   return true;
406 }
407
408 /* Parses a (possibly empty) sequence of slashes, each of which
409    may be followed by an integer.  A slash on its own increases
410    *RECORD by 1 and sets *COLUMN to 1.  A slash followed by an
411    integer sets *RECORD to the integer, as long as that increases
412    *RECORD, and sets *COLUMN to 1.
413
414    Returns true if successful, false on syntax error. */
415 bool
416 parse_record_placement (struct lexer *lexer, int *record, int *column)
417 {
418   while (lex_match (lexer, T_SLASH))
419     {
420       if (lex_is_number (lexer))
421         {
422           if (!lex_force_int_range (lexer, NULL, *record + 1, INT_MAX))
423             return false;
424           *record = lex_integer (lexer);
425           lex_get (lexer);
426         }
427       else
428         (*record)++;
429       *column = 1;
430     }
431   assert (*record >= 1);
432
433   return true;
434 }