2 * Copyright (C) 2013 Intel Corporation.
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.
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.
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
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>
42 /*======================================================================*/
45 # define CONFIGPATH "/etc/tizen-platform.conf"
49 # define TOOLNAME "tzplatform-tool"
52 /*== TYPES =============================================================*/
54 /* for recording read keys */
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) */
64 /* for recording used variables */
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) */
72 /*== STATIC DATA =======================================================*/
74 static char help[] = "\
76 usage: "TOOLNAME" [command] [--] [file]\n\
78 You can specify the 'file' to process.\n\
79 The default file is "CONFIGPATH"\n\
80 Specifying - mean the standard input.\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\
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\
100 enum tzplatform_variable {\n\
101 \t_TZPLATFORM_VARIABLES_INVALID_ = -1,\n\
104 static char genh_tail[] = "\
105 \t_TZPLATFORM_VARIABLES_COUNT_\n\
107 #ifdef __cplusplus\n\
113 static char gperf_head[] = "\
116 enum tzplatform_variable id;\n\
121 static char *gperf_command[] = {
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_\"",
130 static char rpm_head[] = "\
131 # I'm generated. Dont edit me! \n\
135 /*== GLOBALS VARIABLES =================================================*/
137 /* name of the meta file to process */
138 static const char * metafilepath = CONFIGPATH;
140 /* list of the read keys */
141 static struct key *keys = NULL;
143 /* list of the used variables */
144 static struct var *vars = NULL;
146 /* count of errors */
147 static int errcount = 0;
149 /* dependency state */
150 static int dependant = 0;
152 /* action to perform */
153 static enum { CHECK, PRETTY, GENC, GENH, RPM } action = CHECK;
155 /* output of error */
156 static int notstderr = 0;
158 /*======================================================================*/
160 /* write the error message */
161 static void vwriterror( const char *format, va_list ap)
163 vfprintf(notstderr ? stdout : stderr, format, ap);
166 /* write the error message */
167 static void writerror( const char *format, ...)
170 va_start(ap, format);
171 vwriterror( format, ap);
175 /* write error and exit */
176 static void fatal( const char *format, ...)
180 writerror("Error, ");
181 va_start(ap, format);
182 vwriterror( format, ap);
190 /* error in the command line */
191 static void argerror( const char *format, ...)
195 writerror("Error, ");
196 va_start(ap, format);
197 vwriterror( format, ap);
199 writerror(".\nType '"TOOLNAME" help' to get usage.\n");
205 /*== MANAGEMENT OF THE LIST OF READ KEYS ===============================*/
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)
210 struct key *result = keys;
212 while(result!=NULL && (strncmp( result->name, name, lname)!=0
213 || result->name[lname]!=0))
214 result = result->next;
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)
224 struct key *result, *prev;
225 char *sname, *svalue;
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 */
239 /* success: init the structure */
241 result->name = sname;
242 result->value = svalue;
243 result->begin = begin_pos;
244 result->end = end_pos;
245 result->dependant = dependant;
247 /* link at end of the list */
252 while(prev!=NULL && prev->next!=NULL)
261 /*======================================================================*/
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)
266 struct var *result = vars;
267 while(result!=NULL && (strncmp( result->name, name, lname)!=0
268 || result->name[lname]!=0))
269 result = result->next;
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)
278 struct var *result, *prev;
279 char *sname, *normal;
282 /* check for the value */
283 if (action == RPM && value != NULL) {
284 length = strlen( value) + 1;
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 */
302 /* success: init the structure */
304 result->name = sname;
305 result->normal = normal;
306 result->dependant = depend;
308 memcpy( normal, value, length);
313 memcpy( normal, name, lname);
319 /* link at end of the list */
324 while(prev!=NULL && prev->next!=NULL)
333 /*== CALLBACK OF PARSING OF THE META FILE ==============================*/
335 static void conferr( const char *format, ...)
339 notstderr = action == CHECK;
340 writerror( "ERROR ");
341 va_start(ap, format);
342 vwriterror( format, ap);
347 static int errcb( struct parsing *parsing,
348 size_t pos, const char *message)
350 struct parsinfo info;
353 parse_utf8_info( parsing, &info, pos);
356 conferr("line %d: %s\n..: %.*s\n..: %*s\n",
358 (int)info.length, info.begin,
364 /* continue to parse */
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)
375 struct parsinfo here, there;
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, "^");
391 /* search if already defined */
392 key = key_search( name, lname);
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, "^");
410 /* create and record the key */
411 key = key_add( name, lname, value, lvalue, begin_pos, end_pos);
416 /* no can't because of memory! */
417 fatal("out of memory");
422 static const char *getcb( struct parsing *parsing,
423 const char *name, size_t length,
424 size_t begin_pos, size_t end_pos)
426 struct parsinfo here;
432 /* search if already defined */
433 var = var_search( name, length);
435 /* yes cool, return the normalized form */
441 /* search the variable */
442 fkey = foreign( name, length);
443 key = key_search( name, length);
445 if (fkey == _FOREIGN_INVALID_ && key == NULL) {
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, "^");
454 dependant = 1; /* kind of invalidity */
455 return "***error***"; /* avoid further error */
458 /* valid variables: those of foreign or the already defined keys */
460 /* set dependant state */
461 depend = fkey != _FOREIGN_INVALID_ || key->dependant;
465 /* create and record the variable */
466 var = var_add( name, length, depend, key==NULL ? NULL : key->value);
468 /* created, return the normalized form */
471 /* memory depletion */
472 fatal("out of memory");
473 dependant = 1; /* kind of invalidity */
475 return "***error***"; /* avoid further error */
478 /*======================================================================*/
480 /* pretty print the read file */
481 static int pretty( const char *buffer, size_t length, FILE *output)
484 struct key *key = keys;
487 while (pos < length && key != NULL) {
488 if (pos < key->begin) {
489 status = fprintf(output, "%.*s", (int)(key->begin-pos), buffer+pos);
493 status = fprintf( output, "%s=%s", key->name, key->value);
501 status = fprintf( output, "%.*s", (int)(length-pos), buffer+pos);
509 /* generate the header */
510 static int genh( FILE *output)
515 status = fprintf( output, "%s", genh_head);
518 for (key = keys ; key != NULL ; key = key->next) {
519 status = fprintf( output, "\t%s,\n", key->name);
523 status = fprintf( output, "%s", genh_tail);
529 /* generate hash code using gperf */
530 static int genc(FILE *output)
547 fatal( "can't fork");
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");
562 sts = write( fds[1], gperf_head, sizeof(gperf_head)-1);
565 for (key = keys ; key != NULL ; key = key->next) {
566 l = strlen( key->name);
567 sts = write( fds[1], key->name, l);
570 sts = write( fds[1], ", ", 2);
573 sts = write( fds[1], key->name, l);
576 sts = write( fds[1], "\n", 1);
582 sts = WIFEXITED(result) && WEXITSTATUS(result)==0 ? 0 : -1;
589 /* generate the rpm macros */
590 static int rpm( FILE *output)
595 status = fprintf( output, "%s", rpm_head);
598 for (key = keys ; key != NULL ; key = key->next) {
599 if (!key->dependant) {
600 status = fprintf( output, "%%%-40s %s\n", key->name, key->value);
608 /* main of processing */
611 struct parsing parsing;
612 struct buffer buffer;
616 result = buffer_create( &buffer, metafilepath);
618 fatal( "can't read file %s", metafilepath);
623 parsing.buffer = buffer.buffer;
624 parsing.length = buffer.length;
625 parsing.maximum_data_size = 0;
626 parsing.should_escape = action!=RPM;
630 parsing.error = errcb;
632 result = parse_utf8_config( &parsing);
634 buffer_destroy( &buffer);
635 fatal( "while parsing the file %s", metafilepath);
639 buffer_destroy( &buffer);
640 fatal( "%d errors detected %s", errcount, metafilepath);
649 pretty( buffer.buffer, buffer.length, stdout);
662 buffer_destroy( &buffer);
666 /*======================================================================*/
668 /* very simple argument parsing */
669 static int arguments( char **argv)
671 /* skip the program name*/
676 /* no argument then default is to check */
680 /* check if first argument is 'check', 'pretty', 'c', 'h', '-h',
681 '--help' or 'help' */
682 if (0 == strcmp( *argv, "check")) {
686 else if (0 == strcmp( *argv, "pretty")) {
690 else if (0 == strcmp( *argv, "c")) {
694 else if (0 == strcmp( *argv, "h")) {
698 else if (0 == strcmp( *argv, "rpm")) {
702 else if (0 == strcmp( *argv, "help")) {
707 else if (**argv == '-') {
708 if (0 == strcmp( *argv, "--") || 0 == strcmp( *argv, "-") ) {
712 argerror( "unknown option '%s'", *argv);
716 /* skip the -- arg if present */
717 if (*argv != NULL && 0 == strcmp( *argv, "--")) {
720 /* get a meta file argument */
722 if (0 == strcmp( *argv, "-"))
723 metafilepath = "/dev/stdin";
725 metafilepath = *argv;
728 /* check that there is no extra argument */
730 argerror("extra argument found '%s'",*argv);
737 int main(int argc, char **argv)
739 if (arguments(argv) == 0)