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