diff --git a/examples/smpfc.c b/examples/smpfc.c index 31fa6d9..f9ccf55 100644 --- a/examples/smpfc.c +++ b/examples/smpfc.c @@ -71,20 +71,198 @@ struct _remote_host { sxlink_t *link; }; +struct _shll_cmds { + char cmd[64]; + int (*execute)(sxlink_t *, char **, int); +}; + +static int __cwd(sxlink_t *link, char **argv, int argc) +{ + sxchnl_t *channel = sxchannel_open(link, READONLY_CHANNEL); + sxmsg_t *msg; + char buf[1024]; + int r = SXE_SUCCESS; + + if(!channel) return SXE_FAILED; + if(argc < 2) return SXE_SUCCESS; /* nothing to do if we don't have any parameters */ + + snprintf(buf, 1024, "(%s %s)", CWD_CMD, argv[1]); + r = sxmsg_send(channel, buf, strlen(buf), &msg); + + if(channel) sxchannel_close(channel); + + return r; +} + +static void __dirlist_out(FILE *f, list_head_t *list) +{ + char *dname = NULL, *dtype = NULL; + list_node_t *iter, *siter; + struct _nn_stream_entry_node *entry; + int i = 0; + + list_for_each_safe(list, iter, siter) { + entry = list_entry(iter, struct _nn_stream_entry_node, node); + if(!i) dname = entry->value; + else if(i == 1) dtype = entry->value; + i++; + } + fprintf(f, "%-24s | %-12s\n", dname, dtype); + return; +} + +static int __list(sxlink_t *link, char **argv, int argc) +{ + sxmsg_t *msg; + char *opt = NULL; + int r = SXE_SUCCESS; + sxstream_t *stream; + list_head_t *list; + + if(argc > 2) opt = argv[1]; + + fprintf(stdout, "%-24s | %-12s\n", "Name", "Type"); + fprintf(stdout, "---------------------------------------\n"); + + stream = sxstream_open(link, opt, DIRLIST_ID, SXE_O_READ); + if(!stream) { + fprintf(stderr, "Failed to open stream with %d ID (%d).\n", DIRLIST_ID, errno); + return SXE_FAILED; + } + + while((list = sxstream_read(stream)) != NULL) __dirlist_out(stdout, list); + + if(errno != SXE_EOS) fprintf(stderr, "Reading failed (%d)\n", errno); + + sxstream_close(stream); + + return r; +} + +struct _shll_cmds shcmds[] = { + { "cd", __cwd }, + { "ls", __list }, + { "", NULL}, +}; + +/* misc remote commands */ +static int __remote_getcwd(sxlink_t *link, char *buf, size_t buflen) +{ + sxchnl_t *channel = sxchannel_open(link, READONLY_CHANNEL); + sxmsg_t *msg; + sexp_t *sx = NULL, *isx; + int r = SXE_SUCCESS, idx; + + if(!channel || !buf) return SXE_FAILED; + + snprintf(buf, buflen, "(%s)", GETCWD_CMD); + r = sxmsg_send(channel, buf, strlen(buf), &msg); + if(r == SXE_RAPIDMSG || r == SXE_REPLYREQ) { + sx = parse_sexp(sxmsg_payload(msg), strlen(sxmsg_payload(msg))); + + if(r == SXE_RAPIDMSG) sxmsg_clean(msg); + else sxmsg_return(msg, SXE_SUCCESS); + } else goto __fini; + + if(!sx) { r = SXE_ENOMEM; goto __fini; } + + SEXP_ITERATE_LIST(sx, isx, idx) { + if(isx->ty == SEXP_LIST) { r = SXE_BADPROTO; goto __fini; } + if(!idx) strcpy(buf, isx->val); + else { r = SXE_BADPROTO; goto __fini; } + } + + r = SXE_SUCCESS; + + __fini: + if(sx) destroy_sexp(sx); + if(channel) sxchannel_close(channel); + return r; +} + +static int __exec_line(sxlink_t *link, const char *line) +{ + char **argv, *tline = (char *)line, *oline; + int argc, r = SXE_FAILED, i; + int (*exe)(sxlink_t *, char **, int) = NULL; + + if(!strlen(line)) return SXE_NILREPLY; + + /* get arguments count */ + argc = 1; oline = tline; + for(tline = strchr(tline, ' '); tline != NULL; + tline += sizeof(char), tline = strchr(tline, ' ')) { + if((strlen(oline) - strlen(tline)) > sizeof(char)) argc++; + oline = tline; + } + if(!(argv = malloc(sizeof(uintptr_t)*argc))) return SXE_ENOMEM; + + /* fill arguments */ + for(oline = tline = (char *)line, i = 0; i < argc; i++) { + if(!(tline = strchr(tline, ' '))) + argv[i] = strdup(oline); + else if((strlen(oline) - strlen(tline)) > sizeof(char)) /* that's our bottle of beer */ + argv[i] = strndup(oline, strlen(oline) - strlen(tline)); + + tline += sizeof(char); + oline = tline; + } + for(i = 0; i < argc; i++) { /* check up */ + if(argv[i] == NULL) { r = SXE_ENOMEM; goto __fini; } + } + + /* now let's search our cmd */ + for(i = 0; strlen(shcmds[i].cmd); i++) { + if(!strcmp(shcmds[i].cmd, argv[0])) exe = shcmds[i].execute; + } + + if(!exe) r = SXE_IGNORED; /* ignoring stuff like that */ + else r = exe(link, argv, argc); + + __fini: + /* free all arguments */ + if(argv && argc) { + for(i = 0; i < argc; i++) { + if(argv[i]) free(argv[i]); + } + free(argv); + } + return r; +} + /* session processing itself */ static void __shell(sxlink_t *link) { struct _session *s = (struct _session *)sxlink_getpriv(link); - char *line; + char *line, cwd[1024], promt[1024]; + int r, rrc; + + r = __remote_getcwd(link, cwd, 1024); + if(r == SXE_SUCCESS) + snprintf(promt, 1024, "%s$>", cwd); + else snprintf(promt, 1024, "@e:%d$>", r); for(;;) { - line = readline("$>"); + line = readline(promt); if(line && *line) add_history(line); else break; if(!strcmp(line, "exit")) break; + else { + rrc = __exec_line(link, line); + + /* getcwd, in some cases it might be changed */ + r = __remote_getcwd(link, cwd, 1024); + if(r == SXE_SUCCESS) { + if(rrc == SXE_SUCCESS) snprintf(promt, 1024, "%s$>", cwd); + else snprintf(promt, 1024, "[%d]%s$>", rrc, cwd); + } else snprintf(promt, 1024, "@e:%d$>", r); + } } + + free(line); + return; }