* Bug #13468 fixed - Fileio: Scilab hanged when incorrect format was used for file...
[scilab.git] / scilab / modules / fileio / src / c / do_xxscanf.c
index 7272aa5..34709de 100644 (file)
@@ -3,11 +3,14 @@
  * 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.1-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 *, char *, ...);
-typedef int (*FLUSH) (FILE *);
+typedef int (*XXSCANF) (FILE* , char* , ...);
+typedef int (*FLUSH) (FILE*);
 
 /*--------------------------------------------------------------------------*/
-static void set_xxscanf(FILE * fp, XXSCANF * xxscanf, char **target, char **strv)
+static void set_xxscanf(FILE* fp, XXSCANF* xxscanf, char** target, wchar_t* strv)
 {
     if (fp == (FILE *) 0)
     {
-        *target = *strv;
+        *target = wide_string_to_UTF8(strv);
         *xxscanf = (XXSCANF) sscanf;
     }
     else
     {
-        *target = (char *)fp;
+        *target = (char*)fp;
         *xxscanf = (XXSCANF) fscanf;
     }
 }
-
+static void delete_target(FILE* fp, char* target)
+{
+    if (target && fp == (FILE *) 0)
+    {
+        FREE(target);
+    }
+}
 /*--------------------------------------------------------------------------*/
