* Bug #13468 fixed - Fileio: Scilab hanged when incorrect format was used for file...
[scilab.git] / scilab / modules / fileio / src / c / do_xxscanf.c
index 40bc682..34709de 100644 (file)
@@ -2,12 +2,15 @@
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
  * Copyright (C) INRIA
  * ...
- * 
- * This file must be used under the terms of the CeCILL.
- * This source file is licensed as described in the file COPYING, which
- * you should have received as part of this distribution.  The terms
- * are also available at    
- * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
+ *
+ * Copyright (C) 2012 - 2016 - Scilab Enterprises
+ *
+ * This file is hereby licensed under the terms of the GNU GPL v2.0,
+ * pursuant to article 5.3.4 of the CeCILL v.2.1.
+ * This file was originally licensed under the terms of the CeCILL v2.1,
+ * and continues to be available under such terms.
+ * For more information, see the COPYING file which you should have received
+ * along with this program.
  *
  */
 /*--------------------------------------------------------------------------*/
 #include <ctype.h>              /* isdigit */
 #include <string.h>
 #include "BOOL.h"
-#include "MALLOC.h"
+#include "sci_malloc.h"
 #include "do_xxscanf.h"
 #include "Scierror.h"
 #include "localization.h"
-#include "do_xxprintf.h"
 #include "core_math.h"
+#include "os_string.h"
 /*--------------------------------------------------------------------------*/
-typedef int (*XXSCANF) (FILE *, wchar_t *, ...);
-typedef int (*FLUSH) (FILE *);
+typedef int (*XXSCANF) (FILE* , char* , ...);
+typedef int (*FLUSH) (FILE*);
 
 /*--------------------------------------------------------------------------*/
-static void set_xxscanf(FILE * fp, XXSCANF * xxscanf, wchar_t **target, wchar_t **strv)
+static void set_xxscanf(FILE* fp, XXSCANF* xxscanf, char** target, wchar_t* strv)
 {
     if (fp == (FILE *) 0)
     {
-        *target = *strv;
-        *xxscanf = (XXSCANF) swscanf;
+        *target = wide_string_to_UTF8(strv);
+        *xxscanf = (XXSCANF) sscanf;
     }
     else
     {
-        *target = (wchar_t *)fp;
-        *xxscanf = (XXSCANF) fwscanf;
+        *target = (char*)fp;
+        *xxscanf = (XXSCANF) fscanf;
+    }
+}
+static void delete_target(FILE* fp, char* target)
+{
+    if (target && fp == (FILE *) 0)
+    {
+        FREE(target);
     }
 }
-
 /*--------------------------------------------------------------------------*/
