bc7911dbfd1341b51327b11dde664621d9caeda3
[platform/core/system/tizen-platform-wrapper.git] / src / toolbox.c
1 /*
2  * Copyright (C) 2013 Intel Corporation.
3  * 
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  * Authors:
19  *   José Bollo <jose.bollo@open.eurogiciel.org>
20  *   Stéphane Desneux <stephane.desneux@open.eurogiciel.org>
21  *   Jean-Benoit Martin <jean-benoit.martin@open.eurogiciel.org>
22  *
23  */
24 #define _GNU_SOURCE
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <sys/wait.h>
35 #include <stdarg.h>
36
37 #include "parser.h"
38 #include "heap.h"
39 #include "buffer.h"
40 #include "foreign.h"
41
42 /*======================================================================*/
43
44 #ifndef CONFIGPATH
45 # define CONFIGPATH "/etc/tizen-platform.conf"
46 #endif
47
48 #ifndef TOOLNAME
49 # define TOOLNAME "tzplatform-tool"
50 #endif
51
52 /*== TYPES =============================================================*/
53
54 /* for recording read keys */
55 struct key {
56     struct key *next;       /* link to next */
57     const char *name;       /* name of the key */
58     const char *value;      /* value of the key */
59     size_t      begin;      /* positions of begin (used by pretty) */
60     size_t      end;        /* positions of end (used by pretty) */
61     int         dependant;  /* is dependant (used by rpm) */
62 };
63
64 /* for recording used variables */
65 struct var {
66     struct var *next;       /* link to next */
67     const char *name;       /* name of the variable */
68     const char *normal;     /* normalized value: "${name}" (for pretty) */
69     int         dependant;  /* is dependant (used by rpm) */
70 };
71
72 /*== STATIC DATA =======================================================*/
73
74 static char help[] = "\
75 \n\
76 usage: "TOOLNAME" [command] [--] [file]\n\
77 \n\
78 You can specify the 'file' to process.\n\
79 The default file is "CONFIGPATH"\n\
80 Specifying - mean the standard input.\n\
81 \n\
82 Commands:\n\
83 \n\
84 help       Display this help\n\
85 check      Check validity of 'file' (this is the default command)\n\
86 pretty     Pretty print of the 'file' (the normalized format)\n\
87 h          Produce the C header with the enumeration of the variables\n\
88 c          Produce the C code to hash the variable names\n\
89 rpm        Produce the macro file to use with RPM\n\
90 \n\
91 ";
92
93 static char genh_head[] = "\
94 /* I'm generated. Dont edit me! */\n\
95 #ifndef TZPLATFORM_VARIABLES_H\n\
96 #define TZPLATFORM_VARIABLES_H\n\
97 #ifdef __cplusplus\n\
98 extern \"C\" {\n\
99 #endif\n\
100 enum tzplatform_variable {\n\
101 \t_TZPLATFORM_VARIABLES_INVALID_ = -1,\n\
102 ";
103
104 static char genh_tail[] = "\
105 \t_TZPLATFORM_VARIABLES_COUNT_\n\
106 };\n\
107 #ifdef __cplusplus\n\
108 }\n\
109 #endif\n\
110 #endif\n\
111 ";
112
113 static char gperf_head[] = "\
114 struct varassoc {\n\
115   int offset;\n\
116   enum tzplatform_variable id;\n\
117 };\n\
118 %%\n\
119 ";
120
121 static char *gperf_command[] = {
122     "/bin/sh",
123     "-c", 
124     "gperf -r -m 100 --null-strings -C -P -L ANSI-C -c"
125           " -t -N hashvar -Q varpool -K offset -G -W namassoc"
126           " -F \", _TZPLATFORM_VARIABLES_INVALID_\"",
127     NULL
128 };
129
130 static char rpm_head[] = "\
131 # I'm generated. Dont edit me! \n\
132 \n\
133 ";
134
135 /*== GLOBALS VARIABLES =================================================*/
136
137 /* name of the meta file to process */
138 static const char * metafilepath = CONFIGPATH;
139
140 /* list of the read keys */
141 static struct key *keys = NULL;
142
143 /* list of the used variables */
144 static struct var *vars = NULL;
145
146 /* count of errors */
147 static int errcount = 0;
148
149 /* dependency state */
150 static int dependant = 0;
151
152 /* action to perform */
153 static enum { CHECK, PRETTY, GENC, GENH, RPM } action = CHECK;
154
155 /* output of error */
156 static int notstderr = 0;
157
158 /*======================================================================*/
159
160 /* write the error message */
161 static void vwriterror( const char *format, va_list ap)
162 {
163     vfprintf(notstderr ? stdout : stderr, format, ap);
164 }
165
166 /* write the error message */
167 static void writerror( const char *format, ...)
168 {
169     va_list ap;
170     va_start(ap, format);
171     vwriterror( format, ap);
172     va_end(ap);
173 }
174
175 /* write error and exit */
176 static void fatal( const char *format, ...)
177 {
178     va_list ap;
179
180     writerror("Error, ");
181     va_start(ap, format);
182     vwriterror( format, ap);
183     va_end(ap);
184     writerror(".\n");
185
186     /* exit */
187     exit(1);
188 }
189
190 /* error in the command line */
191 static void argerror( const char *format, ...)
192 {
193     va_list ap;
194
195     writerror("Error, ");
196     va_start(ap, format);
197     vwriterror( format, ap);
198     va_end(ap);
199     writerror(".\nType '"TOOLNAME" help' to get usage.\n");
200
201     /* exit */
202     exit(1);
203 }
204
205 /*== MANAGEMENT OF THE LIST OF READ KEYS ===============================*/
206
207 /* search a key of 'name' and length 'lname' and return it or NULL */
208 static struct key *key_search( const char *name, size_t lname)
209 {
210     struct key *result = keys;
211
212     while(result!=NULL && (strncmp( result->name, name, lname)!=0
213                     || result->name[lname]!=0))
214         result = result->next;
215
216     return result;
217 }
218
219 /* append a new key to the list and return it or NULL if allocations failed */
220 static struct key *key_add( const char *name, size_t lname, 
221                             const char *value, size_t lvalue,
222                             size_t begin_pos, size_t end_pos)
223 {
224     struct key *result, *prev;
225     char *sname, *svalue;
226
227     /* allocations */
228     result = malloc(sizeof *result);
229     sname = strndup( name, lname);
230     svalue = strndup( value, lvalue);
231     if (result == NULL || sname == NULL || svalue == NULL) {
232         /* failure of allocations */
233         free( result);
234         free( sname);
235         free( svalue);
236         result = NULL;
237     }
238     else {
239         /* success: init the structure */
240         result->next = NULL;
241         result->name = sname;
242         result->value = svalue;
243         result->begin = begin_pos;
244         result->end = end_pos;
245         result->dependant = dependant;
246
247         /* link at end of the list */
248         prev = keys;
249         if (prev == NULL)
250             keys = result;
251         else {
252             while(prev!=NULL && prev->next!=NULL)
253                 prev = prev->next;
254             prev->next = result;
255         }
256     }
257
258     return result;
259 }
260
261 /*======================================================================*/
262
263 /* search a var of 'name' and length 'lname' and return it or NULL */
264 static struct var *var_search( const char *name, size_t lname)
265 {
266     struct var *result = vars;
267     while(result!=NULL && (strncmp( result->name, name, lname)!=0
268                     || result->name[lname]!=0))
269         result = result->next;
270
271     return result;
272 }
273
274 /* append a new var to the list and return it or NULL if allocations failed */
275 static struct var *var_add( const char *name, size_t lname, 
276                                                 int depend, const char *value)
277 {
278     struct var *result, *prev;
279     char *sname, *normal;
280     size_t length;
281
282     /* check for the value */
283     if (action == RPM && value != NULL) {
284         length = strlen( value) + 1;
285     }
286     else {
287         value = NULL;
288         length = lname + 4;
289     }
290     /* allocations */
291     result = malloc(sizeof *result);
292     sname = strndup( name, lname);
293     normal = malloc( length);
294     if (result == NULL || sname == NULL || normal == NULL) {
295         /* failure of allocations */
296         free( result);
297         free( sname);
298         free( normal);
299         result = NULL;
300     }
301     else {
302         /* success: init the structure */
303         result->next = NULL;
304         result->name = sname;
305         result->normal = normal;
306         result->dependant = depend;
307         if (value) {
308             memcpy( normal, value, length);
309         }
310         else {
311             *normal++ = '$';
312             *normal++ = '{';
313             memcpy( normal, name, lname);
314             normal += lname;
315             *normal++ = '}';
316             *normal = 0;
317         }
318
319         /* link at end of the list */
320         prev = vars;
321         if (prev == NULL)
322             vars = result;
323         else {
324             while(prev!=NULL && prev->next!=NULL)
325                 prev = prev->next;
326             prev->next = result;
327         }
328     }
329
330     return result;
331 }
332
333 /*== CALLBACK OF PARSING OF THE META FILE ==============================*/
334
335 static void conferr( const char *format, ...)
336 {
337     va_list ap;
338
339     notstderr = action == CHECK;
340     writerror( "ERROR ");
341     va_start(ap, format);
342     vwriterror( format, ap);
343     va_end(ap);
344     notstderr = 0;
345 }
346
347 static int errcb( struct parsing *parsing,
348                 size_t pos, const char *message)
349 {
350     struct parsinfo info;
351
352     /* get the info */
353     parse_utf8_info( parsing, &info, pos);
354
355     /* emit the error */
356     conferr("line %d: %s\n..: %.*s\n..: %*s\n", 
357                 info.lino, message, 
358                 (int)info.length, info.begin,
359                 info.colno, "^"); 
360
361     /* count it */
362     errcount++;
363
364     /* continue to parse */
365     return 1;
366 }
367
368 static int putcb( struct parsing *parsing, 
369                 const char *name, size_t lname, 
370                 const char *value, size_t lvalue,
371                 size_t begin_pos, size_t end_pos)
372 {
373     enum fkey fkey;
374     struct key *key;
375     struct parsinfo here, there;
376
377     /* check that it is not a foreign key */
378     fkey = foreign( name, lname);
379     if (fkey != _FOREIGN_INVALID_) {
380         parse_utf8_info( parsing, &here, begin_pos);
381         conferr("line %d: reserved variable name '%.*s'\n" 
382                 "..: %.*s\n..: %*s\n", 
383                    here.lino, (int)lname, name,
384                    here.lino, (int)here.length, here.begin, here.colno, "^"); 
385
386         errcount++;
387         dependant = 0;
388         return 0;
389     }
390
391     /* search if already defined */
392     key = key_search( name, lname);
393     if (key != NULL) {
394
395         /* yes! that's an error */
396         parse_utf8_info( parsing, &here, begin_pos);
397         parse_utf8_info( parsing, &there, key->begin);
398         conferr("line %d: redefinition of '%s'\n" 
399                 "...was defined line %d\n..: %.*s\n..: %*s\n"
400                 "...is redefined line %d\n..: %.*s\n..: %*s\n", 
401                    here.lino, key->name,
402                    there.lino, (int)there.length, there.begin, there.colno, "^",
403                    here.lino, (int)here.length, here.begin, here.colno, "^"); 
404
405         errcount++;
406         dependant = 0;
407         return 0;
408     }
409
410     /* create and record the key */
411     key = key_add( name, lname, value, lvalue, begin_pos, end_pos);
412     dependant = 0;
413     if (key != NULL)
414         return 0;
415
416     /* no can't because of memory! */
417     fatal("out of memory");
418     errcount++;
419     return -1;
420 }
421
422 static const char *getcb( struct parsing *parsing,
423                 const char *name, size_t length,
424                 size_t begin_pos, size_t end_pos)
425 {
426     struct parsinfo here;
427     struct var *var;
428     enum fkey fkey;
429     struct key *key;
430     int depend;
431
432     /* search if already defined */
433     var = var_search( name, length);
434     if (var != NULL) {
435         /* yes cool, return the normalized form */
436         if (var->dependant)
437             dependant = 1;
438         return var->normal;
439     }
440
441     /* search the variable */
442     fkey = foreign( name, length);
443     key = key_search( name, length);
444
445     if (fkey == _FOREIGN_INVALID_ && key == NULL) {
446
447         /* not a valid variable, emit the error */
448         parse_utf8_info( parsing, &here, begin_pos);
449         conferr("line %d: use of unknown variable '%.*s'\n"
450                 "..: %.*s\n..: %*s\n", 
451                     here.lino, (int)length, name,
452                     (int)here.length, here.begin, here.colno, "^"); 
453         errcount++;
454         dependant = 1; /* kind of invalidity */
455         return "***error***"; /* avoid further error */
456     }
457
458     /* valid variables:  those of foreign or the already defined keys */
459
460     /* set dependant state */
461     depend = fkey != _FOREIGN_INVALID_ || key->dependant;
462     if (depend)
463         dependant = 1;
464
465     /* create and record the variable */
466     var = var_add( name, length, depend, key==NULL ? NULL : key->value);
467     if (var != NULL)
468         /* created, return the normalized form */
469         return var->normal;
470
471     /* memory depletion */
472     fatal("out of memory");
473     dependant = 1; /* kind of invalidity */
474     errcount++;
475     return "***error***"; /* avoid further error */
476 }
477
478 /*======================================================================*/
479
480 /* pretty print the read file */
481 static int pretty( const char *buffer, size_t length, FILE *output)
482 {
483     int status;
484     struct key *key = keys;
485     size_t pos = 0;
486
487     while (pos < length && key != NULL) {
488         if (pos < key->begin) {
489             status = fprintf(output, "%.*s", (int)(key->begin-pos), buffer+pos);
490             if (status < 0)
491                 return status;
492         }
493         status = fprintf( output, "%s=%s", key->name, key->value);
494         if (status < 0)
495             return status;
496         pos = key->end;
497         key = key->next;
498     }
499
500     if (pos < length) {
501         status = fprintf( output, "%.*s", (int)(length-pos), buffer+pos);
502         if (status < 0)
503             return status;
504     }
505
506     return 0;
507 }
508
509 /* generate the header */
510 static int genh( FILE *output)
511 {
512     struct key *key;
513     int status;
514
515     status = fprintf( output, "%s", genh_head);
516     if (status < 0)
517         return status;
518     for (key = keys ; key != NULL ; key = key->next) {
519         status = fprintf( output, "\t%s,\n", key->name);
520         if (status < 0)
521             return status;
522     }
523     status = fprintf( output, "%s", genh_tail);
524     if (status < 0)
525         return status;
526     return 0;
527 }
528
529 /* generate hash code using gperf */
530 static int genc(FILE *output)
531 {
532     struct key *key;
533     int fds[2];
534     pid_t pid;
535     int result, sts;
536     size_t l;
537
538     result = pipe(fds);
539     if (result != 0)
540         return result;
541
542     fflush( output);
543     pid = fork();
544     if (pid == -1) {
545         close( fds[0]);
546         close( fds[1]);
547         fatal( "can't fork");
548         result = -1;
549     }
550     else if (pid == 0) {
551         dup2( fds[0], 0);
552         close( fds[0]);
553         close( fds[1]);
554         if (fileno(output) != 1)
555             dup2( fileno(output), 1);
556         result = execve( gperf_command[0], gperf_command, environ);
557         fatal("can't execute gperf");
558         exit(1);
559     }
560     else {
561         close( fds[0]);
562         sts = write( fds[1], gperf_head, sizeof(gperf_head)-1);
563         if (sts < 0)
564             result = sts;
565         for (key = keys ; key != NULL ; key = key->next) {
566             l = strlen( key->name);
567             sts = write( fds[1], key->name, l);
568             if (sts < 0)
569                 result = sts;
570             sts = write( fds[1], ", ", 2);
571             if (sts < 0)
572                 result = sts;
573             sts = write( fds[1], key->name, l);
574             if (sts < 0)
575                 result = sts;
576             sts = write( fds[1], "\n", 1);
577             if (sts < 0)
578                 result = sts;
579         }
580         close( fds[1]);
581         wait(&result);
582         sts = WIFEXITED(result) && WEXITSTATUS(result)==0 ? 0 : -1;
583         if (sts < 0)
584             result = sts;
585     }
586     return result;
587 }
588
589 /* generate the rpm macros */
590 static int rpm( FILE *output)
591 {
592     struct key *key;
593     int status;
594
595     status = fprintf( output, "%s", rpm_head);
596     if (status < 0)
597         return status;
598     for (key = keys ; key != NULL ; key = key->next) {
599         if (!key->dependant) {
600             status = fprintf( output, "%%%-40s %s\n", key->name, key->value);
601             if (status < 0)
602                 return status;
603         }
604     }
605     return 0;
606 }
607
608 /* main of processing */
609 static int process()
610 {
611     struct parsing parsing;
612     struct buffer buffer;
613     int result;
614
615     /* read the file */
616     result = buffer_create( &buffer, metafilepath);
617     if (result != 0) {
618         fatal( "can't read file %s", metafilepath);
619         return -1;
620     }
621
622     /* parse the file */
623     parsing.buffer = buffer.buffer;
624     parsing.length = buffer.length;
625     parsing.maximum_data_size = 0;
626     parsing.should_escape = action!=RPM;
627     parsing.data = 0;
628     parsing.get = getcb;
629     parsing.put = putcb;
630     parsing.error = errcb;
631     dependant = 0;
632     result = parse_utf8_config( &parsing);
633     if (result != 0) {
634         buffer_destroy( &buffer);
635         fatal( "while parsing the file %s", metafilepath);
636         return -1;
637     }
638     if (errcount != 0) {
639         buffer_destroy( &buffer);
640         fatal( "%d errors detected %s", errcount, metafilepath);
641         return -1;
642     }
643
644     /* process */
645     switch( action) {
646     case CHECK:
647         break;
648     case PRETTY:
649         pretty( buffer.buffer, buffer.length, stdout);
650         break;
651     case GENH:
652         genh( stdout);
653         break;
654     case GENC:
655         genc( stdout);
656         break;
657     case RPM:
658         rpm( stdout);
659         break;
660     }
661
662     buffer_destroy( &buffer);
663     return 0;
664 }
665
666 /*======================================================================*/
667
668 /* very simple argument parsing */
669 static int arguments( char **argv)
670 {
671     /* skip the program name*/
672     argv++;
673
674     /* scan first arg */
675     if (*argv == NULL) {
676         /* no argument then default is to check */
677         action = CHECK;
678     }
679     else {
680         /* check if first argument is 'check', 'pretty', 'c', 'h', '-h',
681            '--help' or 'help' */
682         if (0 == strcmp( *argv, "check")) {
683             action = CHECK;
684             argv++;
685         }
686         else if (0 == strcmp( *argv, "pretty")) {
687             action = PRETTY;
688             argv++;
689         }
690         else if (0 == strcmp( *argv, "c")) {
691             action = GENC;
692             argv++;
693         }
694         else if (0 == strcmp( *argv, "h")) {
695             action = GENH;
696             argv++;
697         }
698         else if (0 == strcmp( *argv, "rpm")) {
699             action = RPM;
700             argv++;
701         }
702         else if (0 == strcmp( *argv, "help")) {
703             printf("%s", help);
704             exit(0);
705             return -1;
706         }
707         else if (**argv == '-') {
708             if (0 == strcmp( *argv, "--") || 0 == strcmp( *argv, "-") ) {
709                 action = CHECK;
710             }
711             else {
712                 argerror( "unknown option '%s'", *argv);
713                 return -1;
714             }
715         }
716         /* skip the -- arg if present */
717         if (*argv != NULL && 0 == strcmp( *argv, "--")) {
718             argv++;
719         }
720         /* get a meta file argument */
721         if (*argv != NULL) {
722             if (0 == strcmp( *argv, "-"))
723                 metafilepath = "/dev/stdin";
724             else
725                 metafilepath = *argv;
726             argv++;
727         }
728         /* check that there is no extra argument */
729         if (*argv != NULL) {
730             argerror("extra argument found '%s'",*argv);
731             return -1;
732         }   
733     }
734     return 0;
735 }
736
737 int main(int argc, char **argv)
738 {
739     if (arguments(argv) == 0)
740         if (process() == 0)
741             return 0;
742
743     return 1;
744 }
745
746