diff --git a/examples/filelist.h b/examples/filelist.h index cfb718b..3b0229c 100644 --- a/examples/filelist.h +++ b/examples/filelist.h @@ -46,4 +46,6 @@ #define FREE(x) { if (x) { free(x); x = NULL; } } #define MAX_STREAMS INT_MAX +#define DIRLIST_ID 1 + #endif /*__SXMP_EXAMPLES_FILELIST_H__*/ diff --git a/examples/streamfld.c b/examples/streamfld.c index a5d41d6..69bc918 100644 --- a/examples/streamfld.c +++ b/examples/streamfld.c @@ -54,6 +54,7 @@ #include #include +#include #include #include #include @@ -119,6 +120,109 @@ static int __ping(void *m, sexp_t *sx) return sxmsg_return((sxmsg_t*)m, SXE_SUCCESS); } +/* dir listing stream */ +typedef struct __dirlist_type { + DIR *dp; + struct dirent dent; + struct dirent *dres; +} dirlist_t; + +static int dirlist_open(sxlink_t *link, struct sxstream_opened *stream, + const char *dirname) +{ + dirlist_t *pslist = malloc(sizeof(dirlist_t)); + + if(!pslist) return SXE_ENOMEM; + else memset(pslist, 0, sizeof(dirlist_t)); + + if(!(pslist->dp = opendir(dirname ? dirname : "./"))) { + free(pslist); + return SXE_FAILED; + } else sxstream_opened_setpriv(stream, pslist); + + return SXE_SUCCESS; +} + +static int dirlist_close(struct sxstream_opened *stream) +{ + dirlist_t *pslist = sxstream_opened_getpriv(stream); + list_head_t *llist = sxstream_opened_getelist(stream); + + if(!pslist) return SXE_FAILED; + if(llist) sxstream_generic_slist_free(llist); + + /* close dir and free strcuture */ + if(pslist->dp) closedir(pslist->dp); + free(pslist); + + return SXE_SUCCESS; +} + +static inline const char *dump_type(struct dirent *d) +{ + if(!d) return "nil"; + + switch(d->d_type) { + case DT_REG: return "regular"; + case DT_DIR: return "directory"; + case DT_BLK: return "block"; + case DT_CHR: return "char"; + case DT_FIFO: return "fifo"; + case DT_LNK: return "link"; + case DT_UNKNOWN: return "unknown"; + default: return "another"; + } + + return "nil"; +} + +static size_t dirlist_read(struct sxstream_opened *stream, size_t sz, uint64_t off, + list_head_t **rlist) +{ + dirlist_t *pslist = sxstream_opened_getpriv(stream); + list_head_t *llist_prev = sxstream_opened_getelist(stream); + list_head_t *llist_new = NULL; + + if(!pslist || !llist_new) return -1; + + /* read and fill new list */ + if(readdir_r(pslist->dp, &(pslist->dent), &(pslist->dres))) + return -1; + /* if finished return 0 */ + if(!pslist->dres) return 0; + /* allocate a new */ + if(!(llist_new = sxstream_generic_slist_alloc())) return -1; + else { /* fill this list */ + if(sxstream_generic_slist_additem(llist_new, pslist->dres->d_name)) { + __fail: + sxstream_generic_slist_free(llist_new); + return -1; + } + if(sxstream_generic_slist_additem(llist_new, dump_type(pslist->dres))) + goto __fail; + } + /* otherwise destroy last list */ + sxstream_generic_slist_free(llist_prev); + *rlist = llist_new; /* assign new list */ + + return 1; +} + +static struct sxstream_ops dirlist_ops = { + .s_open = dirlist_open, + .s_close = dirlist_close, + .s_eread = dirlist_read, + .s_ewrite = NULL, +}; + +static struct sxstream_description dirlist_stream = { + .stid = DIRLIST_ID, + .pcid = READONLY_CHANNEL, + .type = 0, /* just a simple one */ + .flags = SXE_O_READ | SXE_O_TRUNC, + .ops = &dirlist_ops, +}; + /* command line options helpers */ static void __help_print(FILE *fso, const char *fmtname) { @@ -252,7 +356,6 @@ int main(int argc, char **argv) /* ok, let's add stream functions */ opt = sxmp_rpclist_add_function(fulist, READONLY_CHANNEL, "ping", __ping); if(opt) { - __fail: fprintf(stderr, "Failed to add functions to typed RPC channel\n Failure.\n"); return opt; } @@ -260,6 +363,9 @@ int main(int argc, char **argv) /* ok, setup it */ sxhub_set_rpcvalidator(sxmphub, __rettlist); + /* setup our stream */ + sxhub_stream_register(sxmphub, &dirlist_stream); + signal(SIGPIPE, SIG_IGN); /* now we're ready to run the listen process */