-int do_xxscanf (wchar_t *fname, FILE *fp, wchar_t *format, int *nargs, wchar_t *strv, int *retval, rec_entry *buf, sfdir *type)
+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)
 {
     int nc[MAXSCAN];
     int n_directive_count = 0;
@@ -55,33 +64,35 @@ int do_xxscanf (wchar_t *fname, FILE *fp, wchar_t *format, int *nargs, wchar_t *
     int width_flag = 0;
     int width_val = 0;
     int ignore_flag = 0;
-    int str_width_flag = 0;
+    int str_flag = 0;
     int num_conversion = -1;
     void *ptrtab[MAXSCAN];
     wchar_t sformat[MAX_STR];
     wchar_t backupcurrrentchar;
     wchar_t directive;
     wchar_t *p1 = NULL;
-    wchar_t *target = NULL;
+    char* target = NULL;
     wchar_t *sval = NULL;
     register wchar_t *currentchar = NULL;
+    char* strFormat = NULL;
 
     XXSCANF xxscanf;
 
-    set_xxscanf(fp, &xxscanf, &target, &strv);
+    set_xxscanf(fp, &xxscanf, &target, strv);
     currentchar = format;
     *retval = 0;
 
     while (TRUE)
     {
         /* scanf */
-        while (*currentchar != '%' && *currentchar != '\0')
+        while (*currentchar != L'%' && *currentchar != L'\0')
+        {
             currentchar++;
-        if (*currentchar == '%' && *(currentchar + 1) == '%')
+        }
+        if (*currentchar == L'%' && *(currentchar + 1) == L'%')
         {
             currentchar = currentchar + 2;
-            while (*currentchar != '%' && *currentchar != '\0')
-                currentchar++;
+            continue;
         }
 
         if (*currentchar == 0)
@@ -93,15 +104,16 @@ int do_xxscanf (wchar_t *fname, FILE *fp, wchar_t *format, int *nargs, wchar_t *
         p1 = currentchar - 1;
 
         while (isdigit(((int)*currentchar)))
+        {
             currentchar++;
+        }
 
         width_flag = 0;
 
         if (p1 + 1 != currentchar)
         {
             wchar_t w = *currentchar;
-
-            *currentchar = '\0';
+            *currentchar = L'\0';
             width_flag = 1;
             swscanf(p1 + 1, L"%d", &width_val);
             *currentchar = w;
@@ -109,7 +121,7 @@ int do_xxscanf (wchar_t *fname, FILE *fp, wchar_t *format, int *nargs, wchar_t *
 
         ignore_flag = 0;
 
-        if (*currentchar == '*')
+        if (*currentchar == L'*')
         {
             ignore_flag = 1;
             currentchar++;
@@ -119,12 +131,12 @@ int do_xxscanf (wchar_t *fname, FILE *fp, wchar_t *format, int *nargs, wchar_t *
             l_flag = h_flag = 0;
         }
 
-        if (*currentchar == 'l')
+        if (*currentchar == L'l')
         {
             currentchar++;
             l_flag = 1;
         }
-        else if (*currentchar == 'h')
+        else if (*currentchar == L'h')
         {
             currentchar++;
             h_flag = 1;
@@ -134,27 +146,33 @@ int do_xxscanf (wchar_t *fname, FILE *fp, wchar_t *format, int *nargs, wchar_t *
 
         directive = *currentchar++;
 
-        if (directive == '[')
+        if (directive == L'[')
         {
             wchar_t *currentchar1 = currentchar--;
 
-            while (*currentchar1 != '\0' && *currentchar1 != ']')
+            while (*currentchar1 != L'\0' && *currentchar1 != L']')
+            {
                 currentchar1++;
+            }
 
-            if (*currentchar1 == '\0')
+            if (*currentchar1 == L'\0')
             {
+                delete_target(fp, target);
                 Scierror(998, _("%s: An error occurred: %s\n"), fname, _("unclosed [ directive."));
                 return DO_XXPRINTF_RET_BUG;
             }
 
-            if (currentchar1 == currentchar +1 || wcsncmp(currentchar,"[^]", 3) == 0)
+            if (currentchar1 == currentchar + 1 || wcsncmp(currentchar, L"[^]", 3) == 0)
             {
                 currentchar1++;
-                while (*currentchar1 != '\0' && *currentchar1 != ']')
+                while (*currentchar1 != L'\0' && *currentchar1 != L']')
+                {
                     currentchar1++;
+                }
 
-                if (*currentchar1 == '\0')
+                if (*currentchar1 == L'\0')
                 {
+                    delete_target(fp, target);
                     Scierror(998, _("%s: An error occurred: %s\n"), fname, _("unclosed [ directive."));
                     return DO_XXPRINTF_RET_BUG;
                 }
@@ -172,202 +190,233 @@ int do_xxscanf (wchar_t *fname, FILE *fp, wchar_t *format, int *nargs, wchar_t *
 
             if (num_conversion >= MAXSCAN)
             {
+                delete_target(fp, target);
                 Scierror(998, _("%s: An error occurred: too many (> %d) conversion required.\n"), fname, MAXSCAN);
                 return DO_XXPRINTF_RET_BUG;
             }
 
             switch (directive)
             {
-            case ']':
-                if (width_flag == 0)
-                    str_width_flag = 1;
-
-                if (width_flag == 1 && width_val > MAX_STR - 1)
-                {
-                    Scierror(998, _("%s: An error occurred: field %d is too long (> %d) for %%[ directive.\n"), fname, width_val, MAX_STR - 1);
-                    return DO_XXPRINTF_RET_BUG;
-                }
-
-                if ((buf[num_conversion].c = MALLOC(MAX_STR)) == NULL)
-                    return DO_XXPRINTF_MEM_LACK;
-                ptrtab[num_conversion] = buf[num_conversion].c;
-                type[num_conversion] = SF_S;
-                break;
-
-            case 's':
-                if (l_flag + h_flag)
-                {
-                    Scierror(998, _("%s: An error occurred: %s\n"), fname, _("Bad conversion."));
-                    return DO_XXPRINTF_RET_BUG;
-                }
-
-                if (width_flag == 0)
-                    str_width_flag = 1;
-                if (width_flag == 1 && width_val > MAX_STR - 1)
-                {
-                    Scierror(998, _("%s: An error occurred: field %d is too long (< %d) for %%s directive.\n"), fname, width_val, MAX_STR - 1);
-                    return DO_XXPRINTF_RET_BUG;
-                }
-
-                if ((buf[num_conversion].c = MALLOC(MAX_STR)) == NULL)
-                    return DO_XXPRINTF_MEM_LACK;
-
-                ptrtab[num_conversion] = buf[num_conversion].c;
-                type[num_conversion] = SF_S;
-                break;
-
-            case 'c':
-                if (l_flag + h_flag)
-                {
-                    Scierror(998, _("%s: An error occurred: %s\n"), fname, _("Bad conversion."));
-                    return DO_XXPRINTF_RET_BUG;
-                }
-
-                if (width_flag == 1)
-                    nc[num_conversion] = width_val;
-                else
-                    nc[num_conversion] = 1;
-
-                if (width_flag == 1 && width_val > MAX_STR - 1)
-                {
-                    Scierror(998, _("%s: An error occurred: field %d is too long (< %d) for %%c directive.\n"), fname, width_val, MAX_STR - 1);
-                    return DO_XXPRINTF_RET_BUG;
-                }
-
-                if ((buf[num_conversion].c = MALLOC(MAX_STR)) == NULL)
-                    return DO_XXPRINTF_MEM_LACK;
-
-                ptrtab[num_conversion] = buf[num_conversion].c;
-                type[num_conversion] = SF_C;
-                break;
-
-            case 'o':
-            case 'u':
-            case 'x':
-            case 'X':
-                if (l_flag)
-                {
-                    ptrtab[num_conversion] = &buf[num_conversion].lui;
-                    type[num_conversion] = SF_LUI;
-                }
-                else if (h_flag)
-                {
-                    ptrtab[num_conversion] = &buf[num_conversion].sui;
-                    type[num_conversion] = SF_SUI;
-                }
-                else
-                {
-                    ptrtab[num_conversion] = &buf[num_conversion].ui;
-                    type[num_conversion] = SF_UI;
-                }
-                break;
-
-            case 'D':
-                ptrtab[num_conversion] = &buf[num_conversion].li;
-                type[num_conversion] = SF_LI;
-                break;
-
-            case 'n':
-                n_directive_count++;
-
-            case 'i':
-            case 'd':
-                if (l_flag)
-                {
+                case L']':
+                    str_flag = 1;
+
+                    if (width_flag == 1 && width_val > MAX_STR - 1)
+                    {
+                        delete_target(fp, target);
+                        Scierror(998, _("%s: An error occurred: field %d is too long (> %d) for %%[ directive.\n"), fname, width_val, MAX_STR - 1);
+                        return DO_XXPRINTF_RET_BUG;
+                    }
+
+                    if ((buf[num_conversion].c = (wchar_t*)MALLOC(MAX_STR * sizeof(wchar_t))) == NULL)
+                    {
+                        delete_target(fp, target);
+                        return DO_XXPRINTF_MEM_LACK;
+                    }
+                    ptrtab[num_conversion] = buf[num_conversion].c;
+                    type[num_conversion] = SF_S;
+                    break;
+
+                case L's':
+                    if (l_flag + h_flag)
+                    {
+                        delete_target(fp, target);
+                        Scierror(998, _("%s: An error occurred: %s\n"), fname, _("Bad conversion."));
+                        return DO_XXPRINTF_RET_BUG;
+                    }
+
+                    str_flag = 1;
+                    if (width_flag == 1 && width_val > MAX_STR - 1)
+                    {
+                        delete_target(fp, target);
+                        Scierror(998, _("%s: An error occurred: field %d is too long (< %d) for %%s directive.\n"), fname, width_val, MAX_STR - 1);
+                        return DO_XXPRINTF_RET_BUG;
+                    }
+
+                    if ((buf[num_conversion].c = (wchar_t*)MALLOC(MAX_STR * sizeof(wchar_t))) == NULL)
+                    {
+                        delete_target(fp, target);
+                        return DO_XXPRINTF_MEM_LACK;
+                    }
+
+                    ptrtab[num_conversion] = buf[num_conversion].c;
+                    type[num_conversion] = SF_S;
+                    break;
+
+                case L'c':
+                    str_flag = 1;
+                    if (l_flag + h_flag)
+                    {
+                        delete_target(fp, target);
+                        Scierror(998, _("%s: An error occurred: %s\n"), fname, _("Bad conversion."));
+                        return DO_XXPRINTF_RET_BUG;
+                    }
+
+                    if (width_flag == 1)
+                    {
+                        nc[num_conversion] = width_val;
+                    }
+                    else
+                    {
+                        nc[num_conversion] = 1;
+                    }
+
+                    if (width_flag == 1 && width_val > MAX_STR - 1)
+                    {
+                        delete_target(fp, target);
+                        Scierror(998, _("%s: An error occurred: field %d is too long (< %d) for %%c directive.\n"), fname, width_val, MAX_STR - 1);
+                        return DO_XXPRINTF_RET_BUG;
+                    }
+
+                    if ((buf[num_conversion].c = (wchar_t*)MALLOC(MAX_STR * sizeof(wchar_t))) == NULL)
+                    {
+                        delete_target(fp, target);
+                        return DO_XXPRINTF_MEM_LACK;
+                    }
+
+                    ptrtab[num_conversion] = buf[num_conversion].c;
+                    type[num_conversion] = SF_C;
+                    break;
+
+                case L'o':
+                case L'u':
+                case L'x':
+                case L'X':
+                    if (l_flag)
+                    {
+                        ptrtab[num_conversion] = &buf[num_conversion].lui;
+                        type[num_conversion] = SF_LUI;
+                    }
+                    else if (h_flag)
+                    {
+                        ptrtab[num_conversion] = &buf[num_conversion].sui;
+                        type[num_conversion] = SF_SUI;
+                    }
+                    else
+                    {
+                        ptrtab[num_conversion] = &buf[num_conversion].ui;
+                        type[num_conversion] = SF_UI;
+                    }
+                    break;
+
+                case L'D':
                     ptrtab[num_conversion] = &buf[num_conversion].li;
                     type[num_conversion] = SF_LI;
-                }
-                else if (h_flag)
-                {
-                    ptrtab[num_conversion] = &buf[num_conversion].si;
-                    type[num_conversion] = SF_SI;
-                }
-                else
-                {
-                    ptrtab[num_conversion] = &buf[num_conversion].i;
-                    type[num_conversion] = SF_I;
-                }
-                break;
-
-            case 'e':
-            case 'f':
-            case 'g':
-            case 'E':
-            case 'G':
-                if (h_flag)
+                    break;
+
+                case L'n':
+                    n_directive_count++;
+                    //pass to next statement
+
+                case L'i':
+                case L'd':
+                    if (l_flag)
+                    {
+                        ptrtab[num_conversion] = &buf[num_conversion].li;
+                        type[num_conversion] = SF_LI;
+                    }
+                    else if (h_flag)
+                    {
+                        ptrtab[num_conversion] = &buf[num_conversion].si;
+                        type[num_conversion] = SF_SI;
+                    }
+                    else
+                    {
+                        ptrtab[num_conversion] = &buf[num_conversion].i;
+                        type[num_conversion] = SF_I;
+                    }
+                    break;
+
+                case L'e':
+                case L'f':
+                case L'g':
+                case L'E':
+                case L'G':
+                    if (h_flag)
+                    {
+                        delete_target(fp, target);
+                        Scierror(998, _("%s: An error occurred: %s\n"), fname, _("Bad conversion."));
+                        return DO_XXPRINTF_RET_BUG;
+                    }
+                    else if (l_flag)
+                    {
+                        ptrtab[num_conversion] = &buf[num_conversion].lf;
+                        type[num_conversion] = SF_LF;
+                    }
+                    else
+                    {
+                        ptrtab[num_conversion] = &buf[num_conversion].f;
+                        type[num_conversion] = SF_F;
+                    }
+                    break;
+
+                default:
                 {
+                    delete_target(fp, target);
                     Scierror(998, _("%s: An error occurred: %s\n"), fname, _("Bad conversion."));
                     return DO_XXPRINTF_RET_BUG;
                 }
-                else if (l_flag)
-                {
-                    ptrtab[num_conversion] = &buf[num_conversion].lf;
-                    type[num_conversion] = SF_LF;
-                }
-                else
-                {
-                    ptrtab[num_conversion] = &buf[num_conversion].f;
-                    type[num_conversion] = SF_F;
-                }
-                break;
-
-            default:
-                Scierror(998, _("%s: An error occurred: %s\n"), fname, _("Bad conversion."));
-                return DO_XXPRINTF_RET_BUG;
             }
             *currentchar = backupcurrrentchar;
         }
     }
 
-    if ( str_width_flag == 1)
+    // replace %s by %ls
+    if (str_flag)
     {
         wchar_t *f1 = format;
         wchar_t *f2 = sformat;
         wchar_t *slast = sformat + MAX_STR - 1 - 4;
 
-        int bFirst = 1;
-        while (*f1 != '\0')
+        int bFirst = 0;
+        while (*f1 != L'\0')
         {
             int n;
-            if(*(f1) == '%')
+            if (*(f1) == L'%')
             {
                 bFirst = 1;
             }
             *f2++ = *f1++;
-            if(bFirst && ( *(f1) == 's'  || *(f1) == '[' || *(f1) == 'c'))
+            while (isdigit(((int)*f1)))
+            {
+                *f2++ = *f1++;
+            }
+
+            if (bFirst && ( *(f1) == L's'  || *(f1) == L'[' || *(f1) == L'c'))
             {
                 bFirst = 0;
-                if(*(f1-1) != 'l' && *(f1-1) != 'L')
+                if (*(f1 - 1) != L'l' && *(f1 - 1) != L'L')
                 {
                     *f2++  = L'l';
                 }
             }
-            if( (*(f1) == 's' || *(f1) == '[')
-                &&
-                (   (*(f1-1) == '%')
-                    ||
-                    ((*(f1-1) == 'l' || *(f1-1) == 'L') && (*(f1-2) == '%'))
-                )
-              )
+            if ( (*(f1) == L's' || *(f1) == L'[')
+                    &&
+                    (   (*(f1 - 1) == L'%')
+                        ||
+                        ((*(f1 - 1) == L'l' || *(f1 - 1) == L'L') && (*(f1 - 2) == L'%'))
+                    )
+               )
             {
                 f2--;
-                n=swprintf(f2, MAX_STR - 1, L"%d%c", MAX_STR - 1, L'l');
+                n = os_swprintf(f2, MAX_STR - 1, L"%d%c", MAX_STR - 1, L'l');
                 f2 += n;
                 *f2++ = *f1++;
             }
 
             if (f2 == slast)
             {
+                delete_target(fp, target);
                 Scierror(998, _("%s: An error occurred: format is too long (> %d).\n"), fname, MAX_STR - 1);
                 return DO_XXPRINTF_RET_BUG;
             }
         }
 
-        *f2 = '\0';
+        *f2 = L'\0';
         format = sformat;
     }
 
-    *retval = (*xxscanf) ((VPTR) target, format,
+    strFormat = wide_string_to_UTF8(format);
+    *retval = (*xxscanf) ((VPTR) target, strFormat,
                           ptrtab[0], ptrtab[1], ptrtab[2], ptrtab[3], ptrtab[4], ptrtab[5], ptrtab[6], ptrtab[7], ptrtab[8], ptrtab[9],
                           ptrtab[10], ptrtab[11], ptrtab[12], ptrtab[13], ptrtab[14], ptrtab[15], ptrtab[16], ptrtab[17], ptrtab[18], ptrtab[19],
                           ptrtab[20], ptrtab[21], ptrtab[22], ptrtab[23], ptrtab[24], ptrtab[25], ptrtab[26], ptrtab[27], ptrtab[28], ptrtab[29],
@@ -379,6 +428,8 @@ int do_xxscanf (wchar_t *fname, FILE *fp, wchar_t *format, int *nargs, wchar_t *
                           ptrtab[80], ptrtab[81], ptrtab[82], ptrtab[83], ptrtab[84], ptrtab[85], ptrtab[86], ptrtab[87], ptrtab[88], ptrtab[89],
                           ptrtab[90], ptrtab[91], ptrtab[92], ptrtab[93], ptrtab[94], ptrtab[95], ptrtab[96], ptrtab[97], ptrtab[98],
                           ptrtab[MAXSCAN - 1]);
+    FREE(strFormat);
+    delete_target(fp, target);
 
     *nargs = Min(num_conversion + 1, Max(*retval + n_directive_count, 0));
 
@@ -387,10 +438,14 @@ int do_xxscanf (wchar_t *fname, FILE *fp, wchar_t *format, int *nargs, wchar_t *
         if (type[i - 1] == SF_C)
         {
             sval = (wchar_t *)ptrtab[i - 1];
-            sval[nc[i - 1]] = '\0';
+            sval[nc[i - 1]] = L'\0';
         }
     }
 
+    if (*retval == 0)
+    {
+        return DO_XXPRINTF_MISMATCH;
+    }
     return 0;
 }