diff options
| author | johannes <johannes.herman@gmail.com> | 2024-02-14 19:06:58 +0100 |
|---|---|---|
| committer | johannes <johannes.herman@gmail.com> | 2024-02-14 19:06:58 +0100 |
| commit | 6275c45aa4b92b54d71186760a8f9c4b95342779 (patch) | |
| tree | 01c19ed6c105f8594f55e2708383f6d73aad112d /src | |
| parent | 8cac1bcb93ebc1f1092b27825880204908e59c28 (diff) | |
changed args parsing
Diffstat (limited to 'src')
| -rw-r--r-- | src/args.c | 342 | ||||
| -rw-r--r-- | src/main.c | 220 |
2 files changed, 370 insertions, 192 deletions
@@ -1,129 +1,275 @@ #include "../inc/args.h" -#include "../inc/commands.h" #include <stdio.h> #include <stdlib.h> +#include <string.h> -void parsecmdstr(cmdinput *cmd, char *cmdstr) +typedef struct parg { - switch (cmd->settype) + argtype type; + char *flag; + char *full; + int numopt; + char *desc[2]; + void (*runarg)(struct arg *); +} parg; + +int argerr = 0; +char *errflag = NULL; + +char *inf = NULL; +char *usg = NULL; + +int PARGC = 0; +int pargscap = 2; +parg *PARGS = NULL; + +int ARGC = 0; +int argscap = 2; +arg *ARGS; + +void setinfo(char *info) +{ + inf = info; +} + +void setusage(char *usage) +{ + usg = usage; +} + +int addparg(argtype type, char *flag, char *full, int numopt, char *desc1, char *desc2, void (*runarg)(struct arg *)) +{ + if (!PARGS) + PARGS = (parg *)malloc(pargscap * sizeof(parg)); + else { - case 'i': - if (sscanf(cmdstr, "%i:%23[^\n]", &cmd->id, cmd->to) != 2) - { - fprintf(stderr, "ERROR: Failed to parse argument '%s' to type 'ID:RESULT'\n", cmdstr); - exit(EXIT_FAILURE); - } - break; - case 'n': - if (sscanf(cmdstr, "%23[^:]:%23[^\n]", cmd->from, cmd->to) != 2) - { - fprintf(stderr, "ERROR: Failed to parse argument '%s' to type 'NAME:RESULT'\n", cmdstr); - exit(EXIT_FAILURE); - } - break; - case '\0': - fprintf(stderr, "ERROR: Found no flag modifier\n"); - exit(EXIT_FAILURE); - break; - default: - fprintf(stderr, "ERROR: Failed to parse flag with '%c' modifier\n", cmd->settype); - exit(EXIT_FAILURE); - break; + pargscap *= 2; + PARGS = (parg *)realloc(PARGS, pargscap * sizeof(parg)); } + PARGS[PARGC].type = type; + PARGS[PARGC].flag = flag; + PARGS[PARGC].full = full; + PARGS[PARGC].numopt = numopt; + PARGS[PARGC].desc[0] = desc1; + PARGS[PARGC].desc[1] = desc2; + PARGS[PARGC].runarg = runarg; + PARGC++; + + return 1; } -void parseargs(input *in, int argc, char *argv[]) +int addarg(char *value, char *desc, void (*runarg)(struct arg *)) { - in->demopath = NULL; - in->mappath = NULL; - in->outpath = NULL; - in->print = 0; - in->extractmap = 0; + if (!value || !desc) + return 0; + addparg(ARGUMENT, NULL, NULL, 0, value, desc, runarg); + return 1; +} + +int addopt(char *flag, char *full, int numopt, char *value, char *desc, void (*runarg)(struct arg *)) +{ + if (!flag || !desc) + return 0; + addparg(OPTION, flag, full, numopt, value, desc, runarg); + return 1; +} + +int checkarg(char *str, parg *par) +{ + if (par->flag && strcmp(str, par->flag) == 0) + return 1; + + if (par->full && strcmp(str, par->full) == 0) + return 1; + + return 0; +} + +int parseargs(int argc, char *args[]) +{ + ARGS = (arg *)malloc(argscap * sizeof(arg)); - in->numcmds = 0; + char inctype[] = {0, 0, 0}; + for (int i = 0; i < PARGC; i++) + inctype[PARGS[i].type]++; - int argi; - for (argi = 1; argi < argc; argi++) + int argumentc = 0; + + for (int i = 1; i < argc; i++) { - if (argv[argi][0] == '-') + char *a = args[i]; + char isopt = 0; + for (int y = 0; y < PARGC; y++) { - cmdinput *cmd = &in->commands[in->numcmds]; - switch (argv[argi][1]) + parg *pa = &PARGS[y]; + if (checkarg(a, pa)) { - case 'n': - if (argi + 1 >= argc) - { - fprintf(stderr, "ERROR: Flag 'n' requires additional argument\n"); - exit(EXIT_FAILURE); - } - cmd->cmdtype = argv[argi][1]; - cmd->settype = argv[argi][2]; - parsecmdstr(cmd, argv[argi + 1]); - in->numcmds++; - argi++; - break; - case 's': - if (argi + 1 >= argc) + if (i + pa->numopt >= argc) { - fprintf(stderr, "ERROR: Flag 's' requires additional argument\n"); - exit(EXIT_FAILURE); + argerr = 1; + errflag = pa->flag; + return 0; } - cmd->cmdtype = argv[argi][1]; - cmd->settype = argv[argi][2]; - parsecmdstr(cmd, argv[argi + 1]); - in->numcmds++; - argi++; - break; - case 'o': - if (argi + 1 >= argc) + isopt = 1; + if (argscap >= ARGC) { - fprintf(stderr, "ERROR: Flag 'o' requires additional argument\n"); - exit(EXIT_FAILURE); + argscap *= 2; + ARGS = (arg *)realloc(ARGS, argscap * sizeof(arg)); } - in->outpath = argv[argi + 1]; - argi++; - break; - case 'p': - in->print = 1; - break; - case 'e': - if (argi + 1 >= argc) - { - fprintf(stderr, "ERROR: Flag 'e' requires additional argument\n"); - exit(EXIT_FAILURE); - } - in->extractmap = argv[argi + 1]; - argi++; - break; - case 'm': - if (argi + 1 >= argc) + ARGS[ARGC].type = pa->type; + ARGS[ARGC].flag = a; + ARGS[ARGC].numopt = pa->numopt; + ARGS[ARGC].runarg = pa->runarg; + ARGS[ARGC].opts = (char **)malloc(pa->numopt * sizeof(char *)); + + for (int j = 0; j < pa->numopt; j++) + ARGS[ARGC].opts[j] = args[i + j + 1]; + + i += pa->numopt; + ARGC++; + } + } + if (isopt) + continue; + + if (argumentc < inctype[ARGUMENT]) + { + ARGS[ARGC].type = ARGUMENT; + for (int y = 0, x = argumentc; y < PARGC; y++) + { + if (PARGS[y].type == ARGUMENT) { - fprintf(stderr, "ERROR: Flag 'm' requires additional argument\n"); - exit(EXIT_FAILURE); + if (x != 0) + x--; + else + { + ARGS[ARGC].numopt = 1; + ARGS[ARGC].flag = "NONE"; + ARGS[ARGC].runarg = PARGS[y].runarg; + ARGS[ARGC].opts = (char **)malloc(sizeof(char *)); + ARGS[ARGC].opts[0] = a; + argumentc++; + ARGC++; + } } - in->mappath = argv[argi + 1]; - argi++; - break; - default: - fprintf(stderr, "ERROR: Unknown flag '%c'\n", argv[argi][1]); - exit(EXIT_FAILURE); - break; } } else { - if (in->demopath) - { - fprintf(stderr, "ERROR: Found two non-flag arguments\n"); - exit(EXIT_FAILURE); - } - in->demopath = argv[argi]; + argerr = 2; + errflag = NULL; + return 0; } } - if (!in->demopath) + return 1; +} + +void runargs() +{ + for (int i = 0; i < ARGC; i++) + { + if (ARGS[i].runarg) + ARGS[i].runarg(&ARGS[i]); + } +} + +arg *getarg(int pos) +{ + for (int i = 0; i < ARGC; i++) + if (ARGS[i].type == ARGUMENT) + { + if (pos == 0) + return &ARGS[i]; + pos--; + } + return NULL; +} + +arg *getopt(char *flag, int pos) +{ + for (int i = 0; i < ARGC; i++) + if (ARGS[i].type == OPTION && strcmp(flag, ARGS[i].flag) == 0) + { + if (pos == 0) + return &ARGS[i]; + pos--; + } + return NULL; +} +void printhelp() +{ + char inctype[ARGTYPELEN] = {0, 0, 0}; + int maxflag[ARGTYPELEN] = {0, 0, 0}; + int maxfull[ARGTYPELEN] = {0, 0, 0}; + int maxdesc0[ARGTYPELEN] = {0, 0, 0}; + int maxdesc1[ARGTYPELEN] = {0, 0, 0}; + + for (int i = 0; i < PARGC; i++) { - fprintf(stderr, "ERROR: Found no demo input\n"); - exit(EXIT_FAILURE); + parg *pa = &PARGS[i]; + int type = pa->type; + + inctype[type]++; + if (pa->flag) + maxflag[type] = (maxflag[type] > strlen(pa->flag) ? maxflag[type] : strlen(pa->flag)); + if (pa->full) + maxfull[type] = (maxfull[type] > strlen(pa->full) ? maxfull[type] : strlen(pa->full)); + if (pa->desc[0]) + maxdesc0[type] = (maxdesc0[type] > strlen(pa->desc[0]) ? maxdesc0[type] : strlen(pa->desc[0])); + if (pa->desc[1]) + maxdesc1[type] = (maxdesc1[type] > strlen(pa->desc[1]) ? maxdesc1[type] : strlen(pa->desc[1])); + } + if (inf) + printf("%s\n\n", inf); + + if (usg) + printf("\e[4mUsage:\e[0m %s\n", usg); + + if (inctype[ARGUMENT]) + { + printf("\n\e[4mArgument%c:\e[0m\n", (inctype[ARGUMENT] < 2) ? '\0' : 's'); + for (int i = 0; i < PARGC; i++) + { + parg *pa = &PARGS[i]; + if (pa->type == ARGUMENT) + printf(" %s %s\n", pa->desc[0], pa->desc[1]); + } + } + + if (inctype[OPTION]) + { + printf("\n\e[4mOption%c:\e[0m\n", (inctype[OPTION] < 2) ? '\0' : 's'); + for (int i = 0; i < PARGC; i++) + { + parg *pa = &PARGS[i]; + if (pa->type == OPTION) + printf(" %*s, %-*s %-*s %s\n", maxflag[OPTION], pa->flag, maxfull[OPTION], pa->full, maxdesc0[OPTION], + (pa->desc[0]) ? pa->desc[0] : "", pa->desc[1]); + } + } +} + +void paerror(char *str) +{ + char *errstr; + switch (argerr) + { + case 0: + errstr = "No error"; + break; + case 1: + errstr = "Missing input for option flag"; + break; + case 2: + errstr = "Too many positional arguments"; + break; + default: + errstr = "Unknown error"; + break; } + if (errflag) + fprintf(stderr, "%s %s '%s'\n", str, errstr, errflag); + else + fprintf(stderr, "%s %s\n", str, errstr); } @@ -6,8 +6,6 @@ #include <stdio.h> #include <stdlib.h> -#include <unistd.h> - int testcompress(char *line) { char inputbuff[4096]; @@ -142,141 +140,175 @@ int mapname(char *mappath, char *out) return 1; } -void run(input *in) -{ - if (!in->demopath) - exit(EXIT_FAILURE); +FILE *demofile = NULL, *outfile = NULL, *mapfile = NULL, *exmapfile = NULL; +demo DEMO; - FILE *demofile, *outfile, *mapfile, *exmapfile; - demofile = NULL; - outfile = NULL; - mapfile = NULL; - exmapfile = NULL; +void exitperror(char *str) +{ + perror(str); + exit(EXIT_FAILURE); +} - demofile = fopen(in->demopath, "r"); +void setdemo(arg *argument) +{ + demofile = fopen(argument->opts[0], "r"); if (!demofile) + exitperror("Error: failed to open demofile, reason"); + if (readdemo(demofile, &DEMO) < 0) { - perror("ERROR: Failed to open demo file, reason"); + fprintf(stderr, "Error: failed to parse demo\n"); exit(EXIT_FAILURE); } +} - if (in->outpath) - { - outfile = fopen(in->outpath, "w"); - if (!outfile) - { - perror("ERROR: Failed to open output file, reason"); - exit(EXIT_FAILURE); - } - } - - if (in->mappath) - { - mapfile = fopen(in->mappath, "r"); - if (!mapfile) - { - perror("ERROR: Failed to open map file, reason"); - exit(EXIT_FAILURE); - } - } +void setmap(arg *argument) +{ + mapfile = fopen(argument->opts[0], "r"); + if (!mapfile) + exitperror("Error: failed to open mapfile, reason"); - if (in->extractmap) + char mapnamebuff[32]; + if (mapname(argument->opts[0], mapnamebuff)) { - exmapfile = fopen(in->extractmap, "r"); - if (!exmapfile) + if (changemap(mapfile, mapnamebuff, &DEMO) < 1) { - perror("ERROR: Failed to open extract map file, reason"); + fprintf(stderr, "Error: failed to set map '%s'\n", argument->opts[0]); exit(EXIT_FAILURE); } - // TODO extract map here } - - demo dmo; - - if (readdemo(demofile, &dmo) < 0) + else { - fprintf(stderr, "ERROR: Failed to parse demo\n"); + fprintf(stderr, "Error: map name is too long (> 32)\n"); exit(EXIT_FAILURE); } +} - if (in->print) - printdemo(&dmo, 0); - - if (mapfile) - { - char mname[32]; - if (mapname(in->mappath, mname)) - { - if (changemap(mapfile, mname, &dmo) < 0) - { - fprintf(stderr, "ERROR: Failed to set map '%s'\n", in->mappath); - exit(EXIT_FAILURE); - } - } - else - { - fprintf(stderr, "ERROR: Given map has too long name (must be < 32)\n"); - exit(EXIT_FAILURE); - } - } - - for (int i = 0; i < in->numcmds; i++) +void runrename(arg *renamearg) +{ + int intid; + int ret; + if (sscanf(renamearg->opts[0], "%d", &intid) == 1) + ret = setnamebyid(intid, renamearg->opts[1], &DEMO); + else + ret = setnamebyname(renamearg->opts[0], renamearg->opts[1], &DEMO); + + if (ret < 0) { - runcommand(&in->commands[i], &dmo); + printf("Error: failed to rename player '%s', reason: name too long\n", renamearg->opts[0]); + exit(EXIT_FAILURE); } +} - if (outfile) +void runsetskin(arg *skinarg) +{ + int intid; + int ret; + if (sscanf(skinarg->opts[0], "%d", &intid) == 1) + ret = setskinbyid(intid, skinarg->opts[1], &DEMO); + else + ret = setskinbyname(skinarg->opts[0], skinarg->opts[1], &DEMO); + + if (ret < 0) { - if (writedemo(outfile, &dmo) < 0) - { - fprintf(stderr, "ERROR: Failed to write demo to '%s'\n", in->outpath); - exit(EXIT_FAILURE); - } + printf("Error: failed to set skin of player '%s', reason: skin name too long\n", skinarg->opts[0]); + exit(EXIT_FAILURE); } - - if (demofile) - freedemo(&dmo); - } -void printhelp() +void runoutput(arg *outarg) { - printf("HELP! I hope this helped you.\n"); + outfile = fopen(outarg->opts[0], "w"); + if (!outfile) + exitperror("Error: failed to write to outputfile, reason"); + if (writedemo(outfile, &DEMO) < 0) + { + fprintf(stderr, "Error: failed to write demo file to outputfile\n"); + exit(EXIT_FAILURE); + } } int main(int argc, char *argv[]) { inithuff(NULL); + setinfo("d(emo)edit, a tool for manipulating teeworlds demos"); + setusage("dedit <demo> [OPTIONS]"); + + addarg("<demo>", "Sets input demo", setdemo); + + addopt("-r", "--rename", 2, "<id> <name>", "Renames player with id to name", NULL); + addopt("-s", "--skin", 2, "<id> <name>", "Set skin of player with id to skin", NULL); + addopt("-m", "--map", 1, "<map>", "Changes the map of demo to map", setmap); + addopt("-e", "--extract-map", 1, "<file>", "Saves the map of demo to file", NULL); + addopt("-o", "--output", 1, "<file>", "Saves the output demo to file", NULL); + addopt("-i", "--info", 0, NULL, "Prints info of demo", NULL); + addopt("-I", "--extended-info", 0, NULL, "Prints extended info of demo", NULL); + addopt("-h", "--help", 0, NULL, "Prints this help info", NULL); + + if (!parseargs(argc, argv)) + { + paerror("Error:"); + printf("For more help run 'dedit --help'\n"); + } + if (argc == 1) { printhelp(); exit(EXIT_SUCCESS); } - input in; + if (getopt("-h", 0)) + printhelp(); - parseargs(&in, argc, argv); + arg *demoarg = getarg(0); + if (demoarg == NULL) + { + printf("Error: Missing required argument <demo>\n"); + exit(EXIT_FAILURE); + } - /* - printf("demopath: %s\n", in.demopath); - printf("outpath: %s\n", in.outpath); - printf("mappath: %s\n", in.mappath); - printf("extractpath: %s\n", in.extractmap); - printf("print: %d\n", in.print); - - printf("\ncommands:\n"); - for (int i = 0; i < in.numcmds; i++) + demoarg->runarg(demoarg); + + arg *outarg = getopt("-o", 0); + arg *maparg = getopt("-m", 0); + arg *exmarg = getopt("-e", 0); + arg *infarg = getopt("-i", 0); + arg *Infarg = getopt("-I", 0); + + if (maparg) + setmap(maparg); + + if (Infarg) + printdemo(&DEMO, 1); + else if (infarg) + printdemo(&DEMO, 0); + + if (exmarg) + printf("Info: not implemented extract map\n"); + + int i = 0; + arg *opt; + while (1) { - cmdinput *c = &in.commands[i]; - printf("command: {cmd: %c, type: %c, id: %d, from: %s, to: %s}\n", c->cmdtype, c->settype, c->id, c->from, - c->to); + opt = getopt("-s", i); + if (opt == NULL) + break; + runsetskin(opt); + i++; } - printf("\nEXITING SUCCESS\n"); - */ + i = 0; + while (1) + { + opt = getopt("-r", i); + if (opt == NULL) + break; + runrename(opt); + i++; + } - run(&in); + if (outarg) + runoutput(outarg); exit(EXIT_SUCCESS); |
