/* This contains all routines involve in parse the command options. */ #include #ifdef HAVE_GETOPT_H #include #endif /* local macro definitions */ #if 0 /* disable this definition since it is not needed now. But keep it for */ /* possible future use if input file can be a dir. */ #define NAGG_inputfiles_Max 100 /* max number of input files */ #endif /* local variables */ /* Function definitions */ /* Display the usage page of the nagg tool. * Return: no return value. */ void usage(void) { fprintf(stderr, "usage:\n" "%s [OPTIONS] ...\n" "OPTIONS\n" " -h, --help\n" " Print command syntax; also list valid types and packaging groupings.\n" " -V, --version\n" " Print version.\n" " -t , --type=\n" " specifies a comma separated list of NPP record type mnemonics.\n" " Unless -S is specified, the granule types will be packaged together.\n" " Types must be compatible to be packaged together. (Use -h to list\n" " valid package groupings). If –t is not specified, -g must be\n" " given to aggregate only the Geolocation product granules.\n" " -n , --number=\n" " is the number of granules of each product in each aggregate file;\n" " must be greater than zero. If not specified, default is 1 (single \n" " granule files).\n" " -A \n" " is the number of seconds of aggregation time span of each\n" " aggregate file; must be a positive integer. It is exclusive with the\n" " -n option.\n" " -g , --geolocation=\n" " is the criterion for searching the Geolocation granules\n" " no | 0: Aggregate product files without Geolocation input or output.\n" " yes | 1: (Default) Allow approximate matching of Geolocation input\n" " filenames.\n" " strict | 2: Require exact matching of Geolocation input filenames.\n" " : aggregate Geolocation product only.\n" " This excludes the use of -t.\n" " -d , --directory=\n" " is name of an existing directory in which the output NPP\n" " files are created. Default is to create output files in the current\n" " directory.\n" " -S, --simple\n" " Simple aggregates are produced. Each type is packaged separately.\n" " Default is all types are packaged in a file.\n" " -O \n" " is the origin identifier, a four character string (required) \n" " -D \n" " is the domain identifier, a three character string (required)\n" " --debug\n" " Read in all granules in the input files, including those not specified\n" " by the -t list. Display all the granules and end the execution without\n" " generating the normal output files.\n" " Note that this option is intended for tool debugging. Files or output\n" " generated should not be used for production purpose. Its behavior may\n" " change from version to version.\n" "\n" " is a list of one or more NPP files\n" "\n" , progname_g); } /* Purpose: * Verify if a directory already exists. * Return TRUE if it is an existing directory; * FALSE otherwise. */ static int isdirectory(char *name){ stat_t st; /* sanity check */ if (!name) return(FALSE); if (HDstat(name, &st)<0) return(FALSE); if (S_ISDIR(st.st_mode)) return TRUE; else return FALSE; } /* Purpose: * Retrieve the output directory argument. * return: output directory given by the -d option; * null if not given. */ const char * get_outdir(void) { return(outDir); } /* Private functions */ /* verify that *pt contains an integer. * Integer is defined as list of digits (0-9) with an optional negative sign ('-'). * Return TRUE if it is an integer; * Otherwise FALSE. */ static int HDisint(char *pt) { if (!pt){ return FALSE; } if (*pt == '-') pt++; while (HDisdigit(*pt)){ if (!(*++pt)) break; } return (*pt ? FALSE : TRUE); } /* Purpose: * Parse command line options, validate the option values and set the option * variables so that the tool may execute according to user request. * return: 0 if succeess; * leave(EXIT_FAILURE) otherwise. */ int parse_options(int argc, char * const argv[]) { int index; int i; int c; char *new_p; char *products_arg=NULL; char *next_product; char *prev_geoproduct=NULL; /* hold previous located geoproduct */ char *tmp_product=NULL; /* hold product name if -A is used. */ iet_t tmp_product_duration; /* duration time of tmp_product */ int aggregatetime=-1; /* Aggregation time. -1 stands for not set. */ /* command line options: See function usage for a description */ char *nagg_options = "A:d:D:g:hn:O:St:V"; #ifdef HAVE_GETOPT_H /* Use getopt_long if available */ struct option nagg_long_options[] = { {"debug", 0, &debug_arg, 1}, {"directory", 1, 0, 'd'}, {"help", 0, 0, 'h'}, {"number", 1, 0, 'n'}, {"simple", 0, 0, 'S'}, {"type", 1, 0, 't'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0} }; int long_option_index = 0; #endif opterr = 0; /* Extract program name from the last component of called name */ if((progname_g=HDstrrchr(argv[0], '/'))) progname_g++; else progname_g = argv[0]; while (1){ c = #ifdef HAVE_GETOPT_LONG getopt_long (argc, argv, nagg_options, nagg_long_options, &long_option_index); #else getopt (argc, argv, nagg_options); #endif if (-1 == c) break; switch (c) { case 0: /* one of the long options matched */ /* no more action needed yet. */ #ifdef DEBUG printf("long option %s found\n", nagg_long_options[long_option_index].name); #endif break; case 'h': usage(); print_product_lists(); leave(EXIT_SUCCESS); break; case 'n': if (!HDisint(optarg)){ NAGG_ERROR("parse_options(): number of granules must be an integer\n"); leave(EXIT_FAILURE); }else{ ngranulesperfile = atoi(optarg); }; if (ngranulesperfile < 1){ fprintf(stderr, "Option error: number of granules must be positive. Got %d\n", ngranulesperfile); usage(); leave(EXIT_FAILURE); } break; case 'A': if (!HDisint(optarg)){ NAGG_ERROR("parse_options(): aggregation time must be an integer\n"); leave(EXIT_FAILURE); }else{ aggregatetime = atoi(optarg); }; if (aggregatetime < 1){ fprintf(stderr, "Option error: aggregate time must be a positive integer. Got %d\n", aggregatetime); usage(); leave(EXIT_FAILURE); } break; case 't': /* dup the argument because it maybe modified later */ if (NULL==(products_arg=HDstrdup(optarg))){ NAGG_ERROR("parse_options(): no memory for strdup\n"); leave(EXIT_FAILURE); } break; case 'd': outDir = optarg; if (!isdirectory(outDir)){ NAGG_ERROR("output directory must be existing.\n"); leave(EXIT_FAILURE); } break; case 'O': origin_arg = optarg; break; case 'D': domain_arg = optarg; break; case 'g': if (HDstreq(optarg,"yes")||HDstreq(optarg,"1")){ geofiles_arg=GEOFILE_YES; }else if (HDstreq(optarg,"no")||HDstreq(optarg,"0")){ geofiles_arg=GEOFILE_NO; }else if (HDstreq(optarg,"strict")||HDstreq(optarg,"2")){ geofiles_arg=GEOFILE_STRICT; }else{ /* check if it is a Geoproduct ID */ if (NULL!=get_product_sname_by_id(optarg)){ geoproduct=optarg; geofiles_arg=GEOFILE_GEOPRODUCT; }else{ NAGG_ERROR("parse_options(): illegal geolocation criterion given\n"); usage(); leave(EXIT_FAILURE); } } break; case 'S': outfileformat = UNPACKAGED; break; case 'V': HDfprintf(stderr, "%s: Version %d.%d.%d-%s, %s", progname_g, NAGG_VER_MAJOR, NAGG_VER_MINOR, NAGG_VER_RELEASE, NAGG_VER_SUBRELEASE, NAGG_RELEASE_DATE); HDfprintf(stderr, "\n"); leave(EXIT_SUCCESS); break; case '?': if (optopt == 'c') fprintf (stderr, "Option -%c requires an argument.\n", optopt); else if (isprint (optopt)) fprintf (stderr, "Unknown option `-%c'.\n", optopt); else fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt); usage(); leave(EXIT_FAILURE); default: NAGG_ERROR("parse_options(): getopt returned unexpected value.\n"); fprintf(stderr, "Unexpected value is %d\n", c); leave(EXIT_FAILURE); } } /* Get the input file arguments, assume remainings are all input files. */ ninputfiles = argc-optind; inputfiles = argv+optind; #if 0 /* Keep this block of code for use if input file argument can be a dir. */ /* allocate space to hold input file names. */ if (NULL==(inputfiles = HDmalloc(sizeof(char*)*NAGG_inputfiles_Max))){ NAGG_ERROR("parse_options(): malloc failed\n"); leave(EXIT_FAILURE); }; /* fetch them in one by one */ for (index = optind; index < argc; index++){ if (ninputfiles >= NAGG_inputfiles_Max){ NAGG_ERROR("parse_options(): max number of input files exceeded\n"); fprintf(stderr, "Max = %d\n", NAGG_inputfiles_Max); leave(EXIT_FAILURE); }; if (NULL==(new_p=HDstrdup(argv[index]))){ NAGG_ERROR("parse_options(): malloc failed\n"); leave(EXIT_FAILURE); }; inputfiles[ninputfiles++] = new_p; } #endif /* Check if all required arguments are provided. */ /* Either -t is given or -g but not both. */ /* First check if both -t and -g are not given, Error. */ nproducts=0; products_list=&products_list_array[0]; if (NULL==products_arg){ if (geofiles_arg!=GEOFILE_GEOPRODUCT){ NAGG_ERROR("parse_options(): no product name given\n"); usage(); leave(EXIT_FAILURE); } tmp_product = geoproduct; /* Need it if -A is used. */ }else{ /* -t is given. Make sure -g is not given too. */ if (geofiles_arg==GEOFILE_GEOPRODUCT){ NAGG_ERROR("parse_options(): -g not allowed if -t is given already\n"); usage(); leave(EXIT_FAILURE); } /* We have a list of products separated by commas. Scan down the list, * replacing commas by \0 and assign each to the products_list_array. */ products_list[0] = products_arg; next_product = products_arg; prev_geoproduct=NULL; tmp_product = products_list[0]; /* Need it if -A is used. */ do{ new_p = HDstrchr(next_product, ','); if (new_p){ /* replace the comma with a null terminator */ *new_p = '\0'; } if (NULL==get_product_sname_by_id(next_product)){ NAGG_ERROR("parse_options(): illegal product ID given\n"); usage(); leave(EXIT_FAILURE); } /* Find the Geoproduct used unless -g no is given */ if (geofiles_arg!=GEOFILE_NO){ if (NULL==(geoproduct=get_gpid_by_id(next_product))){ NAGG_ERROR("parse_options(): could not find Geolocation product ID\n"); usage(); leave(EXIT_FAILURE); } /* See if it is different from previous found geoproduct */ if (prev_geoproduct==NULL){ prev_geoproduct = geoproduct; }else{ if (HDstrneq(prev_geoproduct, geoproduct)){ NAGG_ERROR("parse_options(): found different Geolocation product ID\n"); usage(); leave(EXIT_FAILURE); } } } products_list[nproducts++] = next_product; if (new_p){ next_product = new_p+1; } }while (new_p); } if (nproducts > NAGG_Product_list_max ){ NAGG_ERROR("parse_options(): too many products requested.\n"); fprintf(stderr, "Maximum number of products is %d\n", NAGG_Product_list_max); leave(EXIT_FAILURE); } /* Check Origin name */ if (NULL==origin_arg){ origin_arg="XXXX"; }; /* Check Domain name */ if (NULL==domain_arg){ domain_arg="XXX"; }; /* check if at least one input file is provided. */ if (ninputfiles <= 0){ NAGG_ERROR("parse_options(): no input file given\n"); usage(); leave(EXIT_FAILURE); }; /* Check if -A is used, that -n is not used, then calculate * ngranulesperfile from aggregatetime. */ if (aggregatetime != -1){ if (ngranulesperfile != -1) { NAGG_ERROR("Only one of -A or -n may be used\n"); usage(); leave(EXIT_FAILURE); } assert(tmp_product); if (0 == (tmp_product_duration=get_product_duration_by_id(tmp_product))){ /* product duration time not found */ NAGG_ERROR("parse_options(): can't find duration time\n"); usage(); leave(EXIT_FAILURE); }; ngranulesperfile = (int)ceilf(aggregatetime/micros2s(tmp_product_duration)); #ifdef DEBUG printf("aggregatetime=%d, ngranulesperfile=%d, tmp_product_duration=%ull\n", aggregatetime, ngranulesperfile, tmp_product_duration); #endif }else{ /* if -n is not given, set ngranulesperfile to default value of 1 */ if (ngranulesperfile == -1) ngranulesperfile = 1; }; /* Check that ngranulesperfile has valid value */ if (ngranulesperfile < 1){ NAGG_ERROR("parse_options(): number of granules is illegal\n"); fprintf(stderr, "ngranulesperfile=%d\n", ngranulesperfile); leave(EXIT_FAILURE); } /* All done. */ return(0); }