Page 1 of 1
[Pointless-Fight] Shell Arguments/Parameters
Posted: Thu Oct 20, 2016 9:59 am
by Octacone
It has been a long time (like 30 days) since my last interaction with Basic OS. Now, I am struggling with the console arguments. I want to be able to do stuff like "echo hello", etc. Now I was thinking about getting it to work with some string split methods, but my string split is screwed up. Should I port a random string split or there is another way?
Re: Shell Arguments/Parameters
Posted: Fri Oct 21, 2016 3:52 pm
by SpyderTL
http://forum.osdev.org/viewtopic.php?f=13&t=28654
Here is a discussion that I started 2 years ago (wow...) about my idea for parsing console commands. It may give you some ideas about where to start if you want a fairly simple yet powerful command line parser that supports nested commands, like
Code: Select all
openFile("myFile.txt").writeText("Add this text to the bottom of the file.").getFileLength()
This approach has worked well for my needs, so just let me know if the link makes sense to you, or if you have any questions.
Good luck.
Re: [Pointless-Fight] Shell Arguments/Parameters
Posted: Mon Oct 31, 2016 4:26 am
by Ch4ozz
Well, to give you a simple answer atleast (please dont just copy and paste the code) here is the one I coded for SIMPLE parsing.
I coded it a way so all the data can fit into one page and only one malloc is needed.
This has been done because I do this in kernel rather then usermode.
Code: Select all
char **cmd_to_argv(char *commandline, int *_argc)
{
if(!commandline || !_argc)
return 0;
int argc = 1;
bool b_escaped = true;
char **argv = malloc_p(4096, PTE_WRITE);
argv[0] = commandline;
while(*commandline && argc < 1024)
{
if(*commandline == '"' || *commandline == 39)
{
b_escaped = !b_escaped;
*commandline = '\0';
if(!b_escaped)
{
if(*(commandline + 1) != '"' && *(commandline + 1) != 39 && *(commandline + 1) != '\0')
{
argv[argc] = commandline + 1;
argc++;
}
}
}
else if(*commandline == ' ' && b_escaped)
{
*commandline = '\0';
if(*(commandline + 1) != '"' && *(commandline + 1) != 39 && *(commandline + 1) != ' ' && *(commandline + 1) != '\0')
{
argv[argc] = commandline + 1;
argc++;
}
}
commandline++;
}
*_argc = argc;
return argv;
}
Re: [Pointless-Fight] Shell Arguments/Parameters
Posted: Thu Nov 03, 2016 1:03 am
by crunch
Inspired by Ch4ozz's post (and my own need for a halfway decent non-strtok parser), I cooked something up and figured I would share it. It should fit most general use cases, as you can specify the delimiter and escaped character strings. It relies heavily on the use of strspn() but that should be trivial to implement.
Escaped characters are replaced with '\0' if there is a match (i.e. for quotations), otherwise they are ignored.
Multiple delimiters are likewise ignored (i.e. multiple spaces, tabs, etc). Hopefully someone can find this useful.
example usage as follows:
Code: Select all
char** argv = tokenize("echo \"hello world\"", " ", "\"", &argc);
Code: Select all
/* Released to public domain */
/* Simple argument parsing - returns an array of char* pointers
@str is the string to be parsed
@delim is a string containing characters to split by
@escape is a string containing characters to escape ("\"\'\n", etc) - optional
@_argc is a pointer to integer containing the size of returned pointer array */
char** tokenize(const char* str, const char* delim, const char* escape, int* _argc) {
if (!str || !_argc || !delim)
return NULL;
int i, argc = 0;
char* split = strdup(str);
/* first pass, approximate how many arguments there are for allocation */
while(*str) {
if (strspn(str, delim)) {
argc++;
str += strspn(str, delim);
}
str++;
}
/* allocate a pointer array of the proper size */
char** ret = malloc(sizeof(char*) * argc);
argc = 0;
ret[argc++] = split;
/* second pass, split strings by the delimiter */
while(*split) {
if (escape && strspn(split, escape)) {
i = strspn(split, escape);
/* save the escaped character for matching */
char c = *split;
split += i;
/* if we can't find a matching character to escape, ignore it */
if (!strchr(split, c)) {
ret[argc++] = split - i;
split++;
continue;
}
*(split - i) = '\0';
ret[argc++] = split;
/* pointer to first matching character */
split = strchr(split, c);
*split = '\0';
split++;
/* Make sure we don't return the last character as an argument */
if (!strspn(split, delim) && (strlen(split) > 1))
ret[argc++] = split;
}
if (strspn(split, delim)) {
i = strspn(split, delim);
*split = '\0';
split += i;
/* if there's an escaped character, try to escape it */
if (escape && strspn(split, escape))
continue;
ret[argc++] = split;
}
else
split++;
}
*_argc = argc;
return ret;
}