123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- /****************************************************************************
- *
- * MODULE: g.parser
- * AUTHOR(S): Glynn Clements <glynn gclements.plus.com> (original contributor)
- * Bernhard Reiter <bernhard intevation.de>,
- * Cedric Shock <cedricgrass shockfamily.net>,
- * Hamish Bowman <hamish_nospam yahoo.com>,
- * Paul Kelly <paul-grass stjohnspoint.co.uk>,
- * Radim Blazek <radim.blazek gmail.com>
- * PURPOSE:
- * COPYRIGHT: (C) 2001-2007 by the GRASS Development Team
- *
- * This program is free software under the GNU General Public
- * License (>=v2). Read the file COPYING that comes with GRASS
- * for details.
- *
- *****************************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <ctype.h>
- #include <grass/gis.h>
- #include <grass/glocale.h>
- enum state
- {
- S_TOPLEVEL,
- S_MODULE,
- S_FLAG,
- S_OPTION
- };
- struct context
- {
- struct GModule *module;
- struct Option *option;
- struct Flag *flag;
- struct Option *first_option;
- struct Flag *first_flag;
- int state;
- FILE *fp;
- int line;
- };
- int translate_output = 0;
- /* Returns translated version of a string.
- If global variable to output strings for translation is set it spits them out */
- char *translate(const char *arg)
- {
- if (*arg && translate_output) {
- fputs(arg, stdout);
- fputs("\n", stdout);
- }
- return _(arg);
- }
- static void parse_toplevel(struct context *ctx, const char *cmd)
- {
- if (strcasecmp(cmd, "module") == 0) {
- ctx->state = S_MODULE;
- ctx->module = G_define_module();
- return;
- }
- if (strcasecmp(cmd, "flag") == 0) {
- ctx->state = S_FLAG;
- ctx->flag = G_define_flag();
- if (!ctx->first_flag)
- ctx->first_flag = ctx->flag;
- return;
- }
- if (strcasecmp(cmd, "option") == 0) {
- ctx->state = S_OPTION;
- ctx->option = G_define_option();
- if (!ctx->first_option)
- ctx->first_option = ctx->option;
- return;
- }
- fprintf(stderr, "Unknown command \"%s\" at line %d\n", cmd, ctx->line);
- }
- static void parse_module(struct context *ctx, const char *cmd,
- const char *arg)
- {
- /* Label and description can be internationalized */
- if (strcasecmp(cmd, "label") == 0) {
- ctx->module->label = translate(strdup(arg));
- return;
- }
- if (strcasecmp(cmd, "description") == 0) {
- ctx->module->description = translate(strdup(arg));
- return;
- }
- if (strcasecmp(cmd, "keywords") == 0) {
- G_add_keyword(translate(strdup(arg)));
- return;
- }
- if (strcasecmp(cmd, "end") == 0) {
- ctx->state = S_TOPLEVEL;
- return;
- }
- fprintf(stderr, "Unknown module parameter \"%s\" at line %d\n",
- cmd, ctx->line);
- }
- static void parse_flag(struct context *ctx, const char *cmd, const char *arg)
- {
- if (strcasecmp(cmd, "key") == 0) {
- ctx->flag->key = arg[0];
- return;
- }
- if (strcasecmp(cmd, "answer") == 0) {
- ctx->flag->answer = atoi(arg);
- return;
- }
- /* Label, description, and guisection can all be internationalized */
- if (strcasecmp(cmd, "label") == 0) {
- ctx->flag->label = translate(strdup(arg));
- return;
- }
- if (strcasecmp(cmd, "description") == 0) {
- ctx->flag->description = translate(strdup(arg));
- return;
- }
- if (strcasecmp(cmd, "guisection") == 0) {
- ctx->flag->guisection = translate(strdup(arg));
- return;
- }
- if (strcasecmp(cmd, "end") == 0) {
- ctx->state = S_TOPLEVEL;
- return;
- }
- fprintf(stderr, "Unknown flag parameter \"%s\" at line %d\n",
- cmd, ctx->line);
- }
- static int parse_type(struct context *ctx, const char *arg)
- {
- if (strcasecmp(arg, "integer") == 0)
- return TYPE_INTEGER;
- if (strcasecmp(arg, "double") == 0)
- return TYPE_DOUBLE;
- if (strcasecmp(arg, "string") == 0)
- return TYPE_STRING;
- fprintf(stderr, "Unknown type \"%s\" at line %d\n", arg, ctx->line);
- return TYPE_STRING;
- }
- static int parse_boolean(struct context *ctx, const char *arg)
- {
- if (strcasecmp(arg, "yes") == 0)
- return YES;
- if (strcasecmp(arg, "no") == 0)
- return NO;
- fprintf(stderr, "Unknown boolean value \"%s\" at line %d\n",
- arg, ctx->line);
- return NO;
- }
- static void parse_option(struct context *ctx, const char *cmd,
- const char *arg)
- {
- if (strcasecmp(cmd, "key") == 0) {
- ctx->option->key = strdup(arg);
- return;
- }
- if (strcasecmp(cmd, "type") == 0) {
- ctx->option->type = parse_type(ctx, arg);
- return;
- }
- if (strcasecmp(cmd, "required") == 0) {
- ctx->option->required = parse_boolean(ctx, arg);
- return;
- }
- if (strcasecmp(cmd, "multiple") == 0) {
- ctx->option->multiple = parse_boolean(ctx, arg);
- return;
- }
- if (strcasecmp(cmd, "options") == 0) {
- ctx->option->options = strdup(arg);
- return;
- }
- if (strcasecmp(cmd, "key_desc") == 0) {
- ctx->option->key_desc = strdup(arg);
- return;
- }
- /* Label, description, descriptions, and guisection can all be internationalized */
- if (strcasecmp(cmd, "label") == 0) {
- ctx->option->label = translate(strdup(arg));
- return;
- }
- if (strcasecmp(cmd, "description") == 0) {
- ctx->option->description = translate(strdup(arg));
- return;
- }
- if (strcasecmp(cmd, "descriptions") == 0) {
- ctx->option->descriptions = translate(strdup(arg));
- return;
- }
- if (strcasecmp(cmd, "answer") == 0) {
- ctx->option->answer = strdup(arg);
- return;
- }
- if (strcasecmp(cmd, "gisprompt") == 0) {
- ctx->option->gisprompt = strdup(arg);
- return;
- }
- if (strcasecmp(cmd, "guisection") == 0) {
- ctx->option->guisection = translate(strdup(arg));
- return;
- }
- if (strcasecmp(cmd, "guidependency") == 0) {
- ctx->option->guidependency = translate(strdup(arg));
- return;
- }
- if (strcasecmp(cmd, "end") == 0) {
- ctx->state = S_TOPLEVEL;
- return;
- }
- fprintf(stderr, "Unknown option parameter \"%s\" at line %d\n",
- cmd, ctx->line);
- }
- static int print_options(const struct context *ctx)
- {
- struct Option *option;
- struct Flag *flag;
- const char *overwrite = getenv("GRASS_OVERWRITE");
- const char *verbose = getenv("GRASS_VERBOSE");
- printf("@ARGS_PARSED@\n");
- if (overwrite)
- printf("GRASS_OVERWRITE=%s\n", overwrite);
- if (verbose)
- printf("GRASS_VERBOSE=%s\n", verbose);
- for (flag = ctx->first_flag; flag; flag = flag->next_flag)
- printf("flag_%c=%d\n", flag->key, flag->answer ? 1 : 0);
- for (option = ctx->first_option; option; option = option->next_opt)
- printf("opt_%s=%s\n", option->key,
- option->answer ? option->answer : "");
- return 0;
- }
- static int reinvoke_script(const struct context *ctx, const char *filename)
- {
- struct Option *option;
- struct Flag *flag;
- /* Because shell from MINGW and CygWin converts all variables
- * to uppercase it was necessary to use uppercase variables.
- * Set both until all scripts are updated */
- for (flag = ctx->first_flag; flag; flag = flag->next_flag) {
- char buff[16];
- sprintf(buff, "GIS_FLAG_%c=%d", flag->key, flag->answer ? 1 : 0);
- putenv(G_store(buff));
- sprintf(buff, "GIS_FLAG_%c=%d", toupper(flag->key),
- flag->answer ? 1 : 0);
- G_debug(2, "set %s", buff);
- putenv(G_store(buff));
- }
- for (option = ctx->first_option; option; option = option->next_opt) {
- char upper[4096];
- char *str;
- G_asprintf(&str, "GIS_OPT_%s=%s", option->key,
- option->answer ? option->answer : "");
- putenv(str);
- strcpy(upper, option->key);
- G_str_to_upper(upper);
- G_asprintf(&str, "GIS_OPT_%s=%s", upper,
- option->answer ? option->answer : "");
- G_debug(2, "set %s", str);
- putenv(str);
- }
- #ifdef __MINGW32__
- {
- /* execlp() and _spawnlp ( _P_OVERLAY,..) do not work, they return
- * immediately and that breaks scripts running GRASS scripts
- * because they dont wait until GRASS script finished */
- /* execlp( "sh", "sh", filename, "@ARGS_PARSED@", NULL); */
- /* _spawnlp ( _P_OVERLAY, filename, filename, "@ARGS_PARSED@", NULL ); */
- int ret;
- ret = _spawnlp(_P_WAIT, filename, filename, "@ARGS_PARSED@", NULL);
- G_debug(1, "ret = %d", ret);
- if (ret == -1) {
- perror("_spawnlp() failed");
- return 1;
- }
- return ret;
- }
- #else
- execl(filename, filename, "@ARGS_PARSED@", NULL);
- perror("execl() failed");
- return 1;
- #endif
- }
- int main(int argc, char *argv[])
- {
- struct context ctx;
- const char *filename;
- int standard_output = 0;
- ctx.module = NULL;
- ctx.option = NULL;
- ctx.flag = NULL;
- ctx.first_option = NULL;
- ctx.first_flag = NULL;
- ctx.state = S_TOPLEVEL;
- /* Detect request to get strings to translate from a file */
- /* It comes BEFORE the filename to completely avoid confusion with parser.c behaviours */
- if (argc >= 2 && (strcmp(argv[1], "-t") == 0)) {
- /* Turn on translation output */
- translate_output = 1;
- argv++, argc--;
- }
- if (argc >= 2 && (strcmp(argv[1], "-s") == 0)) {
- /* write to stdout rather than re-invoking */
- standard_output = 1;
- argv++, argc--;
- }
- if ((argc < 2) || ((strcmp(argv[1], "help") == 0) ||
- (strcmp(argv[1], "-help") == 0) ||
- (strcmp(argv[1], "--help") == 0))) {
- fprintf(stderr, "Usage: %s [-t] <filename> [<argument> ...]\n",
- argv[0]);
- return 1;
- }
- filename = argv[1];
- argv++, argc--;
- G_debug(2, "filename = %s", filename);
- ctx.fp = fopen(filename, "r");
- if (!ctx.fp) {
- perror("Unable to open script file");
- return 1;
- }
- G_gisinit((char *)filename);
- for (ctx.line = 1;; ctx.line++) {
- char buff[4096];
- char *cmd, *arg;
- if (!fgets(buff, sizeof(buff), ctx.fp))
- break;
- arg = strchr(buff, '\n');
- if (!arg) {
- fprintf(stderr, "Line too long or missing newline at line %d\n",
- ctx.line);
- return 1;
- }
- *arg = '\0';
- if (buff[0] != '#' || buff[1] != '%')
- continue;
- cmd = buff + 2;
- G_chop(cmd);
- arg = strchr(cmd, ':');
- if (arg) {
- *(arg++) = '\0';
- G_strip(cmd);
- G_strip(arg);
- }
- switch (ctx.state) {
- case S_TOPLEVEL:
- parse_toplevel(&ctx, cmd);
- break;
- case S_MODULE:
- parse_module(&ctx, cmd, arg);
- break;
- case S_FLAG:
- parse_flag(&ctx, cmd, arg);
- break;
- case S_OPTION:
- parse_option(&ctx, cmd, arg);
- break;
- }
- }
- if (fclose(ctx.fp) != 0) {
- perror("Error closing script file");
- return 1;
- }
- /* Stop here successfully if all that was desired was output of text to translate */
- /* Continuing from here would get argc and argv all wrong in G_parser. */
- if (translate_output)
- return EXIT_SUCCESS;
- if (G_parser(argc, argv))
- return 1;
- return standard_output
- ? print_options(&ctx)
- : reinvoke_script(&ctx, filename);
- return 0;
- }
|