Merge remote-tracking branch 'origin/master' into windows
[scilab.git] / scilab / modules / fileio / src / c / do_xxscanf.c
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) INRIA
4  * ...
5  *
6  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  *
15  */
16 /*--------------------------------------------------------------------------*/
17 #if defined(__linux__)
18 #define _GNU_SOURCE             /* Bug 5673 fix: avoid dependency on GLIBC_2.7 */
19 #endif
20
21 #include <stdio.h>
22 #include <ctype.h>              /* isdigit */
23 #include <string.h>
24 #include "BOOL.h"
25 #include "sci_malloc.h"
26 #include "do_xxscanf.h"
27 #include "Scierror.h"
28 #include "localization.h"
29 #include "core_math.h"
30 #include "os_string.h"
31 /*--------------------------------------------------------------------------*/
32 typedef int (*XXSCANF) (FILE* , char* , ...);
33 typedef int (*FLUSH) (FILE*);
34
35 /*--------------------------------------------------------------------------*/
36 static void set_xxscanf(FILE* fp, XXSCANF* xxscanf, char** target, char* strv)
37 {
38     if (fp == (FILE *) 0)
39     {
40         *target = strv;
41         *xxscanf = (XXSCANF) sscanf;
42     }
43     else
44     {
45         *target = (char*)fp;
46         *xxscanf = (XXSCANF) fscanf;
47     }
48 }
49 static void delete_target(FILE* fp, char* target)
50 {
51     if (target && fp == (FILE *) 0)
52     {
53         //FREE(target);
54     }
55 }
56 /*--------------------------------------------------------------------------*/
57 int do_xxscanf (const char *fname, FILE *fp, char *format, int *nargs, char *strv, int *retval, rec_entry *buf, sfdir *type)
58 {
59     int nc[MAXSCAN];
60     int n_directive_count = 0;
61     int i = 0;
62     int l_flag = 0;
63     int h_flag = 0;
64     int width_flag = 0;
65     int width_val = 0;
66     int ignore_flag = 0;
67     int str_flag = 0;
68     int num_conversion = -1;
69     void *ptrtab[MAXSCAN];
70     char sformat[MAX_STR];
71     char backupcurrrentchar;
72     char directive;
73     char *p1 = NULL;
74     char* target = NULL;
75     char* sval = NULL;
76     register char* currentchar = NULL;
77
78     XXSCANF xxscanf;
79
80     set_xxscanf(fp, &xxscanf, &target, strv);
81     currentchar = format;
82     *retval = 0;
83
84     while (TRUE)
85     {
86         /* scanf */
87         while (*currentchar != '%' && *currentchar != '\0')
88         {
89             currentchar++;
90         }
91         if (*currentchar == '%' && *(currentchar + 1) == '%')
92         {
93             currentchar = currentchar + 2;
94             continue;
95         }
96
97         if (*currentchar == 0)
98         {
99             break;
100         }
101
102         currentchar++;
103         p1 = currentchar - 1;
104
105         while (isdigit(((int)*currentchar)))
106         {
107             currentchar++;
108         }
109
110         width_flag = 0;
111
112         if (p1 + 1 != currentchar)
113         {
114             char w = *currentchar;
115             *currentchar = '\0';
116             width_flag = 1;
117             sscanf(p1 + 1, "%d", &width_val);
118             *currentchar = w;
119         }
120
121         ignore_flag = 0;
122
123         if (*currentchar == '*')
124         {
125             ignore_flag = 1;
126             currentchar++;
127         }
128         else
129         {
130             l_flag = h_flag = 0;
131         }
132
133         if (*currentchar == 'l')
134         {
135             currentchar++;
136             l_flag = 1;
137         }
138         else if (*currentchar == 'h')
139         {
140             currentchar++;
141             h_flag = 1;
142         }
143
144         /* directive points to the scan directive  */
145
146         directive = *currentchar++;
147
148         if (directive == '[')
149         {
150             char* currentchar1 = currentchar--;
151
152             while (*currentchar1 != '\0' && *currentchar1 != ']')
153             {
154                 currentchar1++;
155             }
156
157             if (*currentchar1 == '\0')
158             {
159                 delete_target(fp, target);
160                 Scierror(998, _("%s: An error occurred: %s\n"), fname, _("unclosed [ directive."));
161                 return DO_XXPRINTF_RET_BUG;
162             }
163
164             if (currentchar1 == currentchar + 1 || strncmp(currentchar, "[^]", 3) == 0)
165             {
166                 currentchar1++;
167                 while (*currentchar1 != '\0' && *currentchar1 != ']')
168                 {
169                     currentchar1++;
170                 }
171
172                 if (*currentchar1 == '\0')
173                 {
174                     delete_target(fp, target);
175                     Scierror(998, _("%s: An error occurred: %s\n"), fname, _("unclosed [ directive."));
176                     return DO_XXPRINTF_RET_BUG;
177                 }
178             }
179
180             directive = *currentchar1++;
181             currentchar = currentchar1;
182         }
183
184         backupcurrrentchar = *currentchar;
185
186         if (ignore_flag != 1)
187         {
188             num_conversion++;
189
190             if (num_conversion >= MAXSCAN)
191             {
192                 delete_target(fp, target);
193                 Scierror(998, _("%s: An error occurred: too many (> %d) conversion required.\n"), fname, MAXSCAN);
194                 return DO_XXPRINTF_RET_BUG;
195             }
196
197             switch (directive)
198             {
199                 case ']':
200                     str_flag = 1;
201
202                     if (width_flag == 1 && width_val > MAX_STR - 1)
203                     {
204                         delete_target(fp, target);
205                         Scierror(998, _("%s: An error occurred: field %d is too long (> %d) for %%[ directive.\n"), fname, width_val, MAX_STR - 1);
206                         return DO_XXPRINTF_RET_BUG;
207                     }
208
209                     if ((buf[num_conversion].c = (char*)MALLOC(MAX_STR * sizeof(char))) == NULL)
210                     {
211                         delete_target(fp, target);
212                         return DO_XXPRINTF_MEM_LACK;
213                     }
214                     ptrtab[num_conversion] = buf[num_conversion].c;
215                     type[num_conversion] = SF_S;
216                     break;
217
218                 case 's':
219                     if (l_flag + h_flag)
220                     {
221                         delete_target(fp, target);
222                         Scierror(998, _("%s: An error occurred: %s\n"), fname, _("Bad conversion."));
223                         return DO_XXPRINTF_RET_BUG;
224                     }
225
226                     str_flag = 1;
227                     if (width_flag == 1 && width_val > MAX_STR - 1)
228                     {
229                         delete_target(fp, target);
230                         Scierror(998, _("%s: An error occurred: field %d is too long (< %d) for %%s directive.\n"), fname, width_val, MAX_STR - 1);
231                         return DO_XXPRINTF_RET_BUG;
232                     }
233
234                     if ((buf[num_conversion].c = (char*)MALLOC(MAX_STR * sizeof(char))) == NULL)
235                     {
236                         delete_target(fp, target);
237                         return DO_XXPRINTF_MEM_LACK;
238                     }
239
240                     ptrtab[num_conversion] = buf[num_conversion].c;
241                     type[num_conversion] = SF_S;
242                     break;
243
244                 case 'c':
245                     str_flag = 1;
246                     if (l_flag + h_flag)
247                     {
248                         delete_target(fp, target);
249                         Scierror(998, _("%s: An error occurred: %s\n"), fname, _("Bad conversion."));
250                         return DO_XXPRINTF_RET_BUG;
251                     }
252
253                     if (width_flag == 1)
254                     {
255                         nc[num_conversion] = width_val;
256                     }
257                     else
258                     {
259                         nc[num_conversion] = 1;
260                     }
261
262                     if (width_flag == 1 && width_val > MAX_STR - 1)
263                     {
264                         delete_target(fp, target);
265                         Scierror(998, _("%s: An error occurred: field %d is too long (< %d) for %%c directive.\n"), fname, width_val, MAX_STR - 1);
266                         return DO_XXPRINTF_RET_BUG;
267                     }
268
269                     if ((buf[num_conversion].c = (char*)MALLOC(MAX_STR * sizeof(char))) == NULL)
270                     {
271                         delete_target(fp, target);
272                         return DO_XXPRINTF_MEM_LACK;
273                     }
274
275                     ptrtab[num_conversion] = buf[num_conversion].c;
276                     type[num_conversion] = SF_C;
277                     break;
278
279                 case 'o':
280                 case 'u':
281                 case 'x':
282                 case 'X':
283                     if (l_flag)
284                     {
285                         ptrtab[num_conversion] = &buf[num_conversion].lui;
286                         type[num_conversion] = SF_LUI;
287                     }
288                     else if (h_flag)
289                     {
290                         ptrtab[num_conversion] = &buf[num_conversion].sui;
291                         type[num_conversion] = SF_SUI;
292                     }
293                     else
294                     {
295                         ptrtab[num_conversion] = &buf[num_conversion].ui;
296                         type[num_conversion] = SF_UI;
297                     }
298                     break;
299
300                 case 'D':
301                     ptrtab[num_conversion] = &buf[num_conversion].li;
302                     type[num_conversion] = SF_LI;
303                     break;
304
305                 case 'n':
306                     n_directive_count++;
307                     //pass to next statement
308
309                 case 'i':
310                 case 'd':
311                     if (l_flag)
312                     {
313                         ptrtab[num_conversion] = &buf[num_conversion].li;
314                         type[num_conversion] = SF_LI;
315                     }
316                     else if (h_flag)
317                     {
318                         ptrtab[num_conversion] = &buf[num_conversion].si;
319                         type[num_conversion] = SF_SI;
320                     }
321                     else
322                     {
323                         ptrtab[num_conversion] = &buf[num_conversion].i;
324                         type[num_conversion] = SF_I;
325                     }
326                     break;
327
328                 case 'e':
329                 case 'f':
330                 case 'g':
331                 case 'E':
332                 case 'G':
333                     if (h_flag)
334                     {
335                         delete_target(fp, target);
336                         Scierror(998, _("%s: An error occurred: %s\n"), fname, _("Bad conversion."));
337                         return DO_XXPRINTF_RET_BUG;
338                     }
339                     else if (l_flag)
340                     {
341                         ptrtab[num_conversion] = &buf[num_conversion].lf;
342                         type[num_conversion] = SF_LF;
343                     }
344                     else
345                     {
346                         ptrtab[num_conversion] = &buf[num_conversion].f;
347                         type[num_conversion] = SF_F;
348                     }
349                     break;
350
351                 default:
352                 {
353                     delete_target(fp, target);
354                     Scierror(998, _("%s: An error occurred: %s\n"), fname, _("Bad conversion."));
355                     return DO_XXPRINTF_RET_BUG;
356                 }
357             }
358             *currentchar = backupcurrrentchar;
359         }
360     }
361
362     // replace %s by %ls
363     if (str_flag)
364     {
365         char *f1 = format;
366         char *f2 = sformat;
367         char *slast = sformat + MAX_STR - 1 - 4;
368
369         int bFirst = 1;
370         while (*f1 != '\0')
371         {
372             int n;
373             if (*(f1) == '%')
374             {
375                 bFirst = 1;
376             }
377             *f2++ = *f1++;
378             while (isdigit(((int)*f1)))
379             {
380                 *f2++ = *f1++;
381             }
382
383             if (bFirst && ( *(f1) == 's'  || *(f1) == '[' || *(f1) == 'c'))
384             {
385                 bFirst = 0;
386                 if (*(f1 - 1) != L'l' && *(f1 - 1) != L'L')
387                 {
388                     *f2++  = L'l';
389                 }
390             }
391             if ( (*(f1) == 's' || *(f1) == '[')
392                     &&
393                     (   (*(f1 - 1) == '%')
394                         ||
395                         ((*(f1 - 1) == 'l' || *(f1 - 1) == 'L') && (*(f1 - 2) == '%'))
396                     )
397                )
398             {
399                 f2--;
400                 n = os_sprintf(f2, MAX_STR - 1, "%d%c", MAX_STR - 1, 'l');
401                 f2 += n;
402                 *f2++ = *f1++;
403             }
404
405             if (f2 == slast)
406             {
407                 delete_target(fp, target);
408                 Scierror(998, _("%s: An error occurred: format is too long (> %d).\n"), fname, MAX_STR - 1);
409                 return DO_XXPRINTF_RET_BUG;
410             }
411         }
412
413         *f2 = '\0';
414         format = sformat;
415     }
416
417     *retval = (*xxscanf) ((VPTR) target, format,
418                           ptrtab[0], ptrtab[1], ptrtab[2], ptrtab[3], ptrtab[4], ptrtab[5], ptrtab[6], ptrtab[7], ptrtab[8], ptrtab[9],
419                           ptrtab[10], ptrtab[11], ptrtab[12], ptrtab[13], ptrtab[14], ptrtab[15], ptrtab[16], ptrtab[17], ptrtab[18], ptrtab[19],
420                           ptrtab[20], ptrtab[21], ptrtab[22], ptrtab[23], ptrtab[24], ptrtab[25], ptrtab[26], ptrtab[27], ptrtab[28], ptrtab[29],
421                           ptrtab[30], ptrtab[31], ptrtab[32], ptrtab[33], ptrtab[34], ptrtab[35], ptrtab[36], ptrtab[37], ptrtab[38], ptrtab[39],
422                           ptrtab[40], ptrtab[41], ptrtab[42], ptrtab[43], ptrtab[44], ptrtab[45], ptrtab[46], ptrtab[47], ptrtab[48], ptrtab[49],
423                           ptrtab[50], ptrtab[51], ptrtab[52], ptrtab[53], ptrtab[54], ptrtab[55], ptrtab[56], ptrtab[57], ptrtab[58], ptrtab[59],
424                           ptrtab[60], ptrtab[61], ptrtab[62], ptrtab[63], ptrtab[64], ptrtab[65], ptrtab[66], ptrtab[67], ptrtab[68], ptrtab[69],
425                           ptrtab[70], ptrtab[71], ptrtab[72], ptrtab[73], ptrtab[74], ptrtab[75], ptrtab[76], ptrtab[77], ptrtab[78], ptrtab[79],
426                           ptrtab[80], ptrtab[81], ptrtab[82], ptrtab[83], ptrtab[84], ptrtab[85], ptrtab[86], ptrtab[87], ptrtab[88], ptrtab[89],
427                           ptrtab[90], ptrtab[91], ptrtab[92], ptrtab[93], ptrtab[94], ptrtab[95], ptrtab[96], ptrtab[97], ptrtab[98],
428                           ptrtab[MAXSCAN - 1]);
429     delete_target(fp, target);
430
431     *nargs = Min(num_conversion + 1, Max(*retval + n_directive_count, 0));
432
433     for (i = 1; i <= *nargs; i++)
434     {
435         if (type[i - 1] == SF_C)
436         {
437             sval = (char *)ptrtab[i - 1];
438             sval[nc[i - 1]] = '\0';
439         }
440     }
441
442     if (*retval == 0)
443     {
444         return DO_XXPRINTF_MISMATCH;
445     }
446     return 0;
447 }
448
449 /*--------------------------------------------------------------------------*/