Annotation of embedaddon/confuse/examples/cli.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (c) 2015 Peter Rosin <peda@lysator.liu.se>
                      3:  *
                      4:  * Permission to use, copy, modify, and/or distribute this software for any
                      5:  * purpose with or without fee is hereby granted, provided that the above
                      6:  * copyright notice and this permission notice appear in all copies.
                      7:  *
                      8:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                      9:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     10:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     11:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     12:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     13:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     14:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     15:  */
                     16: 
                     17: #include <string.h>
                     18: #include <stdlib.h>
                     19: #include "confuse.h"
                     20: 
                     21: static cfg_t *cfg;
                     22: static int cmdc;
                     23: static char **cmdv;
                     24: static int cmdv_max;
                     25: 
                     26: static int reserve_cmdv(int cmdc)
                     27: {
                     28:        int cmd_max = cmdv_max;
                     29:        char **tmp;
                     30: 
                     31:        if (cmdc < cmd_max)
                     32:                return 0;
                     33: 
                     34:        do
                     35:                cmd_max += 10;
                     36:        while (cmdc >= cmd_max);
                     37: 
                     38:        tmp = realloc(cmdv, cmd_max * sizeof(*tmp));
                     39:        if (!tmp)
                     40:                return -1;
                     41: 
                     42:        cmdv = tmp;
                     43:        cmdv_max = cmd_max;
                     44:        return 0;
                     45: }
                     46: 
                     47: static int split_cmd(char *cmd)
                     48: {
                     49:        char *out = cmd;
                     50:        int arg;
                     51: 
                     52:        cmdc = 0;
                     53: 
                     54:        for (;;) {
                     55:                char ch;
                     56: 
                     57:                arg = 0;
                     58:                while (*cmd == ' ')
                     59:                        ++cmd;
                     60:  next_char:
                     61:                ch = *cmd++;
                     62:                if (ch == '"' || ch == '\'') {
                     63:                        char end = ch;
                     64: 
                     65:                        if (!arg) {
                     66:                                if (reserve_cmdv(cmdc + 1))
                     67:                                        return -1;
                     68:                                cmdv[cmdc++] = out;
                     69:                                arg = 1;
                     70:                        }
                     71:                        while (*cmd && *cmd != end)
                     72:                                *out++ = *cmd++;
                     73:                        if (!*cmd++)
                     74:                                return -1;
                     75:                        goto next_char;
                     76:                }
                     77:                if (ch && ch != ' ') {
                     78:                        if (!arg) {
                     79:                                if (reserve_cmdv(cmdc + 1))
                     80:                                        return -1;
                     81:                                cmdv[cmdc++] = out;
                     82:                                arg = 1;
                     83:                        }
                     84:                        *out++ = ch;
                     85:                        goto next_char;
                     86:                }
                     87:                *out++ = 0;
                     88:                if (!ch)
                     89:                        break;
                     90:        }
                     91:        return cmdc;
                     92: }
                     93: 
                     94: static char *input_cmd(void)
                     95: {
                     96:        int ch;
                     97:        char *cmd = malloc(128);
                     98:        int len = 128;
                     99:        int pos = 0;
                    100: 
                    101:        if (!cmd)
                    102:                return NULL;
                    103: 
                    104:        for (;;) {
                    105:                ch = fgetc(stdin);
                    106:                if (ch < 0)
                    107:                        break;
                    108:                switch (ch) {
                    109:                case '\r':
                    110:                case '\n':
                    111:                        ch = 0;
                    112:                        /* fall through */
                    113:                default:
                    114:                        if (pos == len) {
                    115:                                char *tmp = realloc(cmd, len * 2);
                    116: 
                    117:                                if (!tmp)
                    118:                                        goto cleanup;
                    119:                                cmd = tmp;
                    120:                                len *= 2;
                    121:                        }
                    122:                        cmd[pos++] = ch;
                    123:                        if (!ch)
                    124:                                return cmd;
                    125:                }
                    126:        }
                    127:  cleanup:
                    128:        free(cmd);
                    129:        return NULL;
                    130: }
                    131: 
                    132: static const char *help(int argc, char *argv[])
                    133: {
                    134:        return  "Available commands:\n"
                    135:                "\n"
                    136:                "help\n"
                    137:                "set <option> <value> ...\n"
                    138:                "subset <section> <option> <value>\n"
                    139:                "create <section>\n"
                    140:                "destroy <section>\n"
                    141:                "dump [mod|modified]\n"
                    142:                "quit\n"
                    143:                "\n"
                    144:                "<option> is one of 'bool', 'int' 'string' and 'float'.\n";
                    145: }
                    146: 
                    147: static const char *set(int argc, char *argv[])
                    148: {
                    149:        if (argc < 3)
                    150:                return "Need more args\n";
                    151: 
                    152:        if (!cfg_getopt(cfg, argv[1]))
                    153:                return "Unknown option\n";
                    154: 
                    155:        if (cfg_setmulti(cfg, argv[1], argc - 2, &argv[2]))
                    156:                return "Failure\n";
                    157: 
                    158:        return "OK\n";
                    159: }
                    160: 
                    161: static const char *subset(int argc, char *argv[])
                    162: {
                    163:        cfg_t *sub;
                    164: 
                    165:        if (argc < 4)
                    166:                return "Need more args\n";
                    167:        if (argc > 4)
                    168:                return "Too many args\n";
                    169: 
                    170:        sub = cfg_gettsec(cfg, "sub", argv[1]);
                    171:        if (!sub)
                    172:                return "No such section\n";
                    173: 
                    174:        if (!cfg_getopt(sub, argv[2]))
                    175:                return "Unknown option\n";
                    176: 
                    177:        if (cfg_setmulti(sub, argv[2], argc - 3, &argv[3]))
                    178:                return "Failure\n";
                    179: 
                    180:        return "OK\n";
                    181: }
                    182: 
                    183: static const char *create(int argc, char *argv[])
                    184: {
                    185:        cfg_opt_t *opt;
                    186: 
                    187:        if (argc != 2)
                    188:                return "Need one arg\n";
                    189: 
                    190:        if (cfg_gettsec(cfg, "sub", argv[1]))
                    191:                return "Section exists already\n";
                    192: 
                    193:        opt = cfg_getopt(cfg, "sub");
                    194:        if (!opt || !cfg_setopt(cfg, opt, argv[1]))
                    195:                return "Failure\n";
                    196: 
                    197:        return "OK\n";
                    198: }
                    199: 
                    200: static const char *destroy(int argc, char *argv[])
                    201: {
                    202:        if (argc < 2)
                    203:                return "Need one arg\n";
                    204: 
                    205:        if (!cfg_gettsec(cfg, "sub", argv[1]))
                    206:                return "No such section\n";
                    207: 
                    208:        cfg_rmtsec(cfg, "sub", argv[1]);
                    209:        return "OK\n";
                    210: }
                    211: 
                    212: static int print_modified(cfg_t *cfg, cfg_opt_t *opt)
                    213: {
                    214:        cfg_t *sec;
                    215:        int i;
                    216: 
                    217:        if (opt->type != CFGT_SEC)
                    218:                return !(opt->flags & CFGF_MODIFIED);
                    219: 
                    220:        if (opt->flags & CFGF_MULTI)
                    221:                return 0;
                    222: 
                    223:        /*
                    224:         * This cli example does not have any non-multi section
                    225:         * options, but for completeness, this is a sane way to
                    226:         * handle "static" sections. I.e. filter them out unless
                    227:         * they have at least one sub-option that is not filtered
                    228:         * out.
                    229:         *
                    230:         * A generic solution would have to examine if the section
                    231:         * has its own print filter function and use that, but that
                    232:         * feels out of scope and is left as an exercise for the
                    233:         * reader. If it is needed at some point, a new supporting
                    234:         * API should probably be added to help get it done without
                    235:         * digging in the library guts...
                    236:         */
                    237:        sec = cfg_opt_getnsec(opt, 0);
                    238:        if (!sec)
                    239:                return 1;
                    240: 
                    241:        for (i = 0; sec->opts[i].name; i++) {
                    242:                if (!print_modified(sec, &sec->opts[i]))
                    243:                        return 0;
                    244:        }
                    245:        return 1;
                    246: }
                    247: 
                    248: static const char *dump(int argc, char *argv[])
                    249: {
                    250:        if (argc > 2)
                    251:                return "Too many args\n";
                    252:        if (argc == 2) {
                    253:                if (!strcmp(argv[1], "mod") || !strcmp(argv[1], "modified"))
                    254:                        cfg_set_print_filter_func(cfg, print_modified);
                    255:                else
                    256:                        return "Invalid arg\n";
                    257:        }
                    258:        else
                    259:                cfg_set_print_filter_func(cfg, NULL);
                    260: 
                    261:        cfg_print(cfg, stdout);
                    262:        return "";
                    263: }
                    264: 
                    265: static const char *quit(int argc, char *argv[])
                    266: {
                    267:        return NULL;
                    268: }
                    269: 
                    270: struct cmd_handler {
                    271:        const char *cmd;
                    272:        const char *(*handler)(int argc, char *argv[]);
                    273: };
                    274: 
                    275: static const struct cmd_handler cmds[] = {
                    276:        { "help", help },
                    277:        { "set", set },
                    278:        { "subset", subset },
                    279:        { "create", create },
                    280:        { "destroy", destroy },
                    281:        { "dump", dump },
                    282:        { "quit", quit },
                    283:        { "exit", quit },
                    284:        { NULL, NULL }
                    285: };
                    286: 
                    287: int main(void)
                    288: {
                    289:        cfg_opt_t sub_opts[] = {
                    290:                CFG_BOOL("bool", cfg_false, CFGF_NONE),
                    291:                CFG_STR("string", NULL, CFGF_NONE),
                    292:                CFG_INT("int", 0, CFGF_NONE),
                    293:                CFG_FLOAT("float", 0.0, CFGF_NONE),
                    294:                CFG_END()
                    295:        };
                    296: 
                    297:        cfg_opt_t opts[] = {
                    298:                CFG_BOOL_LIST("bool", cfg_false, CFGF_NONE),
                    299:                CFG_STR_LIST("string", NULL, CFGF_NONE),
                    300:                CFG_INT_LIST("int", 0, CFGF_NONE),
                    301:                CFG_FLOAT_LIST("float", "0.0", CFGF_NONE),
                    302:                CFG_SEC("sub", sub_opts,
                    303:                        CFGF_MULTI | CFGF_TITLE | CFGF_NO_TITLE_DUPES),
                    304:                CFG_END()
                    305:        };
                    306: 
                    307:        char *cmd = NULL;
                    308:        const char *reply;
                    309:        int res;
                    310:        int i;
                    311: 
                    312:        cfg = cfg_init(opts, CFGF_NONE);
                    313: 
                    314:        for (;;) {
                    315:                printf("cli> ");
                    316:                fflush(stdout);
                    317: 
                    318:                if (cmd)
                    319:                        free(cmd);
                    320:                cmd = input_cmd();
                    321:                if (!cmd)
                    322:                        exit(0);
                    323:                res = split_cmd(cmd);
                    324:                if (res < 0) {
                    325:                        printf("Parse error\n");
                    326:                        continue;
                    327:                }
                    328:                if (cmdc == 0)
                    329:                        continue;
                    330:                for (i = 0; cmds[i].cmd; ++i) {
                    331:                        if (strcmp(cmdv[0], cmds[i].cmd))
                    332:                                continue;
                    333:                        reply = cmds[i].handler(cmdc, cmdv);
                    334:                        if (!reply)
                    335:                                exit(0);
                    336:                        printf("%s", reply);
                    337:                        break;
                    338:                }
                    339:                if (!cmds[i].cmd)
                    340:                        printf("Unknown command\n");
                    341:        }
                    342: 
                    343:        cfg_free(cfg);
                    344:        return 0;
                    345: }
                    346: 
                    347: /**
                    348:  * Local Variables:
                    349:  *  indent-tabs-mode: t
                    350:  *  c-file-style: "linux"
                    351:  * End:
                    352:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>