diff --git a/CMakeLists.txt b/CMakeLists.txt index d6a2649..5e6ff9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,9 @@ cmake_minimum_required(VERSION 2.8) project(fatcat) -OPTION(DEFINE_WIN "Compiling windows" OFF) +if(MINGW) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++ -s") +endif() set(SOURCES core/FatEntry.cpp @@ -20,20 +22,18 @@ set(SOURCES analysis/FatChains.cpp analysis/FatSearch.cpp analysis/FatWalk.cpp - - xgetopt/xgetopt.cpp - xgetopt/stdafx.cpp - xgetopt/argcargv.cpp + + xgetopt/xgetopt.cpp + xgetopt/stdafx.cpp + xgetopt/argcargv.cpp + + mingw/utimes.cpp ) foreach(SOURCE ${SOURCES}) set(ALL_SOURCES ${ALL_SOURCES} src/${SOURCE}) endforeach() -IF(DEFINE_WIN) - add_definitions(-D__WIN__) -ENDIF(DEFINE_WIN) - include_directories("${CMAKE_SOURCE_DIR}/src") add_executable(fatcat "src/fatcat.cpp" ${ALL_SOURCES}) diff --git a/build.bat b/build.bat index 385fef6..24b2ad9 100644 --- a/build.bat +++ b/build.bat @@ -1,5 +1,19 @@ -if not exist build md build -cd build -git clean -fdx && cmake .. -DDEFINE_WIN=ON && "c:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe" fatcat.sln /p:OutDir=bin -cd .. -pause \ No newline at end of file +@echo off + +if exist build rmdir /S /Q build +mkdir build +pushd build + +set MINGW_BIN=C:\MinGW\bin +if not exist %MINGW_BIN% goto _msvc + +set PATH=%MINGW_BIN%;%PATH% +cmake .. -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=MINSIZEREL && mingw32-make +goto _the_end + +:_msvc +cmake .. && start "" fatcat.sln + +:_the_end +popd +pause diff --git a/src/FatUtils.h b/src/FatUtils.h index 5080f2a..28983c5 100644 --- a/src/FatUtils.h +++ b/src/FatUtils.h @@ -6,11 +6,6 @@ #include #include #include -#ifdef __WIN__ -#include -#else - -#endif using namespace std; diff --git a/src/analysis/FatExtract.cpp b/src/analysis/FatExtract.cpp index 892a085..c65e867 100644 --- a/src/analysis/FatExtract.cpp +++ b/src/analysis/FatExtract.cpp @@ -4,14 +4,13 @@ #include #include #include -#ifndef __WIN__ +#ifdef _WIN32 +#include +#else #include #endif #include #include "FatExtract.h" -#ifdef __WIN__ -#include -#endif using namespace std; @@ -23,7 +22,7 @@ FatExtract::FatExtract(FatSystem &system) void FatExtract::onDirectory(FatEntry &parent, FatEntry &entry, string name) { string directory = targetDirectory + "/" + name; -#ifdef __WIN__ +#ifdef _WIN32 CreateDirectory(directory.c_str(), NULL); #else mkdir(directory.c_str(), 0755); @@ -42,11 +41,10 @@ void FatExtract::onEntry(FatEntry &parent, FatEntry &entry, string name) string target = targetDirectory + name; cout << "Extracting " << name << " to " << target << endl; - FILE *output = fopen(target.c_str(), "w+"); + FILE *output = fopen(target.c_str(), "wb+"); system.readFile(entry.cluster, entry.size, output, contiguous); fclose(output); -#ifndef __WIN__ time_t mtime = entry.changeDate.timestamp(); if (mtime == (time_t)-1) { // Files on FAT can have dates up to 2107 year inclusive (which is @@ -68,7 +66,6 @@ void FatExtract::onEntry(FatEntry &parent, FatEntry &entry, string name) << ": " << strerror(errno) << endl; } } -#endif } } diff --git a/src/core/FatDate.cpp b/src/core/FatDate.cpp index bf7d0e0..f64f010 100644 --- a/src/core/FatDate.cpp +++ b/src/core/FatDate.cpp @@ -35,7 +35,6 @@ string FatDate::pretty() return string(buffer); } -#ifndef __WIN__ /** * Returns date as a number of seconds elapsed since the Epoch, * 1970-01-01 00:00:00 +0000 (UTC). FAT dates are considered to be in the @@ -59,7 +58,6 @@ time_t FatDate::timestamp() const return mktime(&tm); } -#endif string FatDate::isoFormat() { diff --git a/src/core/FatDate.h b/src/core/FatDate.h index ad14df2..6457ef0 100644 --- a/src/core/FatDate.h +++ b/src/core/FatDate.h @@ -2,9 +2,7 @@ #define _FATCAT_FATDATE_H #include -#ifndef __WIN__ #include -#endif using namespace std; @@ -18,9 +16,7 @@ class FatDate int y, m, d; string pretty(); - #ifndef __WIN__ time_t timestamp() const; - #endif string isoFormat(); }; diff --git a/src/core/FatSystem.cpp b/src/core/FatSystem.cpp index 37be51c..ff1f2d6 100644 --- a/src/core/FatSystem.cpp +++ b/src/core/FatSystem.cpp @@ -1,18 +1,16 @@ -#ifdef __WIN__ -#include -#else +#include +#include +#include +#ifndef _WIN32 #include -#endif #include #include -#include #include #include -#include #include #include #include -#include +#endif #include #include "FatFilename.h" @@ -38,10 +36,18 @@ FatSystem::FatSystem(string filename_, unsigned long long globalOffset_, OutputF rootEntries(0) { this->_outputFormat = outputFormat_; + #ifdef _WIN32 + fd = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + #else fd = open(filename.c_str(), O_RDONLY|O_LARGEFILE); + #endif writeMode = false; + #ifdef _WIN32 + if (fd == INVALID_HANDLE_VALUE) { + #else if (fd < 0) { + #endif ostringstream oss; oss << "! Unable to open the input file: " << filename << " for reading"; @@ -63,10 +69,17 @@ void FatSystem::enableCache() void FatSystem::enableWrite() { + #ifdef _WIN32 + CloseHandle(fd); + fd = CreateFile(filename.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (fd == INVALID_HANDLE_VALUE) { + #else close(fd); fd = open(filename.c_str(), O_RDWR|O_LARGEFILE); if (fd < 0) { + #endif ostringstream oss; oss << "! Unable to open the input file: " << filename << " for writing"; @@ -78,7 +91,11 @@ void FatSystem::enableWrite() FatSystem::~FatSystem() { + #ifdef _WIN32 + CloseHandle(fd); + #else close(fd); + #endif } /** @@ -90,6 +107,16 @@ int FatSystem::readData(unsigned long long address, char *buffer, int size) cerr << "! Trying to read outside the disk" << endl; } + #ifdef _WIN32 + DWORD bytesRead; + + LARGE_INTEGER offset; + offset.QuadPart = globalOffset+address; + + SetFilePointerEx(fd, offset, NULL, FILE_BEGIN); + ReadFile(fd, buffer, size, &bytesRead, NULL); + return bytesRead; + #else lseek64(fd, globalOffset+address, SEEK_SET); int n; @@ -104,6 +131,7 @@ int FatSystem::readData(unsigned long long address, char *buffer, int size) } while ((size>0) && (n>0)); return n; + #endif } int FatSystem::writeData(unsigned long long address, const char *buffer, int size) @@ -112,6 +140,16 @@ int FatSystem::writeData(unsigned long long address, const char *buffer, int siz throw string("Trying to write data while write mode is disabled"); } + #ifdef _WIN32 + DWORD bytesWritten; + + LARGE_INTEGER offset; + offset.QuadPart = globalOffset+address; + + SetFilePointerEx(fd, offset, NULL, FILE_BEGIN); + WriteFile(fd, buffer, size, &bytesWritten, NULL); + return bytesWritten; + #else lseek64(fd, globalOffset+address, SEEK_SET); int n; @@ -126,6 +164,7 @@ int FatSystem::writeData(unsigned long long address, const char *buffer, int siz } while ((size>0) && (n>0)); return n; + #endif } /** @@ -199,12 +238,12 @@ void FatSystem::parseHeader() unsigned int FatSystem::nextCluster(unsigned int cluster, int fat) { int bytes = (bits == 32 ? 4 : 2); -#ifndef __WIN__ +#ifndef _MSC_VER char buffer[bytes]; #else - char *buffer = new char[bytes]; - __try - { + char *buffer = new char[bytes]; + __try + { #endif if (!validCluster(cluster)) { @@ -249,7 +288,7 @@ unsigned int FatSystem::nextCluster(unsigned int cluster, int fat) } } } -#ifdef __WIN__ +#ifdef _MSC_VER } __finally { @@ -264,7 +303,7 @@ __finally bool FatSystem::writeNextCluster(unsigned int cluster, unsigned int next, int fat) { int bytes = (bits == 32 ? 4 : 2); -#ifndef __WIN__ +#ifndef _MSC_VER char buffer[bytes]; #else char *buffer = new char[bytes]; @@ -296,7 +335,7 @@ bool FatSystem::writeNextCluster(unsigned int cluster, unsigned int next, int fa } return writeData(offset, buffer, bytes) == bytes; -#ifdef __WIN__ +#ifdef _MSC_VER } __finally { @@ -594,7 +633,7 @@ void FatSystem::readFile(unsigned int cluster, unsigned int size, FILE *f, bool if (toRead > bytesPerCluster || size < 0) { toRead = bytesPerCluster; } -#ifndef __WIN__ +#ifndef _MSC_VER char buffer[bytesPerCluster]; #else char *buffer = new char[bytesPerCluster]; @@ -636,7 +675,7 @@ void FatSystem::readFile(unsigned int cluster, unsigned int size, FILE *f, bool cluster = currentCluster+1; } } -#ifdef __WIN__ +#ifdef _MSC_VER } __finally { @@ -865,7 +904,7 @@ void FatSystem::rewriteUnallocated(bool random) srand(time(NULL)); for (int cluster=0; cluster #include #include +#ifdef _WIN32 +#include +#endif #include "FatEntry.h" #include "FatPath.h" @@ -13,10 +16,7 @@ #define O_LARGEFILE 0 #define lseek64 lseek #endif -#ifdef __WIN__ -#define O_LARGEFILE 0 -#define lseek64 lseek -#endif + using namespace std; // Last cluster @@ -114,7 +114,11 @@ class FatSystem // File descriptor string filename; unsigned long long globalOffset; + #ifdef _WIN32 + HANDLE fd; + #else int fd; + #endif bool writeMode; // Header values diff --git a/src/fatcat.cpp b/src/fatcat.cpp index ce23ca0..97a0352 100644 --- a/src/fatcat.cpp +++ b/src/fatcat.cpp @@ -2,14 +2,17 @@ #include #ifdef __APPLE__ #include -#else -#ifdef __WIN__ -#include +#elif defined __MINGW32__ +#include "mingw/argp.h" +#elif defined _MSC_VER #include "xgetopt/xgetopt.h" +// For older VC++ (prior 2013) add atoll alternative +#if _MSC_VER < 1800 +#define atoll(arg) _strtoui64(arg, NULL, 10) +#endif #else #include #endif -#endif #include #include diff --git a/src/mingw/argp.h b/src/mingw/argp.h new file mode 100644 index 0000000..be51b77 --- /dev/null +++ b/src/mingw/argp.h @@ -0,0 +1,648 @@ +/* -*- buffer-read-only: t -*- vi: set ro: */ +/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ +/* Hierarchial argument parsing, layered over getopt. + Copyright (C) 1995-1999,2003-2008 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef _ARGP_H +#define _ARGP_H + +#include +#include +#include +#include + +#define __need_error_t +#include + +#ifndef __THROW +# define __THROW +#endif +#ifndef __NTH +# define __NTH(fct) fct __THROW +#endif + +#ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) +# define __attribute__(Spec) /* empty */ +# endif +/* The __-protected variants of `format' and `printf' attributes + are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) || __STRICT_ANSI__ +# define __format__ format +# define __printf__ printf +# endif +#endif + +/* GCC 2.95 and later have "__restrict"; C99 compilers have + "restrict", and "configure" may have defined "restrict". + Other compilers use __restrict, __restrict__, and _Restrict, and + 'configure' might #define 'restrict' to those words. */ +#ifndef __restrict +# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)) +# if 199901L <= __STDC_VERSION__ +# define __restrict restrict +# else +# define __restrict +# endif +# endif +#endif + +#ifndef __error_t_defined +typedef int error_t; +# define __error_t_defined +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* A description of a particular option. A pointer to an array of + these is passed in the OPTIONS field of an argp structure. Each option + entry can correspond to one long option and/or one short option; more + names for the same option can be added by following an entry in an option + array with options having the OPTION_ALIAS flag set. */ +struct argp_option +{ + /* The long option name. For more than one name for the same option, you + can use following options with the OPTION_ALIAS flag set. */ + const char *name; + + /* What key is returned for this option. If > 0 and printable, then it's + also accepted as a short option. */ + int key; + + /* If non-NULL, this is the name of the argument associated with this + option, which is required unless the OPTION_ARG_OPTIONAL flag is set. */ + const char *arg; + + /* OPTION_ flags. */ + int flags; + + /* The doc string for this option. If both NAME and KEY are 0, This string + will be printed outdented from the normal option column, making it + useful as a group header (it will be the first thing printed in its + group); in this usage, it's conventional to end the string with a `:'. + + Write the initial value as N_("TEXT") if you want xgettext to collect + it into a POT file. */ + const char *doc; + + /* The group this option is in. In a long help message, options are sorted + alphabetically within each group, and the groups presented in the order + 0, 1, 2, ..., n, -m, ..., -2, -1. Every entry in an options array with + if this field 0 will inherit the group number of the previous entry, or + zero if it's the first one, unless its a group header (NAME and KEY both + 0), in which case, the previous entry + 1 is the default. Automagic + options such as --help are put into group -1. */ + int group; +}; + +/* The argument associated with this option is optional. */ +#define OPTION_ARG_OPTIONAL 0x1 + +/* This option isn't displayed in any help messages. */ +#define OPTION_HIDDEN 0x2 + +/* This option is an alias for the closest previous non-alias option. This + means that it will be displayed in the same help entry, and will inherit + fields other than NAME and KEY from the aliased option. */ +#define OPTION_ALIAS 0x4 + +/* This option isn't actually an option (and so should be ignored by the + actual option parser), but rather an arbitrary piece of documentation that + should be displayed in much the same manner as the options. If this flag + is set, then the option NAME field is displayed unmodified (e.g., no `--' + prefix is added) at the left-margin (where a *short* option would normally + be displayed), and the documentation string in the normal place. The NAME + field will be translated using gettext, unless OPTION_NO_TRANS is set (see + below). For purposes of sorting, any leading whitespace and punctuation is + ignored, except that if the first non-whitespace character is not `-', this + entry is displayed after all options (and OPTION_DOC entries with a leading + `-') in the same group. */ +#define OPTION_DOC 0x8 + +/* This option shouldn't be included in `long' usage messages (but is still + included in help messages). This is mainly intended for options that are + completely documented in an argp's ARGS_DOC field, in which case including + the option in the generic usage list would be redundant. For instance, + if ARGS_DOC is "FOO BAR\n-x BLAH", and the `-x' option's purpose is to + distinguish these two cases, -x should probably be marked + OPTION_NO_USAGE. */ +#define OPTION_NO_USAGE 0x10 + +/* Valid only in conjunction with OPTION_DOC. This option disables translation + of option name. */ +#define OPTION_NO_TRANS 0x20 + + +struct argp; /* fwd declare this type */ +struct argp_state; /* " */ +struct argp_child; /* " */ + +/* The type of a pointer to an argp parsing function. */ +typedef error_t (*argp_parser_t) (int key, char *arg, + struct argp_state *state); + +/* What to return for unrecognized keys. For special ARGP_KEY_ keys, such + returns will simply be ignored. For user keys, this error will be turned + into EINVAL (if the call to argp_parse is such that errors are propagated + back to the user instead of exiting); returning EINVAL itself would result + in an immediate stop to parsing in *all* cases. */ +#define ARGP_ERR_UNKNOWN E2BIG /* Hurd should never need E2BIG. XXX */ + +/* Special values for the KEY argument to an argument parsing function. + ARGP_ERR_UNKNOWN should be returned if they aren't understood. + + The sequence of keys to a parsing function is either (where each + uppercased word should be prefixed by `ARGP_KEY_' and opt is a user key): + + INIT opt... NO_ARGS END SUCCESS -- No non-option arguments at all + or INIT (opt | ARG)... END SUCCESS -- All non-option args parsed + or INIT (opt | ARG)... SUCCESS -- Some non-option arg unrecognized + + The third case is where every parser returned ARGP_KEY_UNKNOWN for an + argument, in which case parsing stops at that argument (returning the + unparsed arguments to the caller of argp_parse if requested, or stopping + with an error message if not). + + If an error occurs (either detected by argp, or because the parsing + function returned an error value), then the parser is called with + ARGP_KEY_ERROR, and no further calls are made. */ + +/* This is not an option at all, but rather a command line argument. If a + parser receiving this key returns success, the fact is recorded, and the + ARGP_KEY_NO_ARGS case won't be used. HOWEVER, if while processing the + argument, a parser function decrements the NEXT field of the state it's + passed, the option won't be considered processed; this is to allow you to + actually modify the argument (perhaps into an option), and have it + processed again. */ +#define ARGP_KEY_ARG 0 +/* There are remaining arguments not parsed by any parser, which may be found + starting at (STATE->argv + STATE->next). If success is returned, but + STATE->next left untouched, it's assumed that all arguments were consume, + otherwise, the parser should adjust STATE->next to reflect any arguments + consumed. */ +#define ARGP_KEY_ARGS 0x1000006 +/* There are no more command line arguments at all. */ +#define ARGP_KEY_END 0x1000001 +/* Because it's common to want to do some special processing if there aren't + any non-option args, user parsers are called with this key if they didn't + successfully process any non-option arguments. Called just before + ARGP_KEY_END (where more general validity checks on previously parsed + arguments can take place). */ +#define ARGP_KEY_NO_ARGS 0x1000002 +/* Passed in before any parsing is done. Afterwards, the values of each + element of the CHILD_INPUT field, if any, in the state structure is + copied to each child's state to be the initial value of the INPUT field. */ +#define ARGP_KEY_INIT 0x1000003 +/* Use after all other keys, including SUCCESS & END. */ +#define ARGP_KEY_FINI 0x1000007 +/* Passed in when parsing has successfully been completed (even if there are + still arguments remaining). */ +#define ARGP_KEY_SUCCESS 0x1000004 +/* Passed in if an error occurs. */ +#define ARGP_KEY_ERROR 0x1000005 + +/* An argp structure contains a set of options declarations, a function to + deal with parsing one, documentation string, a possible vector of child + argp's, and perhaps a function to filter help output. When actually + parsing options, getopt is called with the union of all the argp + structures chained together through their CHILD pointers, with conflicts + being resolved in favor of the first occurrence in the chain. */ +struct argp +{ + /* An array of argp_option structures, terminated by an entry with both + NAME and KEY having a value of 0. */ + const struct argp_option *options; + + /* What to do with an option from this structure. KEY is the key + associated with the option, and ARG is any associated argument (NULL if + none was supplied). If KEY isn't understood, ARGP_ERR_UNKNOWN should be + returned. If a non-zero, non-ARGP_ERR_UNKNOWN value is returned, then + parsing is stopped immediately, and that value is returned from + argp_parse(). For special (non-user-supplied) values of KEY, see the + ARGP_KEY_ definitions below. */ + argp_parser_t parser; + + /* A string describing what other arguments are wanted by this program. It + is only used by argp_usage to print the `Usage:' message. If it + contains newlines, the strings separated by them are considered + alternative usage patterns, and printed on separate lines (lines after + the first are prefix by ` or: ' instead of `Usage:'). */ + const char *args_doc; + + /* If non-NULL, a string containing extra text to be printed before and + after the options in a long help message (separated by a vertical tab + `\v' character). + Write the initial value as N_("BEFORE-TEXT") "\v" N_("AFTER-TEXT") if + you want xgettext to collect the two pieces of text into a POT file. */ + const char *doc; + + /* A vector of argp_children structures, terminated by a member with a 0 + argp field, pointing to child argps should be parsed with this one. Any + conflicts are resolved in favor of this argp, or early argps in the + CHILDREN list. This field is useful if you use libraries that supply + their own argp structure, which you want to use in conjunction with your + own. */ + const struct argp_child *children; + + /* If non-zero, this should be a function to filter the output of help + messages. KEY is either a key from an option, in which case TEXT is + that option's help text, or a special key from the ARGP_KEY_HELP_ + defines, below, describing which other help text TEXT is. The function + should return either TEXT, if it should be used as-is, a replacement + string, which should be malloced, and will be freed by argp, or NULL, + meaning `print nothing'. The value for TEXT is *after* any translation + has been done, so if any of the replacement text also needs translation, + that should be done by the filter function. INPUT is either the input + supplied to argp_parse, or NULL, if argp_help was called directly. */ + char *(*help_filter) (int __key, const char *__text, void *__input); + + /* If non-zero the strings used in the argp library are translated using + the domain described by this string. Otherwise the currently installed + default domain is used. */ + const char *argp_domain; +}; + +/* Possible KEY arguments to a help filter function. */ +#define ARGP_KEY_HELP_PRE_DOC 0x2000001 /* Help text preceeding options. */ +#define ARGP_KEY_HELP_POST_DOC 0x2000002 /* Help text following options. */ +#define ARGP_KEY_HELP_HEADER 0x2000003 /* Option header string. */ +#define ARGP_KEY_HELP_EXTRA 0x2000004 /* After all other documentation; + TEXT is NULL for this key. */ +/* Explanatory note emitted when duplicate option arguments have been + suppressed. */ +#define ARGP_KEY_HELP_DUP_ARGS_NOTE 0x2000005 +#define ARGP_KEY_HELP_ARGS_DOC 0x2000006 /* Argument doc string. */ + +/* When an argp has a non-zero CHILDREN field, it should point to a vector of + argp_child structures, each of which describes a subsidiary argp. */ +struct argp_child +{ + /* The child parser. */ + const struct argp *argp; + + /* Flags for this child. */ + int flags; + + /* If non-zero, an optional header to be printed in help output before the + child options. As a side-effect, a non-zero value forces the child + options to be grouped together; to achieve this effect without actually + printing a header string, use a value of "". */ + const char *header; + + /* Where to group the child options relative to the other (`consolidated') + options in the parent argp; the values are the same as the GROUP field + in argp_option structs, but all child-groupings follow parent options at + a particular group level. If both this field and HEADER are zero, then + they aren't grouped at all, but rather merged with the parent options + (merging the child's grouping levels with the parents). */ + int group; +}; + +/* Parsing state. This is provided to parsing functions called by argp, + which may examine and, as noted, modify fields. */ +struct argp_state +{ + /* The top level ARGP being parsed. */ + const struct argp *root_argp; + + /* The argument vector being parsed. May be modified. */ + int argc; + char **argv; + + /* The index in ARGV of the next arg that to be parsed. May be modified. */ + int next; + + /* The flags supplied to argp_parse. May be modified. */ + unsigned flags; + + /* While calling a parsing function with a key of ARGP_KEY_ARG, this is the + number of the current arg, starting at zero, and incremented after each + such call returns. At all other times, this is the number of such + arguments that have been processed. */ + unsigned arg_num; + + /* If non-zero, the index in ARGV of the first argument following a special + `--' argument (which prevents anything following being interpreted as an + option). Only set once argument parsing has proceeded past this point. */ + int quoted; + + /* An arbitrary pointer passed in from the user. */ + void *input; + /* Values to pass to child parsers. This vector will be the same length as + the number of children for the current parser. */ + void **child_inputs; + + /* For the parser's use. Initialized to 0. */ + void *hook; + + /* The name used when printing messages. This is initialized to ARGV[0], + or PROGRAM_INVOCATION_NAME if that is unavailable. */ + char *name; + + /* Streams used when argp prints something. */ + FILE *err_stream; /* For errors; initialized to stderr. */ + FILE *out_stream; /* For information; initialized to stdout. */ + + void *pstate; /* Private, for use by argp. */ +}; + +/* Flags for argp_parse (note that the defaults are those that are + convenient for program command line parsing): */ + +/* Don't ignore the first element of ARGV. Normally (and always unless + ARGP_NO_ERRS is set) the first element of the argument vector is + skipped for option parsing purposes, as it corresponds to the program name + in a command line. */ +#define ARGP_PARSE_ARGV0 0x01 + +/* Don't print error messages for unknown options to stderr; unless this flag + is set, ARGP_PARSE_ARGV0 is ignored, as ARGV[0] is used as the program + name in the error messages. This flag implies ARGP_NO_EXIT (on the + assumption that silent exiting upon errors is bad behaviour). */ +#define ARGP_NO_ERRS 0x02 + +/* Don't parse any non-option args. Normally non-option args are parsed by + calling the parse functions with a key of ARGP_KEY_ARG, and the actual arg + as the value. Since it's impossible to know which parse function wants to + handle it, each one is called in turn, until one returns 0 or an error + other than ARGP_ERR_UNKNOWN; if an argument is handled by no one, the + argp_parse returns prematurely (but with a return value of 0). If all + args have been parsed without error, all parsing functions are called one + last time with a key of ARGP_KEY_END. This flag needn't normally be set, + as the normal behavior is to stop parsing as soon as some argument can't + be handled. */ +#define ARGP_NO_ARGS 0x04 + +/* Parse options and arguments in the same order they occur on the command + line -- normally they're rearranged so that all options come first. */ +#define ARGP_IN_ORDER 0x08 + +/* Don't provide the standard long option --help, which causes usage and + option help information to be output to stdout, and exit (0) called. */ +#define ARGP_NO_HELP 0x10 + +/* Don't exit on errors (they may still result in error messages). */ +#define ARGP_NO_EXIT 0x20 + +/* Use the gnu getopt `long-only' rules for parsing arguments. */ +#define ARGP_LONG_ONLY 0x40 + +/* Turns off any message-printing/exiting options. */ +#define ARGP_SILENT (ARGP_NO_EXIT | ARGP_NO_ERRS | ARGP_NO_HELP) + +/* Parse the options strings in ARGC & ARGV according to the options in ARGP. + FLAGS is one of the ARGP_ flags above. If ARG_INDEX is non-NULL, the + index in ARGV of the first unparsed option is returned in it. If an + unknown option is present, ARGP_ERR_UNKNOWN is returned; if some parser + routine returned a non-zero value, it is returned; otherwise 0 is + returned. This function may also call exit unless the ARGP_NO_HELP flag + is set. INPUT is a pointer to a value to be passed in to the parser. */ +extern error_t argp_parse (const struct argp *__restrict __argp, + int /*argc*/, char **__restrict /*argv*/, + unsigned __flags, int *__restrict __arg_index, + void *__restrict __input); +extern error_t __argp_parse (const struct argp *__restrict __argp, + int /*argc*/, char **__restrict /*argv*/, + unsigned __flags, int *__restrict __arg_index, + void *__restrict __input); + +/* Global variables. */ + +/* GNULIB makes sure both program_invocation_name and + program_invocation_short_name are available */ +#ifdef GNULIB_PROGRAM_INVOCATION_NAME +extern char *program_invocation_name; +# undef HAVE_DECL_PROGRAM_INVOCATION_NAME +# define HAVE_DECL_PROGRAM_INVOCATION_NAME 1 +#endif + +#ifdef GNULIB_PROGRAM_INVOCATION_SHORT_NAME +extern char *program_invocation_short_name; +# undef HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME +# define HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME 1 +#endif + +/* If defined or set by the user program to a non-zero value, then a default + option --version is added (unless the ARGP_NO_HELP flag is used), which + will print this string followed by a newline and exit (unless the + ARGP_NO_EXIT flag is used). Overridden by ARGP_PROGRAM_VERSION_HOOK. */ +extern const char *argp_program_version; + +/* If defined or set by the user program to a non-zero value, then a default + option --version is added (unless the ARGP_NO_HELP flag is used), which + calls this function with a stream to print the version to and a pointer to + the current parsing state, and then exits (unless the ARGP_NO_EXIT flag is + used). This variable takes precedent over ARGP_PROGRAM_VERSION. */ +extern void (*argp_program_version_hook) (FILE *__restrict __stream, + struct argp_state *__restrict + __state); + +/* If defined or set by the user program, it should point to string that is + the bug-reporting address for the program. It will be printed by + argp_help if the ARGP_HELP_BUG_ADDR flag is set (as it is by various + standard help messages), embedded in a sentence that says something like + `Report bugs to ADDR.'. */ +extern const char *argp_program_bug_address; + +/* The exit status that argp will use when exiting due to a parsing error. + If not defined or set by the user program, this defaults to EX_USAGE from + . */ +extern error_t argp_err_exit_status; + +/* Flags for argp_help. */ +#define ARGP_HELP_USAGE 0x01 /* a Usage: message. */ +#define ARGP_HELP_SHORT_USAGE 0x02 /* " but don't actually print options. */ +#define ARGP_HELP_SEE 0x04 /* a `Try ... for more help' message. */ +#define ARGP_HELP_LONG 0x08 /* a long help message. */ +#define ARGP_HELP_PRE_DOC 0x10 /* doc string preceding long help. */ +#define ARGP_HELP_POST_DOC 0x20 /* doc string following long help. */ +#define ARGP_HELP_DOC (ARGP_HELP_PRE_DOC | ARGP_HELP_POST_DOC) +#define ARGP_HELP_BUG_ADDR 0x40 /* bug report address */ +#define ARGP_HELP_LONG_ONLY 0x80 /* modify output appropriately to + reflect ARGP_LONG_ONLY mode. */ + +/* These ARGP_HELP flags are only understood by argp_state_help. */ +#define ARGP_HELP_EXIT_ERR 0x100 /* Call exit(1) instead of returning. */ +#define ARGP_HELP_EXIT_OK 0x200 /* Call exit(0) instead of returning. */ + +/* The standard thing to do after a program command line parsing error, if an + error message has already been printed. */ +#define ARGP_HELP_STD_ERR \ + (ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR) +/* The standard thing to do after a program command line parsing error, if no + more specific error message has been printed. */ +#define ARGP_HELP_STD_USAGE \ + (ARGP_HELP_SHORT_USAGE | ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR) +/* The standard thing to do in response to a --help option. */ +#define ARGP_HELP_STD_HELP \ + (ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG | ARGP_HELP_EXIT_OK \ + | ARGP_HELP_DOC | ARGP_HELP_BUG_ADDR) + +/* Output a usage message for ARGP to STREAM. FLAGS are from the set + ARGP_HELP_*. */ +extern void argp_help (const struct argp *__restrict __argp, + FILE *__restrict __stream, + unsigned __flags, char *__restrict __name); +extern void __argp_help (const struct argp *__restrict __argp, + FILE *__restrict __stream, unsigned __flags, + char *__name); + +/* The following routines are intended to be called from within an argp + parsing routine (thus taking an argp_state structure as the first + argument). They may or may not print an error message and exit, depending + on the flags in STATE -- in any case, the caller should be prepared for + them *not* to exit, and should return an appropiate error after calling + them. [argp_usage & argp_error should probably be called argp_state_..., + but they're used often enough that they should be short] */ + +/* Output, if appropriate, a usage message for STATE to STREAM. FLAGS are + from the set ARGP_HELP_*. */ +extern void argp_state_help (const struct argp_state *__restrict __state, + FILE *__restrict __stream, + unsigned int __flags); +extern void __argp_state_help (const struct argp_state *__restrict __state, + FILE *__restrict __stream, + unsigned int __flags); + +#if _LIBC || !defined __USE_EXTERN_INLINES +/* Possibly output the standard usage message for ARGP to stderr and exit. */ +extern void argp_usage (const struct argp_state *__state); +extern void __argp_usage (const struct argp_state *__state); +#endif + +/* If appropriate, print the printf string FMT and following args, preceded + by the program name and `:', to stderr, and followed by a `Try ... --help' + message, then exit (1). */ +extern void argp_error (const struct argp_state *__restrict __state, + const char *__restrict __fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); +extern void __argp_error (const struct argp_state *__restrict __state, + const char *__restrict __fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); + +/* Similar to the standard gnu error-reporting function error(), but will + respect the ARGP_NO_EXIT and ARGP_NO_ERRS flags in STATE, and will print + to STATE->err_stream. This is useful for argument parsing code that is + shared between program startup (when exiting is desired) and runtime + option parsing (when typically an error code is returned instead). The + difference between this function and argp_error is that the latter is for + *parsing errors*, and the former is for other problems that occur during + parsing but don't reflect a (syntactic) problem with the input. */ +extern void argp_failure (const struct argp_state *__restrict __state, + int __status, int __errnum, + const char *__restrict __fmt, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); +extern void __argp_failure (const struct argp_state *__restrict __state, + int __status, int __errnum, + const char *__restrict __fmt, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); + +#if _LIBC || !defined __USE_EXTERN_INLINES +/* Returns true if the option OPT is a valid short option. */ +extern int _option_is_short (const struct argp_option *__opt) __THROW; +extern int __option_is_short (const struct argp_option *__opt) __THROW; + +/* Returns true if the option OPT is in fact the last (unused) entry in an + options array. */ +extern int _option_is_end (const struct argp_option *__opt) __THROW; +extern int __option_is_end (const struct argp_option *__opt) __THROW; +#endif + +/* Return the input field for ARGP in the parser corresponding to STATE; used + by the help routines. */ +extern void *_argp_input (const struct argp *__restrict __argp, + const struct argp_state *__restrict __state) + __THROW; +extern void *__argp_input (const struct argp *__restrict __argp, + const struct argp_state *__restrict __state) + __THROW; + +#ifdef __USE_EXTERN_INLINES + +# if !_LIBC +# define __argp_usage argp_usage +# define __argp_state_help argp_state_help +# define __option_is_short _option_is_short +# define __option_is_end _option_is_end +# endif + +# ifndef ARGP_EI +# ifdef __GNUC__ + /* GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99 + inline semantics, unless -fgnu89-inline is used. It defines a macro + __GNUC_STDC_INLINE__ to indicate this situation or a macro + __GNUC_GNU_INLINE__ to indicate the opposite situation. + GCC 4.2 with -std=c99 or -std=gnu99 implements the GNU C inline + semantics but warns, unless -fgnu89-inline is used: + warning: C99 inline functions are not supported; using GNU89 + warning: to disable this warning use -fgnu89-inline or the gnu_inline function attribute + It defines a macro __GNUC_GNU_INLINE__ to indicate this situation. */ +# if defined __GNUC_STDC_INLINE__ +# define ARGP_EI __inline__ +# elif defined __GNUC_GNU_INLINE__ +# define ARGP_EI extern __inline__ __attribute__ ((__gnu_inline__)) +# else +# define ARGP_EI extern __inline__ +# endif +# else + /* With other compilers, assume the ISO C99 meaning of 'inline', if + the compiler supports 'inline' at all. */ +# define ARGP_EI inline +# endif +# endif + +ARGP_EI void +__argp_usage (const struct argp_state *__state) +{ + __argp_state_help (__state, stderr, ARGP_HELP_STD_USAGE); +} + +ARGP_EI int +__NTH (__option_is_short (const struct argp_option *__opt)) +{ + if (__opt->flags & OPTION_DOC) + return 0; + else + { + int __key = __opt->key; + return __key > 0 && __key <= UCHAR_MAX && isprint (__key); + } +} + +ARGP_EI int +__NTH (__option_is_end (const struct argp_option *__opt)) +{ + return !__opt->key && !__opt->name && !__opt->doc && !__opt->group; +} + +# if !_LIBC +# undef __argp_usage +# undef __argp_state_help +# undef __option_is_short +# undef __option_is_end +# endif +#endif /* Use extern inlines. */ + +#ifdef __cplusplus +} +#endif + +#endif /* argp.h */ diff --git a/src/mingw/utimes.cpp b/src/mingw/utimes.cpp new file mode 100644 index 0000000..e376f27 --- /dev/null +++ b/src/mingw/utimes.cpp @@ -0,0 +1,93 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2005 Jaroslaw Staniek + Copyright (C) 2005 Christian Ehrlicher + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + You should have received a copy of the GNU Library General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifdef _WIN32 + +#include "utimes.h" + +#define KDE_SECONDS_SINCE_1601 11644473600LL +#define KDE_USEC_IN_SEC 1000000LL + +/*after Microsoft KB167296 */ +static void UnixTimevalToFileTime(struct timeval t, LPFILETIME pft) +{ + LONGLONG ll; + + ll = Int32x32To64(t.tv_sec, KDE_USEC_IN_SEC*10) + t.tv_usec*10 + KDE_SECONDS_SINCE_1601*KDE_USEC_IN_SEC*10; + pft->dwLowDateTime = (DWORD)ll; + pft->dwHighDateTime = ll >> 32; +} + +/*errno==EACCES on read-only devices */ +int utimes(const char *filename, const struct timeval times[2]) +{ + FILETIME LastAccessTime; + FILETIME LastModificationTime; + HANDLE hFile; + +#ifdef _WIN32_WCE + const wchar_t *wfilename = wce_mbtowc(filename); +#endif + + if(times) { + UnixTimevalToFileTime(times[0], &LastAccessTime); + UnixTimevalToFileTime(times[1], &LastModificationTime); + } + else { + GetSystemTimeAsFileTime(&LastAccessTime); + GetSystemTimeAsFileTime(&LastModificationTime); + } + +#ifndef _WIN32_WCE + hFile=CreateFileA(filename, FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); +#else + hFile=CreateFileW(wfilename, FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + free(wfilename); +#endif + if(hFile==INVALID_HANDLE_VALUE) { + switch(GetLastError()) { + case ERROR_FILE_NOT_FOUND: + errno=ENOENT; + break; + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_DRIVE: + errno=ENOTDIR; + break; +/* case ERROR_WRITE_PROTECT: reateFile sets ERROR_ACCESS_DENIED on read-only devices + errno=EROFS; + break;*/ + case ERROR_ACCESS_DENIED: + errno=EACCES; + break; + default: + errno=ENOENT; /*what other errors can occur? */ + } + return -1; + } + + if(!SetFileTime(hFile, NULL, &LastAccessTime, &LastModificationTime)) { + /*can this happen? */ + errno=ENOENT; + return -1; + } + CloseHandle(hFile); + return 0; +} + +#endif diff --git a/src/mingw/utimes.h b/src/mingw/utimes.h new file mode 100644 index 0000000..56eafa2 --- /dev/null +++ b/src/mingw/utimes.h @@ -0,0 +1,19 @@ +#ifndef _UTIMES_H +#define _UTIMES_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*errno==EACCES on read-only devices */ +int utimes(const char *filename, const struct timeval times[2]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/table/FatBackup.cpp b/src/table/FatBackup.cpp index a509348..e7ea120 100644 --- a/src/table/FatBackup.cpp +++ b/src/table/FatBackup.cpp @@ -20,7 +20,7 @@ void FatBackup::backup(string backupFile, int fat) int size = system.fatSize; int n = 0; int offset = 0; - FILE *backup = fopen(backupFile.c_str(), "w+"); + FILE *backup = fopen(backupFile.c_str(), "wb+"); if (fat == 0) { size *= 2; @@ -55,7 +55,7 @@ void FatBackup::patch(string backupFile, int fat) char buffer[CHUNKS_SIZES]; // Opening the file - FILE *backup = fopen(backupFile.c_str(), "r"); + FILE *backup = fopen(backupFile.c_str(), "rb"); if (backup == NULL) { ostringstream oss; oss << "Unable to open file " << backupFile << " for reading"; diff --git a/src/xgetopt/argcargv.cpp b/src/xgetopt/argcargv.cpp index d7c9ac8..b47c08e 100644 --- a/src/xgetopt/argcargv.cpp +++ b/src/xgetopt/argcargv.cpp @@ -1,128 +1,128 @@ -//========================================== -// LIBCTINY - Matt Pietrek 2001 -// MSDN Magazine, January 2001 -//========================================== - -// NOTE: THIS CODE HAS BEEN MODIFIED FOR THIS DEMO APP - -// The original source for the LIBCTINY library may be -// found here: www.wheaty.net -#ifdef __WIN__ -#include "stdafx.h" -#include "argcargv.h" - -#define _MAX_CMD_LINE_ARGS 128 - -TCHAR *_ppszArgv[_MAX_CMD_LINE_ARGS + 1]; - -int _ConvertCommandLineToArgcArgv(LPCTSTR lpszSysCmdLine) -{ - if (lpszSysCmdLine == NULL || lpszSysCmdLine[0] == 0) - return 0; - - static LPVOID pHeap = NULL; - - // Set to no argv elements, in case we have to bail out - _ppszArgv[0] = 0; - - // First get a pointer to the system's version of the command line, and - // figure out how long it is. - int cbCmdLine = lstrlen(lpszSysCmdLine); - - // Allocate memory to store a copy of the command line. We'll modify - // this copy, rather than the original command line. Yes, this memory - // currently doesn't explicitly get freed, but it goes away when the - // process terminates. - if (pHeap) // in case we are called multiple times - { - HeapFree(GetProcessHeap(), 0, pHeap); - pHeap = NULL; - } - - pHeap = HeapAlloc(GetProcessHeap(), 0, cbCmdLine * sizeof(TCHAR) + 16); - - if (!pHeap) - return 0; - - LPTSTR pszCmdLine = (LPTSTR)pHeap; - - // Copy the system version of the command line into our copy - lstrcpy(pszCmdLine, lpszSysCmdLine); - - if (_T('"') == *pszCmdLine) // If command line starts with a quote ("), - { // it's a quoted filename. Skip to next quote. - pszCmdLine++; - - _ppszArgv[0] = pszCmdLine; // argv[0] == executable name - - while (*pszCmdLine && (*pszCmdLine != _T('"'))) - pszCmdLine++; - - if (*pszCmdLine) // Did we see a non-NULL ending? - *pszCmdLine++ = _T('\0'); // Null terminate and advance to next char - else - return 0; // Oops! We didn't see the end quote - } - else // A regular (non-quoted) filename - { - _ppszArgv[0] = pszCmdLine; // argv[0] == executable name - - while (*pszCmdLine && (_T(' ') != *pszCmdLine) && (_T('\t') != *pszCmdLine)) - pszCmdLine++; - - if (*pszCmdLine) - *pszCmdLine++ = _T('\0'); // Null terminate and advance to next char - } - - // Done processing argv[0] (i.e., the executable name). Now do th - // actual arguments - - int argc = 1; - - while (1) - { - // Skip over any whitespace - while (*pszCmdLine && (_T(' ') == *pszCmdLine) || (_T('\t') == *pszCmdLine)) - pszCmdLine++; - - if (_T('\0') == *pszCmdLine) // End of command line??? - return argc; - - if (_T('"') == *pszCmdLine) // Argument starting with a quote??? - { - pszCmdLine++; // Advance past quote character - - _ppszArgv[argc++] = pszCmdLine; - _ppszArgv[argc] = 0; - - // Scan to end quote, or NULL terminator - while (*pszCmdLine && (*pszCmdLine != _T('"'))) - pszCmdLine++; - - if (_T('\0') == *pszCmdLine) - return argc; - - if (*pszCmdLine) - *pszCmdLine++ = _T('\0'); // Null terminate and advance to next char - } - else // Non-quoted argument - { - _ppszArgv[argc++] = pszCmdLine; - _ppszArgv[argc] = 0; - - // Skip till whitespace or NULL terminator - while (*pszCmdLine && (_T(' ') != *pszCmdLine) && (_T('\t') != *pszCmdLine)) - pszCmdLine++; - - if (_T('\0') == *pszCmdLine) - return argc; - - if (*pszCmdLine) - *pszCmdLine++ = _T('\0'); // Null terminate and advance to next char - } - - if (argc >= (_MAX_CMD_LINE_ARGS)) - return argc; - } -} +//========================================== +// LIBCTINY - Matt Pietrek 2001 +// MSDN Magazine, January 2001 +//========================================== + +// NOTE: THIS CODE HAS BEEN MODIFIED FOR THIS DEMO APP + +// The original source for the LIBCTINY library may be +// found here: www.wheaty.net +#ifdef _MSC_VER +#include "stdafx.h" +#include "argcargv.h" + +#define _MAX_CMD_LINE_ARGS 128 + +TCHAR *_ppszArgv[_MAX_CMD_LINE_ARGS + 1]; + +int _ConvertCommandLineToArgcArgv(LPCTSTR lpszSysCmdLine) +{ + if (lpszSysCmdLine == NULL || lpszSysCmdLine[0] == 0) + return 0; + + static LPVOID pHeap = NULL; + + // Set to no argv elements, in case we have to bail out + _ppszArgv[0] = 0; + + // First get a pointer to the system's version of the command line, and + // figure out how long it is. + int cbCmdLine = lstrlen(lpszSysCmdLine); + + // Allocate memory to store a copy of the command line. We'll modify + // this copy, rather than the original command line. Yes, this memory + // currently doesn't explicitly get freed, but it goes away when the + // process terminates. + if (pHeap) // in case we are called multiple times + { + HeapFree(GetProcessHeap(), 0, pHeap); + pHeap = NULL; + } + + pHeap = HeapAlloc(GetProcessHeap(), 0, cbCmdLine * sizeof(TCHAR) + 16); + + if (!pHeap) + return 0; + + LPTSTR pszCmdLine = (LPTSTR)pHeap; + + // Copy the system version of the command line into our copy + lstrcpy(pszCmdLine, lpszSysCmdLine); + + if (_T('"') == *pszCmdLine) // If command line starts with a quote ("), + { // it's a quoted filename. Skip to next quote. + pszCmdLine++; + + _ppszArgv[0] = pszCmdLine; // argv[0] == executable name + + while (*pszCmdLine && (*pszCmdLine != _T('"'))) + pszCmdLine++; + + if (*pszCmdLine) // Did we see a non-NULL ending? + *pszCmdLine++ = _T('\0'); // Null terminate and advance to next char + else + return 0; // Oops! We didn't see the end quote + } + else // A regular (non-quoted) filename + { + _ppszArgv[0] = pszCmdLine; // argv[0] == executable name + + while (*pszCmdLine && (_T(' ') != *pszCmdLine) && (_T('\t') != *pszCmdLine)) + pszCmdLine++; + + if (*pszCmdLine) + *pszCmdLine++ = _T('\0'); // Null terminate and advance to next char + } + + // Done processing argv[0] (i.e., the executable name). Now do th + // actual arguments + + int argc = 1; + + while (1) + { + // Skip over any whitespace + while (*pszCmdLine && (_T(' ') == *pszCmdLine) || (_T('\t') == *pszCmdLine)) + pszCmdLine++; + + if (_T('\0') == *pszCmdLine) // End of command line??? + return argc; + + if (_T('"') == *pszCmdLine) // Argument starting with a quote??? + { + pszCmdLine++; // Advance past quote character + + _ppszArgv[argc++] = pszCmdLine; + _ppszArgv[argc] = 0; + + // Scan to end quote, or NULL terminator + while (*pszCmdLine && (*pszCmdLine != _T('"'))) + pszCmdLine++; + + if (_T('\0') == *pszCmdLine) + return argc; + + if (*pszCmdLine) + *pszCmdLine++ = _T('\0'); // Null terminate and advance to next char + } + else // Non-quoted argument + { + _ppszArgv[argc++] = pszCmdLine; + _ppszArgv[argc] = 0; + + // Skip till whitespace or NULL terminator + while (*pszCmdLine && (_T(' ') != *pszCmdLine) && (_T('\t') != *pszCmdLine)) + pszCmdLine++; + + if (_T('\0') == *pszCmdLine) + return argc; + + if (*pszCmdLine) + *pszCmdLine++ = _T('\0'); // Null terminate and advance to next char + } + + if (argc >= (_MAX_CMD_LINE_ARGS)) + return argc; + } +} #endif \ No newline at end of file diff --git a/src/xgetopt/argcargv.h b/src/xgetopt/argcargv.h index edb61d7..7d5a644 100644 --- a/src/xgetopt/argcargv.h +++ b/src/xgetopt/argcargv.h @@ -1,8 +1,8 @@ -#ifndef ARGCARGV_H -#define ARGCARGV_H - -extern TCHAR *_ppszArgv[]; - -int _ConvertCommandLineToArgcArgv(LPCTSTR lpszSysCmdLine); - -#endif //ARGCARGV_H +#ifndef ARGCARGV_H +#define ARGCARGV_H + +extern TCHAR *_ppszArgv[]; + +int _ConvertCommandLineToArgcArgv(LPCTSTR lpszSysCmdLine); + +#endif //ARGCARGV_H diff --git a/src/xgetopt/stdafx.cpp b/src/xgetopt/stdafx.cpp index 73f52ec..aa879eb 100644 --- a/src/xgetopt/stdafx.cpp +++ b/src/xgetopt/stdafx.cpp @@ -1,10 +1,10 @@ -// stdafx.cpp : source file that includes just the standard includes -// XGetoptTest.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information -#ifdef __WIN__ - -#include "stdafx.h" - - - +// stdafx.cpp : source file that includes just the standard includes +// XGetoptTest.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information +#ifdef _MSC_VER + +#include "stdafx.h" + + + #endif \ No newline at end of file diff --git a/src/xgetopt/stdafx.h b/src/xgetopt/stdafx.h index 2f1c723..29d5588 100644 --- a/src/xgetopt/stdafx.h +++ b/src/xgetopt/stdafx.h @@ -1,20 +1,20 @@ -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently -// - -#ifndef STDAFX_H -#define STDAFX_H -#define _AFXDLL 1 -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers -#include // MFC core and standard components -#include // MFC extensions -#include // MFC support for Internet Explorer 4 Common Controls -#ifndef _AFX_NO_AFXCMN_SUPPORT -#include // MFC support for Windows Common Controls -#endif // _AFX_NO_AFXCMN_SUPPORT - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif //STDAFX_H +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#ifndef STDAFX_H +#define STDAFX_H +#define _AFXDLL 1 +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers +#include // MFC core and standard components +#include // MFC extensions +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif //STDAFX_H diff --git a/src/xgetopt/xgetopt.cpp b/src/xgetopt/xgetopt.cpp index c39416e..447c259 100644 --- a/src/xgetopt/xgetopt.cpp +++ b/src/xgetopt/xgetopt.cpp @@ -1,217 +1,217 @@ -// XGetopt.cpp Version 1.2 -// -// Author: Hans Dietrich -// hdietrich2@hotmail.com -// url: https://www.codeproject.com/Articles/1940/XGetopt-A-Unix-compatible-getopt-for-MFC-and-Win32 -// -// Description: -// XGetopt.cpp implements getopt(), a function to parse command lines. -// -// History -// Version 1.2 - 2003 May 17 -// - Added Unicode support -// -// Version 1.1 - 2002 March 10 -// - Added example to XGetopt.cpp module header -// -// This software is released into the public domain. -// You are free to use it in any way you like. -// -// This software is provided "as is" with no expressed -// or implied warranty. I accept no liability for any -// damage or loss of business that this software may cause. -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef __WIN__ -/////////////////////////////////////////////////////////////////////////////// -// if you are using precompiled headers then include this line: -#include "stdafx.h" -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// if you are not using precompiled headers then include these lines: -//#include -//#include -//#include -/////////////////////////////////////////////////////////////////////////////// - -#include "xgetopt.h" - -/////////////////////////////////////////////////////////////////////////////// -// -// X G e t o p t . c p p -// -// -// NAME -// getopt -- parse command line options -// -// SYNOPSIS -// int getopt(int argc, TCHAR *argv[], TCHAR *optstring) -// -// extern TCHAR *optarg; -// extern int optind; -// -// DESCRIPTION -// The getopt() function parses the command line arguments. Its -// arguments argc and argv are the argument count and array as -// passed into the application on program invocation. In the case -// of Visual C++ programs, argc and argv are available via the -// variables __argc and __argv (double underscores), respectively. -// getopt returns the next option letter in argv that matches a -// letter in optstring. (Note: Unicode programs should use -// __targv instead of __argv. Also, all character and string -// literals should be enclosed in _T( ) ). -// -// optstring is a string of recognized option letters; if a letter -// is followed by a colon, the option is expected to have an argument -// that may or may not be separated from it by white space. optarg -// is set to point to the start of the option argument on return from -// getopt. -// -// Option letters may be combined, e.g., "-ab" is equivalent to -// "-a -b". Option letters are case sensitive. -// -// getopt places in the external variable optind the argv index -// of the next argument to be processed. optind is initialized -// to 0 before the first call to getopt. -// -// When all options have been processed (i.e., up to the first -// non-option argument), getopt returns EOF, optarg will point -// to the argument, and optind will be set to the argv index of -// the argument. If there are no non-option arguments, optarg -// will be set to NULL. -// -// The special option "--" may be used to delimit the end of the -// options; EOF will be returned, and "--" (and everything after it) -// will be skipped. -// -// RETURN VALUE -// For option letters contained in the string optstring, getopt -// will return the option letter. getopt returns a question mark (?) -// when it encounters an option letter not included in optstring. -// EOF is returned when processing is finished. -// -// BUGS -// 1) Long options are not supported. -// 2) The GNU double-colon extension is not supported. -// 3) The environment variable POSIXLY_CORRECT is not supported. -// 4) The + syntax is not supported. -// 5) The automatic permutation of arguments is not supported. -// 6) This implementation of getopt() returns EOF if an error is -// encountered, instead of -1 as the latest standard requires. -// -// EXAMPLE -// BOOL CMyApp::ProcessCommandLine(int argc, TCHAR *argv[]) -// { -// int c; -// -// while ((c = getopt(argc, argv, _T("aBn:"))) != EOF) -// { -// switch (c) -// { -// case _T('a'): -// TRACE(_T("option a\n")); -// // -// // set some flag here -// // -// break; -// -// case _T('B'): -// TRACE( _T("option B\n")); -// // -// // set some other flag here -// // -// break; -// -// case _T('n'): -// TRACE(_T("option n: value=%d\n"), atoi(optarg)); -// // -// // do something with value here -// // -// break; -// -// case _T('?'): -// TRACE(_T("ERROR: illegal option %s\n"), argv[optind-1]); -// return FALSE; -// break; -// -// default: -// TRACE(_T("WARNING: no handler for option %c\n"), c); -// return FALSE; -// break; -// } -// } -// // -// // check for non-option args here -// // -// return TRUE; -// } -// -/////////////////////////////////////////////////////////////////////////////// - -TCHAR *optarg; // global argument pointer -int optind = 0; // global argv index - -int getopt(int argc, TCHAR *argv[], TCHAR *optstring) -{ - static TCHAR *next = NULL; - if (optind == 0) - next = NULL; - - optarg = NULL; - - if (next == NULL || *next == _T('\0')) - { - if (optind == 0) - optind++; - - if (optind >= argc || argv[optind][0] != _T('-') || argv[optind][1] == _T('\0')) - { - optarg = NULL; - if (optind < argc) - optarg = argv[optind]; - return EOF; - } - - if (_tcscmp(argv[optind], _T("--")) == 0) - { - optind++; - optarg = NULL; - if (optind < argc) - optarg = argv[optind]; - return EOF; - } - - next = argv[optind]; - next++; // skip past - - optind++; - } - - TCHAR c = *next++; - TCHAR *cp = _tcschr(optstring, c); - - if (cp == NULL || c == _T(':')) - return _T('?'); - - cp++; - if (*cp == _T(':')) - { - if (*next != _T('\0')) - { - optarg = next; - next = NULL; - } - else if (optind < argc) - { - optarg = argv[optind]; - optind++; - } - else - { - return _T('?'); - } - } - - return c; -} +// XGetopt.cpp Version 1.2 +// +// Author: Hans Dietrich +// hdietrich2@hotmail.com +// url: https://www.codeproject.com/Articles/1940/XGetopt-A-Unix-compatible-getopt-for-MFC-and-Win32 +// +// Description: +// XGetopt.cpp implements getopt(), a function to parse command lines. +// +// History +// Version 1.2 - 2003 May 17 +// - Added Unicode support +// +// Version 1.1 - 2002 March 10 +// - Added example to XGetopt.cpp module header +// +// This software is released into the public domain. +// You are free to use it in any way you like. +// +// This software is provided "as is" with no expressed +// or implied warranty. I accept no liability for any +// damage or loss of business that this software may cause. +// +/////////////////////////////////////////////////////////////////////////////// +#ifdef _MSC_VER +/////////////////////////////////////////////////////////////////////////////// +// if you are using precompiled headers then include this line: +#include "stdafx.h" +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// if you are not using precompiled headers then include these lines: +//#include +//#include +//#include +/////////////////////////////////////////////////////////////////////////////// + +#include "xgetopt.h" + +/////////////////////////////////////////////////////////////////////////////// +// +// X G e t o p t . c p p +// +// +// NAME +// getopt -- parse command line options +// +// SYNOPSIS +// int getopt(int argc, TCHAR *argv[], TCHAR *optstring) +// +// extern TCHAR *optarg; +// extern int optind; +// +// DESCRIPTION +// The getopt() function parses the command line arguments. Its +// arguments argc and argv are the argument count and array as +// passed into the application on program invocation. In the case +// of Visual C++ programs, argc and argv are available via the +// variables __argc and __argv (double underscores), respectively. +// getopt returns the next option letter in argv that matches a +// letter in optstring. (Note: Unicode programs should use +// __targv instead of __argv. Also, all character and string +// literals should be enclosed in _T( ) ). +// +// optstring is a string of recognized option letters; if a letter +// is followed by a colon, the option is expected to have an argument +// that may or may not be separated from it by white space. optarg +// is set to point to the start of the option argument on return from +// getopt. +// +// Option letters may be combined, e.g., "-ab" is equivalent to +// "-a -b". Option letters are case sensitive. +// +// getopt places in the external variable optind the argv index +// of the next argument to be processed. optind is initialized +// to 0 before the first call to getopt. +// +// When all options have been processed (i.e., up to the first +// non-option argument), getopt returns EOF, optarg will point +// to the argument, and optind will be set to the argv index of +// the argument. If there are no non-option arguments, optarg +// will be set to NULL. +// +// The special option "--" may be used to delimit the end of the +// options; EOF will be returned, and "--" (and everything after it) +// will be skipped. +// +// RETURN VALUE +// For option letters contained in the string optstring, getopt +// will return the option letter. getopt returns a question mark (?) +// when it encounters an option letter not included in optstring. +// EOF is returned when processing is finished. +// +// BUGS +// 1) Long options are not supported. +// 2) The GNU double-colon extension is not supported. +// 3) The environment variable POSIXLY_CORRECT is not supported. +// 4) The + syntax is not supported. +// 5) The automatic permutation of arguments is not supported. +// 6) This implementation of getopt() returns EOF if an error is +// encountered, instead of -1 as the latest standard requires. +// +// EXAMPLE +// BOOL CMyApp::ProcessCommandLine(int argc, TCHAR *argv[]) +// { +// int c; +// +// while ((c = getopt(argc, argv, _T("aBn:"))) != EOF) +// { +// switch (c) +// { +// case _T('a'): +// TRACE(_T("option a\n")); +// // +// // set some flag here +// // +// break; +// +// case _T('B'): +// TRACE( _T("option B\n")); +// // +// // set some other flag here +// // +// break; +// +// case _T('n'): +// TRACE(_T("option n: value=%d\n"), atoi(optarg)); +// // +// // do something with value here +// // +// break; +// +// case _T('?'): +// TRACE(_T("ERROR: illegal option %s\n"), argv[optind-1]); +// return FALSE; +// break; +// +// default: +// TRACE(_T("WARNING: no handler for option %c\n"), c); +// return FALSE; +// break; +// } +// } +// // +// // check for non-option args here +// // +// return TRUE; +// } +// +/////////////////////////////////////////////////////////////////////////////// + +TCHAR *optarg; // global argument pointer +int optind = 0; // global argv index + +int getopt(int argc, TCHAR *argv[], TCHAR *optstring) +{ + static TCHAR *next = NULL; + if (optind == 0) + next = NULL; + + optarg = NULL; + + if (next == NULL || *next == _T('\0')) + { + if (optind == 0) + optind++; + + if (optind >= argc || argv[optind][0] != _T('-') || argv[optind][1] == _T('\0')) + { + optarg = NULL; + if (optind < argc) + optarg = argv[optind]; + return EOF; + } + + if (_tcscmp(argv[optind], _T("--")) == 0) + { + optind++; + optarg = NULL; + if (optind < argc) + optarg = argv[optind]; + return EOF; + } + + next = argv[optind]; + next++; // skip past - + optind++; + } + + TCHAR c = *next++; + TCHAR *cp = _tcschr(optstring, c); + + if (cp == NULL || c == _T(':')) + return _T('?'); + + cp++; + if (*cp == _T(':')) + { + if (*next != _T('\0')) + { + optarg = next; + next = NULL; + } + else if (optind < argc) + { + optarg = argv[optind]; + optind++; + } + else + { + return _T('?'); + } + } + + return c; +} #endif \ No newline at end of file diff --git a/src/xgetopt/xgetopt.h b/src/xgetopt/xgetopt.h index 57c630a..8123847 100644 --- a/src/xgetopt/xgetopt.h +++ b/src/xgetopt/xgetopt.h @@ -1,24 +1,24 @@ -#include -// XGetopt.h Version 1.2 -// -// Author: Hans Dietrich -// hdietrich2@hotmail.com -// -// This software is released into the public domain. -// You are free to use it in any way you like. -// -// This software is provided "as is" with no expressed -// or implied warranty. I accept no liability for any -// damage or loss of business that this software may cause. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef XGETOPT_H -#define XGETOPT_H - -extern int optind, opterr; -extern TCHAR *optarg; - -int getopt(int argc, TCHAR *argv[], TCHAR *optstring); - -#endif //XGETOPT_H +#include +// XGetopt.h Version 1.2 +// +// Author: Hans Dietrich +// hdietrich2@hotmail.com +// +// This software is released into the public domain. +// You are free to use it in any way you like. +// +// This software is provided "as is" with no expressed +// or implied warranty. I accept no liability for any +// damage or loss of business that this software may cause. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef XGETOPT_H +#define XGETOPT_H + +extern int optind, opterr; +extern TCHAR *optarg; + +int getopt(int argc, TCHAR *argv[], TCHAR *optstring); + +#endif //XGETOPT_H