Browse Source

added spiffsimg host tools project to msvc build configuration. (#2686)

ziggurat29 5 years ago
parent
commit
5a6992c26a

+ 12 - 0
app/spiffs/spiffs_nucleus.h

@@ -476,6 +476,9 @@ typedef struct {
 
 
 // object structs
+#ifdef _MSC_VER
+#pragma pack ( push, 1 )
+#endif
 
 // page header, part of each page except object lookup pages
 // NB: this is always aligned when the data page is an object index,
@@ -492,8 +495,13 @@ typedef struct SPIFFS_PACKED {
 // object index header page header
 typedef struct SPIFFS_PACKED
 #if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
+#ifdef _MSC_VER
+//Note: the following needs to track the sizeof(spiffs_page_ix), which is defined in spiffs_config.h
+                __declspec( align( 2 ) )
+#else
                 __attribute(( aligned(sizeof(spiffs_page_ix)) ))
 #endif
+#endif
 {
   // common page header
   spiffs_page_header p_hdr;
@@ -517,6 +525,10 @@ typedef struct SPIFFS_PACKED {
  u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
 } spiffs_page_object_ix;
 
+#ifdef _MSC_VER
+#pragma pack ( pop )
+#endif
+
 // callback func for object lookup visitor
 typedef s32_t (*spiffs_visitor_f)(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,
     const void *user_const_p, void *user_var_p);

+ 10 - 0
msvc/hosttools.sln

@@ -5,6 +5,8 @@ VisualStudioVersion = 15.0.28307.168
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luac-cross", "luac-cross\luac-cross.vcxproj", "{78A3411A-A18F-41A4-B4A7-D76B273F0E44}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spiffsimg", "spiffsimg\spiffsimg.vcxproj", "{2DD84C09-254C-4884-A863-456EA1E32DCE}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|x64 = Debug|x64
@@ -21,6 +23,14 @@ Global
 		{78A3411A-A18F-41A4-B4A7-D76B273F0E44}.Release|x64.Build.0 = Release|x64
 		{78A3411A-A18F-41A4-B4A7-D76B273F0E44}.Release|x86.ActiveCfg = Release|Win32
 		{78A3411A-A18F-41A4-B4A7-D76B273F0E44}.Release|x86.Build.0 = Release|Win32
+		{2DD84C09-254C-4884-A863-456EA1E32DCE}.Debug|x64.ActiveCfg = Debug|x64
+		{2DD84C09-254C-4884-A863-456EA1E32DCE}.Debug|x64.Build.0 = Debug|x64
+		{2DD84C09-254C-4884-A863-456EA1E32DCE}.Debug|x86.ActiveCfg = Debug|Win32
+		{2DD84C09-254C-4884-A863-456EA1E32DCE}.Debug|x86.Build.0 = Debug|Win32
+		{2DD84C09-254C-4884-A863-456EA1E32DCE}.Release|x64.ActiveCfg = Release|x64
+		{2DD84C09-254C-4884-A863-456EA1E32DCE}.Release|x64.Build.0 = Release|x64
+		{2DD84C09-254C-4884-A863-456EA1E32DCE}.Release|x86.ActiveCfg = Release|Win32
+		{2DD84C09-254C-4884-A863-456EA1E32DCE}.Release|x86.Build.0 = Release|Win32
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 651 - 0
msvc/spiffsimg/getopt.h

@@ -0,0 +1,651 @@
+#ifndef __GETOPT_H__
+/**
+ * DISCLAIMER
+ * This file is part of the mingw-w64 runtime package.
+ *
+ * The mingw-w64 runtime package and its code is distributed in the hope that it 
+ * will be useful but WITHOUT ANY WARRANTY.  ALL WARRANTIES, EXPRESSED OR 
+ * IMPLIED ARE HEREBY DISCLAIMED.  This includes but is not limited to 
+ * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+ /*
+ * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define __GETOPT_H__
+
+/* All the headers include this file. */
+#include <crtdefs.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <windows.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define	REPLACE_GETOPT		/* use this getopt as the system getopt(3) */
+
+#ifdef REPLACE_GETOPT
+int	opterr = 1;		/* if error message should be printed */
+int	optind = 1;		/* index into parent argv vector */
+int	optopt = '?';		/* character checked for validity */
+#undef	optreset		/* see getopt.h */
+#define	optreset		__mingw_optreset
+int	optreset;		/* reset getopt */
+char    *optarg;		/* argument associated with option */
+#endif
+
+//extern int optind;		/* index of first non-option in argv      */
+//extern int optopt;		/* single option character, as parsed     */
+//extern int opterr;		/* flag to enable built-in diagnostics... */
+//				/* (user may set to zero, to suppress)    */
+//
+//extern char *optarg;		/* pointer to argument of current option  */
+
+#define PRINT_ERROR	((opterr) && (*options != ':'))
+
+#define FLAG_PERMUTE	0x01	/* permute non-options to the end of argv */
+#define FLAG_ALLARGS	0x02	/* treat non-options as args to option "-1" */
+#define FLAG_LONGONLY	0x04	/* operate as getopt_long_only */
+
+/* return values */
+#define	BADCH		(int)'?'
+#define	BADARG		((*options == ':') ? (int)':' : (int)'?')
+#define	INORDER 	(int)1
+
+#ifndef __CYGWIN__
+#define __progname __argv[0]
+#else
+extern char __declspec(dllimport) *__progname;
+#endif
+
+#ifdef __CYGWIN__
+static char EMSG[] = "";
+#else
+#define	EMSG		""
+#endif
+
+static int getopt_internal(int, char * const *, const char *,
+			   const struct option *, int *, int);
+static int parse_long_options(char * const *, const char *,
+			      const struct option *, int *, int);
+static int gcd(int, int);
+static void permute_args(int, int, int, char * const *);
+
+static char *place = EMSG; /* option letter processing */
+
+/* XXX: set optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1;   /* first option after non options (for permute) */
+
+/* Error messages */
+static const char recargchar[] = "option requires an argument -- %c";
+static const char recargstring[] = "option requires an argument -- %s";
+static const char ambig[] = "ambiguous option -- %.*s";
+static const char noarg[] = "option doesn't take an argument -- %.*s";
+static const char illoptchar[] = "unknown option -- %c";
+static const char illoptstring[] = "unknown option -- %s";
+
+static void
+_vwarnx(const char *fmt,va_list ap)
+{
+  (void)fprintf(stderr,"%s: ",__progname);
+  if (fmt != NULL)
+    (void)vfprintf(stderr,fmt,ap);
+  (void)fprintf(stderr,"\n");
+}
+
+static void
+warnx(const char *fmt,...)
+{
+  va_list ap;
+  va_start(ap,fmt);
+  _vwarnx(fmt,ap);
+  va_end(ap);
+}
+
+/*
+ * Compute the greatest common divisor of a and b.
+ */
+static int
+gcd(int a, int b)
+{
+	int c;
+
+	c = a % b;
+	while (c != 0) {
+		a = b;
+		b = c;
+		c = a % b;
+	}
+
+	return (b);
+}
+
+/*
+ * Exchange the block from nonopt_start to nonopt_end with the block
+ * from nonopt_end to opt_end (keeping the same order of arguments
+ * in each block).
+ */
+static void
+permute_args(int panonopt_start, int panonopt_end, int opt_end,
+	char * const *nargv)
+{
+	int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+	char *swap;
+
+	/*
+	 * compute lengths of blocks and number and size of cycles
+	 */
+	nnonopts = panonopt_end - panonopt_start;
+	nopts = opt_end - panonopt_end;
+	ncycle = gcd(nnonopts, nopts);
+	cyclelen = (opt_end - panonopt_start) / ncycle;
+
+	for (i = 0; i < ncycle; i++) {
+		cstart = panonopt_end+i;
+		pos = cstart;
+		for (j = 0; j < cyclelen; j++) {
+			if (pos >= panonopt_end)
+				pos -= nnonopts;
+			else
+				pos += nopts;
+			swap = nargv[pos];
+			/* LINTED const cast */
+			((char **) nargv)[pos] = nargv[cstart];
+			/* LINTED const cast */
+			((char **)nargv)[cstart] = swap;
+		}
+	}
+}
+
+#ifdef REPLACE_GETOPT
+/*
+ * getopt --
+ *	Parse argc/argv argument vector.
+ *
+ * [eventually this will replace the BSD getopt]
+ */
+int
+getopt(int nargc, char * const *nargv, const char *options)
+{
+
+	/*
+	 * We don't pass FLAG_PERMUTE to getopt_internal() since
+	 * the BSD getopt(3) (unlike GNU) has never done this.
+	 *
+	 * Furthermore, since many privileged programs call getopt()
+	 * before dropping privileges it makes sense to keep things
+	 * as simple (and bug-free) as possible.
+	 */
+	return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
+}
+#endif /* REPLACE_GETOPT */
+
+//extern int getopt(int nargc, char * const *nargv, const char *options);
+
+#ifdef _BSD_SOURCE
+/*
+ * BSD adds the non-standard `optreset' feature, for reinitialisation
+ * of `getopt' parsing.  We support this feature, for applications which
+ * proclaim their BSD heritage, before including this header; however,
+ * to maintain portability, developers are advised to avoid it.
+ */
+# define optreset  __mingw_optreset
+extern int optreset;
+#endif
+#ifdef __cplusplus
+}
+#endif
+/*
+ * POSIX requires the `getopt' API to be specified in `unistd.h';
+ * thus, `unistd.h' includes this header.  However, we do not want
+ * to expose the `getopt_long' or `getopt_long_only' APIs, when
+ * included in this manner.  Thus, close the standard __GETOPT_H__
+ * declarations block, and open an additional __GETOPT_LONG_H__
+ * specific block, only when *not* __UNISTD_H_SOURCED__, in which
+ * to declare the extended API.
+ */
+#endif /* !defined(__GETOPT_H__) */
+
+#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
+#define __GETOPT_LONG_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct option		/* specification for a long form option...	*/
+{
+  const char *name;		/* option name, without leading hyphens */
+  int         has_arg;		/* does it take an argument?		*/
+  int        *flag;		/* where to save its status, or NULL	*/
+  int         val;		/* its associated status value		*/
+};
+
+enum    		/* permitted values for its `has_arg' field...	*/
+{
+  no_argument = 0,      	/* option never takes an argument	*/
+  required_argument,		/* option always requires an argument	*/
+  optional_argument		/* option may take an argument		*/
+};
+
+/*
+ * parse_long_options --
+ *	Parse long options in argc/argv argument vector.
+ * Returns -1 if short_too is set and the option does not match long_options.
+ */
+static int
+parse_long_options(char * const *nargv, const char *options,
+	const struct option *long_options, int *idx, int short_too)
+{
+	char *current_argv, *has_equal;
+	size_t current_argv_len;
+	int i, ambiguous, match;
+
+#define IDENTICAL_INTERPRETATION(_x, _y)                                \
+	(long_options[(_x)].has_arg == long_options[(_y)].has_arg &&    \
+	 long_options[(_x)].flag == long_options[(_y)].flag &&          \
+	 long_options[(_x)].val == long_options[(_y)].val)
+
+	current_argv = place;
+	match = -1;
+	ambiguous = 0;
+
+	optind++;
+
+	if ((has_equal = strchr(current_argv, '=')) != NULL) {
+		/* argument found (--option=arg) */
+		current_argv_len = has_equal - current_argv;
+		has_equal++;
+	} else
+		current_argv_len = strlen(current_argv);
+
+	for (i = 0; long_options[i].name; i++) {
+		/* find matching long option */
+		if (strncmp(current_argv, long_options[i].name,
+		    current_argv_len))
+			continue;
+
+		if (strlen(long_options[i].name) == current_argv_len) {
+			/* exact match */
+			match = i;
+			ambiguous = 0;
+			break;
+		}
+		/*
+		 * If this is a known short option, don't allow
+		 * a partial match of a single character.
+		 */
+		if (short_too && current_argv_len == 1)
+			continue;
+
+		if (match == -1)	/* partial match */
+			match = i;
+		else if (!IDENTICAL_INTERPRETATION(i, match))
+			ambiguous = 1;
+	}
+	if (ambiguous) {
+		/* ambiguous abbreviation */
+		if (PRINT_ERROR)
+			warnx(ambig, (int)current_argv_len,
+			     current_argv);
+		optopt = 0;
+		return (BADCH);
+	}
+	if (match != -1) {		/* option found */
+		if (long_options[match].has_arg == no_argument
+		    && has_equal) {
+			if (PRINT_ERROR)
+				warnx(noarg, (int)current_argv_len,
+				     current_argv);
+			/*
+			 * XXX: GNU sets optopt to val regardless of flag
+			 */
+			if (long_options[match].flag == NULL)
+				optopt = long_options[match].val;
+			else
+				optopt = 0;
+			return (BADARG);
+		}
+		if (long_options[match].has_arg == required_argument ||
+		    long_options[match].has_arg == optional_argument) {
+			if (has_equal)
+				optarg = has_equal;
+			else if (long_options[match].has_arg ==
+			    required_argument) {
+				/*
+				 * optional argument doesn't use next nargv
+				 */
+				optarg = nargv[optind++];
+			}
+		}
+		if ((long_options[match].has_arg == required_argument)
+		    && (optarg == NULL)) {
+			/*
+			 * Missing argument; leading ':' indicates no error
+			 * should be generated.
+			 */
+			if (PRINT_ERROR)
+				warnx(recargstring,
+				    current_argv);
+			/*
+			 * XXX: GNU sets optopt to val regardless of flag
+			 */
+			if (long_options[match].flag == NULL)
+				optopt = long_options[match].val;
+			else
+				optopt = 0;
+			--optind;
+			return (BADARG);
+		}
+	} else {			/* unknown option */
+		if (short_too) {
+			--optind;
+			return (-1);
+		}
+		if (PRINT_ERROR)
+			warnx(illoptstring, current_argv);
+		optopt = 0;
+		return (BADCH);
+	}
+	if (idx)
+		*idx = match;
+	if (long_options[match].flag) {
+		*long_options[match].flag = long_options[match].val;
+		return (0);
+	} else
+		return (long_options[match].val);
+#undef IDENTICAL_INTERPRETATION
+}
+
+/*
+ * getopt_internal --
+ *	Parse argc/argv argument vector.  Called by user level routines.
+ */
+static int
+getopt_internal(int nargc, char * const *nargv, const char *options,
+	const struct option *long_options, int *idx, int flags)
+{
+	char *oli;				/* option letter list index */
+	int optchar, short_too;
+	static int posixly_correct = -1;
+
+	if (options == NULL)
+		return (-1);
+
+	/*
+	 * XXX Some GNU programs (like cvs) set optind to 0 instead of
+	 * XXX using optreset.  Work around this braindamage.
+	 */
+	if (optind == 0)
+		optind = optreset = 1;
+
+	/*
+	 * Disable GNU extensions if POSIXLY_CORRECT is set or options
+	 * string begins with a '+'.
+	 *
+	 * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
+	 *                 optreset != 0 for GNU compatibility.
+	 */
+	if (posixly_correct == -1 || optreset != 0)
+		posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
+	if (*options == '-')
+		flags |= FLAG_ALLARGS;
+	else if (posixly_correct || *options == '+')
+		flags &= ~FLAG_PERMUTE;
+	if (*options == '+' || *options == '-')
+		options++;
+
+	optarg = NULL;
+	if (optreset)
+		nonopt_start = nonopt_end = -1;
+start:
+	if (optreset || !*place) {		/* update scanning pointer */
+		optreset = 0;
+		if (optind >= nargc) {          /* end of argument vector */
+			place = EMSG;
+			if (nonopt_end != -1) {
+				/* do permutation, if we have to */
+				permute_args(nonopt_start, nonopt_end,
+				    optind, nargv);
+				optind -= nonopt_end - nonopt_start;
+			}
+			else if (nonopt_start != -1) {
+				/*
+				 * If we skipped non-options, set optind
+				 * to the first of them.
+				 */
+				optind = nonopt_start;
+			}
+			nonopt_start = nonopt_end = -1;
+			return (-1);
+		}
+		if (*(place = nargv[optind]) != '-' ||
+		    (place[1] == '\0' && strchr(options, '-') == NULL)) {
+			place = EMSG;		/* found non-option */
+			if (flags & FLAG_ALLARGS) {
+				/*
+				 * GNU extension:
+				 * return non-option as argument to option 1
+				 */
+				optarg = nargv[optind++];
+				return (INORDER);
+			}
+			if (!(flags & FLAG_PERMUTE)) {
+				/*
+				 * If no permutation wanted, stop parsing
+				 * at first non-option.
+				 */
+				return (-1);
+			}
+			/* do permutation */
+			if (nonopt_start == -1)
+				nonopt_start = optind;
+			else if (nonopt_end != -1) {
+				permute_args(nonopt_start, nonopt_end,
+				    optind, nargv);
+				nonopt_start = optind -
+				    (nonopt_end - nonopt_start);
+				nonopt_end = -1;
+			}
+			optind++;
+			/* process next argument */
+			goto start;
+		}
+		if (nonopt_start != -1 && nonopt_end == -1)
+			nonopt_end = optind;
+
+		/*
+		 * If we have "-" do nothing, if "--" we are done.
+		 */
+		if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
+			optind++;
+			place = EMSG;
+			/*
+			 * We found an option (--), so if we skipped
+			 * non-options, we have to permute.
+			 */
+			if (nonopt_end != -1) {
+				permute_args(nonopt_start, nonopt_end,
+				    optind, nargv);
+				optind -= nonopt_end - nonopt_start;
+			}
+			nonopt_start = nonopt_end = -1;
+			return (-1);
+		}
+	}
+
+	/*
+	 * Check long options if:
+	 *  1) we were passed some
+	 *  2) the arg is not just "-"
+	 *  3) either the arg starts with -- we are getopt_long_only()
+	 */
+	if (long_options != NULL && place != nargv[optind] &&
+	    (*place == '-' || (flags & FLAG_LONGONLY))) {
+		short_too = 0;
+		if (*place == '-')
+			place++;		/* --foo long option */
+		else if (*place != ':' && strchr(options, *place) != NULL)
+			short_too = 1;		/* could be short option too */
+
+		optchar = parse_long_options(nargv, options, long_options,
+		    idx, short_too);
+		if (optchar != -1) {
+			place = EMSG;
+			return (optchar);
+		}
+	}
+
+	if ((optchar = (int)*place++) == (int)':' ||
+	    (optchar == (int)'-' && *place != '\0') ||
+	    (oli = (char*)strchr(options, optchar)) == NULL) {
+		/*
+		 * If the user specified "-" and  '-' isn't listed in
+		 * options, return -1 (non-option) as per POSIX.
+		 * Otherwise, it is an unknown option character (or ':').
+		 */
+		if (optchar == (int)'-' && *place == '\0')
+			return (-1);
+		if (!*place)
+			++optind;
+		if (PRINT_ERROR)
+			warnx(illoptchar, optchar);
+		optopt = optchar;
+		return (BADCH);
+	}
+	if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
+		/* -W long-option */
+		if (*place)			/* no space */
+			/* NOTHING */;
+		else if (++optind >= nargc) {	/* no arg */
+			place = EMSG;
+			if (PRINT_ERROR)
+				warnx(recargchar, optchar);
+			optopt = optchar;
+			return (BADARG);
+		} else				/* white space */
+			place = nargv[optind];
+		optchar = parse_long_options(nargv, options, long_options,
+		    idx, 0);
+		place = EMSG;
+		return (optchar);
+	}
+	if (*++oli != ':') {			/* doesn't take argument */
+		if (!*place)
+			++optind;
+	} else {				/* takes (optional) argument */
+		optarg = NULL;
+		if (*place)			/* no white space */
+			optarg = place;
+		else if (oli[1] != ':') {	/* arg not optional */
+			if (++optind >= nargc) {	/* no arg */
+				place = EMSG;
+				if (PRINT_ERROR)
+					warnx(recargchar, optchar);
+				optopt = optchar;
+				return (BADARG);
+			} else
+				optarg = nargv[optind];
+		}
+		place = EMSG;
+		++optind;
+	}
+	/* dump back option letter */
+	return (optchar);
+}
+
+/*
+ * getopt_long --
+ *	Parse argc/argv argument vector.
+ */
+int
+getopt_long(int nargc, char * const *nargv, const char *options,
+    const struct option *long_options, int *idx)
+{
+
+	return (getopt_internal(nargc, nargv, options, long_options, idx,
+	    FLAG_PERMUTE));
+}
+
+/*
+ * getopt_long_only --
+ *	Parse argc/argv argument vector.
+ */
+int
+getopt_long_only(int nargc, char * const *nargv, const char *options,
+    const struct option *long_options, int *idx)
+{
+
+	return (getopt_internal(nargc, nargv, options, long_options, idx,
+	    FLAG_PERMUTE|FLAG_LONGONLY));
+}
+
+//extern int getopt_long(int nargc, char * const *nargv, const char *options,
+//    const struct option *long_options, int *idx);
+//extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
+//    const struct option *long_options, int *idx);
+/*
+ * Previous MinGW implementation had...
+ */
+#ifndef HAVE_DECL_GETOPT
+/*
+ * ...for the long form API only; keep this for compatibility.
+ */
+# define HAVE_DECL_GETOPT	1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */

+ 207 - 0
msvc/spiffsimg/spiffsimg.vcxproj

@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <VCProjectVersion>15.0</VCProjectVersion>
+    <ProjectGuid>{2DD84C09-254C-4884-A863-456EA1E32DCE}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>spiffsimg</RootNamespace>
+    <WindowsTargetPlatformVersion>7.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141_xp</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141_xp</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141_xp</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141_xp</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+    <OutDir>$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
+    <IntDir>$(ProjectDir)$(Platform)\$(Configuration)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+    <OutDir>$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
+    <IntDir>$(ProjectDir)$(Platform)\$(Configuration)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <OutDir>$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
+    <IntDir>$(ProjectDir)$(Platform)\$(Configuration)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+    <OutDir>$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
+    <IntDir>$(ProjectDir)$(Platform)\$(Configuration)\</IntDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>NODEMCU_SPIFFS_NO_INCLUDE;dbg_printf=printf;_CRT_SECURE_NO_WARNINGS;_CONSOLE;_DEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <AdditionalIncludeDirectories>$(ProjectDir)\..\..\app\include;$(ProjectDir)\..\..\app\spiffs;$(ProjectDir)</AdditionalIncludeDirectories>
+      <ForcedIncludeFiles>$(ProjectDir)\..\..\tools\spiffsimg\spiffs_typedefs.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <GenerateMapFile>true</GenerateMapFile>
+      <AdditionalDependencies>setargv.obj;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>NODEMCU_SPIFFS_NO_INCLUDE;dbg_printf=printf;_CRT_SECURE_NO_WARNINGS;_CONSOLE;_DEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <AdditionalIncludeDirectories>$(ProjectDir)\..\..\app\include;$(ProjectDir)\..\..\app\spiffs;$(ProjectDir)</AdditionalIncludeDirectories>
+      <ForcedIncludeFiles>$(ProjectDir)\..\..\tools\spiffsimg\spiffs_typedefs.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <GenerateMapFile>true</GenerateMapFile>
+      <AdditionalDependencies>setargv.obj;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>NODEMCU_SPIFFS_NO_INCLUDE;dbg_printf=printf;_CRT_SECURE_NO_WARNINGS;_CONSOLE;NDEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <AdditionalIncludeDirectories>$(ProjectDir)\..\..\app\include;$(ProjectDir)\..\..\app\spiffs;$(ProjectDir)</AdditionalIncludeDirectories>
+      <ForcedIncludeFiles>$(ProjectDir)\..\..\tools\spiffsimg\spiffs_typedefs.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <GenerateMapFile>true</GenerateMapFile>
+      <AdditionalDependencies>setargv.obj;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>NODEMCU_SPIFFS_NO_INCLUDE;dbg_printf=printf;_CRT_SECURE_NO_WARNINGS;_CONSOLE;NDEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <AdditionalIncludeDirectories>$(ProjectDir)\..\..\app\include;$(ProjectDir)\..\..\app\spiffs;$(ProjectDir)</AdditionalIncludeDirectories>
+      <ForcedIncludeFiles>$(ProjectDir)\..\..\tools\spiffsimg\spiffs_typedefs.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <GenerateMapFile>true</GenerateMapFile>
+      <AdditionalDependencies>setargv.obj;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\app\spiffs\spiffs_cache.c" />
+    <ClCompile Include="..\..\app\spiffs\spiffs_check.c" />
+    <ClCompile Include="..\..\app\spiffs\spiffs_gc.c" />
+    <ClCompile Include="..\..\app\spiffs\spiffs_hydrogen.c" />
+    <ClCompile Include="..\..\app\spiffs\spiffs_nucleus.c" />
+    <ClCompile Include="..\..\tools\spiffsimg\main.c">
+      <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4996</DisableSpecificWarnings>
+      <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">4996</DisableSpecificWarnings>
+      <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4996</DisableSpecificWarnings>
+      <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4996</DisableSpecificWarnings>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\app\include\user_config.h" />
+    <ClInclude Include="..\..\app\platform\cpu_esp8266.h" />
+    <ClInclude Include="..\..\app\spiffs\nodemcu_spiffs.h" />
+    <ClInclude Include="..\..\app\spiffs\spiffs.h" />
+    <ClInclude Include="..\..\app\spiffs\spiffs_config.h" />
+    <ClInclude Include="..\..\app\spiffs\spiffs_nucleus.h" />
+    <ClInclude Include="..\..\tools\spiffsimg\spiffs_typedefs.h" />
+    <ClInclude Include="getopt.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 81 - 0
msvc/spiffsimg/spiffsimg.vcxproj.filters

@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+    <Filter Include="tools">
+      <UniqueIdentifier>{cc72cbf7-30a4-4c62-9413-509516a67c12}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="tools\spiffsimg">
+      <UniqueIdentifier>{2796bdda-1fd8-4088-8d4e-41fdd71d5170}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="app">
+      <UniqueIdentifier>{ba2fdaa9-bc69-4fb5-b789-9d2b46d7fd31}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="app\spiffs">
+      <UniqueIdentifier>{d6547699-189a-45e8-82d8-4af0a0b4cfd7}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="app\include">
+      <UniqueIdentifier>{131db3e8-d55b-4d0a-810b-ae33c5e41bb3}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="app\platform">
+      <UniqueIdentifier>{184f25b5-aca7-476f-981f-16d7a8294ca7}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\tools\spiffsimg\main.c">
+      <Filter>tools\spiffsimg</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\app\spiffs\spiffs_cache.c">
+      <Filter>app\spiffs</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\app\spiffs\spiffs_check.c">
+      <Filter>app\spiffs</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\app\spiffs\spiffs_gc.c">
+      <Filter>app\spiffs</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\app\spiffs\spiffs_hydrogen.c">
+      <Filter>app\spiffs</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\app\spiffs\spiffs_nucleus.c">
+      <Filter>app\spiffs</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\tools\spiffsimg\spiffs_typedefs.h">
+      <Filter>tools\spiffsimg</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\app\spiffs\spiffs.h">
+      <Filter>app\spiffs</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\app\spiffs\spiffs_nucleus.h">
+      <Filter>app\spiffs</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\app\spiffs\spiffs_config.h">
+      <Filter>app\spiffs</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\app\spiffs\nodemcu_spiffs.h">
+      <Filter>app\spiffs</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\app\include\user_config.h">
+      <Filter>app\include</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\app\platform\cpu_esp8266.h">
+      <Filter>app\platform</Filter>
+    </ClInclude>
+    <ClInclude Include="getopt.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>

+ 501 - 456
tools/spiffsimg/main.c

@@ -1,456 +1,501 @@
-/*
- * Copyright 2015 Dius Computing Pty Ltd. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the
- *   distribution.
- * - Neither the name of the copyright holders nor the names of
- *   its contributors may be used to endorse or promote products derived
- *   from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @author Johny Mattsson <jmattsson@dius.com.au>
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include "spiffs.h"
-#define NO_CPU_ESP8266_INCLUDE
-#include "../platform/cpu_esp8266.h"
-
-static spiffs fs;
-static uint8_t *flash;
-
-static int retcode = 0;
-
-#define LOG_PAGE_SIZE 256
-
-// If the caclulated size is this or less, then use smaller blocks
-// (1 page) rather than the normal 2 pages. This gives a little bit
-// more flexibility for the file system, at the expense of a bit of
-// efficiency
-#define SMALL_FILESYSTEM	(128 * 1024)
-
-static int delete_on_die = 0;
-static const char *delete_list[10];
-static int delete_list_index = 0;
-
-static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2];
-static u8_t spiffs_fds[32*4];
-
-static s32_t flash_read (u32_t addr, u32_t size, u8_t *dst) {
-  memcpy (dst, flash + addr, size);
-  return SPIFFS_OK;
-}
-
-static s32_t flash_write (u32_t addr, u32_t size, u8_t *src) {
-  memcpy (flash + addr, src, size);
-  return SPIFFS_OK;
-}
-
-static s32_t flash_erase (u32_t addr, u32_t size) {
-  memset (flash + addr, 0xff, size);
-  return SPIFFS_OK;
-}
-
-
-static void die (const char *what)
-{
-  if (errno == 0) {
-    fprintf(stderr, "%s: fatal error\n", what);
-  } else {
-    perror (what);
-  }
-  if (delete_on_die) {
-    const char **p = delete_list;
-    while (*p) {
-      unlink(*p);
-      p++;
-    }
-  }
-  exit (1);
-}
-
-
-static void list (void)
-{
-  spiffs_DIR dir;
-  if (!SPIFFS_opendir (&fs, "/", &dir))
-    die ("spiffs_opendir");
-  struct spiffs_dirent de;
-  while (SPIFFS_readdir (&dir, &de))
-  {
-    static const char types[] = "?fdhs"; // file, dir, hardlink, softlink
-    char name[sizeof(de.name)+1] = { 0 };
-    memcpy (name, de.name, sizeof(de.name));
-    printf("%c %6u %s\n", types[de.type], de.size, name);
-  }
-  SPIFFS_closedir (&dir);
-}
-
-
-static void cat (char *fname)
-{
-  spiffs_file fh = SPIFFS_open (&fs, fname, SPIFFS_RDONLY, 0);
-  char buff[512];
-  s32_t n;
-  while ((n = SPIFFS_read (&fs, fh, buff, sizeof (buff))) > 0)
-    write (STDOUT_FILENO, buff, n);
-  SPIFFS_close (&fs, fh);
-}
-
-
-static void import (char *src, char *dst)
-{
-  int fd = open (src, O_RDONLY);
-  if (fd < 0)
-    die (src);
-
-  spiffs_file fh = SPIFFS_open (&fs, dst, SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_WRONLY, 0);
-  if (fh < 0)
-    die ("spiffs_open");
-
-  char buff[16384];
-  s32_t n;
-  while ((n = read (fd, buff, sizeof (buff))) > 0)
-    if (SPIFFS_write (&fs, fh, buff, n) < 0)
-      die ("spiffs_write");
-
-  if (SPIFFS_close (&fs, fh) < 0)
-    die("spiffs_close");
-  close (fd);
-}
-
-
-static void export (char *src, char *dst)
-{
-  spiffs_file fh = SPIFFS_open (&fs, src, SPIFFS_RDONLY, 0);
-  if (fh < 0)
-    die ("spiffs_open");
-
-  int fd = open (dst, O_CREAT | O_TRUNC | O_WRONLY, 0664);
-  if (fd < 0)
-    die (dst);
-
-  char buff[512];
-  s32_t n;
-  while ((n = SPIFFS_read (&fs, fh, buff, sizeof (buff))) > 0)
-    if (write (fd, buff, n) < 0)
-      die ("write");
-
-  SPIFFS_close (&fs, fh);
-  close (fd);
-}
-
-
-char *trim (char *in)
-{
-  if (!in)
-    return "";
-
-  char *out = 0;
-  while (*in)
-  {
-    if (!out && !isspace (*in))
-      out = in;
-    ++in;
-  }
-  if (!out)
-    return "";
-  while (--in > out && isspace (*in))
-    ;
-  in[1] = 0;
-  return out;
-}
-
-
-void syntax (void)
-{
-  fprintf (stderr,
-    "Syntax: spiffsimg -f <filename> [-d] [-o <locationfilename>] [-c size] [-S flashsize] [-U usedsize] [-l | -i | -r <scriptname> ]\n\n"
-  );
-  exit (1);
-}
-
-static size_t getsize(const char *s)
-{
-  char *end = 0;
-  size_t val = strtoul(s, &end, 0);
-
-  if (end) {
-    int factor;
-    if (*end == 'k' || *end == 'K') {
-      factor = 1 << 10;
-      end++;
-    } else if (*end == 'm' || *end == 'M') {
-      factor = 1 << 20;
-      end++;
-    } else {
-      factor = 1;
-    }
-    // Capital B is bytes
-    if (*end == 'B') {
-      factor = factor << 3;
-    }
-    // we want bytes
-    val = (val * factor) / 8;
-  }
-
-  return val;
-}
-
-int main (int argc, char *argv[])
-{
-  if (argc == 1)
-    syntax ();
-
-  int opt;
-  const char *fname = 0;
-  bool create = false;
-  enum { CMD_NONE, CMD_LIST, CMD_INTERACTIVE, CMD_SCRIPT } command = CMD_NONE;
-  int sz = 0;
-  const char *script_name = 0;
-  const char *resolved = 0;
-  int flashsize = 0;
-  int used = 0;
-  while ((opt = getopt (argc, argv, "do:f:c:lir:S:U:")) != -1)
-  {
-    switch (opt)
-    {
-      case 'f': fname = optarg; break;
-      case 'o': resolved = optarg; break;
-      case 'c': create = true; sz = strtol(optarg, 0, 0); break;
-      case 'S': create = true; flashsize = getsize(optarg); break;
-      case 'U': create = true; used = strtol(optarg, 0, 0); break;
-      case 'd': delete_on_die = 1; break;
-      case 'l': command = CMD_LIST; break;
-      case 'i': command = CMD_INTERACTIVE; break;
-      case 'r': command = CMD_SCRIPT; script_name = optarg; break;
-      default: die ("unknown option");
-    }
-  }
-
-  if (!fname) {
-    die("Need a filename");
-  }
-
-  int fd;
-
-  if (create)
-  {
-    if (!sz) {
-      if (!flashsize || !used) {
-	die("Missing flashSize or Used");
-      }
-      sz = flashsize - used - SYS_PARAM_SEC_NUM * 4096;   // This leaves space for the parameter area
-      if (sz < 0x4000) {
-	die("Not enough space");
-      }
-      if (sz > SMALL_FILESYSTEM) {
-	used = (used + 0xffff) & ~0xffff;
-      } else {
-	used = (used + 0x1fff) & ~0x1fff;
-      }
-      sz = flashsize - used - SYS_PARAM_SEC_NUM * 4096;
-    }
-    sz &= ~(0x1fff);
-
-    if (used == 0) {
-      if (strchr(fname, '%')) {
-	die("Unable to calculate where to put the flash image, and % present in filename");
-      }
-    }
-
-    char fnamebuff[1024];
-
-    sprintf(fnamebuff, fname, used);
-
-    delete_list[delete_list_index++] = strdup(fnamebuff);;
-    fd = open (fnamebuff, (create ? (O_CREAT | O_TRUNC) : 0) | O_RDWR, 0664);
-    if (fd == -1)
-      die ("open");
-
-    if (resolved) {
-      delete_list[delete_list_index++] = resolved;
-      FILE *f = fopen(resolved, "w");
-      fprintf(f, "0x%x", used);
-      fclose(f);
-    }
-
-    if (lseek (fd, sz -1, SEEK_SET) == -1)
-      die ("lseek");
-    if (write (fd, "", 1) != 1)
-      die ("write");
-  }
-  else {
-    fd = open (fname, O_RDWR, 0664);
-    if (fd == -1)
-      die ("open");
-
-    if (!sz)
-    {
-      off_t offs = lseek (fd, 0, SEEK_END);
-      if (offs == -1)
-	die ("lseek");
-      sz = offs;
-    }
-  }
-
-  if (sz & (0x1000 -1))
-    die ("file size not multiple of erase block size");
-
-  flash = mmap (0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-  if (!flash)
-    die ("mmap");
-
-  if (create)
-    memset (flash, 0xff, sz);
-
-  spiffs_config cfg;
-  cfg.phys_size = sz;
-  cfg.phys_addr = 0;
-  cfg.phys_erase_block = 0x1000;
-  cfg.log_block_size = 0x1000 * (sz > SMALL_FILESYSTEM ? 2 : 1);
-  cfg.log_page_size = LOG_PAGE_SIZE;
-  cfg.hal_read_f = flash_read;
-  cfg.hal_write_f = flash_write;
-  cfg.hal_erase_f = flash_erase;
-  if (cfg.phys_size < 4 * cfg.log_block_size) {
-    die("disk not large enough for four blocks");
-  }
-
-  if (SPIFFS_mount (&fs, &cfg,
-      spiffs_work_buf,
-      spiffs_fds,
-      sizeof(spiffs_fds),
-      malloc(65536), 65536, 0) != 0) {
-    if (create) {
-      if (SPIFFS_format(&fs) != 0) {
-        die("spiffs_format");
-      }
-      if (SPIFFS_mount (&fs, &cfg,
-          spiffs_work_buf,
-          spiffs_fds,
-          sizeof(spiffs_fds),
-          malloc(65536), 65536, 0) != 0) {
-        die ("spiffs_mount");
-      }
-      if (command == CMD_INTERACTIVE) {
-	printf("Created filesystem -- size 0x%x, block_size=%d\n", cfg.phys_size, cfg.log_block_size);
-      }
-    } else {
-      die ("spiffs_mount");
-    }
-  }
-
-  if (command == CMD_NONE)
-    ; // maybe just wanted to create an empty image?
-  else if (command == CMD_LIST)
-    list ();
-  else
-  {
-    FILE *in = (command == CMD_INTERACTIVE) ? stdin : fopen (script_name, "r");
-    if (!in)
-      die ("fopen");
-    char buff[128] = { 0 };
-    if (in == stdin)
-      printf("> ");
-    while (fgets (buff, sizeof (buff) -1, in))
-    {
-      char *line = trim (buff);
-      if (!line[0] || line[0] == '#')
-        continue;
-      if (strcmp (line, "ls") == 0)
-        list ();
-      else if (strncmp (line, "import ", 7) == 0)
-      {
-        char *src = 0, *dst = 0;
-        if (sscanf (line +7, " %ms %ms", &src, &dst) != 2)
-        {
-          fprintf (stderr, "SYNTAX ERROR: %s\n", line);
-          retcode = 1;
-        }
-        else
-          import (src, dst);
-        free (src);
-        free (dst);
-      }
-      else if (strncmp (line, "export ", 7) == 0)
-      {
-        char *src = 0, *dst = 0;
-        if (sscanf (line + 7, " %ms %ms", &src, &dst) != 2)
-        {
-          fprintf (stderr, "SYNTAX ERROR: %s\n", line);
-          retcode = 1;
-        }
-        else
-          export (src, dst);
-        free (src);
-        free (dst);
-      }
-      else if (strncmp (line, "rm ", 3) == 0)
-      {
-        if (SPIFFS_remove (&fs, trim (line + 3)) < 0)
-        {
-          fprintf (stderr, "FAILED: %s\n", line);
-          retcode = 1;
-        }
-      }
-      else if (strncmp (line, "cat ", 4) == 0)
-        cat (trim (line + 4));
-      else if (strncmp (line, "info", 4) == 0)
-      {
-        u32_t total, used;
-        if (SPIFFS_info (&fs, &total, &used) < 0)
-        {
-          fprintf (stderr, "FAILED: %s\n", line);
-          retcode = 1;
-        }
-        else
-          printf ("Total: %u, Used: %u\n", total, used);
-      }
-      else
-      {
-        printf ("SYNTAX ERROR: %s\n", line);
-        retcode = 1;
-      }
-
-      if (in == stdin)
-        printf ("> ");
-    }
-    if (in == stdin)
-      printf ("\n");
-  }
-
-  SPIFFS_unmount (&fs);
-  munmap (flash, sz);
-  close (fd);
-  return retcode;
-}
+/*
+ * Copyright 2015 Dius Computing Pty Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the
+ *   distribution.
+ * - Neither the name of the copyright holders nor the names of
+ *   its contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @author Johny Mattsson <jmattsson@dius.com.au>
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#ifdef _MSC_VER
+#include "getopt.h"		/* local copy from MingW project */
+#include <io.h>
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+typedef ptrdiff_t off_t;
+#else
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/mman.h>
+#endif
+#include <fcntl.h>
+#include <errno.h>
+#include "spiffs.h"
+#define NO_CPU_ESP8266_INCLUDE
+#include "../platform/cpu_esp8266.h"
+
+static spiffs fs;
+static uint8_t *flash;
+
+static int retcode = 0;
+
+#define LOG_PAGE_SIZE 256
+
+// If the caclulated size is this or less, then use smaller blocks
+// (1 page) rather than the normal 2 pages. This gives a little bit
+// more flexibility for the file system, at the expense of a bit of
+// efficiency
+#define SMALL_FILESYSTEM	(128 * 1024)
+
+static int delete_on_die = 0;
+static const char *delete_list[10];
+static int delete_list_index = 0;
+
+static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2];
+static u8_t spiffs_fds[32*4];
+
+static s32_t flash_read (u32_t addr, u32_t size, u8_t *dst) {
+  memcpy (dst, flash + addr, size);
+  return SPIFFS_OK;
+}
+
+static s32_t flash_write (u32_t addr, u32_t size, u8_t *src) {
+  memcpy (flash + addr, src, size);
+  return SPIFFS_OK;
+}
+
+static s32_t flash_erase (u32_t addr, u32_t size) {
+  memset (flash + addr, 0xff, size);
+  return SPIFFS_OK;
+}
+
+
+static void die (const char *what)
+{
+  if (errno == 0) {
+    fprintf(stderr, "%s: fatal error\n", what);
+  } else {
+    perror (what);
+  }
+  if (delete_on_die) {
+    const char **p = delete_list;
+    while (*p) {
+      unlink(*p);
+      p++;
+    }
+  }
+  exit (1);
+}
+
+
+static void list (void)
+{
+  spiffs_DIR dir;
+  if (!SPIFFS_opendir (&fs, "/", &dir))
+    die ("spiffs_opendir");
+  struct spiffs_dirent de;
+  while (SPIFFS_readdir (&dir, &de))
+  {
+    static const char types[] = "?fdhs"; // file, dir, hardlink, softlink
+    char name[sizeof(de.name)+1] = { 0 };
+    memcpy (name, de.name, sizeof(de.name));
+    printf("%c %6u %s\n", types[de.type], de.size, name);
+  }
+  SPIFFS_closedir (&dir);
+}
+
+
+static void cat (char *fname)
+{
+  spiffs_file fh = SPIFFS_open (&fs, fname, SPIFFS_RDONLY, 0);
+  char buff[512];
+  s32_t n;
+  while ((n = SPIFFS_read (&fs, fh, buff, sizeof (buff))) > 0)
+    write (STDOUT_FILENO, buff, n);
+  SPIFFS_close (&fs, fh);
+}
+
+
+static void import (char *src, char *dst)
+{
+  int fd = open (src, O_RDONLY);
+  if (fd < 0)
+    die (src);
+
+  spiffs_file fh = SPIFFS_open (&fs, dst, SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_WRONLY, 0);
+  if (fh < 0)
+    die ("spiffs_open");
+
+  char buff[16384];
+  s32_t n;
+  while ((n = read (fd, buff, sizeof (buff))) > 0)
+    if (SPIFFS_write (&fs, fh, buff, n) < 0)
+      die ("spiffs_write");
+
+  if (SPIFFS_close (&fs, fh) < 0)
+    die("spiffs_close");
+  close (fd);
+}
+
+
+static void export (char *src, char *dst)
+{
+  spiffs_file fh = SPIFFS_open (&fs, src, SPIFFS_RDONLY, 0);
+  if (fh < 0)
+    die ("spiffs_open");
+
+  int fd = open (dst, O_CREAT | O_TRUNC | O_WRONLY, 0664);
+  if (fd < 0)
+    die (dst);
+
+  char buff[512];
+  s32_t n;
+  while ((n = SPIFFS_read (&fs, fh, buff, sizeof (buff))) > 0)
+    if (write (fd, buff, n) < 0)
+      die ("write");
+
+  SPIFFS_close (&fs, fh);
+  close (fd);
+}
+
+
+char *trim (char *in)
+{
+  if (!in)
+    return "";
+
+  char *out = 0;
+  while (*in)
+  {
+    if (!out && !isspace (*in))
+      out = in;
+    ++in;
+  }
+  if (!out)
+    return "";
+  while (--in > out && isspace (*in))
+    ;
+  in[1] = 0;
+  return out;
+}
+
+
+void syntax (void)
+{
+  fprintf (stderr,
+    "Syntax: spiffsimg -f <filename> [-d] [-o <locationfilename>] [-c size] [-S flashsize] [-U usedsize] [-l | -i | -r <scriptname> ]\n\n"
+  );
+  exit (1);
+}
+
+static size_t getsize(const char *s)
+{
+  char *end = 0;
+  size_t val = strtoul(s, &end, 0);
+
+  if (end) {
+    int factor;
+    if (*end == 'k' || *end == 'K') {
+      factor = 1 << 10;
+      end++;
+    } else if (*end == 'm' || *end == 'M') {
+      factor = 1 << 20;
+      end++;
+    } else {
+      factor = 1;
+    }
+    // Capital B is bytes
+    if (*end == 'B') {
+      factor = factor << 3;
+    }
+    // we want bytes
+    val = (val * factor) / 8;
+  }
+
+  return val;
+}
+
+int main (int argc, char *argv[])
+{
+  if (argc == 1)
+    syntax ();
+
+  int opt;
+  const char *fname = 0;
+  bool create = false;
+  enum { CMD_NONE, CMD_LIST, CMD_INTERACTIVE, CMD_SCRIPT } command = CMD_NONE;
+  int sz = 0;
+  const char *script_name = 0;
+  const char *resolved = 0;
+  int flashsize = 0;
+  int used = 0;
+  while ((opt = getopt (argc, argv, "do:f:c:lir:S:U:")) != -1)
+  {
+    switch (opt)
+    {
+      case 'f': fname = optarg; break;
+      case 'o': resolved = optarg; break;
+      case 'c': create = true; sz = strtol(optarg, 0, 0); break;
+      case 'S': create = true; flashsize = getsize(optarg); break;
+      case 'U': create = true; used = strtol(optarg, 0, 0); break;
+      case 'd': delete_on_die = 1; break;
+      case 'l': command = CMD_LIST; break;
+      case 'i': command = CMD_INTERACTIVE; break;
+      case 'r': command = CMD_SCRIPT; script_name = optarg; break;
+      default: die ("unknown option");
+    }
+  }
+
+  if (!fname) {
+    die("Need a filename");
+  }
+
+#ifdef _MSC_VER
+  _set_fmode( _O_BINARY );	//change default open mode to binary rather than text
+#endif
+  int fd;
+
+  if (create)
+  {
+    if (!sz) {
+      if (!flashsize || !used) {
+	die("Missing flashSize or Used");
+      }
+      sz = flashsize - used - SYS_PARAM_SEC_NUM * 4096;   // This leaves space for the parameter area
+      if (sz < 0x4000) {
+	die("Not enough space");
+      }
+      if (sz > SMALL_FILESYSTEM) {
+	used = (used + 0xffff) & ~0xffff;
+      } else {
+	used = (used + 0x1fff) & ~0x1fff;
+      }
+      sz = flashsize - used - SYS_PARAM_SEC_NUM * 4096;
+    }
+    sz &= ~(0x1fff);
+
+    if (used == 0) {
+      if (strchr(fname, '%')) {
+	die("Unable to calculate where to put the flash image, and % present in filename");
+      }
+    }
+
+    char fnamebuff[1024];
+
+    sprintf(fnamebuff, fname, used);
+
+    delete_list[delete_list_index++] = strdup(fnamebuff);;
+    fd = open (fnamebuff, (create ? (O_CREAT | O_TRUNC) : 0) | O_RDWR, 0664);
+    if (fd == -1)
+      die ("open");
+
+    if (resolved) {
+      delete_list[delete_list_index++] = resolved;
+      FILE *f = fopen(resolved, "w");
+      fprintf(f, "0x%x", used);
+      fclose(f);
+    }
+
+    if (lseek (fd, sz -1, SEEK_SET) == -1)
+      die ("lseek");
+    if (write (fd, "", 1) != 1)
+      die ("write");
+  }
+  else {
+    fd = open (fname, O_RDWR, 0664);
+    if (fd == -1)
+      die ("open");
+
+    if (!sz)
+    {
+      off_t offs = lseek (fd, 0, SEEK_END);
+      if (offs == -1)
+	die ("lseek");
+      sz = offs;
+    }
+  }
+
+  if (sz & (0x1000 -1))
+    die ("file size not multiple of erase block size");
+
+#ifdef _MSC_VER
+  //We don't have a mmap(), so we simply allocate a file buffer we write out
+  //at the end of the program.  This also means that we need to let the program
+  //end normally (i.e. not via Ctrl-C) or else that final write will not happen.
+  //If you are in interactive mode, there is not a command for 'exit', however
+  //EOF may be used to end the interactive loop by pressing Ctrl-Z, return.
+  flash = (uint8_t*)malloc( sz );
+  if ( lseek( fd, 0, SEEK_SET ) == -1 )
+	  die( "lseek" );
+  if ( read( fd, flash, sz ) != sz )
+	  die( "write" );
+#else
+  flash = mmap( 0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
+#endif
+  if (!flash)
+    die ("mmap");
+
+  if (create)
+    memset (flash, 0xff, sz);
+
+  spiffs_config cfg;
+  cfg.phys_size = sz;
+  cfg.phys_addr = 0;
+  cfg.phys_erase_block = 0x1000;
+  cfg.log_block_size = 0x1000 * (sz > SMALL_FILESYSTEM ? 2 : 1);
+  cfg.log_page_size = LOG_PAGE_SIZE;
+  cfg.hal_read_f = flash_read;
+  cfg.hal_write_f = flash_write;
+  cfg.hal_erase_f = flash_erase;
+  if (cfg.phys_size < 4 * cfg.log_block_size) {
+    die("disk not large enough for four blocks");
+  }
+
+  if (SPIFFS_mount (&fs, &cfg,
+      spiffs_work_buf,
+      spiffs_fds,
+      sizeof(spiffs_fds),
+      malloc(65536), 65536, 0) != 0) {
+    if (create) {
+      if (SPIFFS_format(&fs) != 0) {
+        die("spiffs_format");
+      }
+      if (SPIFFS_mount (&fs, &cfg,
+          spiffs_work_buf,
+          spiffs_fds,
+          sizeof(spiffs_fds),
+          malloc(65536), 65536, 0) != 0) {
+        die ("spiffs_mount");
+      }
+      if (command == CMD_INTERACTIVE) {
+	printf("Created filesystem -- size 0x%x, block_size=%d\n", cfg.phys_size, cfg.log_block_size);
+      }
+    } else {
+      die ("spiffs_mount");
+    }
+  }
+
+  if (command == CMD_NONE)
+    ; // maybe just wanted to create an empty image?
+  else if (command == CMD_LIST)
+    list ();
+  else
+  {
+    FILE *in = (command == CMD_INTERACTIVE) ? stdin : fopen (script_name, "r");
+    if (!in)
+      die ("fopen");
+    char buff[128] = { 0 };
+    if (in == stdin)
+      printf("> ");
+    while (fgets (buff, sizeof (buff) -1, in))
+    {
+      char *line = trim (buff);
+      if (!line[0] || line[0] == '#')
+        continue;
+      if (strcmp (line, "ls") == 0)
+        list ();
+      else if (strncmp (line, "import ", 7) == 0)
+      {
+        char *src = 0, *dst = 0;
+#ifdef _MSC_VER
+        src = (char*)malloc(260 + 1);	//MAX_PATH
+        dst = (char*)malloc( 260 + 1 );
+        if (sscanf (line +7, " %260s %260s", src, dst) != 2)
+#else
+        if (sscanf (line +7, " %ms %ms", &src, &dst) != 2)
+#endif
+        {
+          fprintf (stderr, "SYNTAX ERROR: %s\n", line);
+          retcode = 1;
+        }
+        else
+          import (src, dst);
+        free (src);
+        free (dst);
+      }
+      else if (strncmp (line, "export ", 7) == 0)
+      {
+        char *src = 0, *dst = 0;
+#ifdef _MSC_VER
+        src = (char*)malloc( 260 + 1 );	//MAX_PATH
+        dst = (char*)malloc( 260 + 1 );
+        if ( sscanf( line + 7, " %260s %260s", src, dst ) != 2 )
+#else
+        if (sscanf (line + 7, " %ms %ms", &src, &dst) != 2)
+#endif
+        {
+          fprintf (stderr, "SYNTAX ERROR: %s\n", line);
+          retcode = 1;
+        }
+        else
+          export (src, dst);
+        free (src);
+        free (dst);
+      }
+      else if (strncmp (line, "rm ", 3) == 0)
+      {
+        if (SPIFFS_remove (&fs, trim (line + 3)) < 0)
+        {
+          fprintf (stderr, "FAILED: %s\n", line);
+          retcode = 1;
+        }
+      }
+      else if (strncmp (line, "cat ", 4) == 0)
+        cat (trim (line + 4));
+      else if (strncmp (line, "info", 4) == 0)
+      {
+        u32_t total, used;
+        if (SPIFFS_info (&fs, &total, &used) < 0)
+        {
+          fprintf (stderr, "FAILED: %s\n", line);
+          retcode = 1;
+        }
+        else
+          printf ("Total: %u, Used: %u\n", total, used);
+      }
+      else
+      {
+        printf ("SYNTAX ERROR: %s\n", line);
+        retcode = 1;
+      }
+
+      if (in == stdin)
+        printf ("> ");
+    }
+    if (in == stdin)
+      printf ("\n");
+  }
+
+  SPIFFS_unmount (&fs);
+#ifdef _MSC_VER
+  if ( lseek( fd, 0, SEEK_SET ) == -1 )
+    die( "lseek" );
+  if ( write( fd, flash, sz ) != sz )
+    die( "write" );
+  free( flash );
+#else
+  munmap (flash, sz);
+#endif
+  close (fd);
+  return retcode;
+}

+ 1 - 1
tools/spiffsimg/spiffs_typedefs.h

@@ -10,7 +10,7 @@ typedef uint16_t u16_t;
 typedef   int8_t s8_t;
 typedef  uint8_t u8_t;
 
-#ifndef __CYGWIN__
+#if !defined(__CYGWIN__) && !defined(_MSC_VER)
 typedef long long ptrdiff_t;
 #define offsetof(type, member)  __builtin_offsetof (type, member)
 #endif