summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/args.c342
-rw-r--r--src/main.c220
2 files changed, 370 insertions, 192 deletions
diff --git a/src/args.c b/src/args.c
index 1b756d5..f995903 100644
--- a/src/args.c
+++ b/src/args.c
@@ -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);
}
diff --git a/src/main.c b/src/main.c
index 3fd2ed8..0fd0868 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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);