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