473,581 Members | 2,783 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Command Line Interface (CLI): your recommendations

Hello, All!

I'm implementing simple CLI (flat model, no tree-style menu etc.). Command
line looks like this: <command> <param1> <param2> ... <paramN> (where
N=1..4)
And idea is pretty simple:

1) get whole string of input line
2) preset table of strings matching <command>
3) preset table of function calls
4) scan <command> table for string, if match - call matching function (I
declare ALL callback functions as having the same format)

Here is code implementing part of this algorithm. The problem I came across
is if pressing 'Enter' continuously then sometimes output of PROMPT turnes
out clumsy, i.e. it's printed repeatedly in a line.

Before I went too far, I would like to ask your opinion about concept I'm
using and recommendations if possible:

#define _GNU_SOURCE

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#define COUNT(a) (sizeof(a) / sizeof(a[0]))

const char *PROMPT = "CLI>";

enum errCodes { RC_SUCCESS = 0, RC_ERROR = -1 };

/* table of <commands> */
const char *commands[] = {
"show",
"version",
"help",
"port",
"exit"
};

/* callback function */
typedef int (*handler_ptr_t )(int, char**);

/* define command line: <command> <param1> <param2> ... <paramN> */
typedef struct cmdLineEntry_s {
#define MAX_NAME 20
char command[MAX_NAME];
#define MAX_ARGS 4
char params[MAX_ARGS];
unsigned int params_num;
handler_ptr_t cmd_handler;
} cmdLineEntry_t;

int cliShow(int argc, char *argv[])
{
puts("cliShow() stub");
return 0;
}

int cliVersion(int argc, char *argv[])
{
puts("cliVersio n() stub");
return 0;
}

int cliHelp(int argc, char *argv[])
{
puts("cliHelp() stub");
return 0;
}

int cliPort(int argc, char *argv[])
{
puts("cliPort() stub");
return 0;
}

int cliExit(int argc, char *argv[])
{
puts("cliExit() stub");
exit(EXIT_SUCCE SS);
}

/* define table functions pointers */
handler_ptr_t ftable[] = { cliShow, cliVersion, cliHelp, cliPort, cliExit };

/* parse command line and fill structure */
static int
cliParseCommand Line(char *buf, cmdLineEntry_t *cli)
{
const char delim[] = " \t\n";
unsigned int i;
char *token;

memset(cli, 0, sizeof *cli);

token = strtok(buf, delim);
for (i = 0; i < COUNT(commands) ; i++) {
if (!strcmp(token, commands[i])) {
strcpy(cli->command, token);
cli->cmd_handler = ftable[i];
i = 0;
for (token = strtok(NULL, delim); token != NULL; ) {
cli->params[i++] = token;
token = strtok(NULL, delim);
}
cli->params_num = i;
return 0;
}
}
return -1;
}

int main(void)
{
char buf[BUFSIZ] = {0};
cmdLineEntry_t cli = { {0}, {NULL}, 0, NULL };

while (1) {
printf("%s", PROMPT);
if ( fgets(buf, BUFSIZ, stdin) ) {
/* skip LF/CR/TAB/SP */
if (buf[0] == '\n' || buf[0] == ' ' || buf[0] == '\r' || buf[0]
== '\t')
continue;

/* parse stream */
if ( cliParseCommand Line(buf, &cli) < 0 ) {
printf("Error : invalid command!\n");
continue;
}
else {
cli.cmd_handler (cli.params_num , cli.params);
}
}
else continue; /* EOL */
} /* while */

return 0;
}

