cake
/
p7utils
Archived
1
0
Fork 0
This repository has been archived on 2024-03-16. You can view files and clone it, but cannot push or open issues or pull requests.
p7utils/src/p7/args.c

335 lines
11 KiB
C

/* ************************************************************************** */
/* _____ _ */
/* args.c |_ _|__ _ _| |__ ___ _ _ */
/* | Project : p7 | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/08/21 19:10:17 |___/ */
/* */
/* ************************************************************************** */
#include "main.h"
#include <getopt.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
/* ************************************************************************** */
/* Help and version messages */
/* ************************************************************************** */
/* Version message */
static const char version_message[] =
"P7 v" QUOTE(VERSION) " (licensed under " QUOTE(LICENSE) ")\n"
"Made by " QUOTE(AUTHOR) " <" QUOTE(AUTHOR_MAIL) ">.\n"
"\n"
"This is free software; see the source for copying conditions.\n"
"There is NO warranty; not even for MERCHANTABILITY or\n"
"FITNESS FOR A PARTICULAR PURPOSE.";
/* Main help message */
static const char help_main[] =
"Usage: p7 [--version|-v] [--help|-h] [--no-init] [--no-exit]\n"
" [--storage abc0] [--device /dev/omg0]\n"
" <subcommand> [options...]\n"
"\n"
"Subcommands you can use are:\n"
" send Send a file to the calculator.\n"
" get Get a file from the calculator.\n"
" copy Copy a file into another on the calculator.\n"
" del Delete a file on the calculator.\n"
" reset Reset the flash memory.\n"
" optimize Optimize the distant filesystem.\n"
" ls List files on the distant filesystem.\n"
" info Dump info about the calculator.\n"
"\n"
"General options:\n"
" -h, --help Display the help page of the (sub)command and quit.\n"
" -v, --version Display the version message and quit.\n"
" --device dev The calculator device (ttyUSBx).\n"
" By default, will use the first appropriate device found.\n"
" --storage abc0 The storage device with which to interact (fls0, crd0).\n"
" Default storage device is '" QUOTE(DEFAULT_STORAGE) "'.\n"
" --no-exit Does not terminate connection when action is completed.\n"
" --no-init Does not initialize connection (should only be used\n"
" when --no-exit was used last time p7 was called).\n"
"\n"
"Type \"p7 <subcommand> --help\" for some help about the subcommand.\n"
"Report bugs to " QUOTE(AUTHOR) " <" QUOTE(AUTHOR_MAIL) ">.";
/* Sending help message */
static const char help_send[] =
"Usage: p7 send [-f] [-o <on-calc filename>]\n"
" [-d <on-calc directory>] [-#] <local file>\n"
"Send a file to the calculator.\n"
"\n"
"Options are:\n"
" -f, --force Overwrite without asking\n"
" -o <name> The output filename on the calculator (by default, the same\n"
" as the local file)\n"
" -d <dir> The directory on-calc in which the file will be stored (by\n"
" default, the root directory)\n"
" -# Display a nice little loading bar\n"
"\n"
"Type \"p7 --help\" for other subcommands and general options.";
/* Getting help message */
static const char help_get[] =
"Usage: p7 get [-o <local file>]\n"
" [-d <on-calc directory>] <on-calc filename>\n"
"Request a file from the calculator.\n"
"\n"
"Options are:\n"
" -o <name> The output filename (by default, the same as the on-calc file)\n"
" -d <dir> The directory on-calc in which to get the file (by default,\n"
" the root directory)\n"
" -# Display a nice little loading bar (if output isn't stdout)\n"
"\n"
"Type \"p7 --help\" for other subcommands and general options.";
/* Copying help message */
static const char help_copy[] =
"Usage: p7 copy [-f] [-d <source directory]\n"
" [-t <destination directory>] <source file> <dest file>\n"
"Copies a file into the other on the calculator.\n"
"\n"
"Options are:\n"
" -d <srcdir> The source directory (by default, the root directory)\n"
" -t <dstdir> The dest. directory (by default, the root directory)\n"
"\n"
"Type \"p7 --help\" for other subcommands and general options.";
/* Deleting help message */
static const char help_del[] =
"Usage: p7 del [-d <on-calc directory] <on-calc filename>\n"
"Delete a file on the calculator.\n"
"\n"
"Options are:\n"
" -d <dir> The directory on-calc in which to remove the file (by default,\n"
" the root directory)\n"
"\n"
"Type \"p7 --help\" for other subcommands and general options.";
/* Listing help message */
static const char help_ls[] =
"Usage: p7 ls\n"
"List files on the distant filesystem.\n"
"\n"
"Type \"p7 --help\" for other subcommands and general options.";
/* Resetting help message */
static const char help_reset[] =
"Usage: p7 reset\n"
"Reset the distant filesystem.\n"
"\n"
"Type \"p7 --help\" for other subcommands and general options.";
/* Optimizing help message */
static const char help_optimize[] =
"Usage: p7 optimize\n"
"Optimize the distant filesystem.\n"
"\n"
"Type \"p7 --help\" for other subcommands and general options.";
/* Dumping help message */
static const char help_info[] =
"Usage: p7 info\n"
"Dump information about the calculator.\n"
"\n"
"Type \"p7 --help\" for other subcommands and general options.";
/* ************************************************************************** */
/* Main function */
/* ************************************************************************** */
/* useful macros */
#define sub_init(CMD, NARGS) \
args->menu = mn_##CMD; \
if (help || aac != 1 + (NARGS)) { \
puts(help_##CMD); \
return (0); \
}
/**
* parse_args:
* Args parsing main function.
*
* Was my very first experiment with getopt.
* Then I took an arrow in the knee.
*
* @arg ac the arguments count
* @arg av the arguments values
* @arg args the parsed args pointer
* @return if it was successfully parsed
*/
int parse_args(int ac, char **av, args_t *args)
{
/* initialize args */
*args = (args_t){
.menu = 0,
.nicedisp = 0,
.dirname = NULL, .filename = NULL,
.newdir = NULL, .newname = NULL,
.local = NULL, .force = 0,
.device = NULL,
.storage = QUOTE(DEFAULT_STORAGE),
.noinit = 0, .noexit = 0};
/* define options */
char short_options[] = "hvfo:d:t:#";
struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{"device", required_argument, NULL, 'p'},
{"storage", required_argument, NULL, 's'},
{"force", no_argument, NULL, 'f'},
{"output", required_argument, NULL, 'o'},
{"directory", required_argument, NULL, 'd'},
{"to", required_argument, NULL, 't'},
{"no-init", no_argument, NULL, 'i'},
{"no-start", no_argument, NULL, 'i'},
{"no-exit", no_argument, NULL, 'e'},
{"no-term", no_argument, NULL, 'e'},
{NULL, 0, NULL, 0}
};
/* get all options */
int c; opterr = 0;
int help = 0;
const char *s_out = NULL, *s_dir = NULL, *s_todir = NULL;
while ((c = getopt_long(ac, av, short_options, long_options, NULL)) != -1) {
switch (c) {
/* help */
case 'h': help = 1; break;
/* version */
case 'v': puts(version_message); return (0); break;
/* force */
case 'f': args->force = 1; break;
/* nice display */
case '#': args->nicedisp = 1; break;
/* output file (on calc or local) */
case 'o': s_out = optarg; break;
/* directory name */
case 'd': s_dir = optarg; break;
/* destination directory name */
case 't': s_todir = optarg; break;
/* device */
case 'p': args->device = optarg; break;
/* storage */
case 's': args->storage = optarg; break;
/* force no initialization */
case 'i': args->noinit = 1; break;
/* force no exit */
case 'e': args->noexit = 1; break;
/* in case of error */
case '?':
if (optopt == 'o')
log("-o, --output: expected an argument\n");
else if (optopt == 'd')
log("-d, --directory: expected an argument\n");
else if (optopt == 't')
log("-t, --to: expected an argument\n");
else if (optopt == 'p')
log("--device: expected an argument\n");
else if (optopt == 's')
log("--storage: expected an argument\n");
else
break;
return (0);
break;
}
}
/* get non-option arguments (subcommand and parameters) */
int aac = ac - optind;
char **aav = &av[optind];
/* get subcommand and things to check */
char fpmode[2] = " ";
args->localpath = NULL;
/* - all subcommands - */
if (!aac || !strcmp(aav[0], "help")) {
puts(help_main);
return (0);
} else if (!strcmp(aav[0], "info")) {
sub_init(info, 0)
} else if (!strcmp(aav[0], "ls")) {
sub_init(ls, 0)
} else if (!strcmp(aav[0], "reset")) {
sub_init(reset, 0)
} else if (!strcmp(aav[0], "optimize")) {
sub_init(optimize, 0)
} else if (!strcmp(aav[0], "send")) {
sub_init(send, 1)
/* put arguments to check */
fpmode[0] = 'r';
args->localpath = aav[1];
args->dirname = s_dir ? s_dir : NULL;
if (s_out) args->filename = s_out;
else {
char *rs = strrchr(args->localpath, '/');
args->filename = rs ? rs + 1 : args->localpath;
}
} else if (!strcmp(aav[0], "get")) {
sub_init(get, 1)
/* put arguments to check */
fpmode[0] = 'w';
args->filename = aav[1];
args->dirname = s_dir ? s_dir : NULL;
args->localpath = s_out ? s_out : args->filename;
} else if (!strcmp(aav[0], "copy")) {
sub_init(copy, 2)
/* get filename */
args->filename = aav[1];
args->dirname = s_dir ? s_dir : NULL;
args->newname = aav[2];
args->newdir = s_todir ? s_todir : NULL;
} else if (!strcmp(aav[0], "del")) {
sub_init(del, 1)
/* get filename */
args->filename = aav[1];
args->dirname = s_dir ? s_dir : NULL;
} else {
/* unknown subcommand ! */
log("Unknown subcommand '%s'.\n", aav[0]);
return (0);
}
/* check string lengths */
int noerror = 0;
if (args->filename && strnlen(args->filename, 13) == 13)
log("On-calc filename must have 12 chars or less!\n");
else if (args->newname && strnlen(args->newname, 13) == 13)
log("Destination filename must have 12 chars or less!\n");
else if (args->dirname && strnlen(args->dirname, 9) == 9)
log("On-calc directory name must have 8 chars or less!\n");
else if (args->newdir && strnlen(args->newdir, 9) == 9)
log("Destination directory name must have 8 chars or less!\n");
else if (strnlen(args->storage, 5) != 4)
log("Storage device (%s) should be 4 chars long!\n", args->storage);
else
noerror = 1;
if (!noerror) return (0);
/* check local path */
if (args->localpath) {
if (fpmode[0] == 'w' && !strcmp(args->localpath, "-"))
args->local = stdout;
else if (!(args->local = fopen(args->localpath, fpmode))) {
log("Could not open local file : %s\n", strerror(errno));
if (fpmode[0] == 'w')
unlink(args->localpath);
return (0);
}
}
/* everything went well */
return (1);
}