2 * Copyright (C) 2013-2014 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>
41 #include "sha256sum.h"
43 /*======================================================================*/
46 # define CONFIGPATH "/etc/tizen-platform.conf"
50 # define TOOLNAME "tzplatform-tool"
53 /*== TYPES =============================================================*/
55 /* for recording read keys */
57 struct key *next; /* link to next */
58 const char *name; /* name of the key */
59 const char *value; /* value of the key */
60 size_t begin; /* positions of begin (used by pretty) */
61 size_t end; /* positions of end (used by pretty) */
62 int dependant; /* is dependant (used by rpm) */
65 /* for recording used variables */
67 struct var *next; /* link to next */
68 const char *name; /* name of the variable */
69 const char *normal; /* normalized value: "${name}" (for pretty) */
70 int dependant; /* is dependant (used by rpm) */
73 /*== STATIC DATA =======================================================*/
75 static char help[] = "\
77 usage: "TOOLNAME" [command] [--] [file]\n\
79 You can specify the 'file' to process.\n\
80 The default file is "CONFIGPATH"\n\
81 Specifying - mean the standard input.\n\
85 help Display this help\n\
86 check Check validity of 'file' (this is the default command)\n\
87 pretty Pretty print of the 'file' (the normalized format)\n\
88 h Produce the C header with the enumeration of the variables\n\
89 c Produce the C code to hash the variable names\n\
90 rpm Produce the macro file to use with RPM\n\
91 signup Produce the signup data for the proxy linked statically\n\
95 static char genh_head[] = "\
96 /* I'm generated. Dont edit me! */\n\
97 #ifndef TZPLATFORM_VARIABLES_H\n\
98 #define TZPLATFORM_VARIABLES_H\n\
102 enum tzplatform_variable {\n\
103 \t_TZPLATFORM_VARIABLES_INVALID_ = -1,\n\
106 static char genh_tail[] = "\
107 \t_TZPLATFORM_VARIABLES_COUNT_\n\
109 #ifdef __cplusplus\n\
115 static char gperf_head[] = "\
123 static char *gperf_command[] = {
126 "gperf -r -m 100 --null-strings -C -P -L ANSI-C -c"
127 " -t -N hashvar -Q varpool -K offset -G -W namassoc"
128 " -F \", _TZPLATFORM_VARIABLES_INVALID_\"",
132 static char rpm_head[] = "\
133 # I'm generated. Dont edit me! \n\
137 static char signup_head[] = "\
138 /* I'm generated. Dont edit me! */\n\
139 static char tizen_platform_config_signup[33] = {\n\
143 static char signup_tail[] = "\
147 /*== GLOBALS VARIABLES =================================================*/
149 /* name of the meta file to process */
150 static const char * metafilepath = CONFIGPATH;
152 /* list of the read keys */
153 static struct key *keys = NULL;
155 /* list of the used variables */
156 static struct var *vars = NULL;
158 /* count of errors */
159 static int errcount = 0;
161 /* dependency state */
162 static int dependant = 0;
164 /* action to perform */
165 static enum { CHECK, PRETTY, GENC, GENH, RPM, SIGNUP } action = CHECK;
167 /* output of error */
168 static int notstderr = 0;
170 /*======================================================================*/
172 /* write the error message */
173 static void vwriterror( const char *format, va_list ap)
175 vfprintf(notstderr ? stdout : stderr, format, ap);
178 /* write the error message */
179 static void writerror( const char *format, ...)
182 va_start(ap, format);
183 vwriterror( format, ap);
187 /* write error and exit */
188 static void fatal( const char *format, ...)
192 writerror("Error, ");
193 va_start(ap, format);
194 vwriterror( format, ap);
202 /* error in the command line */
203 static void argerror( const char *format, ...)
207 writerror("Error, ");
208 va_start(ap, format);
209 vwriterror( format, ap);
211 writerror(".\nType '"TOOLNAME" help' to get usage.\n");
217 /*== MANAGEMENT OF THE LIST OF READ KEYS ===============================*/
219 /* search a key of 'name' and length 'lname' and return it or NULL */
220 static struct key *key_search( const char *name, size_t lname)
222 struct key *result = keys;
224 while(result!=NULL && (strncmp( result->name, name, lname)!=0
225 || result->name[lname]!=0))
226 result = result->next;
231 /* append a new key to the list and return it or NULL if allocations failed */
232 static struct key *key_add( const char *name, size_t lname,
233 const char *value, size_t lvalue,
234 size_t begin_pos, size_t end_pos)
236 struct key *result, *prev;
237 char *sname, *svalue;
240 result = malloc(sizeof *result);
241 sname = strndup( name, lname);
242 svalue = strndup( value, lvalue);
243 if (result == NULL || sname == NULL || svalue == NULL) {
244 /* failure of allocations */
251 /* success: init the structure */
253 result->name = sname;
254 result->value = svalue;
255 result->begin = begin_pos;
256 result->end = end_pos;
257 result->dependant = dependant;
259 /* link at end of the list */
264 while(prev!=NULL && prev->next!=NULL)
273 /*======================================================================*/
275 /* search a var of 'name' and length 'lname' and return it or NULL */
276 static struct var *var_search( const char *name, size_t lname)
278 struct var *result = vars;
279 while(result!=NULL && (strncmp( result->name, name, lname)!=0
280 || result->name[lname]!=0))
281 result = result->next;
286 /* append a new var to the list and return it or NULL if allocations failed */
287 static struct var *var_add( const char *name, size_t lname,
288 int depend, const char *value)
290 struct var *result, *prev;
291 char *sname, *normal;
294 /* check for the value */
295 if (action == RPM && value != NULL) {
296 length = strlen( value) + 1;
303 result = malloc(sizeof *result);
304 sname = strndup( name, lname);
305 normal = malloc( length);
306 if (result == NULL || sname == NULL || normal == NULL) {
307 /* failure of allocations */
314 /* success: init the structure */
316 result->name = sname;
317 result->normal = normal;
318 result->dependant = depend;
320 memcpy( normal, value, length);
325 memcpy( normal, name, lname);
331 /* link at end of the list */
336 while(prev!=NULL && prev->next!=NULL)
345 /*== CALLBACK OF PARSING OF THE META FILE ==============================*/
347 static void conferr( const char *format, ...)
351 notstderr = action == CHECK;
352 writerror( "ERROR ");
353 va_start(ap, format);
354 vwriterror( format, ap);
359 static int errcb( struct parsing *parsing,
360 size_t pos, const char *message)
362 struct parsinfo info;
365 parse_utf8_info( parsing, &info, pos);
368 conferr("line %d: %s\n..: %.*s\n..: %*s\n",
370 (int)info.length, info.begin,
376 /* continue to parse */
380 static int putcb( struct parsing *parsing,
381 const char *name, size_t lname,
382 const char *value, size_t lvalue,
383 size_t begin_pos, size_t end_pos)
387 struct parsinfo here, there;
389 /* check that it is not a foreign key */
390 fkey = foreign( name, lname);
391 if (fkey != _FOREIGN_INVALID_) {
392 parse_utf8_info( parsing, &here, begin_pos);
393 conferr("line %d: reserved variable name '%.*s'\n"
394 "..: %.*s\n..: %*s\n",
395 here.lino, (int)lname, name,
396 here.lino, (int)here.length, here.begin, here.colno, "^");
403 /* search if already defined */
404 key = key_search( name, lname);
407 /* yes! that's an error */
408 parse_utf8_info( parsing, &here, begin_pos);
409 parse_utf8_info( parsing, &there, key->begin);
410 conferr("line %d: redefinition of '%s'\n"
411 "...was defined line %d\n..: %.*s\n..: %*s\n"
412 "...is redefined line %d\n..: %.*s\n..: %*s\n",
413 here.lino, key->name,
414 there.lino, (int)there.length, there.begin, there.colno, "^",
415 here.lino, (int)here.length, here.begin, here.colno, "^");
422 /* create and record the key */
423 key = key_add( name, lname, value, lvalue, begin_pos, end_pos);
428 /* no can't because of memory! */
429 fatal("out of memory");
434 static const char *getcb( struct parsing *parsing,
435 const char *name, size_t length,
436 size_t begin_pos, size_t end_pos)
438 struct parsinfo here;
444 /* search if already defined */
445 var = var_search( name, length);
447 /* yes cool, return the normalized form */
453 /* search the variable */
454 fkey = foreign( name, length);
455 key = key_search( name, length);
457 if (fkey == _FOREIGN_INVALID_ && key == NULL) {
459 /* not a valid variable, emit the error */
460 parse_utf8_info( parsing, &here, begin_pos);
461 conferr("line %d: use of unknown variable '%.*s'\n"
462 "..: %.*s\n..: %*s\n",
463 here.lino, (int)length, name,
464 (int)here.length, here.begin, here.colno, "^");
466 dependant = 1; /* kind of invalidity */
467 return "***error***"; /* avoid further error */
470 /* valid variables: those of foreign or the already defined keys */
472 /* set dependant state */
473 depend = fkey != _FOREIGN_INVALID_ || key->dependant;
477 /* create and record the variable */
478 var = var_add( name, length, depend, key==NULL ? NULL : key->value);
480 /* created, return the normalized form */
483 /* memory depletion */
484 fatal("out of memory");
485 dependant = 1; /* kind of invalidity */
487 return "***error***"; /* avoid further error */
490 /*======================================================================*/
492 /* compare two keys */
493 static int keycmp(const void *a, const void *b)
495 const struct key *ka = *(const struct key **)a;
496 const struct key *kb = *(const struct key **)b;
497 return strcmp(ka->name, kb->name);
500 /* sort the keys and return their count */
501 static int sortkeys()
503 struct key *key = keys, **array;
504 int count = 0, index;
511 array = malloc( count * sizeof * array);
519 array[index++] = key;
523 qsort(array, count, sizeof * array, keycmp);
526 array[--index]->next = key;
535 /*======================================================================*/
537 /* pretty print the read file */
538 static int pretty( const char *buffer, size_t length, FILE *output)
541 struct key *key = keys;
544 while (pos < length && key != NULL) {
545 if (pos < key->begin) {
546 status = fprintf(output, "%.*s", (int)(key->begin-pos), buffer+pos);
550 status = fprintf( output, "%s=%s", key->name, key->value);
558 status = fprintf( output, "%.*s", (int)(length-pos), buffer+pos);
566 /* generate the header */
567 static int genh( FILE *output)
578 status = fprintf( output, "%s", genh_head);
581 for (key = keys ; key != NULL ; key = key->next) {
582 status = fprintf( output, "\t%s,\n", key->name);
586 status = fprintf( output, "%s", genh_tail);
592 /* generate hash code using gperf */
593 static int genc(FILE *output)
616 fatal( "can't fork");
623 if (fileno(output) != 1)
624 dup2( fileno(output), 1);
625 result = execve( gperf_command[0], gperf_command, environ);
626 fatal("can't execute gperf");
631 sts = write( fds[1], gperf_head, sizeof(gperf_head)-1);
634 for (key = keys ; key != NULL ; key = key->next) {
635 l = strlen( key->name);
636 sts = write( fds[1], key->name, l);
639 sts = write( fds[1], ", ", 2);
642 sts = write( fds[1], key->name, l);
645 sts = write( fds[1], "\n", 1);
651 sts = WIFEXITED(result) && WEXITSTATUS(result)==0 ? 0 : -1;
658 /* generate the rpm macros */
659 static int rpm( FILE *output)
670 status = fprintf( output, "%s", rpm_head);
673 for (key = keys ; key != NULL ; key = key->next) {
674 if (!key->dependant) {
675 status = fprintf( output, "%%%-40s %s\n", key->name, key->value);
683 /* generate the signup */
684 static int signup( FILE *output)
689 struct sha256sum *sum;
699 sum = sha256sum_create();
704 for (key = keys ; key != NULL ; key = key->next) {
705 status = sha256sum_add_data(sum, key->name, strlen(key->name));
707 sha256sum_destroy(sum);
710 status = sha256sum_add_data(sum, &term, 1);
712 sha256sum_destroy(sum);
717 status = sha256sum_get(sum, signup);
718 sha256sum_destroy(sum);
722 status = fprintf( output, "%s", signup_head);
726 for (i=0 ; i<32 ; i++) {
727 status = fprintf( output, "%s'\\x%02x'%s",
729 (int)(unsigned char)signup[i],
730 (i & 7) < 7 ? "," : i == 31 ? "\n" : ",\n");
734 status = fprintf( output, "%s", signup_tail);
740 /* main of processing */
743 struct parsing parsing;
744 struct buffer buffer;
748 result = buffer_create( &buffer, metafilepath);
750 fatal( "can't read file %s", metafilepath);
755 parsing.buffer = buffer.buffer;
756 parsing.length = buffer.length;
757 parsing.maximum_data_size = 0;
758 parsing.should_escape = action!=RPM;
762 parsing.error = errcb;
764 result = parse_utf8_config( &parsing);
766 buffer_destroy( &buffer);
767 fatal( "while parsing the file %s", metafilepath);
771 buffer_destroy( &buffer);
772 fatal( "%d errors detected %s", errcount, metafilepath);
781 pretty( buffer.buffer, buffer.length, stdout);
797 buffer_destroy( &buffer);
801 /*======================================================================*/
803 /* very simple argument parsing */
804 static int arguments( char **argv)
806 /* skip the program name*/
811 /* no argument then default is to check */
815 /* check if first argument is 'check', 'pretty', 'c', 'h', '-h',
816 '--help' or 'help' */
817 if (0 == strcmp( *argv, "check")) {
821 else if (0 == strcmp( *argv, "pretty")) {
825 else if (0 == strcmp( *argv, "c")) {
829 else if (0 == strcmp( *argv, "h")) {
833 else if (0 == strcmp( *argv, "rpm")) {
837 else if (0 == strcmp( *argv, "signup")) {
841 else if (0 == strcmp( *argv, "help") || 0 == strcmp( *argv, "--help")) {
846 else if (**argv == '-') {
847 if (0 == strcmp( *argv, "--") || 0 == strcmp( *argv, "-") ) {
851 argerror( "unknown option '%s'", *argv);
855 /* skip the -- arg if present */
856 if (*argv != NULL && 0 == strcmp( *argv, "--")) {
859 /* get a meta file argument */
861 if (0 == strcmp( *argv, "-"))
862 metafilepath = "/dev/stdin";
864 metafilepath = *argv;
867 /* check that there is no extra argument */
869 argerror("extra argument found '%s'",*argv);
876 int main(int argc, char **argv)
878 if (arguments(argv) == 0)