diff options
Diffstat (limited to 'libSYS/src/cmdl_parser.cpp')
-rw-r--r-- | libSYS/src/cmdl_parser.cpp | 522 |
1 files changed, 522 insertions, 0 deletions
diff --git a/libSYS/src/cmdl_parser.cpp b/libSYS/src/cmdl_parser.cpp new file mode 100644 index 0000000..a2578c3 --- /dev/null +++ b/libSYS/src/cmdl_parser.cpp @@ -0,0 +1,522 @@ +/************************** Fraunhofer IIS FDK SysLib ********************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: command line parser + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + + + +#define _CRT_SECURE_NO_WARNINGS + +/* Work around for broken android toolchain: sys/types.h:137: error: 'uint64_t' does not name a type */ +#define _SYS_TYPES_H_ + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> + +#include "cmdl_parser.h" +#include "genericStds.h" + + + +/************************ interface ************************/ + +static INT GetArgFromString(INT argc, TEXTCHAR* argv[], TEXTCHAR* search_string, TEXTCHAR type, TEXTCHAR* found_string , INT* switches_used); +static void RemoveWhiteSpace(const TEXTCHAR* pReqArgs, TEXTCHAR* Removed); +static INT CheckArg(TEXTCHAR* arg, TEXTCHAR* str, UINT numArgs, TEXTCHAR type, TEXTCHAR* current_str); +static INT CheckForUnusedSwitches(INT argc, /*TEXTCHAR* argv[],*/ INT* switches_used); +static INT ParseString(TEXTCHAR* str, INT*, TEXTCHAR*, TEXTCHAR*); +static void GetNumberOfArgs(TEXTCHAR* str, INT* nArgs); + +static +void removeQuotes(char *str) +{ + if (str[0] == '"') { + FDKstrcpy(str, str+1); + str[FDKstrlen(str)-1] = 0; + } +} + + +/********************** implementation *********************/ + +INT IIS_ScanCmdl(INT argc, TEXTCHAR* argv[], const TEXTCHAR* str, ...) +{ + INT i = 0; + INT found_and_set = 0; + INT nArgs = 0; + INT* switches_used = 0; + INT* b_str_opt = 0; + TEXTCHAR* s_str = 0; + TEXTCHAR* c_str_type = 0; + TEXTCHAR* str_clean = 0; + + va_list ap; + + if (argc == 0 || argc == 1) + { + FDKprintf("No command line arguments\n"); + goto bail; + } + + str_clean = (TEXTCHAR*) FDKcalloc((unsigned int)_tcslen(str), sizeof(TEXTCHAR)); + if (str_clean == NULL) { + FDKprintf("Error allocating memory line %d, file %s\n", __LINE__, __FILE__); + return 0; + } + + RemoveWhiteSpace(str, str_clean ); + GetNumberOfArgs(str_clean, &nArgs); + + b_str_opt = (INT*) FDKcalloc(nArgs, sizeof(INT)); + s_str = (TEXTCHAR*) FDKcalloc(nArgs*CMDL_MAX_ARGC, sizeof(TEXTCHAR) ); + c_str_type = (TEXTCHAR*) FDKcalloc(nArgs, sizeof(TEXTCHAR)); + switches_used = (INT*) FDKcalloc(argc, sizeof(INT)); + + if (b_str_opt == NULL || s_str == NULL || c_str_type == NULL || switches_used == NULL) { + FDKprintf("Error allocating memory line %d, file %s\n", __LINE__, __FILE__); + goto bail; + } + + if ( ParseString( str_clean, b_str_opt, s_str, c_str_type )) { + goto bail; + } + + va_start(ap, str); + + for ( i = 0; i < nArgs; i++ ) + { + TEXTCHAR arg[CMDL_MAX_STRLEN] = {L'\0'}; + TEXTCHAR* p_arg = arg; + TEXTCHAR* current_str = &(s_str[i*CMDL_MAX_ARGC]); + + if (GetArgFromString(argc, argv, current_str, c_str_type[i], arg, switches_used ) + && !b_str_opt[i] ) + { +#ifdef _UNICODE + _ftprintf(stderr, _TEXT("\n\nError: Parsing argument for required switch '%ls'.\n" ), current_str); +#else + _ftprintf(stderr, _TEXT("\n\nError: Parsing argument for required switch '%s'.\n" ), current_str); +#endif + found_and_set = 0; + goto bail; + } + if (CheckArg(p_arg, s_str, nArgs, c_str_type[i], current_str)) + { + goto bail; + } + + switch (c_str_type[i] ) + { + case 's': + { + TEXTCHAR* tmp; + tmp = va_arg(ap, TEXTCHAR*); + + if ( arg[0] == '\0' ) + break; + + _tcsncpy( tmp, arg, CMDL_MAX_STRLEN ); + /* Remove quotes. Windows Mobile Workaround. */ + removeQuotes(tmp); + found_and_set++; + break; + } + case 'd': + { + INT* tmp = va_arg(ap, INT*); + + if ( arg[0] == '\0' ) + break; + + *tmp = _tcstol(arg, NULL, 0); + found_and_set++; + break; + } + case 'c': + { + char* tmp = va_arg(ap, char*); + + if ( arg[0] == '\0' ) + break; + + *tmp = *arg; + found_and_set++; + break; + } + case 'u': + { + UCHAR* tmp = va_arg(ap, UCHAR*); + + if ( arg[0] == '\0' ) + break; + + *tmp = _tstoi(arg); + found_and_set++; + break; + } + case 'f': + { + float* tmp = (float*) va_arg( ap,double*); + + if ( arg[0] == '\0' ) + break; + + *tmp = (float) _tstof(arg); + found_and_set++; + break; + } + case 'y': // support 'data type double' + { + double* tmp = (double*) va_arg( ap,double*); + // use sscanf instead _tstof because of gcc + //_tstof(arg,"%lf",tmp); // '%lf' reads as double + *tmp = _tstof(arg); // '%lf' reads as double + found_and_set++; + break; + } + case '1': + { + + INT* tmp = va_arg( ap, INT*); + + if ( arg[0] == '\0' ) + break; + + *tmp = 1; + found_and_set++; + break; + } + + default: + FDKprintfErr("Bug: unsupported data identifier \"%c\"\n", c_str_type[i]); + break; + + } + + } + + va_end(ap); + + CheckForUnusedSwitches(argc, /*argv,*/ switches_used); + +bail: + if (b_str_opt) FDKfree(b_str_opt); + if (s_str) FDKfree(s_str); + if (c_str_type) FDKfree(c_str_type); + if (str_clean) FDKfree(str_clean); + if (switches_used) FDKfree(switches_used); + + return found_and_set; +} + + +void GetNumberOfArgs(TEXTCHAR* str, INT* nArgs) +{ + UINT i = 0; + for ( i = 0; i < _tcslen(str); ++i ) + { + if ( str[i] == '%') + *nArgs+= 1; + } + +} + +INT ParseString(TEXTCHAR* str, INT* b_str_opt, TEXTCHAR* s_str, TEXTCHAR* c_str_type ) +{ + UINT i = 0; + INT argCounter = 0; + + TEXTCHAR* str_start = 0; + TEXTCHAR* str_stop = 0; + + + str_start = str; + str_stop = str_start; + + for ( i = 0; i < _tcslen(str) - 1; ++i ) + { + if ( str[i] == '%' ) /* We have an Argument */ + { + if ( argCounter ) + { + if ( b_str_opt[argCounter-1] ) + str_start = str_stop + 3; + + else + str_start = str_stop + 2; + } + + /* Save Argument type */ + c_str_type[argCounter] = str[i+1]; + + if ( *str_start == '(' ) /* Optional Argument */ + { + b_str_opt[argCounter] = 1; + str_start++; + } + + /* Save Argument */ + str[i] = '\0'; + + _tcsncpy(&(s_str[argCounter*CMDL_MAX_ARGC]), str_start, CMDL_MAX_ARGC ); + + str[i] = '%'; + + str_stop = &(str[i]); + + if ( b_str_opt[argCounter] ) + { + if ( i+2 > ( _tcslen(str) -1 )) + { + _ftprintf(stderr,_TEXT("\n\nInternal Parser Error: Strlen Problem\n") ); + return 1; + } + if ( str[i+2] != ')' ) + { + _ftprintf(stderr,_TEXT("\n\nInternal Parser Error: Missing bracket ')'\n") ); + return 1; + } + + } + + + argCounter++; + } + + + } + + return 0; + } + + + + +void RemoveWhiteSpace(const TEXTCHAR* pReqArgs, TEXTCHAR* pRemoved) +{ + UINT i = 0; + INT k = 0; + UINT len = (UINT)_tcslen(pReqArgs); + + + for ( i = 0; i < len; ++i ) + { + + if ( pReqArgs[i] != ' ' ) + { + pRemoved[k] = pReqArgs[i]; + k++; + } + } +} + + +INT GetArgFromString(INT argc, TEXTCHAR* argv[], TEXTCHAR* search_string, TEXTCHAR type, TEXTCHAR* found_string, INT* sw_used ) +{ + INT i = 0; + + for (i = 1; i < argc; ++i ) { + if ( !_tcscmp(search_string, argv[i]) ) /* Strings are equal */ + { + if ( type == '1' ) /* Switch without argument */ + { + _tcsncpy( found_string, _TEXT("1"), 1); + sw_used[i] = 1; + return 0; + + } + + if ( i == (argc - 1)) /* We have %s or %d but are finished*/ + return 1; + + if ( _tcslen(argv[i+1]) > CMDL_MAX_STRLEN ) + { +#ifdef _UNICODE + _ftprintf (stderr,_TEXT("Warning: Ignoring argument for switch '%ls'. "), search_string ); +#else + _ftprintf (stderr,_TEXT("Warning: Ignoring argument for switch '%s'. "), search_string ); +#endif + _ftprintf (stderr,_TEXT("Argument is too LONG.\n") ); + return 1; + } + else + { + _tcsncpy( found_string, argv[i+1], CMDL_MAX_STRLEN); + sw_used[i] = 1; + sw_used[i+1] = 1; + return 0; + } + } + } + return 1; +} + + + +INT CheckArg(TEXTCHAR* arg, TEXTCHAR* str, UINT numArgs, TEXTCHAR type, TEXTCHAR* cur_str) +{ + UINT i = 0; + + /* No argument given-> return */ + if (arg[0] == '\0') + return 0; + + + /* Check if arg is switch */ + for ( i = 0; i < numArgs; ++i ) + { + if (!_tcscmp(arg, &(str[i*CMDL_MAX_ARGC]))) + { +#ifdef _UNICODE + _ftprintf(stderr, _TEXT("\n\nError: Argument '%ls' for switch '%ls' is not valid \n" ), arg, cur_str ); +#else + _ftprintf(stderr, _TEXT("\n\nError: Argument '%s' for switch '%s' is not valid \n" ), arg, cur_str ); +#endif + return 1; + } + + } + /* Check if type is %d but a string is given */ + + for ( i = 0; i < _tcslen(arg); ++i ) + { + if ( (type == 'd') && !_istdigit(arg[i]) && arg[i] != 'x' ) + { +#ifdef _UNICODE + _ftprintf(stderr, _TEXT("\n\nError: Argument '%ls' for switch '%ls' is not a valid number.\n" ), arg, cur_str); +#else + _ftprintf(stderr, _TEXT("\n\nError: Argument '%s' for switch '%s' is not a valid number.\n" ), arg, cur_str); +#endif + return 1; + } + } + + + return 0; +} + + +INT CheckForUnusedSwitches(INT argc, /*TEXTCHAR* argv[],*/ INT* switches_used) +{ + INT i = 0; + + for( i = 1; i < argc; ++i ) + { + if ( !switches_used[i] ) + { + ++i; + } + } + + return 0; +} + + + +static char line[CMDL_MAX_STRLEN*CMDL_MAX_ARGC]; +static char *argv_ptr[CMDL_MAX_ARGC]; +#ifdef CMDFILE_PREFIX +static char tmp[256]; /* this array is used to store the prefix and the filepath/name */ +#endif + +int IIS_ProcessCmdlList(const char* param_filename, int (*pFunction)(int, TEXTCHAR**)) +{ + /* static to reduce required stack size */ + + FDKFILE *config_fp; + int argc; + char *line_ptr; + +#ifdef CMDFILE_PREFIX + FDKstrcpy(tmp, CMDFILE_PREFIX); + FDKstrcpy(tmp+FDKstrlen(CMDFILE_PREFIX), param_filename); + /* Open the file with command lines */ + config_fp = FDKfopen(tmp, "r"); +#else + /* Open the file with command lines */ + config_fp = FDKfopen(param_filename, "r"); +#endif + + if(config_fp == NULL) + { +#ifdef CMDFILE_PREFIX + FDKprintf("\ncould not open config file %s", tmp); +#else + FDKprintf("\ncould not open config file %s", param_filename); +#endif + return 1; + } + + /* Obtain a command line from config file */ + while (FDKfgets(line, CMDL_MAX_STRLEN*CMDL_MAX_ARGC, config_fp) != NULL) + { + argc = 1; + + /* Eat \n */ + line_ptr = (char*)FDKstrchr(line, '\n'); + if (line_ptr != NULL) + *line_ptr = ' '; + + line_ptr = line; + + /* Scan the line and put the command line params into argv */ + do { + /* Skip consecutive blanks. */ + while (*line_ptr == ' ' && line_ptr < line+CMDL_MAX_STRLEN) + line_ptr++; + /* Assign argument. TODO: maybe handle quotes */ + argv_ptr[argc] = line_ptr; + /* Get pointer to next blank. */ + line_ptr = (char*)FDKstrchr(line_ptr, ' '); + /* */ + if (line_ptr != NULL) { + /* Null terminate */ + *line_ptr = 0; + /* Skip former blank (now null character) */ + line_ptr++; + /* Advance argument counter */ + } + argc++; + } while ( line_ptr != NULL && argc < CMDL_MAX_ARGC); + + /* call "would be main()" */ + if (argc > 2 && *argv_ptr[1] != '#' && FDKstrlen(argv_ptr[1])>1) + { + int retval; + + retval = (*pFunction)(argc, argv_ptr); + + FDKprintf("main returned %d\n", retval); + } + } + + FDKfclose(config_fp); + return 0; +} + |