-int do_xxscanf(char *fname, FILE * fp, char *format, int *nargs, char *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,37 +64,35 @@ int do_xxscanf(char *fname, FILE * fp, char *format, int *nargs, char *strv, int
     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];
-    char sformat[MAX_STR];
-    char backupcurrrentchar;
-    char directive;
-    char *p1 = NULL;
-    char *target = NULL;
-    char *sval = NULL;
-    register char *currentchar = NULL;
+    wchar_t sformat[MAX_STR];
+    wchar_t backupcurrrentchar;
+    wchar_t directive;
+    wchar_t *p1 = 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)
@@ -105,17 +112,16 @@ int do_xxscanf(char *fname, FILE * fp, char *format, int *nargs, char *strv, int
 
         if (p1 + 1 != currentchar)
         {
-            char w = *currentchar;
-
-            *currentchar = '\0';
+            wchar_t w = *currentchar;
+            *currentchar = L'\0';
             width_flag = 1;
-            sscanf(p1 + 1, "%d", &width_val);
+            swscanf(p1 + 1, L"%d", &width_val);
             *currentchar = w;
         }
 
         ignore_flag = 0;
 
-        if (*currentchar == '*')
+        if (*currentchar == L'*')
         {
             ignore_flag = 1;
             currentchar++;
@@ -125,12 +131,12 @@ int do_xxscanf(char *fname, FILE * fp, char *format, int *nargs, char *strv, int
             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;
@@ -140,33 +146,35 @@ int do_xxscanf(char *fname, FILE * fp, char *format, int *nargs, char *strv, int
 
         directive = *currentchar++;
 
-        if (directive == '[')
+        if (directive == L'[')
         {
-            char *currentchar1 = currentchar--;
+            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 RET_BUG;
+                return DO_XXPRINTF_RET_BUG;
             }
 
-            if (currentchar1 == currentchar + 1 || strncmp(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 RET_BUG;
+                    return DO_XXPRINTF_RET_BUG;
                 }
             }
 
@@ -182,63 +190,65 @@ int do_xxscanf(char *fname, FILE * fp, char *format, int *nargs, char *strv, int
 
             if (num_conversion >= MAXSCAN)
             {
+                delete_target(fp, target);
                 Scierror(998, _("%s: An error occurred: too many (> %d) conversion required.\n"), fname, MAXSCAN);
-                return RET_BUG;
+                return DO_XXPRINTF_RET_BUG;
             }
 
             switch (directive)
             {
-                case ']':
-                    if (width_flag == 0)
-                    {
-                        str_width_flag = 1;
-                    }
+                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 RET_BUG;
+                        return DO_XXPRINTF_RET_BUG;
                     }
 
-                    if ((buf[num_conversion].c = MALLOC(MAX_STR)) == NULL)
+                    if ((buf[num_conversion].c = (wchar_t*)MALLOC(MAX_STR * sizeof(wchar_t))) == NULL)
                     {
-                        return MEM_LACK;
+                        delete_target(fp, target);
+                        return DO_XXPRINTF_MEM_LACK;
                     }
                     ptrtab[num_conversion] = buf[num_conversion].c;
                     type[num_conversion] = SF_S;
                     break;
 
-                case 's':
+                case L's':
                     if (l_flag + h_flag)
                     {
+                        delete_target(fp, target);
                         Scierror(998, _("%s: An error occurred: %s\n"), fname, _("Bad conversion."));
-                        return RET_BUG;
+                        return DO_XXPRINTF_RET_BUG;
                     }
 
-                    if (width_flag == 0)
-                    {
-                        str_width_flag = 1;
-                    }
+                    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 RET_BUG;
+                        return DO_XXPRINTF_RET_BUG;
                     }
 
-                    if ((buf[num_conversion].c = MALLOC(MAX_STR)) == NULL)
+                    if ((buf[num_conversion].c = (wchar_t*)MALLOC(MAX_STR * sizeof(wchar_t))) == NULL)
                     {
-                        return MEM_LACK;
+                        delete_target(fp, target);
+                        return DO_XXPRINTF_MEM_LACK;
                     }
 
                     ptrtab[num_conversion] = buf[num_conversion].c;
                     type[num_conversion] = SF_S;
                     break;
 
-                case 'c':
+                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 RET_BUG;
+                        return DO_XXPRINTF_RET_BUG;
                     }
 
                     if (width_flag == 1)
@@ -252,23 +262,25 @@ int do_xxscanf(char *fname, FILE * fp, char *format, int *nargs, char *strv, int
 
                     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 RET_BUG;
+                        return DO_XXPRINTF_RET_BUG;
                     }
 
-                    if ((buf[num_conversion].c = MALLOC(MAX_STR)) == NULL)
+                    if ((buf[num_conversion].c = (wchar_t*)MALLOC(MAX_STR * sizeof(wchar_t))) == NULL)
                     {
-                        return MEM_LACK;
+                        delete_target(fp, target);
+                        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':
+                case L'o':
+                case L'u':
+                case L'x':
+                case L'X':
                     if (l_flag)
                     {
                         ptrtab[num_conversion] = &buf[num_conversion].lui;
@@ -286,16 +298,17 @@ int do_xxscanf(char *fname, FILE * fp, char *format, int *nargs, char *strv, int
                     }
                     break;
 
-                case 'D':
+                case L'D':
                     ptrtab[num_conversion] = &buf[num_conversion].li;
                     type[num_conversion] = SF_LI;
                     break;
 
-                case 'n':
+                case L'n':
                     n_directive_count++;
+                    //pass to next statement
 
-                case 'i':
-                case 'd':
+                case L'i':
+                case L'd':
                     if (l_flag)
                     {
                         ptrtab[num_conversion] = &buf[num_conversion].li;
@@ -313,15 +326,16 @@ int do_xxscanf(char *fname, FILE * fp, char *format, int *nargs, char *strv, int
                     }
                     break;
 
-                case 'e':
-                case 'f':
-                case 'g':
-                case 'E':
-                case 'G':
+                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 RET_BUG;
+                        return DO_XXPRINTF_RET_BUG;
                     }
                     else if (l_flag)
                     {
@@ -336,44 +350,73 @@ int do_xxscanf(char *fname, FILE * fp, char *format, int *nargs, char *strv, int
                     break;
 
                 default:
+                {
+                    delete_target(fp, target);
                     Scierror(998, _("%s: An error occurred: %s\n"), fname, _("Bad conversion."));
-                    return RET_BUG;
+                    return DO_XXPRINTF_RET_BUG;
+                }
             }
             *currentchar = backupcurrrentchar;
         }
     }
 
-    if (str_width_flag == 1)
+    // replace %s by %ls
+    if (str_flag)
     {
-        char *f1 = format;
-        char *f2 = sformat;
-        char *slast = sformat + MAX_STR - 1 - 4;
+        wchar_t *f1 = format;
+        wchar_t *f2 = sformat;
+        wchar_t *slast = sformat + MAX_STR - 1 - 4;
 
-        while (*f1 != '\0')
+        int bFirst = 0;
+        while (*f1 != L'\0')
         {
             int n;
-
+            if (*(f1) == L'%')
+            {
+                bFirst = 1;
+            }
             *f2++ = *f1++;
+            while (isdigit(((int)*f1)))
+            {
+                *f2++ = *f1++;
+            }
 
-            if (*(f1 - 1) == '%' && (*(f1) == 's' || *(f1) == '['))
+            if (bFirst && ( *(f1) == L's'  || *(f1) == L'[' || *(f1) == L'c'))
             {
-                n = sprintf(f2, "%d", MAX_STR - 1);
+                bFirst = 0;
+                if (*(f1 - 1) != L'l' && *(f1 - 1) != L'L')
+                {
+                    *f2++  = L'l';
+                }
+            }
+            if ( (*(f1) == L's' || *(f1) == L'[')
+                    &&
+                    (   (*(f1 - 1) == L'%')
+                        ||
+                        ((*(f1 - 1) == L'l' || *(f1 - 1) == L'L') && (*(f1 - 2) == L'%'))
+                    )
+               )
+            {
+                f2--;
+                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 RET_BUG;
+                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],
@@ -385,6 +428,8 @@ int do_xxscanf(char *fname, FILE * fp, char *format, int *nargs, char *strv, int
                           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));
 
@@ -392,11 +437,15 @@ int do_xxscanf(char *fname, FILE * fp, char *format, int *nargs, char *strv, int
     {
         if (type[i - 1] == SF_C)
         {
-            sval = (char *)ptrtab[i - 1];
-            sval[nc[i - 1]] = '\0';
+            sval = (wchar_t *)ptrtab[i - 1];
+            sval[nc[i - 1]] = L'\0';
         }
     }
 
+    if (*retval == 0)
+    {
+        return DO_XXPRINTF_MISMATCH;
+    }
     return 0;
 }