有点复杂的剧透:
/*********************************************************************
** http:\\www.mahonri.info/SO/23796987_run-command-through-string-in-c.c
** If you like it, vote for it.
**
** Allows the user to submit various commands through stdin.
** Depending of the specific command, the program will execute various
** functions.
**
** Example usage (this code compiled into a program called 'test'):
**
** > echo "EXE_Add(1:2) EXE_Subtract(10:5) bye()" | ./test
** 1+2=3
** 10-5=5
** No such command: [bye]
** Done.
*/
/*********************************************************************
** Compiler setup.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define CMD_TRUE (-1)
#define CMD_FALSE (0)
typedef struct CMD_REC_S
{
char *commandStr;
int (*commandFn)(int, int);
} CMD_REC_T;
/*********************************************************************
** EXE_Add command handler.
*/
int EXE_Add(
int I__a,
int I__b
)
{
printf("%d+%d=%d\n", I__a, I__b, I__a+I__b);
return(0);
}
/*********************************************************************
** EXE_Subtract command handler.
*/
int EXE_Subtract(
int I__a,
int I__b
)
{
printf("%d-%d=%d\n", I__a, I__b, I__a-I__b);
return(0);
}
/*********************************************************************
** Command table identifies the name of all stdin commands (above).
*/
CMD_REC_T CMD_table[] =
{
{"EXE_Add", EXE_Add},
{"EXE_Subtract", EXE_Subtract},
{NULL, NULL}
};
/*********************************************************************
** Fetch a command from stdin. Return the command in allocated memory.
*/
int CMD_Fetch(
char **_O_command
)
{
int rCode = 0;
char *command = NULL;
size_t commandLen = 0;
int found = CMD_FALSE;
/* Initialize dynamic command buffer. */
errno=0;
command = malloc(++commandLen);
if(NULL == command)
{
rCode = errno ? errno : ENOMEM;
fprintf(stderr, "malloc() failed. errno:%d\n", errno);
goto CLEANUP;
}
*command = '\0';
/* Read characters from stdin to a dynamic command buffer
* until a ')' character is encountered.
*/
while(!found)
{
char *tmp;
int character;
/* Read & process a character from stdin. */
character=getchar();
switch(character)
{
case EOF:
rCode=ENOENT;
goto CLEANUP;
case ')':
found=CMD_TRUE;
break;
case '\t':
case ' ':
continue;
default:
break;
};
/* Add the character to the dynamic command buffer. */
errno=0;
tmp=realloc(command, ++commandLen);
if(NULL == tmp)
{
rCode = errno ? errno : ENOMEM;
fprintf(stderr, "realloc() failed. errno:%d\n", errno);
goto CLEANUP;
}
command=tmp;
command[commandLen-2] = character;
command[commandLen-1] = '\0';
}
/* Return results. */
if(_O_command)
{
*_O_command = command;
command=NULL;
}
CLEANUP:
if(command)
free(command);
return(rCode);
}
/*********************************************************************
** Execute command.
*/
int CMD_Execute(
const char *I__command
)
{
int rCode=0;
char *cp;
CMD_REC_T *commandRec = CMD_table;
int a, b;
/* Isolate the function name. */
cp=strchr(I__command, '(');
if(NULL == cp)
{
rCode=EINVAL;
fprintf(stderr, "Parsing error: I__command[%s] is missing '('\n", I__command);
goto CLEANUP;
}
*cp='\0';
++cp;
/* Fetch the CMD_REC_T from the CMD_table */
while(commandRec->commandStr)
{
if(0 == strcmp(commandRec->commandStr, I__command))
break;
++commandRec;
}
if(NULL == commandRec->commandStr)
{
rCode=ENOENT;
goto CLEANUP;
}
/* Parse the two integers, a & b */
a=atoi(cp);
cp=strchr(cp, ':');
if(NULL == cp)
{
rCode=EINVAL;
fprintf(stderr, "Parsing error: Missing ':'\n");
goto CLEANUP;
}
b=atoi(++cp);
/* Verify that the commandRec->commandFn is non-NULL. */
if(NULL == commandRec->commandFn)
{
rCode=ENOSYS;
fprintf(stderr, "Function %s() is unavailable.\n", commandRec->commandStr);
goto CLEANUP;
}
/* Call the specified function. */
rCode=(*commandRec->commandFn)(a, b);
if(rCode)
{
fprintf(stderr, "%s() reports: %d\n", commandRec->commandStr, rCode);
goto CLEANUP;
}
CLEANUP:
return(rCode);
}
/*********************************************************************
** Program start.
*/
int main()
{
int rCode=0;
char *command=NULL;
int done=CMD_FALSE;
while(!done)
{
rCode=CMD_Fetch(&command);
switch(rCode)
{
case 0:
break;
case ENOENT:
rCode=0;
done=CMD_TRUE;
printf("Done.\n");
continue;
default:
fprintf(stderr, "CMD_Fetch() reports: %d\n", rCode);
goto CLEANUP;
}
rCode=CMD_Execute(command);
switch(rCode)
{
case 0:
break;
case ENOENT:
fprintf(stderr, "No such command: [%s]\n", command);
continue;
default:
fprintf(stderr, "CMD_Execute() reports: %d\n", rCode);
goto CLEANUP;
}
free(command);
command=NULL;
}
CLEANUP:
if(command)
free(command);
return(rCode);
}