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 */
250 /* success: init the structure */
252 result->name = sname;
253 result->value = svalue;
254 result->begin = begin_pos;
255 result->end = end_pos;
256 result->dependant = dependant;
258 /* link at end of the list */
263 while (prev != NULL && prev->next != NULL)
272 /*======================================================================*/
274 /* search a var of 'name' and length 'lname' and return it or NULL */
275 static struct var *var_search(const char *name, size_t lname)
277 struct var *result = vars;
278 while (result != NULL && (strncmp(result->name, name, lname) != 0
279 || result->name[lname] != 0))
280 result = result->next;
285 /* append a new var to the list and return it or NULL if allocations failed */
286 static struct var *var_add(const char *name, size_t lname,
287 int depend, const char *value)
289 struct var *result, *prev;
290 char *sname, *normal;
293 /* check for the value */
294 if (action == RPM && value != NULL) {
295 length = strlen(value) + 1;
301 result = malloc(sizeof *result);
302 sname = strndup(name, lname);
303 normal = malloc(length);
304 if (result == NULL || sname == NULL || normal == NULL) {
305 /* failure of allocations */
311 /* success: init the structure */
313 result->name = sname;
314 result->normal = normal;
315 result->dependant = depend;
317 memcpy(normal, value, length);
321 memcpy(normal, name, lname);
327 /* link at end of the list */
332 while (prev != NULL && prev->next != NULL)
341 /*== CALLBACK OF PARSING OF THE META FILE ==============================*/
343 static void conferr(const char *format, ...)
347 notstderr = action == CHECK;
349 va_start(ap, format);
350 vwriterror(format, ap);
355 static int errcb(struct parsing *parsing,
356 size_t pos, const char *message)
358 struct parsinfo info;
361 parse_utf8_info(parsing, &info, pos);
364 conferr("line %d: %s\n..: %.*s\n..: %*s\n",
366 (int)info.length, info.begin,
372 /* continue to parse */
376 static int putcb(struct parsing *parsing,
377 const char *name, size_t lname,
378 const char *value, size_t lvalue,
379 size_t begin_pos, size_t end_pos)
383 struct parsinfo here, there;
385 /* check that it is not a foreign key */
386 fkey = foreign(name, lname);
387 if (fkey != _FOREIGN_INVALID_) {
388 parse_utf8_info(parsing, &here, begin_pos);
389 conferr("line %d: reserved variable name '%.*s'\n"
390 "..: %.*s\n..: %*s\n",
391 here.lino, (int)lname, name,
392 here.lino, (int)here.length, here.begin, here.colno, "^");
399 /* search if already defined */
400 key = key_search(name, lname);
403 /* yes! that's an error */
404 parse_utf8_info(parsing, &here, begin_pos);
405 parse_utf8_info(parsing, &there, key->begin);
406 conferr("line %d: redefinition of '%s'\n"
407 "...was defined line %d\n..: %.*s\n..: %*s\n"
408 "...is redefined line %d\n..: %.*s\n..: %*s\n",
409 here.lino, key->name,
410 there.lino, (int)there.length, there.begin, there.colno, "^",
411 here.lino, (int)here.length, here.begin, here.colno, "^");
418 /* create and record the key */
419 key = key_add(name, lname, value, lvalue, begin_pos, end_pos);
424 /* no can't because of memory! */
425 fatal("out of memory");
430 static const char *getcb(struct parsing *parsing,
431 const char *name, size_t length,
432 size_t begin_pos, size_t end_pos)
434 struct parsinfo here;
440 /* search if already defined */
441 var = var_search(name, length);
443 /* yes cool, return the normalized form */
449 /* search the variable */
450 fkey = foreign(name, length);
451 key = key_search(name, length);
453 if (fkey == _FOREIGN_INVALID_ && key == NULL) {
455 /* not a valid variable, emit the error */
456 parse_utf8_info(parsing, &here, begin_pos);
457 conferr("line %d: use of unknown variable '%.*s'\n"
458 "..: %.*s\n..: %*s\n",
459 here.lino, (int)length, name,
460 (int)here.length, here.begin, here.colno, "^");
462 dependant = 1; /* kind of invalidity */
463 return "***error***"; /* avoid further error */
466 /* valid variables: those of foreign or the already defined keys */
468 /* set dependant state */
469 depend = fkey != _FOREIGN_INVALID_ || key->dependant;
473 /* create and record the variable */
474 var = var_add(name, length, depend, key == NULL ? NULL : key->value);
476 /* created, return the normalized form */
479 /* memory depletion */
480 fatal("out of memory");
481 dependant = 1; /* kind of invalidity */
483 return "***error***"; /* avoid further error */
486 /*======================================================================*/
488 /* compare two keys */
489 static int keycmp(const void *a, const void *b)
491 const struct key *ka = *(const struct key **)a;
492 const struct key *kb = *(const struct key **)b;
493 return strcmp(ka->name, kb->name);
496 /* sort the keys and return their count */
497 static int sortkeys()
499 struct key *key = keys, **array;
500 int count = 0, index;
507 array = malloc(count * sizeof * array);
515 array[index++] = key;
519 qsort(array, count, sizeof * array, keycmp);
522 array[--index]->next = key;
531 /*======================================================================*/
533 /* pretty print the read file */
534 static int pretty(const char *buffer, size_t length, FILE *output)
537 struct key *key = keys;
540 while (pos < length && key != NULL) {
541 if (pos < key->begin) {
542 status = fprintf(output, "%.*s", (int)(key->begin-pos), buffer+pos);
546 status = fprintf(output, "%s=%s", key->name, key->value);
554 status = fprintf(output, "%.*s", (int)(length-pos), buffer+pos);
562 /* generate the header */
563 static int genh(FILE *output)
574 status = fprintf(output, "%s", genh_head);
577 for (key = keys ; key != NULL ; key = key->next) {
578 status = fprintf(output, "\t%s,\n", key->name);
582 status = fprintf(output, "%s", genh_tail);
588 /* generate hash code using gperf */
589 static int genc(FILE *output)
614 } else if (pid == 0) {
618 if (fileno(output) != 1)
619 dup2(fileno(output), 1);
620 result = execve(gperf_command[0], gperf_command, environ);
621 fatal("can't execute gperf");
625 sts = write(fds[1], gperf_head, sizeof(gperf_head)-1);
628 for (key = keys ; key != NULL ; key = key->next) {
629 l = strlen(key->name);
630 sts = write(fds[1], key->name, l);
633 sts = write(fds[1], ", ", 2);
636 sts = write(fds[1], key->name, l);
639 sts = write(fds[1], "\n", 1);
645 sts = WIFEXITED(result) && WEXITSTATUS(result) == 0 ? 0 : -1;
652 /* generate the rpm macros */
653 static int rpm(FILE *output)
664 status = fprintf(output, "%s", rpm_head);
667 for (key = keys ; key != NULL ; key = key->next) {
668 if (!key->dependant) {
669 status = fprintf(output, "%%%-40s %s\n", key->name, key->value);
677 /* generate the signup */
678 static int signup(FILE *output)
683 struct sha256sum *sum;
693 sum = sha256sum_create();
698 for (key = keys ; key != NULL ; key = key->next) {
699 status = sha256sum_add_data(sum, key->name, strlen(key->name));
701 sha256sum_destroy(sum);
704 status = sha256sum_add_data(sum, &term, 1);
706 sha256sum_destroy(sum);
711 status = sha256sum_get(sum, signup);
712 sha256sum_destroy(sum);
716 status = fprintf(output, "%s", signup_head);
720 for (i = 0 ; i < 32 ; i++) {
721 status = fprintf(output, "%s'\\x%02x'%s",
723 (int)(unsigned char)signup[i],
724 (i & 7) < 7 ? "," : i == 31 ? "\n" : ",\n");
728 status = fprintf(output, "%s", signup_tail);
734 /* main of processing */
737 struct parsing parsing;
738 struct buffer buffer;
742 result = buffer_create(&buffer, metafilepath);
744 fatal("can't read file %s", metafilepath);
749 parsing.buffer = buffer.buffer;
750 parsing.length = buffer.length;
751 parsing.maximum_data_size = 0;
752 parsing.should_escape = action != RPM;
756 parsing.error = errcb;
758 result = parse_utf8_config(&parsing);
760 buffer_destroy(&buffer);
761 fatal("while parsing the file %s", metafilepath);
765 buffer_destroy(&buffer);
766 fatal("%d errors detected %s", errcount, metafilepath);
775 pretty(buffer.buffer, buffer.length, stdout);
791 buffer_destroy(&buffer);
795 /*======================================================================*/
797 /* very simple argument parsing */
798 static int arguments(char **argv)
800 /* skip the program name*/
805 /* no argument then default is to check */
808 /* check if first argument is 'check', 'pretty', 'c', 'h', '-h',
809 '--help' or 'help' */
810 if (0 == strcmp(*argv, "check")) {
813 } else if (0 == strcmp(*argv, "pretty")) {
816 } else if (0 == strcmp(*argv, "c")) {
819 } else if (0 == strcmp(*argv, "h")) {
822 } else if (0 == strcmp(*argv, "rpm")) {
825 } else if (0 == strcmp(*argv, "signup")) {
828 } else if (0 == strcmp(*argv, "help") || 0 == strcmp(*argv, "--help")) {
832 } else if (**argv == '-') {
833 if (0 == strcmp(*argv, "--") || 0 == strcmp(*argv, "-")) {
836 argerror("unknown option '%s'", *argv);
840 /* skip the -- arg if present */
841 if (*argv != NULL && 0 == strcmp(*argv, "--"))
843 /* get a meta file argument */
845 if (0 == strcmp(*argv, "-"))
846 metafilepath = "/dev/stdin";
848 metafilepath = *argv;
851 /* check that there is no extra argument */
853 argerror("extra argument found '%s'", *argv);
860 int main(int argc, char **argv)
862 if (arguments(argv) == 0)