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>