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