Skip to content

Instantly share code, notes, and snippets.

@gabrieleara
Created November 30, 2015 19:24
Show Gist options
  • Select an option

  • Save gabrieleara/78a8478f69db64768007 to your computer and use it in GitHub Desktop.

Select an option

Save gabrieleara/78a8478f69db64768007 to your computer and use it in GitHub Desktop.
Simple (?) library that handle some command from stdin. The commands can have zero or one parameters that MUST be specified in the same line of the command. The files include a sample main which uses this library
#include "standard.h"
#include "console.h"
#include <sys/select.h>
struct command
{
char string[15];
bool active;
void (*callback)();
};
struct command_keeper
{
struct command* cmds;
int length;
int size;
} my_cmd_list = { .cmds = NULL, .length = 0, .size = 0 };
fd_set console_master_set;
char* last_arg;
#define REMOVE_LAST_ARG() if(last_arg != NULL) { free(last_arg); last_arg = NULL; }
int init_command_list(int size)
{
if(my_cmd_list.size != 0 || my_cmd_list.cmds != NULL || size <= 0)
{
/* TODO: add more error flags */
return -1;
}
my_cmd_list.size = size;
my_cmd_list.length = 0;
my_cmd_list.cmds = malloc(sizeof(struct command) * size);
FD_ZERO(&console_master_set);
/* Zero is the number of file descriptor
* for stdin, according to man page.
*/
FD_SET(0, &console_master_set);
REMOVE_LAST_ARG();
return 0;
}
int valid_cmd(char* cmd)
{
int i = 1;
bool valid = false;
if(*cmd == 0)
return 0;
for( ; i < 15 && !valid; ++i)
{
if(cmd[i] == 0)
valid = true;
}
return valid;
}
int find_valid_cmd(char* cmd)
{
int i = 0, length = my_cmd_list.length;
for(i = 0; i < length; ++i)
{
if(strncmp(my_cmd_list.cmds[i].string, cmd, 15) == 0)
return i;
}
return -1;
}
int find_cmd(char* cmd)
{
if(!valid_cmd(cmd))
return -1;
return find_valid_cmd(cmd);
}
int add_command(char* cmd, void (*f)())
{
int i = my_cmd_list.length;
if(my_cmd_list.length >= my_cmd_list.size
|| !valid_cmd(cmd) || find_valid_cmd(cmd) >= 0)
{
/* TODO: add more error flags */
return -1;
}
my_cmd_list.cmds[i].active = 0;
my_cmd_list.cmds[i].callback = f;
strncpy(my_cmd_list.cmds[i].string, cmd, 15);
++my_cmd_list.length;
return 0;
}
int set_command_status(char* cmd, bool active)
{
int i;
if(( i = find_cmd(cmd) ) < 0)
{
/* TODO: add more error flags */
return -1;
}
my_cmd_list.cmds[i].active = active;
return 0;
}
int select_stdin(char** str, long timeout)
{
char buffer[100];
int code, num;
struct timeval tv_out = { .tv_sec = timeout, .tv_usec = 0 };
fd_set console_to_read;
FD_ZERO(&console_to_read);
console_to_read = console_master_set;
/* Zero is the number of file descriptor
* for stdin, according to man page.
*/
code = select(1, &console_to_read, NULL, NULL, &tv_out);
if(code == 0)
return CMD_TIMER_EXCEDED;
if(code <= -1 || !(FD_ISSET(0, &console_to_read)))
return CMD_INPUT_ERROR;
/*strncpy(buffer, "\0\0\0", 1);*/
fgets(buffer, sizeof(buffer), stdin);
num = sscanf(buffer, "%ms %ms", str, &last_arg);
if(num < 1)
{
/* TODO: a better check */
return CMD_NO_COMMAND;
}
/* If command need an argument, but there isn't,
* it will do some stuff itself.
*/
if(num < 2)
REMOVE_LAST_ARG();
return 0;
}
int wait_for_command(void (**callback)(), long timeout)
{
char* command;
int i, code;
REMOVE_LAST_ARG();
code = select_stdin(&command, timeout);
if(code < 0)
return code;
if((i = find_cmd(command)) < 0)
{
return CMD_INVALID;
}
free(command);
if(!my_cmd_list.cmds[i].active)
return CMD_UNACTIVE;
*callback = my_cmd_list.cmds[i].callback;
return 0;
}
int get_argument(char** arg)
{
size_t n;
if(last_arg == NULL)
return CMD_NO_ARG;
/* I'm sure it's a zero-terminated string. */
n = strlen(last_arg);
*arg = malloc((n + 1) * sizeof(char));
strncpy(*arg, last_arg, n + 1);
REMOVE_LAST_ARG();
return n;
}
#undef REMOVE_LAST_ARG
#ifndef ARA_CONSOLE_H
#define ARA_CONSOLE_H
/*
* Initialize a list of commands and relative handlers.
*
* Arguments:
* size - the size of the command list; it must be greater than zero.
*
* Returns:
* A non negative value in case of success.
* A negative value in case of list already initialized.
*/
int init_command_list(int size);
/*
* Add a command and its handler to the list.
* Any of the comamnds added to the list must be esplicitly activated
* via a call to set_command_status (see below).
*
* Arguments:
* cmd - the string of the command, must be at most 14 characters long
* (so 15 counting the '\0' character);
* f - a pointer fo a void function with a string argument, which will
* be the rest of the line containing the command.
*
* Returns:
* A non negative value in case of success.
* A negative value in case of:
* - list already full;
* - invalid cmd string;
* - cmd already present;
*/
int add_command(char* cmd, void (*f)(char*));
/*
* Sets the status of a command in the list, if present. An active command
* will result in a call to his handler when prompted, an inactive command
* will be treated like an invalid command and will display an error
* when prompted.
*
* Arguments:
* cmd - the string of the command, must be at most 14 characters long
* (so 15 counting the '\0' character);
* active - a boolean representing the status of the comamnd:
* true will set a command as active (even if it was already active);
* false will deactivate a command (even if it was already non active).
*
* Returns:
* A non negative value in case of success.
* A negative value in case of failure - i.e. the cmd is invalid or not found.
*/
int set_command_status(char* cmd, bool active);
/* TODO list: every function behind this point isn't implemented yet. */
#define CMD_TIMER_EXCEDED -1
#define CMD_INPUT_ERROR -2
#define CMD_NO_COMMAND -3
#define CMD_INVALID -4
#define CMD_UNACTIVE -5
#define CMD_NO_ARG CMD_TIMER_EXCEDED
/*
* Wait the user to prompt for a command - i.e. pressing enter - for at most
* timeout seconds. If the user prompts a valid commands marked as active,
* then the callback parameter will be filled with a valid handler for that
* command.
*
*
* -- NOTICE: This does not affect this implementation.
* -- This is just here as a reminder.
* -- For separated thread implementation only:
* Notice that this function, in order to work correctly, should be called
* if and only if any other execution of a command handler has already
* terminated.
*
*
* Arguments:
* callback- a pointer to a command handler - i.e. a function pointer of type
* void which accepts a string argument.
* timeout - the time, in seconds, which this function will wait for
* a command or, in general, for any information to come from
* the standard input.
*
* Returns:
* A non negative value in case of a valid and active command, a negative
* value otherwise.
*
* Possible negative values minings are:
* CMD_TIMER_EXCEDED - when his execution is aborted by the timer;
* CMD_INPUT_ERROR - when some error with stream occurs;
* CMD_INVALID - when user prompts an invalid command;
* CMD_UNACTIVE - when user prompts a non active command.
*
* The callback parameter will contain a valid handler for the command
* prompted in case of success; it will be untouched in case of failure.
*
*/
int wait_for_command(void (**callback)(), long timeout);
/*
* Fill the given string pointer arg with the last command's
* argument (if present).
*
* Arguments:
* arg - a pointer to a string to be filled with the argument
* of the callback. It will be allocated dynamically.
*
* Returns:
* The length of the argument string in case of success,
* CMD_NO_ARG otherwise (which is a negative value).
*/
int get_argument(char** arg);
#endif
#include "standard.h"
#include "console.h"
char* cmdA = "AAA";
char* cmdB = "pincopanco";
void callA()
{
printf("A: attivazione comando pincopanco\r\n");
if(set_command_status(cmdB, true) < 0)
printf("ERROR 7\r\n");
return;
}
void callB()
{
char* arg = NULL;
int code;
if( (code = get_argument(&arg)) < 0)
{
printf("Errore, nessun argomento. Codice %d.\r\n", code);
if(arg != NULL)
printf("CHE?");
return;
}
printf("B: %s\r\n", arg);
return;
}
int main()
{
void (*callback)();
int code;
if(init_command_list(2) < 0)
{
printf("ERROR 1\r\n");
return -1;
}
if(add_command(cmdA, callA) < 0)
{
printf("ERROR 2\r\n");
return -1;
}
if(add_command(cmdB, callB) < 0)
{
printf("ERROR 2\r\n");
return -1;
}
if(set_command_status(cmdA, true) < 0)
{
printf("ERROR 3\r\n");
return -1;
}
while(1)
{
printf("> ");
fflush(stdout);
if((code = wait_for_command(&callback, 60)) < 0)
{
switch(code)
{
case CMD_TIMER_EXCEDED:
printf("Il programma terminerà ora.\r\n");
return 0;
case CMD_INPUT_ERROR:
printf("Uh, oh...\r\n");
break;
case CMD_NO_COMMAND:
break;
case CMD_INVALID:
printf("Il comando inserito non e' valido.\r\n");
break;
case CMD_UNACTIVE:
printf("Il comando inserito non e' al momento attivo.\r\n");
break;
default:
printf("WHAT?");
}
continue;
}
callback();
}
}
#ifndef ARA_STANDARD_H
#define ARA_STANDARD_H
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment