Annotation of embedaddon/confuse/examples/cli.c, revision 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>