#include #include #include #include #include #include #include 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) { ctx->module->keywords = 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, "end") == 0) { ctx->state = S_TOPLEVEL; return; } fprintf(stderr, "Unknown option parameter \"%s\" at line %d\n", cmd, ctx->line); } int main(int argc, char *argv[]) { struct context ctx; struct Option *option; struct Flag *flag; const char *filename; 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; } if (argc < 2 + translate_output) { fprintf(stderr, "Usage: %s [-t] [ ...]\n", argv[0]); return 1; } filename = argv[1 + translate_output]; 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_strip(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 - 1, argv + 1) < 0) return 1; /* 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[12]; 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 buff[1024]; sprintf(buff, "GIS_OPT_%s=%s", option->key, option->answer ? option->answer : ""); putenv(G_store(buff)); G_str_to_upper(option->key); sprintf(buff, "GIS_OPT_%s=%s", option->key, option->answer ? option->answer : ""); G_debug ( 2, "set %s", buff ); putenv(G_store(buff)); } #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, "sh", "sh", filename, "@ARGS_PARSED@", NULL ); */ int ret; ret = _spawnlp ( _P_WAIT, "sh", "sh", 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 }