/** * @file args.cpp * Parses command line arguments. * * @author Ben Gardner * @license GPL v2+ * * $Id: args.cpp 824 2007-07-27 20:41:59Z bengardner $ */ #include "args.h" #include #include /** * Store the values and allocate enough memory for the 'used' flags. * * @param argc The argc that was passed to main() * @param argv The argv that was passed to main() */ Args::Args(int argc, char **argv) { m_count = argc; m_values = argv; int len = (argc >> 3) + 1; m_used = new UINT8[len]; if (m_used != NULL) { memset(m_used, 0, len); } } Args::~Args() { if (m_used != NULL) { delete[] m_used; m_used = NULL; } m_count = 0; } /** * Check for an exact match * * @param token The token string to match * @return true/false -- Whether the argument was present */ bool Args::Present(const char *token) { int idx; if (token != NULL) { for (idx = 0; idx < m_count; idx++) { if (strcmp(token, m_values[idx]) == 0) { SetUsed(idx); return(true); } } } return(false); } /** * Just call arg_params() with an index of 0. * * @param token The token string to match * @return NULL or the pointer to the string */ const char *Args::Param(const char *token) { int idx = 0; return(Params(token, idx)); } /** * Scan for a match * * @param token The token string to match * @return NULL or the pointer to the string */ const char *Args::Params(const char *token, int& index) { int idx; int token_len; int arg_len; if (token == NULL) { return(NULL); } token_len = strlen(token); for (idx = index; idx < m_count; idx++) { arg_len = strlen(m_values[idx]); if ((arg_len >= token_len) && (memcmp(token, m_values[idx], token_len) == 0)) { SetUsed(idx); if (arg_len > token_len) { if (m_values[idx][token_len] == '=') { token_len++; } index = idx + 1; return(&m_values[idx][token_len]); } idx++; index = idx + 1; if (idx < m_count) { SetUsed(idx); return(m_values[idx]); } return(""); } } return(NULL); } /** * Gets whether an argument has been used, by index. * * @param idx The index of the argument */ bool Args::GetUsed(int idx) { if ((m_used != NULL) && (idx >= 0) && (idx < m_count)) { return((m_used[idx >> 3] & (1 << (idx & 0x07))) != 0); } return(false); } /** * Marks an argument as being used. * * @param idx The index of the argument */ void Args::SetUsed(int idx) { if ((m_used != NULL) && (idx >= 0) && (idx < m_count)) { m_used[idx >> 3] |= (1 << (idx & 0x07)); } } /** * This function retrieves all unused parameters. * You must set the index before the first call. * Set the index to 1 to skip argv[0]. * * @param idx Pointer to the index * @return NULL (done) or the pointer to the string */ const char *Args::Unused(int& index) { int idx; if (m_used == NULL) { return(NULL); } for (idx = index; idx < m_count; idx++) { if (!GetUsed(idx)) { index = idx + 1; return(m_values[idx]); } } index = m_count; return(NULL); } /** * Takes text and splits it into arguments. * args is an array of char * pointers that will get populated. * num_args is the maximum number of args split off. * If there are more than num_args, the remaining text is ignored. * Note that text is modified (zeroes are inserted) * * @param text The text to split (modified) * @param args The char * array to populate * @param num_args The number of items in args * @return The number of arguments parsed (always <= num_args) */ int Args::SplitLine(char *text, char *args[], int num_args) { char cur_quote = 0; bool in_backslash = false; bool in_arg = false; int argc = 0; char *dest = text; while ((*text != 0) && (argc <= num_args)) { /* Detect the start of an arg */ if (!in_arg && !isspace(*text)) { in_arg = true; args[argc] = dest; argc++; } if (in_arg) { if (in_backslash) { in_backslash = false; *dest = *text; dest++; } else if (*text == '\\') { in_backslash = true; } else if (*text == cur_quote) { cur_quote = 0; } else if ((*text == '\'') || (*text == '"') || (*text == '`')) { cur_quote = *text; } else if (cur_quote != 0) { *dest = *text; dest++; } else if (isspace(*text)) { *dest = 0; dest++; in_arg = false; if (argc == num_args) { break; } } else { *dest = *text; dest++; } } text++; } *dest = 0; return(argc); }