/* ut-demo2.c - complex example of using MicroThreads */ /* Jon Mayo - PUBLIC DOMAIN - January 29, 2007 */ #define NDEBUG #include #include #include #include #include #include "ut.h" #define NR(x) (sizeof(x)/sizeof*(x)) /* number of elements in an array */ struct client_state { struct ut_state uts; unsigned cmdid; char tinybuf[16]; /* very small buffer! */ unsigned len; int keep_going; /* flag if command input should continue */ }; /* returns -1 if there is not a complete word in the buffer */ static int has_word(const char *buf, unsigned len) { unsigned i; for(i=0;ikeep_going=0; break; default: printf("Unknown command %d\n", cmdid); } } /* buf - provide length terminated string data. * len - pointer to length of string, modified to indicate consumption */ static int parser_th(struct client_state *cl, char *buf, unsigned *len) { static const char * const command_str[] = { "enable", "disable", "show", "service", "access-list", "ping", "diag", "configure", "reset", "help", "quit", "exit" }; int tmplen; #ifndef NDEBUG printf("%s():enter. len=%d\n", __func__, *len); #endif UT_BEGIN(&cl->uts); /* command word */ UT_WAIT_UNTIL(&cl->uts, (tmplen=has_word(buf, *len)) != -1); printf("COMMAND: '%.*s'\n", tmplen, buf); /* save the command as a number so we can empty the buffer */ cl->cmdid=word_to_int(buf, tmplen, command_str, NR(command_str)); /* eat trailing whitespaces if there are any left in this buffer, does * not eat any of the whitespaces that might be send in the next buffer */ while(tmplen<*len && buf[tmplen]==' ' && buf[tmplen]=='\t') tmplen++; /* shift consumed buffer */ *len-=tmplen; memmove(buf, buf+tmplen, *len); /* arguments of command */ /* TODO: figure out how to consume leading whitespaces */ /* TODO: handle each argument as a word to minimize buffer space, it * would make this function massively more complex but allow for very * long commands to be entered and make for easier command completion * in the future. */ UT_WAIT_UNTIL(&cl->uts, (tmplen=has_line(buf, *len)) != -1); printf("ARGS: '%.*s'\n", tmplen, buf); buf[tmplen++]=0; /* null terminate buffer (write over \n) */ command_run(cl, cl->cmdid, buf); /* shift consumed buffer */ *len-=tmplen; memmove(buf, buf+tmplen, *len); #ifndef NDEBUG printf("%s():complete. len=%d\n", __func__, *len); #endif UT_END(&cl->uts); } static void client_init(struct client_state *cl) { assert(cl != NULL); UT_INITIALIZE(&cl->uts); cl->cmdid=-1; cl->len=0; cl->keep_going=1; memset(cl->tinybuf, 0, sizeof cl->tinybuf); } static int get_command(struct client_state *cl) { assert(cl != NULL); /* keep calling the thread's reentry until it returns non-zero */ while(cl->keep_going && (printf("> "),fgets(cl->tinybuf+cl->len, sizeof cl->tinybuf-cl->len, stdin))) { /* fill the buffer with data */ cl->len+=strlen(cl->tinybuf+cl->len); if(parser_th(cl, cl->tinybuf, &cl->len)==UT_STATUS_EXITED) { /* completed command */ printf("\n"); } if(cl->len >= sizeof cl->tinybuf-1) { /* nothing was consumed */ fprintf(stderr, "error:Buffer Overflow?\n"); return 0; } #ifndef NDEBUG printf("%s():Looping...\n", __func__); #endif } return 1; } int main(int argc, char **argv) { struct client_state ex; client_init(&ex); printf("Welcome. type 'help' for help.\n"); if(!get_command(&ex)) { printf("\nThere was a fatal error.\n"); return EXIT_FAILURE; } return 0; }