Coverity: graphics module resource leaks fixed
[scilab.git] / scilab / modules / graphics / sci_gateway / c / sci_plot2d.c
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2006 - INRIA - Fabrice Leray
4  * Copyright (C) 2006 - INRIA - Jean-Baptiste Silvy
5  *
6  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  *
15  */
16
17 /*------------------------------------------------------------------------*/
18 /* file: sci_plot2d.c                                                     */
19 /* desc : interface for plot2d routine                                    */
20 /*------------------------------------------------------------------------*/
21 #include <string.h>
22 #include "gw_graphics.h"
23 #include "GetCommandArg.h"
24 #include "api_scilab.h"
25 #include "BasicAlgos.h"
26 #include "sciCall.h"
27 #include "DefaultCommandArg.h"
28 #include "Scierror.h"
29 #include "localization.h"
30 #include <sciprint.h>
31
32 #include "BuildObjects.h"
33 #include "sci_malloc.h"
34
35 /*------------------------------------------------------------------------*/
36 int sci_plot2d(char* fname, void *pvApiCtx)
37 {
38     SciErr sciErr;
39
40     int* piAddrl1 = NULL;
41     double* l1 = NULL;
42     int* piAddrl2 = NULL;
43     double* l2 = NULL;
44     double* lt = NULL;
45     int iTypel1 = 0;
46     int iTypel2 = 0;
47     int lw = 0;
48
49     int m1 = 0, n1 = 0, m2 = 0, n2 = 0;
50     int test = 0, i = 0, j = 0, iskip = 0;
51     int frame_def = 8;
52     int *frame = &frame_def;
53     int axes_def = 1;
54     int *axes = &axes_def;
55
56     /* F.Leray 18.05.04 : log. case test*/
57     int size_x = 0, size_y = 0;
58     char dataflag = 0;
59
60     char* logFlags = NULL;
61     int* style = NULL;
62     double* rect = NULL;
63     char* strf = NULL;
64     char* legend = NULL;
65     int* nax = NULL;
66     BOOL flagNax = FALSE;
67     char strfl[4];
68     BOOL freeStrf = FALSE;
69     BOOL freeLegend = FALSE;
70
71     rhs_opts opts[] =
72     {
73         { -1, "axesflag", -1, 0, 0, NULL},
74         { -1, "frameflag", -1, 0, 0, NULL},
75         { -1, "leg", -1, 0, 0, NULL},
76         { -1, "logflag", -1, 0, 0, NULL},
77         { -1, "nax", -1, 0, 0, NULL},
78         { -1, "rect", -1, 0, 0, NULL},
79         { -1, "strf", -1, 0, 0, NULL},
80         { -1, "style", -1, 0, 0, NULL},
81         { -1, NULL, -1, 0, 0, NULL}
82     };
83
84     if (nbInputArgument(pvApiCtx) == 0)
85     {
86         sci_demo(fname, pvApiCtx);
87         return 0;
88     }
89
90     CheckInputArgument(pvApiCtx, 1, 9);
91
92     iskip = 0;
93     if (getOptionals(pvApiCtx, fname, opts) == 0)
94     {
95         ReturnArguments(pvApiCtx);
96         return 0;
97     }
98
99     if (checkInputArgumentType(pvApiCtx, 1, sci_strings))
100     {
101         /* logflags */
102         if (get_logflags_arg(pvApiCtx, fname, 1, opts, &logFlags) == 0)
103         {
104             return 0;
105         }
106         iskip = 1;
107     }
108
109     if (FirstOpt(pvApiCtx) == 2 + iskip)                                /** plot2d([loglags,] y, <opt_args>); **/
110     {
111         sciErr = getVarAddressFromPosition(pvApiCtx, 1 + iskip, &piAddrl2);
112         if (sciErr.iErr)
113         {
114             printError(&sciErr, 0);
115             return 1;
116         }
117
118         sciErr = getVarType(pvApiCtx, piAddrl2, &iTypel2);
119         if (sciErr.iErr)
120         {
121             printError(&sciErr, 0);
122             return 1;
123         }
124
125         // the argument can be a matrix of doubles or other
126         // If it is not a matrix of doubles, call overload
127         if (iTypel2 == sci_matrix)
128         {
129
130             // Retrieve a matrix of double at position 1 + iskip.
131             sciErr = getMatrixOfDouble(pvApiCtx, piAddrl2, &m2, &n2, &l2);
132             if (sciErr.iErr)
133             {
134                 printError(&sciErr, 0);
135                 Scierror(202, _("%s: Wrong type for argument #%d: A real expected.\n"), fname, 1 + iskip);
136                 return 1;
137             }
138         }
139         else
140         {
141             OverLoad(1);
142             return 0;
143         }
144
145         if (m2 == 1 && n2 > 1)
146         {
147             m2 = n2;
148             n2 = 1;
149         }
150
151         m1 = m2;
152         n1 = n2;
153
154         sciErr = allocMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 1, m1, n1, &l1);
155         if (sciErr.iErr)
156         {
157             printError(&sciErr, 0);
158             Scierror(999, _("%s: Memory allocation error.\n"), fname);
159             return 1;
160         }
161
162         for (i = 0; i < m2 ; ++i)
163         {
164             for (j = 0 ; j < n2 ;  ++j)
165             {
166                 *(l1 + i + m2 * j) = (double) i + 1;
167             }
168         }
169     }
170     else if (FirstOpt(pvApiCtx) >= 3 + iskip)     /** plot2d([loglags,] x, y[, style [,...]]); **/
171     {
172         /* x */
173         sciErr = getVarAddressFromPosition(pvApiCtx, 1 + iskip, &piAddrl1);
174         if (sciErr.iErr)
175         {
176             printError(&sciErr, 0);
177             return 1;
178         }
179
180         sciErr = getVarType(pvApiCtx, piAddrl1, &iTypel1);
181         if (sciErr.iErr)
182         {
183             printError(&sciErr, 0);
184             return 1;
185         }
186
187         // x can be a matrix of doubles or other
188         // If x is not a matrix of doubles, call overload
189         if (iTypel1 == sci_matrix)
190         {
191
192             // Retrieve a matrix of double at position 1 + iskip.
193             sciErr = getMatrixOfDouble(pvApiCtx, piAddrl1, &m1, &n1, &l1);
194             if (sciErr.iErr)
195             {
196                 printError(&sciErr, 0);
197                 Scierror(202, _("%s: Wrong type for argument #%d: A real expected.\n"), fname, 1 + iskip);
198                 return 1;
199             }
200         }
201         else
202         {
203             OverLoad(1);
204             return 0;
205         }
206
207         /* y */
208         sciErr = getVarAddressFromPosition(pvApiCtx, 2 + iskip, &piAddrl2);
209         if (sciErr.iErr)
210         {
211             printError(&sciErr, 0);
212             return 1;
213         }
214
215         sciErr = getVarType(pvApiCtx, piAddrl2, &iTypel2);
216         if (sciErr.iErr)
217         {
218             printError(&sciErr, 0);
219             return 1;
220         }
221
222         // y can be a matrix of doubles or other
223         // If y is not a matrix of doubles, call overload
224         if (iTypel2 == sci_matrix)
225         {
226
227             // Retrieve a matrix of double at position 1 + iskip.
228             sciErr = getMatrixOfDouble(pvApiCtx, piAddrl2, &m2, &n2, &l2);
229             if (sciErr.iErr)
230             {
231                 printError(&sciErr, 0);
232                 Scierror(202, _("%s: Wrong type for argument #%d: A real expected.\n"), fname, 2 + iskip);
233                 return 1;
234             }
235         }
236         else
237         {
238             OverLoad(2);
239             return 0;
240         }
241
242         test = (m1 * n1 == 0) ||
243                ((m1 == 1 || n1 == 1) && (m2 == 1 || n2 == 1) && (m1 * n1 == m2 * n2))  ||
244                ((m1 == m2) && (n1 == n2)) ||
245                ((m1 == 1 && n1 == m2) || (n1 == 1 && m1 == m2));
246         //CheckDimProp
247         if (!test)
248         {
249             Scierror(999, _("%s: Wrong size for input arguments: Incompatible sizes.\n"), fname);
250             return 1;
251         }
252
253         if (m1 * n1 == 0)
254         {
255             /* default x=1:n */
256             sciErr = allocMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 1, m2, n2, &lt);
257             if (sciErr.iErr)
258             {
259                 printError(&sciErr, 0);
260                 Scierror(999, _("%s: Memory allocation error.\n"), fname);
261                 return 1;
262             }
263
264             if (m2 == 1 && n2 > 1)
265             {
266                 m2 = n2;
267                 n2 = 1;
268             }
269             for (i = 0; i < m2 ; ++i)
270             {
271                 for (j = 0 ; j < n2 ;  ++j)
272                 {
273                     *(lt + i + m2 * j) = (double) i + 1;
274                 }
275             }
276             m1 = m2;
277             n1 = n2;
278             l1 = lt;
279         }
280         else if ((m1 == 1 || n1 == 1) && (m2 != 1 && n2 != 1))
281         {
282             /* a single x vector for mutiple columns for y */
283             sciErr = allocMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 1, m2, n2, &lt);
284             if (sciErr.iErr)
285             {
286                 printError(&sciErr, 0);
287                 Scierror(999, _("%s: Memory allocation error.\n"), fname);
288                 return 1;
289             }
290
291             for (i = 0; i < m2 ; ++i)
292             {
293                 for (j = 0 ; j < n2 ;  ++j)
294                 {
295                     *(lt + i + m2 * j) = *(l1 + i);
296                 }
297             }
298             m1 = m2;
299             n1 = n2;
300             l1 = lt;
301         }
302         else if ((m1 == 1 && n1 == 1) && (n2 != 1))
303         {
304             /* a single y row vector  for a single x */
305             sciErr = allocMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 1, m1, n2, &lt);
306             if (sciErr.iErr)
307             {
308                 printError(&sciErr, 0);
309                 Scierror(999, _("%s: Memory allocation error.\n"), fname);
310                 return 1;
311             }
312
313             for (j = 0 ; j < n2 ;  ++j)
314             {
315                 lt[j] = *l1;
316             }
317             n1 = n2;
318             l1 = lt;
319         }
320         else
321         {
322             if (m2 == 1 && n2 > 1)
323             {
324                 m2 = n2;
325                 n2 = 1;
326             }
327             if (m1 == 1 && n1 > 1)
328             {
329                 m1 = n1;
330                 n1 = 1;
331             }
332         }
333     }
334     else
335     {
336         Scierror(999, _("%s: Wrong number of mandatory input arguments. At least %d expected.\n"), fname, 1);
337         return 0;
338     }
339
340     if (n1 == -1 || n2 == -1 || m1 == -1 || m2 == -1)
341     {
342         Scierror(999, _("%s: Wrong size for input arguments #%d and #%d.\n"), fname, 1, 2); /* @TODO : detail error */
343         return 0;
344     }
345
346     if (get_style_arg(pvApiCtx, fname, 3 + iskip, n1, opts, &style) == 0)
347     {
348         return 0;
349     }
350     if (get_strf_arg(pvApiCtx, fname, 4 + iskip, opts, &strf) == 0)
351     {
352         FREE(style);
353         return 0;
354     }
355     freeStrf = !isDefStrf(strf);
356     if (get_legend_arg(pvApiCtx, fname, 5 + iskip, opts, &legend) == 0)
357     {
358         if (freeStrf)
359         {
360             freeAllocatedSingleString(strf);
361         }
362         FREE(style);
363         return 0;
364     }
365     freeLegend = !isDefLegend(legend);
366     if (get_rect_arg(pvApiCtx, fname, 6 + iskip, opts, &rect) == 0)
367     {
368         if (freeStrf)
369         {
370             freeAllocatedSingleString(strf);
371         }
372         if (freeLegend)
373         {
374             freeAllocatedSingleString(legend);
375         }
376         FREE(style);
377         return 0;
378     }
379     if (get_nax_arg(pvApiCtx, 7 + iskip, opts, &nax, &flagNax)==0)
380     {
381         if (freeStrf)
382         {
383             freeAllocatedSingleString(strf);
384         }
385         if (freeLegend)
386         {
387             freeAllocatedSingleString(legend);
388         }
389         FREE(style);
390         return 0;
391     }
392
393     if (iskip == 0)
394     {
395         if (get_logflags_arg(pvApiCtx, fname, 8, opts, &logFlags) == 0)
396         {
397             if (freeStrf)
398             {
399                 freeAllocatedSingleString(strf);
400             }
401             if (freeLegend)
402             {
403                 freeAllocatedSingleString(legend);
404             }
405             FREE(style);
406             return 0;
407         }
408     }
409
410     // Check strf [0-1][0-8][0-5]
411     if (!isDefStrf(strf) && (strlen(strf) != 3 || strf[0] < '0' || strf[0] > '1' || strf[1] < '0' || strf[1] > '8' || strf[2] < '0' || strf[2] > '5'))
412     {
413         Scierror(999, _("%s: Wrong value for strf option: %s.\n"), fname, strf);
414         if (freeStrf)
415         {
416             freeAllocatedSingleString(strf);
417         }
418         if (freeLegend)
419         {
420             freeAllocatedSingleString(legend);
421         }
422         FREE(style);
423         return -1;
424     }
425
426     if (isDefStrf(strf))
427     {
428         strcpy(strfl, DEFSTRFN);
429
430         strf = strfl;
431         if (!isDefRect(rect))
432         {
433             strfl[1] = '7';
434         }
435         if (!isDefLegend(legend))
436         {
437             strfl[0] = '1';
438         }
439
440         if (get_optional_int_arg(pvApiCtx, fname, 9, "frameflag", &frame, 1, opts) == 0)
441         {
442             if (freeLegend)
443             {
444                 freeAllocatedSingleString(legend);
445             }
446             FREE(style);
447             return 0;
448         }
449         if (frame != &frame_def)
450         {
451             if (*frame >= 0 && *frame <= 8)
452             {
453                 strfl[1] = (char)(*frame + 48);
454             }
455             else
456             {
457                 Scierror(999, _("%s: Wrong value for frameflag option.\n"), fname);
458                 if (freeLegend)
459                 {
460                     freeAllocatedSingleString(legend);
461                 }
462                 FREE(style);
463                 return -1;
464             }
465         }
466
467         if (get_optional_int_arg(pvApiCtx, fname, 9, "axesflag", &axes, 1, opts) == 0)
468         {
469             if (freeLegend)
470             {
471                 freeAllocatedSingleString(legend);
472             }
473             FREE(style);
474             return 0;
475         }
476         if (axes != &axes_def)
477         {
478             if ((*axes >= 0 && *axes <= 5) || *axes == 9)
479             {
480                 strfl[2] = (char)(*axes + 48);
481             }
482             else
483             {
484                 Scierror(999, _("%s: Wrong value for axesflag option.\n"), fname);
485                 if (freeLegend)
486                 {
487                     freeAllocatedSingleString(legend);
488                 }
489                 FREE(style);
490                 return -1;
491             }
492         }
493     }
494
495     /* Make a test on log. mode : available or not depending on the bounds set by Rect arg. or xmin/xmax :
496        Rect case :
497        - if the min bound is strictly posivite, we can use log. mode
498        - if not, send error message
499        x/y min/max case:
500        - we find the first strictly positive min bound in Plo2dn.c ?? */
501
502     switch (strf[1])
503     {
504         case '0':
505             /* no computation, the plot use the previous (or default) scale */
506             break;
507         case '1' :
508         case '3' :
509         case '5' :
510         case '7':
511             /* based on Rect arg */
512             if (rect[0] > rect[2] || rect[1] > rect[3])
513             {
514                 Scierror(999, _("%s: Impossible status min > max in x or y rect data.\n"), fname);
515                 if (freeStrf)
516                 {
517                     freeAllocatedSingleString(strf);
518                 }
519                 if (freeLegend)
520                 {
521                     freeAllocatedSingleString(legend);
522                 }
523                 FREE(style);
524                 return -1;
525             }
526
527             if (rect[0] <= 0. && logFlags[1] == 'l') /* xmin */
528             {
529                 Scierror(999, _("%s: Bounds on x axis must be strictly positive to use logarithmic mode.\n"), fname);
530                 if (freeStrf)
531                 {
532                     freeAllocatedSingleString(strf);
533                 }
534                 if (freeLegend)
535                 {
536                     freeAllocatedSingleString(legend);
537                 }
538                 FREE(style);
539                 return -1;
540             }
541
542             if (rect[1] <= 0. && logFlags[2] == 'l') /* ymin */
543             {
544                 Scierror(999, _("%s: Bounds on y axis must be strictly positive to use logarithmic mode.\n"), fname);
545                 if (freeStrf)
546                 {
547                     freeAllocatedSingleString(strf);
548                 }
549                 if (freeLegend)
550                 {
551                     freeAllocatedSingleString(legend);
552                 }
553                 FREE(style);
554                 return -1;
555             }
556
557             break;
558         case '2' :
559         case '4' :
560         case '6' :
561         case '8':
562         case '9':
563             /* computed from the x/y min/max */
564             if ((int)strlen(logFlags) < 1)
565             {
566                 dataflag = 'g';
567             }
568             else
569             {
570                 dataflag = logFlags[0];
571             }
572
573             switch (dataflag)
574             {
575                 case 'e' :
576                     size_x = (m1 != 0) ? 2 : 0;
577                     break;
578                 case 'o' :
579                     size_x = m1;
580                     break;
581                 case 'g' :
582                 default  :
583                     size_x = (n1 * m1);
584                     break;
585             }
586
587             if (size_x != 0)
588             {
589                 if (logFlags[1] == 'l' && sciFindStPosMin((l1), size_x) <= 0.0)
590                 {
591                     Scierror(999, _("%s: At least one x data must be strictly positive to compute the bounds and use logarithmic mode.\n"), fname);
592                     if (freeStrf)
593                     {
594                         freeAllocatedSingleString(strf);
595                     }
596                     if (freeLegend)
597                     {
598                         freeAllocatedSingleString(legend);
599                     }
600                     FREE(style);
601                     return -1;
602                 }
603             }
604
605             size_y = (n1 * m1);
606
607             if (size_y != 0)
608             {
609                 if (logFlags[2] == 'l' && sciFindStPosMin((l2), size_y) <= 0.0)
610                 {
611                     Scierror(999, _("%s: At least one y data must be strictly positive to compute the bounds and use logarithmic mode\n"), fname);
612                     if (freeStrf)
613                     {
614                         freeAllocatedSingleString(strf);
615                     }
616                     if (freeLegend)
617                     {
618                         freeAllocatedSingleString(legend);
619                     }
620                     FREE(style);
621                     return -1;
622                 }
623             }
624
625             break;
626     }
627
628     // open a figure if none already exists
629     getOrCreateDefaultSubwin();
630
631     Objplot2d (1, logFlags, (l1), (l2), &n1, &m1, style, strf, legend, rect, nax, flagNax);
632
633     // Allocated by sciGetStyle (get_style_arg function in GetCommandArg.c)
634     FREE(style);
635
636     if (freeStrf)
637     {
638         freeAllocatedSingleString(strf);
639     }
640     if (freeLegend)
641     {
642         freeAllocatedSingleString(legend);
643     }
644
645     AssignOutputVariable(pvApiCtx, 1) = 0;
646     ReturnArguments(pvApiCtx);
647     return 0;
648 }
649 /*------------------------------------------------------------------------*/