Created
August 5, 2017 02:48
-
-
Save hamsham/cff3f62873888e6c68f8a472399cd133 to your computer and use it in GitHub Desktop.
Simple example of how to parse arguments from a single string, with quote-handling.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Test for parsing command-line arguments from a single string | |
* | |
* gcc -std=c11 -Wall -Werror -Wextra -pedantic -pedantic-errors parse_args.c -o parse_args | |
*/ | |
#include <stdio.h> // printf(), fprintf() | |
#include <string.h> // strlen() | |
#include <stdbool.h> // bool, true, false | |
#include <ctype.h> // isspace() | |
/*------------------------------------- | |
* Count the number of arguments in an argument string | |
-------------------------------------*/ | |
bool _args_from_string(char* const pArgString) | |
{ | |
if (!pArgString || pArgString[0] == '\0') | |
{ | |
fprintf(stderr, "Invalid input: %s\n", pArgString); | |
return false; | |
} | |
unsigned argc = 0; | |
bool isQuotedS = false; | |
bool isQuotedD = false; | |
bool isEscaped = false; | |
bool wasQuotedD = false; | |
bool wasQuotedS = false; | |
unsigned lastArg = 0; | |
unsigned i = 0; | |
// count all arguments in the string | |
do | |
{ | |
const char c = pArgString[i]; | |
// single quotes embedded in double quotes aren't counted | |
// and vice-versa | |
if ((c == '\"') && !isEscaped && !isQuotedS) | |
{ | |
isQuotedD = !isQuotedD; | |
wasQuotedD = true; | |
++lastArg; | |
} | |
if ((c == '\'') && !isEscaped && !isQuotedD) | |
{ | |
isQuotedS = !isQuotedS; | |
wasQuotedS = true; | |
++lastArg; | |
} | |
const bool wasQuoted = wasQuotedS || wasQuotedD; | |
const bool isQuoted = isQuotedS || isQuotedD; | |
const bool isDelimiter = (!isEscaped && isspace(c)) || c == '\0'; | |
// count arguments which are not separated by an escaped space | |
if (isDelimiter && !isQuoted) | |
{ | |
const unsigned length = i - wasQuoted; | |
const char* subStr = pArgString + lastArg; | |
const char temp = pArgString[length]; | |
pArgString[length] = '\0'; | |
printf("Argument found: %s\n", subStr); | |
// printf("\tQuoted: %d\n", wasQuoted); | |
// printf("\tOffset: %u - %u\n", lastArg, length); | |
// printf("\tlength: %zu\n", strlen(subStr)); | |
pArgString[length] = temp; | |
lastArg = i; | |
isQuotedS = isQuotedD = false; | |
wasQuotedS = wasQuotedD = false; | |
++argc; | |
} | |
// Flip the check for character escapes | |
isEscaped = (c == '\\'); | |
} | |
while (pArgString[i++] != '\0'); | |
// printf("%d arguments found in the input string: %s\n\n", argc, pArgString); | |
return !isQuotedS && !isQuotedD; | |
} | |
int main(int argc, char* argv[]) | |
{ | |
int ret = 0; | |
printf("%d Arguments available to parse.\n", argc); | |
for (int i = 0; i < argc; ++i) | |
{ | |
ret += _args_from_string(argv[i]); | |
} | |
return ret; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment