Remove memory leaks
[scilab.git] / scilab / modules / output_stream / src / c / do_xxprintf.c
1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2006 - INRIA
4 * Copyright (C) 2009-2012 - DIGITEO - Allan CORNET
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 #include <stdio.h>
15 #include <ctype.h>
16 #include <math.h>
17 #include "machine.h"
18 #include "MALLOC.h"
19 #include "stack-c.h"
20 #include "do_xxprintf.h"
21 #include "Scierror.h"
22 #include "Scierror.h"
23 #include "scilabmode.h"
24 #include "localization.h"
25 #include "set_xxprintf.h"
26 #include "scistrtostr.h"
27 #include "charEncoding.h"
28
29 #ifdef _MSC_VER
30 #include "strdup_windows.h"
31 #endif
32 /*--------------------------------------------------------------------------*/
33 #define  PF_C       0
34 #define  PF_S       1
35 #define  PF_D       2
36 #define  PF_LD      3
37 #define  PF_F       4
38 #define  TAB_CHAR   9
39 #define  CR_CHAR    13
40 /*--------------------------------------------------------------------------*/
41 #define  MAX_SPRINTF_SIZE  bsiz
42 char sprintf_buffer[MAX_SPRINTF_SIZE];
43 static char *sprintf_limit = sprintf_buffer + MAX_SPRINTF_SIZE;
44 /*--------------------------------------------------------------------------*/
45 static int GetScalarInt(char *fname,int *first,int *arg,int narg, int *ir,int ic,int *ival);
46 static int GetString (char *fname,int *first,int *arg,int narg, int *ir,int ic,char **sval);
47 static int GetScalarDouble(char *fname,int *prev,int *arg,int narg, int *ic,int ir,double *dval);
48 static void error_on_rval(XXPRINTF xxprintf,FLUSH flush,char *target);
49 static char* readNextUTFChar(char* utfstream,int* size);
50 static int call_printf(XXPRINTF xxprintf,char *target,char *p,char *sval,int *asterisk,int asterisk_count,int conversion_type,double dval );
51 #ifndef signbit
52 /* signbit does not exist with VS 2008 */
53 static int signbit(double x);
54 #endif
55 /*--------------------------------------------------------------------------*/
56 static void error_on_rval(XXPRINTF xxprintf,FLUSH flush,char *target)
57 {
58     (*xxprintf) ((VPTR) target, "\n");
59     (*flush) ((FILE *) target);
60     Scierror(998,_("%s: Not enough arguments.\n"),"printf");
61 }
62 /*--------------------------------------------------------------------------*/
63 static int call_printf(XXPRINTF xxprintf,char *target,char *p,char *sval,int *asterisk,int asterisk_count,int conversion_type,double dval )
64 {
65     /* for switch on number of '*' and type */
66     #define  choosetype(num,type)  (5*(num)+(type))
67
68     int retval = -1;
69
70     switch (choosetype (asterisk_count, conversion_type))
71     {
72     case choosetype (0, PF_S):
73         retval += (*xxprintf) ((VPTR) target, p, sval);
74         FREE(sval);
75         break;
76
77     case choosetype (1, PF_S):
78         retval += (*xxprintf) ((VPTR) target, p, asterisk[0], sval);
79         FREE(sval);
80         break;
81
82     case choosetype (2, PF_S):
83         retval += (*xxprintf) ((VPTR) target, p, asterisk[0], asterisk[1], sval);
84         FREE(sval);
85         break;
86
87     case choosetype (0, PF_C):
88         retval += (*xxprintf) ((VPTR) target, p, sval[0]);
89         FREE(sval);
90         break;
91
92     case choosetype (1, PF_C):
93         retval += (*xxprintf) ((VPTR) target, p, asterisk[0], sval[0]);
94         FREE(sval);
95         break;
96
97     case choosetype (2, PF_C):
98         retval += (*xxprintf) ((VPTR) target, p, asterisk[0], asterisk[1],sval[0]);
99         FREE(sval);
100         break;
101
102     case choosetype (0, PF_D):
103         {
104             retval += (*xxprintf) ((VPTR) target, p, (long long)dval);
105         }
106         break;
107
108     case choosetype (1, PF_D):
109         retval += (*xxprintf) ((VPTR) target, p, asterisk[0], (int) dval);
110         break;
111
112     case choosetype (2, PF_D):
113         retval += (*xxprintf) ((VPTR) target, p, asterisk[0], asterisk[1], (int) dval);
114         break;
115
116     case choosetype (0, PF_LD):
117         retval += (*xxprintf) ((VPTR) target, p, (long int) dval);
118         break;
119
120     case choosetype (1, PF_LD):
121         retval += (*xxprintf) ((VPTR) target, p, asterisk[0], (long int) dval);
122         break;
123
124     case choosetype (2, PF_LD):
125         retval += (*xxprintf) ((VPTR) target, p, asterisk[0], asterisk[1], (long int) dval);
126         break;
127
128     case choosetype (0, PF_F):
129         retval += (*xxprintf) ((VPTR) target, p, dval);
130         break;
131
132     case choosetype (1, PF_F):
133         retval += (*xxprintf) ((VPTR) target, p, asterisk[0], dval);
134         break;
135
136     case choosetype (2, PF_F):
137         retval += (*xxprintf) ((VPTR) target, p, asterisk[0], asterisk[1], dval);
138         break;
139     }
140     return retval;
141 }
142 /*--------------------------------------------------------------------------*/
143 int do_xxprintf (char *fname, FILE *fp, char *format, int nargs, int argcount, int lcount, char **strv)
144 {
145     int retval    = 0; /* return value */
146     int arg_count = 0;
147     int ccount    = 0;
148     int prev      = 0;
149
150     XXPRINTF xxprintf          = NULL; /* sprintf sciprint2 fprintf */
151     FLUSH flush                = NULL;
152     char *target               = NULL;
153     register char *currentchar = NULL;
154
155     currentchar = format;
156     arg_count   = argcount;
157     ccount      = 1;
158
159     set_xxprintf(fp,&xxprintf,&flush,&target);
160
161     /* "scan" string format. */
162     while (TRUE)
163     {
164         char *p = NULL;
165         char *sval = NULL;
166
167         int ival      = 0;
168         int low_flag  = 0;
169         int high_flag = 0;
170
171         int asterisk_count = 0;
172         int asterisk[2];
173         int rval = 0;
174
175         int conversion_type           = 0;
176         double dval                   = 0.0;
177         register char *tmpcurrentchar = NULL;
178
179         asterisk[0] = 0;
180         asterisk[1] = 0;
181
182         if (fp)
183         {
184             while (*currentchar != '%')
185             {
186                 switch (*currentchar)
187                 {
188                 case 0 :
189                     fflush (fp);
190                     return (retval);
191                     break;
192                 case '\\':
193                     currentchar++;
194                     switch (*currentchar)
195                     {
196                     case 0 :
197                         fflush (fp);
198                         return (retval);
199                         break;
200                     case 'r':
201                         (*xxprintf) ((VPTR) target, "\r");
202                         currentchar++;
203                         retval++;
204                         break;
205                     case 'n':
206 #ifdef _MSC_VER
207                         if (getScilabMode() != SCILAB_STD)
208                         {
209                             if ( fp == stdout ) (*xxprintf) ((VPTR) target, "\r");
210                         }
211 #endif
212                         (*xxprintf) ((VPTR) target, "\n");
213                         currentchar++;
214                         retval++;
215                         break;
216                     case 't':
217                         (*xxprintf) ((VPTR) target, "\t");
218                         currentchar++;
219                         retval++;
220                         break;
221                     case '\\':
222                         (*xxprintf) ((VPTR) target, "\\");
223                         currentchar++;
224                         retval++;
225                         break;
226                     default:
227                         /* putc */
228                         (*xxprintf) ((VPTR) target, "%c",*currentchar);
229                         currentchar++;
230                         retval++;
231                     }
232                     break;
233
234                 default:
235                     /* putc */
236                     {
237                         int  charBytes = 0;
238                         char *UTFChar = NULL;
239                         char* outStr = NULL; /** locale char at most 2 bytes*/
240
241                         UTFChar = readNextUTFChar(currentchar,&charBytes);
242                         currentchar += charBytes;
243                         outStr = UTFChar;
244                         retval += charBytes;
245                         (*xxprintf) ((VPTR) target, "%s",outStr);
246                     }
247                     break;
248                 }
249             }
250         }
251         else
252         {
253             /* sprintf() */
254             while (*currentchar != '%') /* loop while we meet a % */
255             {
256                 if (*currentchar == 0) /* End of the char * */
257                 {
258                     if (target > sprintf_limit) /* over sprintf_limit */
259                     {
260                         Scierror(998,_("%s: An error occurred: %s\n"),fname,_("Buffer too small."));
261                         return RET_BUG;
262                     }
263                     else
264                     {
265                         /* done */
266                         *target = '\0';
267                         *strv = sprintf_buffer;
268                         return (retval);
269                     }
270                 }
271                 else
272                 {
273                     if (*currentchar == '\\')
274                     {
275                         currentchar++;
276                         if (*currentchar == '\\')
277                         {
278                             *target++ = *currentchar++;
279                             retval++;
280                         }
281                         else if (*currentchar == 't')
282                         {
283                             *target++ = (char)TAB_CHAR;
284                             *currentchar++;
285                             retval++;
286                         }
287                         else if (*currentchar == 'r')
288                         {
289                             *target++ = (char)CR_CHAR;
290                             *currentchar++;
291                             retval++;
292                         }
293                     }
294                     else
295                     {
296                         *target++ = *currentchar++;
297                         retval++;
298                     }
299                 }
300             }
301         }
302
303         if (*++currentchar == '%')  /* %% */
304         {
305             if (fp)
306             {
307                 /* bug 2602 fixed */
308                 (*xxprintf) ((VPTR) target, "%c",*currentchar);
309                 retval++;
310             }
311             else
312             {
313                 *target++ = *currentchar;
314             }
315             currentchar++;
316             continue;
317         }
318
319         p = currentchar - 1;
320
321         /* remove '-' '+' ' ' '#' '0' */
322         while (*currentchar == '-' || *currentchar == '+' || *currentchar == ' ' || *currentchar == '#' || *currentchar == '0') currentchar++;
323
324         asterisk_count = 0;
325         if (*currentchar == '*')
326         {
327             rval=GetScalarInt(fname,&prev,&arg_count,nargs,&ccount,lcount,&ival);
328
329             if (rval <= 0)
330             {
331                 if (rval== NOT_ENOUGH_ARGS)
332                 {
333                     error_on_rval(xxprintf,flush,target);
334                     return RET_BUG;
335                 }
336                 return rval;
337             }
338
339             asterisk[asterisk_count++] = ival;
340             currentchar++;
341
342         }
343         else while ( isdigit(((int)*currentchar)))  currentchar++;
344
345         if (*currentchar == '.')        /* precision */
346         {
347             currentchar++;
348             if (*currentchar == '*')
349             {
350                 rval=GetScalarInt(fname,&prev,&arg_count,nargs,&ccount,lcount,&ival);
351                 if (rval <= 0) {
352                     if (rval== NOT_ENOUGH_ARGS)
353                     {
354                         error_on_rval(xxprintf,flush,target);
355                         return RET_BUG;
356                     }
357                     return rval;
358                 }
359                 asterisk[asterisk_count++] = ival;
360                 currentchar++;
361             }
362             else while ( isdigit(((int)*currentchar)) ) currentchar++;
363         }
364
365         low_flag = high_flag = 0;
366
367         if (*currentchar == 'l')
368         {
369             currentchar++;
370             low_flag = 1;
371         }
372         else if (*currentchar == 'h')
373         {
374             currentchar++;
375             high_flag = 1;
376         }
377
378         /* set conversion_type */
379         tmpcurrentchar = currentchar;
380         switch (*(currentchar++))
381         {
382         case 's':
383         case 'c':
384             {
385                 if (low_flag + high_flag)
386                 {
387                     if (*tmpcurrentchar == 's')
388                     {
389                         Scierror(998,_("%s: Bad conversion 'l' or 'h' flag mixed with 's' directive.\n"),fname);
390                     }
391                     else /* 'c' */
392                     {
393                         Scierror(998,_("%s: Bad conversion 'l' or 'h' flag mixed with 'c' directive.\n"),fname);
394                     }
395                 }
396
397                 rval = GetString(fname,&prev,&arg_count,nargs,&ccount,lcount,&sval);
398
399                 if (rval <= 0)
400                 {
401                     if (rval== NOT_ENOUGH_ARGS)
402                     {
403                         error_on_rval(xxprintf,flush,target);
404                         return RET_BUG;
405                     }
406                     return rval;
407                 }
408
409                 if (*tmpcurrentchar == 's')
410                 {
411                     conversion_type = PF_S;
412                 }
413                 else /* 'c' */
414                 {
415                     conversion_type = PF_C;
416                 }
417                 break;
418             }
419
420         case 'd':
421         case 'x':
422         case 'X':
423             rval = GetScalarDouble(fname, &prev, &arg_count, nargs, &ccount, lcount, &dval);
424             if (rval <= 0)
425             {
426                 if (rval == NOT_ENOUGH_ARGS)
427                 {
428                     error_on_rval(xxprintf, flush, target);
429                     return RET_BUG;
430                 }
431                 return rval;
432             }
433             conversion_type = PF_D;
434             break;
435
436         case 'i':
437         case 'u':
438             rval = GetScalarDouble(fname, &prev, &arg_count, nargs, &ccount, lcount, &dval);
439             if (rval <= 0)
440             {
441                 if (rval== NOT_ENOUGH_ARGS)
442                 {
443                     error_on_rval(xxprintf, flush, target);
444                     return RET_BUG;
445                 }
446                 return rval;
447             }
448             conversion_type = low_flag ? PF_LD : PF_D;
449             break;
450
451         case 'e':
452         case 'g':
453         case 'f':
454         case 'E':
455         case 'G':
456             if (high_flag + low_flag)
457             {
458                 Scierror(998,_("%s: An error occurred: %s\n"),fname,_("Bad conversion."));
459                 return RET_BUG;
460             }
461             rval = GetScalarDouble(fname, &prev, &arg_count, nargs, &ccount, lcount, &dval);
462             if (rval <= 0)
463             {
464                 if (rval == NOT_ENOUGH_ARGS)
465                 {
466                     error_on_rval(xxprintf, flush, target);
467                     return RET_BUG;
468                 }
469                 return rval;
470             }
471             conversion_type = PF_F;
472             break;
473
474         case 'o':
475             {
476                 rval = GetScalarDouble(fname, &prev, &arg_count, nargs, &ccount, lcount, &dval);
477                 if (rval <= 0)
478                 {
479                     if (rval == NOT_ENOUGH_ARGS)
480                     {
481                         error_on_rval(xxprintf, flush, target);
482                         return RET_BUG;
483                     }
484                     return rval;
485                 }
486                 conversion_type = PF_D;
487             }
488             break;
489
490         default:
491             Scierror(998,_("%s: An error occurred: %s\n"),fname,_("Bad conversion."));
492             return RET_BUG;
493         }
494
495         tmpcurrentchar = NULL;
496         {
497             char backupcurrentchar;
498             backupcurrentchar = *currentchar;
499             *currentchar = 0;
500
501             #define NanString "Nan"
502             #define InfString "Inf"
503             #define NegInfString "-Inf"
504
505             /* print is not a string or a char */
506             if ( (conversion_type != PF_S) && (conversion_type != PF_C) )
507             {
508                 if (ISNAN(dval)) /* it is a %nan */
509                 {
510                     char formatnan[3] = "%s";
511                     char *valuenan = strdup(NanString);
512                     conversion_type = PF_S;
513                     dval = 0.;
514                     /* valuenan FREED in call_printf */
515                     call_printf(xxprintf,target,formatnan,valuenan,asterisk,asterisk_count,conversion_type,dval );
516                 }
517                 else
518                 {
519                     if (finite(dval) != 0) /* not %inf */
520                     {
521                         call_printf(xxprintf,target,p,sval,asterisk,asterisk_count,conversion_type,dval );
522                     }
523                     else /* %inf */
524                     {
525                         char formatinf[3] = "%s";
526                         char *valueinf = NULL;
527
528                         if ( signbit(dval) )
529                         {
530                             valueinf = strdup(NegInfString);
531                         }
532                         else
533                         {
534                             valueinf =  strdup(InfString);
535                         }
536
537                         conversion_type = PF_S;
538                         dval = 0.;
539                         /* valueinf FREED in call_printf */
540                         call_printf(xxprintf,target,formatinf,valueinf,asterisk,asterisk_count,conversion_type,dval );
541                     }
542                 }
543             }
544             else
545             {
546                 if ((int)strlen(sval) > MAX_SPRINTF_SIZE) /* over sprintf_limit */
547                 {
548                     Scierror(998,_("%s: An error occurred: %s\n"),fname,_("Buffer too small."));
549                     return RET_BUG;
550                 }
551                 call_printf(xxprintf,target,p,sval,asterisk,asterisk_count,conversion_type,dval );
552             }
553
554             if (fp == (FILE *) 0) while (*target) target++;
555             *currentchar = backupcurrentchar;
556         }
557     }
558     return (retval);
559 }
560 /*--------------------------------------------------------------------------*/
561 static char* readNextUTFChar(char* utfstream,int* size)
562 {
563     static char UTFChar[5]; /**UTF char. at most 4 bytes*/
564     unsigned char charcode = (unsigned)*utfstream;
565     /** UTF-8 format: ref. http://en.wikipedia.org/wiki/UTF-8/ */
566     if(charcode > 193 && charcode <= 223 )
567     { /* twi bytes UTF-8 */
568         UTFChar[0] = *utfstream;
569         UTFChar[1] = *(utfstream+1);
570         UTFChar[2] = '\0';
571         *size = 2;
572     }
573     else if(charcode > 223 && charcode <= 239 )
574     {/* three bytes UTF-8*/
575         UTFChar[0] = *utfstream;
576         UTFChar[1] = *(utfstream+1);
577         UTFChar[2] = *(utfstream+2);
578         UTFChar[3] = '\0';
579         *size = 3;
580     }
581     else if(charcode > 239 && charcode < 245 )
582     {/* four bytes UTF-8*/
583         UTFChar[0] = *utfstream;
584         UTFChar[1] = *(utfstream+1);
585         UTFChar[2] = *(utfstream+2);
586         UTFChar[3] = *(utfstream+3);
587         UTFChar[4] = '\0';
588         *size = 4;
589     }
590     else
591     {
592         UTFChar[0] = *utfstream;
593         UTFChar[1] = '\0';
594         *size = 1;
595     }
596     return UTFChar;
597 }
598 /*--------------------------------------------------------------------------*/
599 static int GetScalarInt(char *fname, int *prev, int *arg, int narg, int *ic, int ir, int *ival)
600 {
601     int mx = 0, nx = 0, lx = 0;
602
603     if (*prev != 1)
604     {
605         *arg = *arg + 1;
606         *ic = 1;
607         *prev = 1;
608     }
609
610     GetRhsVar(*arg,MATRIX_OF_INTEGER_DATATYPE,&mx,&nx,&lx);
611
612     if ( (*ic>nx) || (*prev != 1))
613     {
614         *arg = *arg + 1;
615         if (*arg > narg )
616         {
617             return NOT_ENOUGH_ARGS;
618         }
619         *ic = 1;
620         GetRhsVar(*arg,MATRIX_OF_INTEGER_DATATYPE,&mx,&nx,&lx);
621     }
622
623     if (ir > mx) return RET_END;
624     *ival = *(istk(lx+ir-1+mx*(*ic-1)));
625     *ic = *ic + 1;
626     return OK;
627 }
628 /*--------------------------------------------------------------------------*/
629 static int GetString(char *fname, int *prev, int *arg, int narg, int *ic, int ir, char **sval)
630 {
631     int mx = 0, nx = 0, il = 0, ild = 0, lw = 0, k = 0, one = 1;
632     char *p = NULL;
633
634     if (*prev != 2)
635     {
636         *arg = *arg + 1;
637         *ic = 1;
638         *prev = 2;
639     }
640     lw = *arg + Top - Rhs;
641
642     if (! C2F(getwsmat)(fname,&Top,&lw,&mx,&nx,&il,&ild,(unsigned long)strlen(fname)))
643     {
644         return RET_BUG;
645     }
646     else
647     {
648         if ( *ic > nx )
649         {
650             *arg = *arg + 1;
651             if (*arg > narg)
652             {
653                 return NOT_ENOUGH_ARGS;
654             }
655             *ic = 1;
656             lw = *arg + Top - Rhs;
657             if (! C2F(getwsmat)(fname,&Top,&lw,&mx,&nx,&il,&ild,(unsigned long) strlen(fname)))
658             {
659                 return RET_BUG;
660             }
661         }
662     }
663     if (ir > mx)
664     {
665         return RET_END;
666     }
667     k = ir - 1 + mx*(*ic - 1);
668     if (SciStrtoStr(istk(il-1+*istk(ild+k)),&one,istk(ild+k),&p) < 0)
669     {
670         return MEM_LACK;
671     }
672     *ic = *ic + 1;
673     *sval = p;
674     return OK;
675 }
676 /*--------------------------------------------------------------------------*/
677 static int GetScalarDouble(char *fname, int *prev, int *arg, int narg, int *ic, int ir, double *dval)
678 {
679     int mx = 0, nx = 0, lx = 0;
680
681     if (*prev != 1)
682     {
683         *arg = *arg + 1;
684         *ic = 1;
685         *prev = 1;
686     }
687     GetRhsVar(*arg, MATRIX_OF_DOUBLE_DATATYPE, &mx, &nx, &lx);
688     if (*ic > nx)
689     {
690         *arg = *arg + 1;
691         if (*arg > narg )
692         {
693             return NOT_ENOUGH_ARGS;
694         }
695         *ic = 1;
696         GetRhsVar(*arg,MATRIX_OF_DOUBLE_DATATYPE,&mx,&nx,&lx);
697     }
698     if (ir > mx)
699     {
700         return RET_END;
701     }
702     *dval =  *(stk(lx + ir - 1 + mx*(*ic - 1)));
703     *ic = *ic + 1;
704     return OK;
705 }
706 /*--------------------------------------------------------------------------*/
707 #ifndef signbit
708 static int signbit(double x)
709 {
710     union
711     {
712         double d;
713         short s[4];
714         int i[2];
715     } u;
716
717     u.d = x;
718 #if SIZEOF_INT == 4
719     return u.i[1] < 0;
720 #else
721     return u.s[3] < 0;
722 #endif
723 }
724 #endif /* signbit */
725 /*--------------------------------------------------------------------------*/