taisei/src/cli.c
Andrei Alexeyev 513d613387
Consistent indentation: indent with tabs, align with spaces (#104)
I would've preferred to just go with 4-spaces for indent and no tabs,
but lao is a bit conservative about it. :^)

Still, this is a ton better than mixing different styles all over the
place, especially within the same file.
2018-01-12 20:26:07 +02:00

190 lines
4.7 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (c) 2011-2018, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2018, Andrei Alexeyev <akari@alienslab.net>.
*/
#include "taisei.h"
#include "cli.h"
#include <getopt.h>
#include <string.h>
#include <stdlib.h>
#include "difficulty.h"
#include "util.h"
#include "log.h"
#include "stage.h"
#include "plrmodes.h"
struct TsOption { struct option opt; const char *help; const char *argname;};
static void print_help(struct TsOption* opts) {
tsfprintf(stdout, "Usage: taisei [OPTIONS]\nTaisei is an open source Touhou clone.\n\nOptions:\n");
int margin = 20;
for(struct TsOption *opt = opts; opt->opt.name; opt++) {
tsfprintf(stdout, " -%c, --%s ", opt->opt.val,opt->opt.name);
int length = margin-(int)strlen(opt->opt.name);
if(opt->argname) {
tsfprintf(stdout, "%s", opt->argname);
length -= (int)strlen(opt->argname);
}
for(int i = 0; i < length; i++)
tsfprintf(stdout, " ");
if(opt->argname)
tsfprintf(stdout, opt->help, opt->argname);
else
tsfprintf(stdout, "%s", opt->help);
tsfprintf(stdout, "\n");
}
}
int cli_args(int argc, char **argv, CLIAction *a) {
struct TsOption taisei_opts[] =
{{{"replay", required_argument, 0, 'r'}, "Play a replay from %s", "FILE"},
#ifdef DEBUG
{{"play", no_argument, 0, 'p'}, "Play a specific stage", 0},
{{"sid", required_argument, 0, 'i'}, "Select stage by %s", "ID"},
{{"diff", required_argument, 0, 'd'}, "Select a difficulty (Easy/Normal/Hard/Lunatic)", "DIFF"},
{{"shotmode", required_argument, 0, 's'}, "Select a shotmode (marisaA/youmuA/marisaB/youmuB)", "SMODE"},
{{"dumpstages", no_argument, 0, 'u'}, "Print a list of all stages in the game", 0},
{{"vfs-tree", required_argument, 0, 't'}, "Print the virtual filesystem tree starting from %s", "PATH"},
#endif
{{"frameskip", optional_argument, 0, 'f'}, "Disable FPS limiter, render only every %s frame", "FRAME"},
{{"credits", no_argument, 0, 'c'}, "Show the credits scene and exit"},
{{"help", no_argument, 0, 'h'}, "Display this help"},
{{0,0,0,0},0,0}
};
memset(a,0,sizeof(CLIAction));
int nopts = sizeof(taisei_opts)/sizeof(taisei_opts[0]);
struct option opts[nopts];
char optc[2*nopts+1];
char *ptr = optc;
for(int i = 0; i < nopts; i++) {
opts[i] = taisei_opts[i].opt;
*ptr = opts[i].val;
ptr++;
if(opts[i].has_arg != no_argument) {
*ptr = ':';
ptr++;
if(opts[i].has_arg == optional_argument) {
*ptr = ':';
ptr++;
}
}
}
*ptr = 0;
// on OS X, programs get passed some strange parameter when they are run from bundles.
for(int i = 0; i < argc; i++) {
if(strstartswith(argv[i],"-psn_"))
argv[i][0] = 0;
}
int c;
uint16_t stageid = 0;
PlayerMode *plrmode = NULL;
while((c = getopt_long(argc, argv, optc, opts, 0)) != -1) {
char *endptr = NULL;
switch(c) {
case 'h':
case '?':
print_help(taisei_opts);
// a->type = CLI_Quit;
exit(1);
break;
case 'r':
a->type = CLI_PlayReplay;
a->filename = strdup(optarg);
break;
case 'p':
a->type = CLI_SelectStage;
break;
case 'i':
stageid = strtol(optarg, &endptr, 16);
if(!*optarg || endptr == optarg)
log_fatal("Stage id '%s' is not a number", optarg);
break;
case 'u':
a->type = CLI_DumpStages;
break;
case 'd':
a->diff = D_Any;
for(int i = D_Easy ; i <= NUM_SELECTABLE_DIFFICULTIES; i++) {
if(strcasecmp(optarg, difficulty_name(i)) == 0) {
a->diff = i;
break;
}
}
if(a->diff == D_Any) {
log_fatal("Invalid difficulty '%s'", optarg);
}
break;
case 's':
if(!(plrmode = plrmode_parse(optarg)))
log_fatal("Invalid shotmode '%s'", optarg);
break;
case 'f':
a->frameskip = 1;
if(optarg) {
a->frameskip = strtol(optarg, &endptr, 10);
if(endptr == optarg) {
log_fatal("Frameskip value '%s' is not a number", optarg);
}
if(a->frameskip < 0) {
a->frameskip = INT_MAX;
}
}
break;
case 't':
a->type = CLI_DumpVFSTree,
a->filename = strdup(optarg ? optarg : "");
break;
case 'c':
a->type = CLI_Credits;
break;
default:
log_fatal("Unknown option (this shouldnt happen)");
}
}
if(stageid) {
if(a->type != CLI_PlayReplay && a->type != CLI_SelectStage) {
log_warn("--sid was ignored");
} else if(!stage_get(stageid)) {
log_fatal("Invalid stage id: %X", stageid);
}
}
if(plrmode) {
if(a->type == CLI_SelectStage) {
a->plrmode = plrmode;
} else {
log_warn("--shotmode was ignored");
}
}
a->stageid = stageid;
if(a->type == CLI_SelectStage && !stageid)
log_fatal("StageSelect mode, but no stage id was given");
return 0;
}
void free_cli_action(CLIAction *a) {
free(a->filename);
}