From 1fb6b70cdacaf3ca3c069a6d96434eed3b6bc22f Mon Sep 17 00:00:00 2001 From: Shao Miller Date: Sat, 3 Jul 2010 19:06:10 -0400 Subject: [PATCH] dos: Work-in-progress --- MCONFIG.local | 1 + dos/Makefile | 5 +- dos/ctype.h | 3 + dos/getopt.h | 25 ++++++++ dos/getopt_long.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++ dos/stdio.h | 2 + dos/stdlib.h | 3 + dos/strchr.c | 17 ++++++ dos/string.h | 2 + dos/strntoumax.c | 73 +++++++++++++++++++++++ dos/strtoul.c | 15 +++++ dos/sysexits.h | 1 + dos/syslinux.c | 21 +++---- libinstaller/syslxopt.c | 8 ++- 14 files changed, 311 insertions(+), 17 deletions(-) create mode 100644 MCONFIG.local mode change 100644 => 100755 dos/Makefile create mode 100644 dos/ctype.h create mode 100755 dos/getopt.h create mode 100755 dos/getopt_long.c mode change 100644 => 100755 dos/stdlib.h create mode 100644 dos/strchr.c create mode 100644 dos/strntoumax.c create mode 100644 dos/strtoul.c create mode 100644 dos/sysexits.h mode change 100644 => 100755 dos/syslinux.c diff --git a/MCONFIG.local b/MCONFIG.local new file mode 100644 index 0000000..f91fc16 --- /dev/null +++ b/MCONFIG.local @@ -0,0 +1 @@ +CFLAGS += -DDEBUG=1 diff --git a/dos/Makefile b/dos/Makefile old mode 100644 new mode 100755 index 574b65e..3d19ff2 --- a/dos/Makefile +++ b/dos/Makefile @@ -28,6 +28,7 @@ INCLUDES = -include code16.h -nostdinc -iwithprefix include \ SRCS = syslinux.c \ ../libinstaller/fat.c \ ../libinstaller/syslxmod.c \ + ../libinstaller/syslxopt.c \ ../libinstaller/setadv.c \ ../libinstaller/bootsect_bin.c \ ../libinstaller/ldlinux_bin.c \ @@ -35,8 +36,8 @@ SRCS = syslinux.c \ $(wildcard ../libfat/*.c) OBJS = header.o crt0.o $(patsubst %.c,%.o,$(notdir $(SRCS))) LIBOBJS = int2526.o conio.o memcpy.o memset.o memmove.o skipatou.o atou.o \ - malloc.o free.o getsetsl.o \ - argv.o printf.o __divdi3.o __udivmoddi4.o + malloc.o free.o getopt_long.o getsetsl.o strchr.o strtoul.o \ + strntoumax.o argv.o printf.o __divdi3.o __udivmoddi4.o VPATH = .:../libfat:../libinstaller diff --git a/dos/ctype.h b/dos/ctype.h new file mode 100644 index 0000000..c0d00c0 --- /dev/null +++ b/dos/ctype.h @@ -0,0 +1,3 @@ +static int isspace(int c) { + return (c == ' '); +} diff --git a/dos/getopt.h b/dos/getopt.h new file mode 100755 index 0000000..a1b74b1 --- /dev/null +++ b/dos/getopt.h @@ -0,0 +1,25 @@ +#ifndef _GETOPT_H +#define _GETOPT_H + +/* (Very slightly) adapted from klibc */ + +struct option { + const char *name; + int has_arg; + int *flag; + int val; +}; + +enum { + no_argument = 0, + required_argument = 1, + optional_argument = 2, +}; + +extern char *optarg; +extern int optind, opterr, optopt; + +extern int getopt_long(int, char *const *, const char *, + const struct option *, int *); + +#endif /* _GETOPT_H */ diff --git a/dos/getopt_long.c b/dos/getopt_long.c new file mode 100755 index 0000000..1458779 --- /dev/null +++ b/dos/getopt_long.c @@ -0,0 +1,152 @@ +/* + * getopt.c + * + * getopt_long(), or at least a common subset thereof: + * + * - Option reordering is not supported + * - -W foo is not supported + * - First optstring character "-" not supported. + */ + +#include +#include +#include +#include "mystuff.h" + +char *optarg; +int optind, opterr, optopt; +static struct getopt_private_state { + const char *optptr; + const char *last_optstring; + char *const *last_argv; +} pvt; + +static inline const char *option_matches(const char *arg_str, + const char *opt_name) +{ + while (*arg_str != '\0' && *arg_str != '=') { + if (*arg_str++ != *opt_name++) + return NULL; + } + + if (*opt_name) + return NULL; + + return arg_str; +} + +int getopt_long(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *longindex) +{ + const char *carg; + const char *osptr; + int opt; + + /* getopt() relies on a number of different global state + variables, which can make this really confusing if there is + more than one use of getopt() in the same program. This + attempts to detect that situation by detecting if the + "optstring" or "argv" argument have changed since last time + we were called; if so, reinitialize the query state. */ + + if (optstring != pvt.last_optstring || argv != pvt.last_argv || + optind < 1 || optind > argc) { + /* optind doesn't match the current query */ + pvt.last_optstring = optstring; + pvt.last_argv = argv; + optind = 1; + pvt.optptr = NULL; + } + + carg = argv[optind]; + + /* First, eliminate all non-option cases */ + + if (!carg || carg[0] != '-' || !carg[1]) + return -1; + + if (carg[1] == '-') { + const struct option *lo; + const char *opt_end = NULL; + + optind++; + + /* Either it's a long option, or it's -- */ + if (!carg[2]) { + /* It's -- */ + return -1; + } + + for (lo = longopts; lo->name; lo++) { + if ((opt_end = option_matches(carg+2, lo->name))) + break; + } + if (!opt_end) + return '?'; + + if (longindex) + *longindex = lo-longopts; + + if (*opt_end == '=') { + if (lo->has_arg) + optarg = (char *)opt_end+1; + else + return '?'; + } else if (lo->has_arg == 1) { + if (!(optarg = argv[optind])) + return '?'; + optind++; + } + + if (lo->flag) { + *lo->flag = lo->val; + return 0; + } else { + return lo->val; + } + } + + if ((uintptr_t) (pvt.optptr - carg) > (uintptr_t) strlen(carg)) { + /* Someone frobbed optind, change to new opt. */ + pvt.optptr = carg + 1; + } + + opt = *pvt.optptr++; + + if (opt != ':' && (osptr = strchr(optstring, opt))) { + if (osptr[1] == ':') { + if (*pvt.optptr) { + /* Argument-taking option with attached + argument */ + optarg = (char *)pvt.optptr; + optind++; + } else { + /* Argument-taking option with non-attached + argument */ + if (argv[optind + 1]) { + optarg = (char *)argv[optind+1]; + optind += 2; + } else { + /* Missing argument */ + optind++; + return (optstring[0] == ':') + ? ':' : '?'; + } + } + return opt; + } else { + /* Non-argument-taking option */ + /* pvt.optptr will remember the exact position to + resume at */ + if (!*pvt.optptr) + optind++; + return opt; + } + } else { + /* Unknown option */ + optopt = opt; + if (!*pvt.optptr) + optind++; + return '?'; + } +} diff --git a/dos/stdio.h b/dos/stdio.h index 2c25666..c7ca25c 100644 --- a/dos/stdio.h +++ b/dos/stdio.h @@ -16,6 +16,8 @@ int printf(const char *fmt, ...); #define stdout 1 #define stderr 2 +#define EOF (-1) + #define fprintf(x, y, ...) printf(y, ## __VA_ARGS__) #endif /* STDIO_H */ diff --git a/dos/stdlib.h b/dos/stdlib.h old mode 100644 new mode 100755 index 71af690..d346705 --- a/dos/stdlib.h +++ b/dos/stdlib.h @@ -10,4 +10,7 @@ void *malloc(size_t); void *calloc(size_t, size_t); void free(void *); +extern unsigned long int strtoul(const char *nptr, + char **endptr, int base); + #endif diff --git a/dos/strchr.c b/dos/strchr.c new file mode 100644 index 0000000..8315311 --- /dev/null +++ b/dos/strchr.c @@ -0,0 +1,17 @@ +/* + * strchr.c + */ + +#include +#include "mystuff.h" + +char *strchr(const char *s, int c) +{ + while (*s != (char)c) { + if (!*s) + return NULL; + s++; + } + + return (char *)s; +} diff --git a/dos/string.h b/dos/string.h index 5ee829e..f648de2 100644 --- a/dos/string.h +++ b/dos/string.h @@ -21,4 +21,6 @@ static inline int memcmp(const void *__m1, const void *__m2, unsigned int __n) return rv; } +extern char *strchr(const char *s, int c); + #endif /* _STRING_H */ diff --git a/dos/strntoumax.c b/dos/strntoumax.c new file mode 100644 index 0000000..d8bc73b --- /dev/null +++ b/dos/strntoumax.c @@ -0,0 +1,73 @@ +/* + * strntoumax.c + * + * The strntoumax() function and associated + */ + +#include +#include +#include + +static inline int digitval(int ch) +{ + if (ch >= '0' && ch <= '9') { + return ch - '0'; + } else if (ch >= 'A' && ch <= 'Z') { + return ch - 'A' + 10; + } else if (ch >= 'a' && ch <= 'z') { + return ch - 'a' + 10; + } else { + return -1; + } +} + +uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n) +{ + int minus = 0; + uintmax_t v = 0; + int d; + + while (n && isspace((unsigned char)*nptr)) { + nptr++; + n--; + } + + /* Single optional + or - */ + if (n && *nptr == '-') { + minus = 1; + nptr++; + n--; + } else if (n && *nptr == '+') { + nptr++; + } + + if (base == 0) { + if (n >= 2 && nptr[0] == '0' && (nptr[1] == 'x' || nptr[1] == 'X')) { + n -= 2; + nptr += 2; + base = 16; + } else if (n >= 1 && nptr[0] == '0') { + n--; + nptr++; + base = 8; + } else { + base = 10; + } + } else if (base == 16) { + if (n >= 2 && nptr[0] == '0' && (nptr[1] == 'x' || nptr[1] == 'X')) { + n -= 2; + nptr += 2; + } + } + + while (n && (d = digitval(*nptr)) >= 0 && d < base) { + v = v * base + d; + n--; + nptr++; + } + + if (endptr) + *endptr = (char *)nptr; + + return minus ? -v : v; +} diff --git a/dos/strtoul.c b/dos/strtoul.c new file mode 100644 index 0000000..3be9430 --- /dev/null +++ b/dos/strtoul.c @@ -0,0 +1,15 @@ +/* + * strtoul.c + * + * strtoul() function + */ + +#include +#include + +extern uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n); + +unsigned long strtoul(const char *nptr, char **endptr, int base) +{ + return (unsigned long) strntoumax(nptr, endptr, base, ~(size_t) 0); +} diff --git a/dos/sysexits.h b/dos/sysexits.h new file mode 100644 index 0000000..483d3ba --- /dev/null +++ b/dos/sysexits.h @@ -0,0 +1 @@ +#define EX_USAGE 0x40 diff --git a/dos/syslinux.c b/dos/syslinux.c old mode 100644 new mode 100755 index 9574553..891980e --- a/dos/syslinux.c +++ b/dos/syslinux.c @@ -18,15 +18,18 @@ */ #include +#include #include #include #include -#include +//#include #include "mystuff.h" #include "syslinux.h" #include "libfat.h" #include "setadv.h" +#include "sysexits.h" +#include "syslxopt.h" const char *program = "syslinux"; /* Name of program */ uint16_t dos_version; @@ -44,12 +47,6 @@ void pause(void) # define pause() ((void)0) #endif -void __attribute__ ((noreturn)) usage(void) -{ - puts("Usage: syslinux [-sfmar][-d directory] : [bootsecfile]\n"); - exit(1); -} - void unlock_device(int); void __attribute__ ((noreturn)) die(const char *msg) @@ -617,7 +614,7 @@ int main(int argc, char *argv[]) if (**argp == '-') { opt = *argp + 1; if (!*opt) - usage(); + usage(EX_USAGE, MODE_SYSLINUX_DOSWIN); while (*opt) { switch (*opt) { @@ -641,13 +638,13 @@ int main(int argc, char *argv[]) subdir = *++argp; break; default: - usage(); + usage(EX_USAGE, MODE_SYSLINUX_DOSWIN); } opt++; } } else { if (bootsecfile) - usage(); + usage(EX_USAGE, MODE_SYSLINUX_DOSWIN); else if (device) bootsecfile = *argp; else @@ -656,7 +653,7 @@ int main(int argc, char *argv[]) } if (!device) - usage(); + usage(EX_USAGE, MODE_SYSLINUX_DOSWIN); /* * Create an ADV in memory... this should be smarter. @@ -668,7 +665,7 @@ int main(int argc, char *argv[]) */ dev_fd = (device[0] & ~0x20) - 0x40; if (dev_fd < 1 || dev_fd > 26 || device[1] != ':' || device[2]) - usage(); + usage(EX_USAGE, MODE_SYSLINUX_DOSWIN); set_lock_device(dev_fd); diff --git a/libinstaller/syslxopt.c b/libinstaller/syslxopt.c index e7f405a..eb00dbd 100755 --- a/libinstaller/syslxopt.c +++ b/libinstaller/syslxopt.c @@ -108,7 +108,10 @@ void __attribute__ ((noreturn)) usage(int rv, enum syslinux_mode mode) " --raid -r Fall back to the next device on boot failure\n" " --once=... %s Execute a command once upon boot\n" " --clear-once -O Clear the boot-once command\n" - " --reset-adv Reset auxilliary data\n" + " --reset-adv Reset auxilliary data\n", + mode == MODE_SYSLINUX ? " " : "-o"); + /* Have to chop this roughly in half for the DOS installer for some reason */ + fprintf(stderr, " --menu-save= -M Set the label to select as default on the next boot\n" " --mbr -m Install an MBR (DOS/Win32 installers only)\n" " --active -a Mark partition as active (DOS/Win32 installers only)\n" @@ -120,8 +123,7 @@ void __attribute__ ((noreturn)) usage(int rv, enum syslinux_mode mode) " which includes zipdisks and LS-120 superfloppies.\n" "\n" " The -z option is useful for USB devices which are considered\n" - " hard disks by some BIOSes and zipdrives by other BIOSes.\n", - mode == MODE_SYSLINUX ? " " : "-o"); + " hard disks by some BIOSes and zipdrives by other BIOSes.\n"); exit(rv); } -- 2.7.4