TIA!
With best regards, Roman Mashak. E-mail: mr*@tusur.ru
Feb 11 '06 #1
34 6838
In article <ds**********@r elay.tomsk.ru>, Roman Mashak <mr*@tusur.ru > wrote:
I'm implementing simple CLI Here is code implementing part of this algorithm. The problem I came across
is if pressing 'Enter' continuously then sometimes output of PROMPT turnes
out clumsy, i.e. it's printed repeatedly in a line. const char *PROMPT = "CLI>"; int main(void)
{
char buf[BUFSIZ] = {0};
cmdLineEntry_t cli = { {0}, {NULL}, 0, NULL };

while (1) {
printf("%s", PROMPT);
There is in \n in your PROMPT, and you do not fflush()
the output, so your prompt is not certain to appear at any
particular place relative to the input. It might not appear at
all until you happen to output a \n for other reasons.

if ( fgets(buf, BUFSIZ, stdin) ) {
/* skip LF/CR/TAB/SP */
if (buf[0] == '\n' || buf[0] == ' ' || buf[0] == '\r' || buf[0]
== '\t')
continue;


That continue is relative to the while(), and you do not print
anything out in the case of the empty line. Thus if you have
a series of \n in your buffer, you will end up doing repeated
printf("%s", PROMPT) and since there is no \n in that, the several
prompts will all come out on one line.
--
Okay, buzzwords only. Two syllables, tops. -- Laurie Anderson
Feb 11 '06 #2

"Roman Mashak" <mr*@tusur.ru > wrote in message
news:ds******** **@relay.tomsk. ru...
Hello, All!

I'm implementing simple CLI (flat model, no tree-style menu etc.). Command
line looks like this: <command> <param1> <param2> ... <paramN> (where
N=1..4)
And idea is pretty simple:
Does this compile cleanly for you? If I gcc -Wall, I get two errors.

The first error is here: for (token = strtok(NULL, delim); token != NULL; ) {
cli->params[i++] = token;
token = strtok(NULL, delim);
I think the middle line should be:
cli->params[i++] = *token;

The second error is here: else {
cli.cmd_handler (cli.params_num , cli.params);


cli.params is an array of char, but the handler_pointer _t functions accept a
pointer to array of char, 'char *argv[]', for the second argument.
Rod Pemberton


Feb 11 '06 #3

"Rod Pemberton" <do*********@so rry.bitbucket.c mm> wrote in message
news:43******** @news.bea.com.. .

"Roman Mashak" <mr*@tusur.ru > wrote in message
news:ds******** **@relay.tomsk. ru...
Hello, All!

I'm implementing simple CLI (flat model, no tree-style menu etc.).

Command

After thought, you might want a setbuf() or two:

setbuf(stdin,NU LL);
setbuf(stdout,N ULL);
Rod Pemberton
Feb 11 '06 #4
Hello, Rod!
You wrote on Sat, 11 Feb 2006 15:48:55 -0500:

RP> The first error is here:
??>> for (token = strtok(NULL, delim); token != NULL; ) {
??>> cli->params[i++] = token;
??>> token = strtok(NULL, delim);

RP> I think the middle line should be:
RP> cli->params[i++] = *token;

RP> The second error is here:
??>> else {
??>> cli.cmd_handler (cli.params_num , cli.params);

RP> cli.params is an array of char, but the handler_pointer _t functions
RP> accept a pointer to array of char, 'char *argv[]', for the second
RP> argument.
Sorry I made typo in first post, right definition of "cmdLineEntry_t " is:

/* define command line: <command> <param1> <param2> ... <paramN> */
typedef struct cmdLineEntry_s {
#define MAX_NAME 20
char command[MAX_NAME];
#define MAX_ARGS 10
char *params[MAX_ARGS];
unsigned int params_num;
handler_ptr_t cmd_handler;
} cmdLineEntry_t;

i.e. params is array of pointers to char.

With best regards, Roman Mashak. E-mail: mr*@tusur.ru
Feb 12 '06 #5
Hello, Walter!
You wrote on Sat, 11 Feb 2006 18:02:16 +0000 (UTC):

??>> const char *PROMPT = "CLI>";

??>> int main(void)
??>> {
??>> char buf[BUFSIZ] = {0};
??>> cmdLineEntry_t cli = { {0}, {NULL}, 0, NULL };
??>>
??>> while (1) {
??>> printf("%s", PROMPT);

WR> There is in \n in your PROMPT,
Why do I need '\n' in PROMP? Otherwise cursor jumps next line, which is
wrong...
I don't get you here, please clarify.
WR> and you do not fflush() the output, so your prompt is not certain to
WR> appear at any particular place relative to the input. It might not
WR> appear at all until you happen to output a \n for other reasons.

??>> if ( fgets(buf, BUFSIZ, stdin) ) {
??>> /* skip LF/CR/TAB/SP */
??>> if (buf[0] == '\n' || buf[0] == ' ' || buf[0] == '\r' ||
??>> buf[0] == '\t') continue;

WR> That continue is relative to the while(), and you do not print
WR> anything out in the case of the empty line. Thus if you have
If I press only 'Enter', it generates '\n' into buffer and according to
'continue' flow will jump back to 'while' loop, where PROMPT is printed.
I can't grasp your idea, unfortunately.. .
WR> a series of \n in your buffer, you will end up doing repeated
WR> printf("%s", PROMPT) and since there is no \n in that, the several
WR> prompts will all come out on one line.

With best regards, Roman Mashak. E-mail: mr*@tusur.ru
Feb 12 '06 #6
"Roman Mashak" <mr*@tusur.ru > writes:
Hello, Walter!
You wrote on Sat, 11 Feb 2006 18:02:16 +0000 (UTC):
??>> const char *PROMPT = "CLI>"; [...] ??>> printf("%s", PROMPT);

WR> There is in \n in your PROMPT,
Why do I need '\n' in PROMP? Otherwise cursor jumps next line, which is
wrong...
I don't get you here, please clarify.
He already did:
WR> and you do not fflush() the output, so your prompt is not certain to
WR> appear at any particular place relative to the input. It might not
WR> appear at all until you happen to output a \n for other reasons.


stdout is typically line-buffered, so the prompt won't necessarily
appear until you either print a new-line character *or* call
fflush(stdout).

--
Keith Thompson (The_Other_Keit h) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Feb 12 '06 #7
Hello, Keith!
You wrote on Sun, 12 Feb 2006 07:48:24 GMT:

WR>>> and you do not fflush() the output, so your prompt is not certain to
WR>>> appear at any particular place relative to the input. It might not
WR>>> appear at all until you happen to output a \n for other reasons.

KT> stdout is typically line-buffered, so the prompt won't necessarily
KT> appear until you either print a new-line character *or* call
KT> fflush(stdout).
Ok, I simplified my code to minimum in order to catch error, but same effect
remained, here it is:

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

static const char *PROMPT = "CLI>";

int main(void)
{
char buf[BUFSIZ] = {0};

while (1) {
printf("%s", PROMPT);
fflush(stdout);

if ( fgets(buf, BUFSIZ, stdin) ) {
/* do something */
}
else continue; /* EOL */
} /* while */

return 0;
}

With best regards, Roman Mashak. E-mail: mr*@tusur.ru
Feb 12 '06 #8
"Roman Mashak" <mr*@tusur.ru > writes:
You wrote on Sun, 12 Feb 2006 07:48:24 GMT:

WR>>> and you do not fflush() the output, so your prompt is not certain to
WR>>> appear at any particular place relative to the input. It might not
WR>>> appear at all until you happen to output a \n for other reasons.

KT> stdout is typically line-buffered, so the prompt won't necessarily
KT> appear until you either print a new-line character *or* call
KT> fflush(stdout).
Ok, I simplified my code to minimum in order to catch error, but same effect
remained, here it is:

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

static const char *PROMPT = "CLI>";

int main(void)
{
char buf[BUFSIZ] = {0};

while (1) {
printf("%s", PROMPT);
fflush(stdout);

if ( fgets(buf, BUFSIZ, stdin) ) {
/* do something */
}
else continue; /* EOL */
} /* while */

return 0;
}


<unistd.h> isn't a standard C header, and _GNU_SOURCE isn't standard C
either, but your program doesn't seem to depend on either of them.

I don't know what you mean by "same effect remained". Is there a
problem?

--
Keith Thompson (The_Other_Keit h) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Feb 12 '06 #9
On Sun, 12 Feb 2006 01:14:51 +0700, "Roman Mashak" <mr*@tusur.ru >
wrote:
Hello, All!

I'm implementing simple CLI (flat model, no tree-style menu etc.). Command
line looks like this: <command> <param1> <param2> ... <paramN> (where
N=1..4)
And idea is pretty simple:

1) get whole string of input line
2) preset table of strings matching <command>
3) preset table of function calls
4) scan <command> table for string, if match - call matching function (I
declare ALL callback functions as having the same format)

Here is code implementing part of this algorithm. The problem I came across
is if pressing 'Enter' continuously then sometimes output of PROMPT turnes
out clumsy, i.e. it's printed repeatedly in a line.


i don't see where the problem is

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#define UC unsigned char

static const char *pc = "CLI[\"vexit\" to end]>";

struct you{
char* name;
char* pointer;
unsigned npar;
struct you* prev;
};

struct you *last=0;

int inserisci(const char* name, char* pointer)
{struct you *tm;
char *tmp;
unsigned sz;
///////////////////
if( name==0 ||(sz=strlen(na me))==0 )
return 0;
if( (tm =malloc(sizeof( struct you)))==0 )
return 0;
if( (tmp=malloc(siz eof(sz+2)))==0 )
{free(tm); return 0;}
tm->name=tmp; strcpy(tm->name, name);
tm->pointer= pointer; tm->npar=0;
tm->prev=last; last=tm;
return 1;
}

void free_list(void)
{struct you *p=last, *v;
while(1) {if(p==0) break;
v=p; p=p->prev;
free(v->name); free(v);
}
}
int show(int aargc, char** aargv){puts("cl iShow() stub");return 0;}
int version(int aargc, char** aargv){puts("cl iVersion() stub");return
0;}
int help(int aargc, char** aargv){puts("cl iHelp() stub");return 0;}
int port(int aargc, char** aargv){puts("cl iPort() stub"); return
0;}
void vexit(int aargc, char** aargv)
{puts("cliExit( ) stub");
free_list();
exit(0);
}

int main(void)
{char buf[BUFSIZ] = {0}, *cp, *cp1;
struct you *p;
/////////////////////////////////
inserisci("show ",(char*) show);
inserisci("vers ion", (char*) version);
inserisci("help ", (char*) help);
inserisci("port ", (char*) port);
inserisci("vexi t",(char*) vexit);

while (1) {printf("%s", pc); fflush(stdout);
if ( fgets(buf, BUFSIZ, stdin)!=0 )
{for(cp=buf; isspace((UC)*cp ); ++cp);
if(*cp!=0)
{for(cp1=cp; !isspace((UC)*c p1) && *cp1!=0; ++cp1);
if(*cp1!=0) *cp1=0;
for(p=last; p ;p=p->prev)
if(strcmp(p->name, cp)==0)
switch(p->npar)
{case 0:
( ( void (*)(void) ) (p->pointer))( );
break;
case 1:
( ( void (*)(int) )(p->pointer))(1) ;
break;
}
}
}
}
return 0;

}
Feb 12 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

8
1855
by: djc | last post by:
I'm new to this and was wondering what the options are for interpreting the command line using a CLI program. Specifically methods for interpreting the parameters passed to the program on the command line. I noticed that visual studio adds the following for you when creating a new CLI program: void main(string args) { }
51
4118
by: Ojas | last post by:
Hi!, I just out of curiosity want to know how top detect the client side application under which the script is getting run. I mean to ask the how to know whether the script is running under Command Prompt or Browser or some other application? Ojas.
0
7804
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
0
8156
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. ...
1
7910
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For...
0
6563
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then...
1
5681
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
5366
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert...
0
3832
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
2307
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
1
1409
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.