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