Author: mladen.turk(a)jboss.com
Date: 2008-03-31 08:14:20 -0400 (Mon, 31 Mar 2008)
New Revision: 1489
Added:
trunk/build/install/xtool/
trunk/build/install/xtool/NMAKEmakefile
trunk/build/install/xtool/jboss.ico
trunk/build/install/xtool/redhat.ico
trunk/build/install/xtool/xtool.c
trunk/build/install/xtool/xtool.rc
Log:
Add Generic build tool utilities (rmdir, touch, etc)
Added: trunk/build/install/xtool/NMAKEmakefile
===================================================================
--- trunk/build/install/xtool/NMAKEmakefile (rev 0)
+++ trunk/build/install/xtool/NMAKEmakefile 2008-03-31 12:14:20 UTC (rev 1489)
@@ -0,0 +1,71 @@
+# Copyright(c) 2006 Red Hat Middleware, LLC,
+# and individual contributors as indicated by the @authors tag.
+# See the copyright.txt in the distribution for a
+# full listing of individual contributors.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library in the file COPYING.LIB;
+# if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+#
+# @author Mladen Turk
+#
+
+TARGET = EXE
+PROJECT = xtool
+!include <..\..\NMAKEcommon.inc>
+
+!IF !DEFINED(SRCDIR) || "$(SRCDIR)" == ""
+SRCDIR = .
+!ENDIF
+
+LFLAGS = $(LFLAGS) user32.lib shell32.lib advapi32.lib psapi.lib
+
+PDBFLAGS = -Fo$(WORKDIR)\ -Fd$(WORKDIR)\$(PROJECT)-src
+OBJECTS = \
+ $(WORKDIR)\xtool.obj
+
+OBJDEPS = NMAKEmakefile
+
+BUILDLOC = $(PREFIX)\bin
+BUILDEXE = $(WORKDIR)\$(PROJECT).exe
+BUILDPDB = $(WORKDIR)\$(PROJECT).pdb
+BUILDRES = $(WORKDIR)\$(PROJECT).res
+BUILDMAN = $(BUILDEXE).manifest
+
+all : $(WORKDIR) $(BUILDEXE)
+
+$(BUILDLOC) :
+ @if not exist "$(BUILDLOC)\$(NULL)" mkdir "$(BUILDLOC)"
+
+$(WORKDIR) :
+ @$(MAKEWORKDIR)
+
+{$(SRCDIR)}.c{$(WORKDIR)}.obj:
+ $(CC) $(CFLAGS) $(INCLUDES) $(PDBFLAGS) $<
+
+$(BUILDRES): $(SRCDIR)/$(PROJECT).rc
+ $(RC) $(RCFLAGS) /fo $(BUILDRES) $(SRCDIR)/$(PROJECT).rc
+
+$(OBJECTS): $(OBJDEPS)
+
+$(BUILDEXE): $(WORKDIR) $(OBJECTS) $(BUILDRES)
+ $(LINK) $(LFLAGS) $(OBJECTS) $(BUILDRES) $(LIBS) $(LDIRS) /pdb:$(BUILDPDB)
/out:$(BUILDEXE)
+ IF EXIST $(BUILDMAN) \
+ mt -nologo -manifest $(BUILDMAN) -outputresource:$(BUILDEXE);1
+
+clean:
+ @$(CLEANTARGET)
+
+install: $(BUILDLOC) $(WORKDIR) $(BUILDEXE)
+ @xcopy "$(WORKDIR)\*.exe" "$(BUILDLOC)" /Y /Q
Property changes on: trunk/build/install/xtool/NMAKEmakefile
___________________________________________________________________
Name: svn:eol-style
+ native
Added: trunk/build/install/xtool/jboss.ico
===================================================================
(Binary files differ)
Property changes on: trunk/build/install/xtool/jboss.ico
___________________________________________________________________
Name: svn:mime-type
+ image/x-icon
Added: trunk/build/install/xtool/redhat.ico
===================================================================
(Binary files differ)
Property changes on: trunk/build/install/xtool/redhat.ico
___________________________________________________________________
Name: svn:mime-type
+ image/x-icon
Added: trunk/build/install/xtool/xtool.c
===================================================================
--- trunk/build/install/xtool/xtool.c (rev 0)
+++ trunk/build/install/xtool/xtool.c 2008-03-31 12:14:20 UTC (rev 1489)
@@ -0,0 +1,2369 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *
http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file xtools.c
+ * @brief Windows generic build tool
+ * @author mturk(a)redhat.com
+ */
+
+#if defined(_MSC_VER) && _MSC_VER >= 1200
+#pragma warning(push, 3)
+#endif
+
+/*
+ * disable or reduce the frequency of...
+ * C4057: indirection to slightly different base types
+ * C4075: slight indirection changes (unsigned short* vs short[])
+ * C4100: unreferenced formal parameter
+ * C4127: conditional expression is constant
+ * C4163: '_rotl64' : not available as an intrinsic function
+ * C4201: nonstandard extension nameless struct/unions
+ * C4244: int to char/short - precision loss
+ * C4514: unreferenced inline function removed
+ */
+#pragma warning(disable: 4100 4127 4163 4201 4514; once: 4057 4075 4244)
+
+/*
+ * Ignore Microsoft's interpretation of secure development
+ * and the POSIX string handling API
+ */
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+#pragma warning(disable: 4996)
+
+#define WIN32_LEAN_AND_MEAN
+/*
+ * Restrict the server to a subset of Windows NT 4.0 header files by default
+ */
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+#include <windows.h>
+#include <shellapi.h>
+#include <psapi.h>
+#include <shlobj.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <sys/timeb.h>
+#include <errno.h>
+#include <conio.h>
+#include <process.h>
+#include <direct.h>
+#include <io.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <crtdbg.h>
+
+/*
+ * ---------------------------------------------------------------------
+ * begin of local defines
+ * ---------------------------------------------------------------------
+ */
+
+/* An arbitrary size that is digestable. True max is a bit less than 32000 */
+#define X_MAX_PATH 8192
+/* Make hash size always as 0xFF value */
+#define DEFAULT_HASH_SIZE 256
+/* Maximum size for environment expansion */
+#define INFO_BUFFER_SIZE 32767
+
+/*
+ * Alignment macros
+ */
+
+/* X_ALIGN() is only to be used to align on a power of 2 boundary */
+#define X_ALIGN(size, boundary) \
+ (((size) + ((boundary) - 1)) & ~((boundary) - 1))
+
+/** Default alignment */
+#define X_ALIGN_DEFAULT(size) X_ALIGN(size, 8)
+
+#define x_isalnum(c) (isalnum(((unsigned char)(c))))
+#define x_isalpha(c) (isalpha(((unsigned char)(c))))
+#define x_isdigit(c) (isdigit(((unsigned char)(c))))
+#define x_isspace(c) (isspace(((unsigned char)(c))))
+
+typedef enum {
+ SYSDLL_KERNEL32 = 0, // kernel32 From WinBase.h
+ SYSDLL_NTDLL = 1, // ntdll From our real kernel
+ SYSDLL_USER32 = 2, // user32 From WinUser.h
+ SYSDLL_defined = 3 // must define as last idx_ + 1
+} x_dlltoken_e;
+
+static FARPROC x_load_dll_func(x_dlltoken_e, const char *);
+
+#define DECLARE_LATE_DLL_FUNC(lib, rettype, def, \
+ calltype, fn, args, names) \
+ typedef rettype (calltype *x_late_fpt_##fn) args; \
+ static x_late_fpt_##fn x_late_pfn_##fn = NULL; \
+ static __inline rettype x_late_##fn args \
+ { if (!x_late_pfn_##fn) \
+ x_late_pfn_##fn = (x_late_fpt_##fn) \
+ x_load_dll_func(lib, #fn); \
+ if (x_late_pfn_##fn) \
+ return (*(x_late_pfn_##fn)) names; \
+ else return def; } //
+
+DECLARE_LATE_DLL_FUNC(SYSDLL_KERNEL32, BOOL, FALSE,
+ WINAPI, IsWow64Process, (
+ IN HANDLE hProcess,
+ OUT PBOOL Wow64Process),
+ (hProcess, Wow64Process));
+#undef IsWow64Process
+#define IsWow64Process x_late_IsWow64Process
+
+
+/*
+ * ---------------------------------------------------------------------
+ * end of local defines
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * ---------------------------------------------------------------------
+ * begin of local variables
+ * ---------------------------------------------------------------------
+ */
+
+static int xtools_pause = 0;
+static SYSTEM_INFO win_osinf;
+static OSVERSIONINFOEXA win_osver;
+static int verbose = 0;
+
+/*
+ * ---------------------------------------------------------------------
+ * end of local variables
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * ---------------------------------------------------------------------
+ * begin of forward declrations
+ * ---------------------------------------------------------------------
+ */
+
+int utf8_to_unicode_path(wchar_t*, size_t, const char *, size_t);
+int unicode_to_utf8_path(char *, size_t, const wchar_t *);
+int utf8_to_unicode(wchar_t *, size_t, const char *);
+int unicode_to_utf8(char *, size_t, const wchar_t* srcstr);
+int x_wfullpath(wchar_t *, size_t, const char *);
+
+/*
+ * ---------------------------------------------------------------------
+ * end of forward declrations
+ * ---------------------------------------------------------------------
+ */
+
+
+/*
+ * ---------------------------------------------------------------------
+ * begin of local types
+ * ---------------------------------------------------------------------
+ */
+
+typedef struct hash_node_t hash_node_t;
+
+struct hash_node_t {
+ hash_node_t *next;
+ void *data;
+ char key[1];
+};
+
+typedef struct hash_t {
+ int icase;
+ unsigned int size;
+ hash_node_t **nodes;
+} hash_t;
+
+typedef struct sbuffer {
+ char *data;
+ size_t pos;
+ size_t size;
+} sbuffer;
+
+typedef struct ini_node_t ini_node_t;
+
+struct ini_node_t {
+ ini_node_t *next;
+ ini_node_t **last;
+ char *key;
+ char *val;
+};
+
+typedef struct ini_section_t ini_section_t;
+
+struct ini_section_t {
+ ini_section_t *next;
+ ini_section_t **last;
+ char *name;
+ ini_node_t *nodes;
+};
+
+/*
+ * ---------------------------------------------------------------------
+ * end of of local types
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * ---------------------------------------------------------------------
+ * begin of stdlib replacement functions
+ * ---------------------------------------------------------------------
+ */
+
+static int c_errno_table[] = {
+
+ 0, /* NO_ERROR */
+ EINVAL, /* ERROR_INVALID_FUNCTION */
+ ENOENT, /* ERROR_FILE_NOT_FOUND */
+ ENOENT, /* ERROR_PATH_NOT_FOUND */
+ EMFILE, /* ERROR_TOO_MANY_OPEN_FILES */
+ EACCES, /* ERROR_ACCESS_DENIED */
+ EBADF, /* ERROR_INVALID_HANDLE */
+ ENOMEM, /* ERROR_ARENA_TRASHED */
+ ENOMEM, /* ERROR_NOT_ENOUGH_MEMORY */
+ ENOMEM, /* ERROR_INVALID_BLOCK */
+ E2BIG, /* ERROR_BAD_ENVIRONMENT */
+ ENOEXEC, /* ERROR_BAD_FORMAT */
+ EINVAL, /* ERROR_INVALID_ACCESS */
+ EINVAL, /* ERROR_INVALID_DATA */
+ 14, /* **** reserved */
+ ENOENT, /* ERROR_INVALID_DRIVE */
+ EACCES, /* ERROR_CURRENT_DIRECTORY */
+ EXDEV, /* ERROR_NOT_SAME_DEVICE */
+ ENOENT, /* ERROR_NO_MORE_FILES */
+ 0
+};
+
+int x_cerror(int err)
+{
+ if (err == 0) {
+ if ((err = GetLastError()) == 0)
+ return 0;
+ }
+ if (err < 0 || err > ERROR_NO_MORE_FILES) {
+ switch (err) {
+ case 1026:
+ return ENOENT;
+ break;
+ case ERROR_ALREADY_EXISTS:
+ return EEXIST;
+ case ERROR_INSUFFICIENT_BUFFER:
+ return ENAMETOOLONG;
+ break;
+ default:
+ return err;
+ break;
+ }
+ }
+ else
+ return c_errno_table[err];
+}
+
+static void x_free(void *p)
+{
+ if (p != NULL) {
+ free(p);
+ }
+}
+
+static void *x_malloc(size_t size)
+{
+ void *p = malloc(size);
+ if (p == NULL) {
+ perror("malloc");
+ _exit(ENOMEM);
+ }
+ return p;
+}
+
+static void *x_calloc(size_t size)
+{
+ void *p = calloc(1, size);
+ if (p == NULL) {
+ perror("calloc");
+ _exit(ENOMEM);
+ }
+ return p;
+}
+
+static void *x_realloc(void *m, size_t size)
+{
+ m = realloc(m, size);
+ if (m == NULL) {
+ perror("realloc");
+ _exit(ENOMEM);
+ }
+ return m;
+}
+
+static char *x_strdup(const char *s)
+{
+ char *p;
+ size_t size;
+ if (s != NULL)
+ size = strlen(s);
+ else
+ return NULL;
+ p = (char *)x_malloc(size + 2);
+ memcpy(p, s, size);
+ p[size++] = '\0';
+ p[size] = '\0';
+ return p;
+}
+
+static wchar_t *x_wstrdup_utf8(const char *str)
+{
+ int len;
+ wchar_t *res;
+ if (!str)
+ return NULL;
+ len = strlen(str);
+ res = x_malloc((len + 2) * sizeof(wchar_t));
+ if (!MultiByteToWideChar(CP_UTF8, 0, str, -1, res, len + 1)) {
+ x_free(res);
+ return NULL;
+ }
+ else {
+ len = wcslen(res);
+ res[len + 1] = L'\0';
+ return res;
+ }
+}
+
+static char *x_strdup_utf8(const wchar_t *str)
+{
+ size_t l;
+ char *r;
+
+ if (!(l = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, 0)))
+ return NULL;
+ r = x_malloc(l + 1);
+ if (!(l = WideCharToMultiByte(CP_UTF8, 0, str, -1, r, l, NULL, 0))) {
+ x_free(r);
+ return NULL;
+ }
+ else {
+ r[l] = '\0';
+ return r;
+ }
+}
+
+
+/*
+ * Replacement for the strncpy() function. We roll our
+ * own to implement these specific changes:
+ * (1) strncpy() doesn't always null terminate and we want it to.
+ * (2) strncpy() null fills, which is bogus, esp. when copy 8byte
+ * strings into 8k blocks.
+ * (3) Instead of returning the pointer to the beginning of
+ * the destination string, we return a pointer to the
+ * terminating '\0' to allow us to "check" for truncation
+ *
+ * x_strncpy() follows the same call structure as strncpy().
+ */
+static char *x_strncpy(char *d, const char *s, size_t l)
+{
+ char *dst, *end;
+ if (l == 0)
+ return d;
+ if (s == NULL) {
+ *d = '\0';
+ return d;
+ }
+ dst = d;
+ end = d + l - 1;
+
+ for (; dst < end; ++dst, ++s) {
+ if (!(*dst = *s))
+ return dst;
+ }
+
+ *dst = '\0'; /* always null terminate */
+ return dst;
+}
+
+static char *x_strvcat(const char *str, ...)
+{
+ char *dst = NULL;
+ const char *ptr = str;
+ size_t len = 0;
+ va_list v;
+ if (!str)
+ return NULL;
+ va_start(v, str);
+ while (ptr) {
+ len += strlen(ptr);
+ ptr = va_arg(v, const char *);
+ }
+ va_end(v);
+ dst = x_malloc(len + 2);
+ *dst = '\0';
+ ptr = str;
+ va_start(v, str);
+ while (ptr) {
+ strcat(dst, ptr);
+ ptr = va_arg(v, const char *);
+ }
+ va_end(v);
+ dst[len + 1] = '\0';
+ return dst;
+}
+
+static char *x_strcat(char *dst, const char *add)
+{
+ if (dst) {
+ size_t len = strlen(dst) + strlen(add);
+ char *res = realloc(dst, len + 2);
+ if (!res) {
+ res = x_malloc(len + 2);
+ strcpy(res, dst);
+ }
+ strcat(res, add);
+ res[len + 1] = '\0';
+ return res;
+ }
+ else
+ return x_strdup(add);
+}
+
+static char *__argv0 = NULL;
+static char *__pname = NULL;
+static char *__ppath = NULL;
+static char *__paren = NULL;
+
+static const char *getprogname()
+{
+ char *p;
+
+ if (__pname)
+ return __pname;
+ if ((p = strrchr(__argv0, '\\')))
+ p++;
+ else
+ p = __argv0;
+ __pname = x_strdup(p);
+ /* Remove extension */
+ if ((p = strrchr(__pname, '.')))
+ *p = '\0';
+ return __pname;
+}
+
+static const char *getexecpath()
+{
+ char *p;
+
+ if (__ppath)
+ return __ppath;
+ __ppath = x_strdup(__argv0);
+ if ((p = strrchr(__ppath, '\\')))
+ *++p = '\0';
+ return __ppath;
+}
+
+static const char *getexecparent()
+{
+ char *p;
+
+ if (__paren)
+ return __paren;
+ __paren = x_strdup(getexecpath());
+ if ((p = strrchr(__paren, '\\')))
+ *++p = '\0';
+ if ((p = strrchr(__paren, '\\')))
+ *++p = '\0';
+ return __paren;
+}
+
+#define progname getprogname()
+#define execpath getexecpath()
+#define execparent getexecparent()
+
+static const char *wstrerror(int err)
+{
+ static char buff[X_MAX_PATH] = {0};
+
+ FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ buff,
+ X_MAX_PATH,
+ NULL);
+
+ return buff;
+}
+
+static const char *cstrerror(int err)
+{
+ if (err > EILSEQ)
+ return wstrerror(err);
+ else
+ return strerror(err);
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * end of stdlib replacement functions
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * ---------------------------------------------------------------------
+ * begin of string utilities
+ * ---------------------------------------------------------------------
+ */
+
+/* Match = 0, NoMatch = 1, Abort = -1
+ * Based loosely on sections of wildmat.c by Rich Salz
+ */
+static int wildchar_match(const char *str, const char *exp, int icase)
+{
+ int x, y;
+
+ for (x = 0, y = 0; exp[y]; ++y, ++x) {
+ if (!str[x] && exp[y] != '*')
+ return -1;
+ if (exp[y] == '*') {
+ while (exp[++y] == '*');
+ if (!exp[y])
+ return 0;
+ while (str[x]) {
+ int ret;
+ if ((ret = wildchar_match(&str[x++], &exp[y], icase)) != 1)
+ return ret;
+ }
+ return -1;
+ }
+ else if (exp[y] != '?') {
+ if (icase && (tolower(str[x]) != tolower(exp[y])))
+ return 1;
+ else if (!icase && str[x] != exp[y])
+ return 1;
+ }
+ }
+ return (str[x] != '\0');
+}
+
+/* Win32 Exceptions:
+ *
+ * Note that trailing spaces and trailing periods are never recorded
+ * in the file system, except by a very obscure bug where any file
+ * that is created with a trailing space or period, followed by the
+ * ':' stream designator on an NTFS volume can never be accessed again.
+ * In other words, don't ever accept them when designating a stream!
+ *
+ * An interesting side effect is that two or three periods are both
+ * treated as the parent directory, although the fourth and on are
+ * not [strongly suggest all trailing periods are trimmed off, or
+ * down to two if there are no other characters.]
+ *
+ * Leading spaces and periods are accepted, however.
+ * The * ? < > codes all have wildcard side effects
+ * The " / \ : are exclusively component separator tokens
+ * The system doesn't accept | for any (known) purpose
+ * Oddly, \x7f _is_ acceptable ;)
+ */
+
+/* apr_c_is_fnchar[] maps Win32's file name and shell escape symbols
+ *
+ * element & 1 == valid file name character [excluding delimiters]
+ * element & 2 == character should be shell (caret) escaped from cmd.exe
+ *
+ * this must be in-sync with Apache httpd's gen_test_char.c for cgi escaping.
+ */
+
+static const char is_valid_fnchar[256] = {
+ /* Reject all ctrl codes... Escape \n and \r (ascii 10 and 13) */
+ 0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ /* ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = >
? */
+ 1,1,2,1,3,3,3,3,3,3,2,1,1,1,1,0, 1,1,1,1,1,1,1,1,1,1,0,3,2,1,2,2,
+ /* @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ */
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,3,2,3,3,1,
+ /* ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ */
+ 3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,3,2,3,3,1,
+ /* High bit codes are accepted (subject to utf-8->Unicode xlation) */
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
+};
+
+
+#define IS_FNCHAR(c) (is_valid_fnchar[(unsigned char)(c)] & 1)
+#define IS_SHCHAR(c) ((is_valid_fnchar[(unsigned char)(c)] & 2) == 2)
+
+/* Is = 1, No = 0, Error = -1
+ */
+static int is_wildpath(const char *path)
+{
+ size_t i = 0;
+ size_t len;
+
+ if (!path) {
+ errno = EINVAL;
+ return -1;
+ }
+ len = strlen(path);
+ if (len > 8 && !strncmp(path, "\\\\?\\UNC\\", 8))
+ path += 8;
+ else if (len > 4 && !strncmp(path, "\\\\?\\", 4))
+ path += 4;
+ if (x_isalpha(*path) && (path[1] == ':')) {
+ path += 2;
+ }
+ while (*path) {
+ if (!IS_FNCHAR(*path) && (*path != '\\') && (*path !=
'/')) {
+ if (*path == '?' || *path == '*')
+ return 1;
+ else {
+ errno = ENOENT;
+ return -1;
+ }
+ }
+ ++path;
+ }
+ return 0;
+}
+
+static char *rtrim(char *s)
+{
+ size_t i;
+ /* check for empty strings */
+ if (!(i = strlen(s)))
+ return s;
+ for (i = i - 1; i >= 0 && x_isspace(s[i]); i--)
+ ;
+ s[i + 1] = '\0';
+ return s;
+}
+
+static char *ltrim(char *s)
+{
+ size_t i;
+ for (i = 0; s[i] != '\0' && x_isspace(s[i]); i++)
+ ;
+
+ return s + i;
+}
+
+static char *rltrim(char *s)
+{
+ size_t i;
+ /* check for empty strings */
+ if (!(i = strlen(s)))
+ return s;
+ for (i = i - 1; i >= 0 && x_isspace(s[i]); i--)
+ ;
+ s[i + 1] = '\0';
+ for (i = 0; s[i] != '\0' && x_isspace(s[i]); i++)
+ ;
+
+ return s + i;
+}
+/*
+ * ---------------------------------------------------------------------
+ * end of string utilities
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * ---------------------------------------------------------------------
+ * begin of hash
+ * ---------------------------------------------------------------------
+ */
+
+static unsigned int strhash(const char *string, int icase)
+{
+ unsigned int hash = 0;
+ int i;
+
+ while (*string) {
+ if (icase)
+ i = toupper(*string);
+ else
+ i = *string;
+ hash = hash * 33 + i;
+ string ++;
+ }
+ return hash;
+}
+
+static void free_node(void *unused, void *data)
+{
+ unused;
+ x_free(data);
+}
+
+static hash_t *hash_create(unsigned int size, int icase)
+{
+ hash_t *h;
+ if (!size)
+ size = DEFAULT_HASH_SIZE;
+ else
+ size = X_ALIGN_DEFAULT(size);
+ h = (hash_t *)x_malloc(sizeof(hash_t));
+ h->nodes = (hash_node_t **)x_calloc(sizeof(hash_node_t *) * size);
+ h->size = size;
+ h->icase = icase;
+ return h;
+}
+
+static void *hash_insert(hash_t *ht, const char *key, void *data)
+{
+ unsigned int ikey;
+ if (!ht || !key)
+ return NULL;
+ ikey = strhash(key, ht->icase) % ht->size;
+ if (!ht->nodes[ikey]) {
+ ht->nodes[ikey] = (hash_node_t *)x_malloc(sizeof(hash_node_t) +
+ strlen(key));
+ strcpy(ht->nodes[ikey]->key, key);
+ ht->nodes[ikey]->data = data;
+ ht->nodes[ikey]->next = NULL;
+ }
+ else {
+ hash_node_t *p;
+ for (p = ht->nodes[ikey]; p; p = p->next) {
+ if (ht->icase ? stricmp(p->key, key) : strcmp(p->key, key)) {
+ void *org = p->data;
+ p->data = data;
+ return org;
+ }
+ }
+ p = (hash_node_t *)x_malloc(sizeof(hash_node_t) + strlen(key));
+ strcpy(p->key, key);
+ p->data = data;
+ p->next = ht->nodes[ikey];
+ ht->nodes[ikey] = p;
+ }
+ return NULL;
+}
+
+static void *hash_find(hash_t *ht, const char *key, int *found)
+{
+ unsigned int ikey;
+ if (!ht || !key)
+ return NULL;
+ ikey = strhash(key, ht->icase) % ht->size;
+
+ if (found)
+ *found = 0;
+ if (!ht->nodes[ikey])
+ return NULL;
+ else {
+ hash_node_t *p;
+ for (p = ht->nodes[ikey]; p; p = p->next) {
+ if (ht->icase ? stricmp(p->key, key) : strcmp(p->key, key)) {
+ if (found)
+ *found = 1;
+ return p->data;
+ }
+ }
+ }
+ return NULL;
+}
+
+static void hash_foreach(hash_t *ht, void *opaque,
+ void (*callback)(void *, const char *, void *))
+{
+ unsigned int i;
+
+ for (i = 0; i < ht->size; i++) {
+ if (ht->nodes[i]) {
+ hash_node_t *p;
+ for (p = ht->nodes[i]; p; p = p->next) {
+ (*callback)(opaque, p->key, p->data);
+ }
+ }
+ }
+}
+
+static void hash_destroy(hash_t *ht, void *opaque,
+ void (*callback)(void *, const char *, void *))
+{
+ unsigned int i;
+ for (i = 0; i < ht->size; i++) {
+ if (ht->nodes[i]) {
+ hash_node_t *p = ht->nodes[i];
+ while (p) {
+ hash_node_t *next = p->next;
+ if (callback)
+ (*callback)(opaque, p->key, p->data);
+ x_free(p);
+ p = next;
+ }
+ }
+ }
+ x_free(ht->nodes);
+ x_free(ht);
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * end of hash
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * ---------------------------------------------------------------------
+ * begin of posix
+ * ---------------------------------------------------------------------
+ */
+
+static FILE *x_fopen(const char *name, const char *mode)
+{
+ DWORD acc = 0;
+ DWORD mod = OPEN_EXISTING;
+ HANDLE fh;
+ wchar_t fname[X_MAX_PATH];
+ int r;
+ int flags = _O_RDONLY;
+ FILE *f;
+
+ /* Do some param checking */
+ if (!name || !*name || !mode || !*mode) {
+ errno = EINVAL;
+ return NULL;
+ }
+ if (strchr(mode, 'r'))
+ acc = GENERIC_READ;
+ if (strchr(mode, 'w')) {
+ acc = GENERIC_READ | GENERIC_WRITE;
+ mod = CREATE_ALWAYS;
+ flags = _O_RDWR;
+ }
+ if (strchr(mode, 'a')) {
+ acc = GENERIC_WRITE;
+ mod = OPEN_ALWAYS;
+ flags = _O_WRONLY;
+ }
+ if (strchr(mode, '+')) {
+ acc = GENERIC_READ | GENERIC_WRITE;
+ flags = _O_RDWR;
+ }
+ if (strchr(mode, 't'))
+ flags |= _O_TEXT;
+ else if (strchr(mode, 'b'))
+ flags |= _O_BINARY;
+ if ((r = x_wfullpath(fname, X_MAX_PATH, name)) != 0) {
+ errno = r;
+ return NULL;
+ }
+ fh = CreateFileW(fname, acc, FILE_SHARE_READ, NULL,
+ mod, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (fh == INVALID_HANDLE_VALUE) {
+ errno = x_cerror(0);
+ return NULL;
+ }
+ if ((r = _open_osfhandle((long)fh, flags)) < 0) {
+ CloseHandle(fh);
+ return NULL;
+ }
+ if (!(f = _fdopen(r, mode))) {
+ CloseHandle(fh);
+ return NULL;
+ }
+ printf("Opened %S\n", fname);
+ return f;
+}
+
+static void vwarnx(const char *fmt, va_list ap)
+{
+ fprintf(stderr, "%s: ", getprogname());
+ if (fmt != NULL)
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+}
+
+static void warnx(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vwarnx(fmt, ap);
+ va_end(ap);
+}
+
+static int optslash = '/'; /* allow slashes as option modifiers */
+static int optsbrk = 1; /* Break if slash is unknown modifier */
+static int opterr = 1; /* if error message should be printed */
+static int optind = 1; /* index into parent argv vector */
+static int optopt = 0; /* character checked for validity */
+static int optlong = 1; /* Allow long options */
+static int optreset = 1; /* reset getopt */
+static char *optarg = NULL; /* argument associated with option */
+
+#define BADCH '?'
+#define BADARG ':'
+#define LNGOPT '.'
+#define EMSG ""
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ * However this one allows both - and / as argument options
+ */
+int getopt(int nargc, const char **nargv, const char *ostr)
+{
+ static const char *place = EMSG; /* option letter processing */
+ char *oli = NULL; /* option letter list index */
+ int first = 0;
+
+ optarg = NULL;
+ if (optreset || *place == 0) { /* update scanning pointer */
+ optreset = 0;
+ place = nargv[optind];
+ if (optind >= nargc) {
+ /* Argument is absent or is not an option */
+ place = EMSG;
+ return EOF;
+ }
+ first = *place++;
+ if (first != '-' && first != optslash) {
+ /* Argument is absent or is not an option */
+ place = EMSG;
+ return EOF;
+ }
+ optopt = *place++;
+ /* Check for invalid sequence */
+ if ((optslash == '/') &&
+ ((first == '-' && optopt == '/') ||
+ (first == '/' && optopt == '-'))) {
+ ++optind;
+ if (opterr)
+ warnx("Invalid sequence -- %c%c",
+ first, optopt);
+ place = EMSG;
+ return BADCH;
+
+ }
+ if (first == '-' && optopt == '-') {
+ ++optind;
+ if (*place == 0 || !optlong) {
+ place = EMSG;
+ /* "--" => end of options */
+ return EOF;
+ }
+ else {
+ optarg = (char *)place;
+ place = EMSG;
+ /* "--long" => long option */
+ return LNGOPT;
+ }
+ }
+ if (optopt == 0) {
+ /*
+ * Solitary '-', treat as a '-' option
+ * if the program (eg su) is looking for it.
+ */
+ place = EMSG;
+ if (strchr(ostr, first) == NULL)
+ return EOF;
+ optopt = first;
+ }
+ if (optopt == optslash) {
+ ++optind;
+ place = EMSG;
+ /* "//" => end of options */
+ return EOF;
+ }
+ }
+ else
+ optopt = *place++;
+
+ /* See if option letter is one the caller wanted... */
+ if (optopt == BADARG || (oli = strchr(ostr, optopt)) == NULL) {
+ if (!optsbrk && optslash == '/' && first == optslash) {
+ /* Non option starting with / */
+ place = EMSG;
+ return EOF;
+ }
+ if (*place == 0)
+ ++optind;
+ if (opterr && *ostr != ':')
+ warnx("unknown option -- %c\n"
+ "Try '%s --help' for more information.",
+ optopt, progname);
+ return BADCH;
+ }
+
+ /* Does this option need an argument? */
+ if (oli[1] != ':') {
+ /* don't need argument */
+ optarg = NULL;
+ if (*place == 0) {
+ ++optind;
+ place = EMSG;
+ }
+ else if (optslash == '/' && first == optslash) {
+ ++optind;
+ optarg = (char *)place;
+ place = EMSG;
+ }
+ } else {
+ /*
+ * Option-argument is either the rest of this argument or the
+ * entire next argument.
+ */
+ if (*place)
+ optarg = (char *)place;
+ else if (nargc > ++optind)
+ optarg = (char *)nargv[optind];
+ else {
+ /* option-argument absent */
+ place = EMSG;
+ if (*ostr == ':')
+ return BADARG;
+ if (opterr)
+ warnx("option requires an argument -- %c\n"
+ "Try '%s --help' for more information.",
+ optopt, progname);
+ return BADCH;
+ }
+ place = EMSG;
+ ++optind;
+ }
+ return optopt; /* return option letter */
+}
+
+
+/*
+ * ---------------------------------------------------------------------
+ * end of posix
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * ---------------------------------------------------------------------
+ * begin of misc
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * Convert all forward slashes to backward slashes
+ */
+static char *x_backslash(const char *s)
+{
+ char *c;
+ char *p = x_strdup(s);
+ for (c = p; *c; c++) {
+ if (*c == '/')
+ *c = '\\';
+ }
+ return p;
+}
+
+/*
+ * Convert all forward slashes to backward slashes
+ * in place.
+ */
+static char *fixslash(char *s)
+{
+ char *c = s;
+ for (; *c; c++) {
+ if (*c == '/')
+ *c = '\\';
+ }
+ return s;
+}
+
+static char *expand_envars(char *str)
+{
+ wchar_t ibuf[INFO_BUFFER_SIZE];
+ wchar_t ebuf[INFO_BUFFER_SIZE];
+ char *rv = str;
+
+ if (MultiByteToWideChar(CP_UTF8, 0, str, -1, ibuf, INFO_BUFFER_SIZE)) {
+ DWORD el = ExpandEnvironmentStringsW(ibuf, ebuf,
+ INFO_BUFFER_SIZE);
+ if (el > INFO_BUFFER_SIZE) {
+ if (verbose)
+ warnx("expansion string to large %d", el);
+ }
+ else if (el) {
+ if ((rv = x_strdup_utf8(ebuf)))
+ x_free(str);
+ else
+ rv = str;
+ }
+ }
+ return rv;
+}
+
+
+/* This is the helper code to resolve late bound entry points
+ * missing from one or more releases of the Win32 API
+ */
+
+static const char* const late_dll_mames[SYSDLL_defined] = {
+ "kernel32",
+ "ntdll.dll",
+ "user32.dll"
+};
+
+static HMODULE late_dll_handles[SYSDLL_defined] = { NULL, NULL, NULL};
+
+static FARPROC x_load_dll_func(x_dlltoken_e fnLib, const char* fnName)
+{
+ if (!late_dll_handles[fnLib]) {
+ /* First see if the .dll is already loaded in the process */
+ late_dll_handles[fnLib] = GetModuleHandleA(late_dll_mames[fnLib]);
+ if (!late_dll_handles[fnLib]) {
+ /* Do not display error messages when loading library */
+ UINT em = SetErrorMode(SEM_FAILCRITICALERRORS);
+ late_dll_handles[fnLib] = LoadLibraryA(late_dll_mames[fnLib]);
+ SetErrorMode(em);
+ }
+ if (!late_dll_handles[fnLib])
+ return NULL;
+ }
+ return GetProcAddress(late_dll_handles[fnLib], fnName);
+}
+
+
+/*
+ * ---------------------------------------------------------------------
+ * end of misc
+ * ---------------------------------------------------------------------
+ */
+
+
+/*
+ * ---------------------------------------------------------------------
+ * begin of file functions
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * Makes a full path from partial path
+ */
+static char *x_fullpath(const char *s)
+{
+ wchar_t full[X_MAX_PATH];
+ wchar_t path[X_MAX_PATH];
+ char *res;
+ wchar_t *fn;
+ size_t len;
+ int r;
+
+ if ((r = utf8_to_unicode_path(path, X_MAX_PATH, s, X_MAX_PATH))) {
+ errno = r;
+ return NULL;
+ }
+ len = GetFullPathNameW(path,
+ X_MAX_PATH,
+ full, &fn);
+ if (len >= X_MAX_PATH) {
+ errno = ERANGE;
+ return NULL;
+ }
+ if (len == 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+ res = x_malloc(X_MAX_PATH);
+ if ((r = unicode_to_utf8_path(res, X_MAX_PATH, full))) {
+ errno = r;
+ x_free(res);
+ return NULL;
+ }
+ return res;
+}
+
+/*
+ * Makes a full path from partial path
+ */
+static int x_wfullpath(wchar_t *full, size_t len, const char *s)
+{
+ wchar_t path[X_MAX_PATH];
+ wchar_t *fn;
+ int r;
+ if (!s || !*s)
+ return EINVAL;
+ *full = L'\0';
+ if ((r = utf8_to_unicode_path(path, X_MAX_PATH, s, X_MAX_PATH)))
+ return r;
+ len = GetFullPathNameW(path, len,
+ full, &fn);
+ if (len >= X_MAX_PATH)
+ return ERANGE;
+ else if (len == 0)
+ return EINVAL;
+ else
+ return 0;
+}
+
+
+/*
+ * Makes a full path ending with \ from partial path
+ */
+static char *x_fulldir(const char *s)
+{
+ wchar_t full[X_MAX_PATH];
+ wchar_t path[X_MAX_PATH];
+ char *res;
+ wchar_t *fn;
+ size_t len;
+ int r;
+
+ if ((r = utf8_to_unicode_path(path, X_MAX_PATH, s, X_MAX_PATH))) {
+ errno = r;
+ return NULL;
+ }
+ len = GetFullPathNameW(path,
+ X_MAX_PATH - 2,
+ full, &fn);
+ if (len >= (X_MAX_PATH - 2)) {
+ errno = ERANGE;
+ }
+ if (len == 0) {
+ errno = x_cerror(GetLastError());
+ return NULL;
+ }
+ res = x_malloc(X_MAX_PATH);
+ if ((r = unicode_to_utf8_path(res, X_MAX_PATH - 2, full))) {
+ errno = r;
+ x_free(res);
+ return NULL;
+ }
+ len = strlen(res);
+ if (res[len - 1] != '\\' &&
+ res[len - 1] != '*') {
+ res[len++] = '\\';
+ res[len] = '\0';
+ }
+ return res;
+}
+
+static int x_createdir(const char *dir)
+{
+ wchar_t path[X_MAX_PATH];
+ int r;
+
+ if ((r = utf8_to_unicode_path(path, X_MAX_PATH, dir, MAX_PATH)))
+ return r;
+ if (!CreateDirectoryW(path, NULL)) {
+ r = x_cerror(GetLastError());
+ if (r == EEXIST) {
+ if (verbose)
+ warnx("cannot create directory '%S': %s",
+ path, cstrerror(EEXIST));
+ return EEXIST;
+ }
+ else if (r == ENOENT) {
+ return ENOENT;
+ }
+ else {
+ if (verbose)
+ warnx("cannot create directory '%S': %s",
+ path, cstrerror(r));
+ return r;
+ }
+ }
+ else {
+ if (verbose)
+ warnx("created directory '%S'", path);
+ return 0;
+ }
+}
+
+static int dir_make_parent(char *path)
+{
+ int rv;
+ char *ch = strrchr(path, '\\');
+ if (!ch)
+ return ENOENT;
+
+ *ch = '\0';
+ rv = x_createdir(path); /* Try to make straight off */
+
+ if (rv == ENOENT) {
+ /* Missing an intermediate dir */
+ rv = dir_make_parent(path);
+ if (rv == 0)
+ rv = x_createdir(path); /* And complete the path */
+ }
+
+ *ch = '\\'; /* Always replace the slash before returning */
+ return rv;
+}
+
+static int x_createdir_r(const char *path)
+{
+ int rv;
+ char *dir = x_fullpath(path);
+
+ rv = x_createdir(dir);
+ if (rv == EEXIST) {
+ /* It's OK if PATH exists */
+ x_free(dir);
+ return 0;
+ }
+ else if (rv == ENOENT) { /* Missing an intermediate dir */
+ rv = dir_make_parent(dir); /* Make intermediate dirs */
+ if (rv == 0) {
+ rv = x_createdir(dir); /* And complete the path */
+ }
+ }
+ x_free(dir);
+ return rv;
+}
+
+static int x_rmdir(const char *src)
+{
+ wchar_t path[X_MAX_PATH];
+ int r;
+ char *loc = x_fulldir(src);
+
+ if ((r = utf8_to_unicode_path(path, X_MAX_PATH, loc, MAX_PATH))) {
+ x_free(loc);
+ return r;
+ }
+ if (!RemoveDirectoryW(path))
+ r = x_cerror(GetLastError());
+ if (verbose) {
+ if (r)
+ warnx("cannot remove directory '%S': %s",
+ path, cstrerror(r));
+ else
+ warnx("removed directory '%S'", path);
+ }
+ x_free(loc);
+ return r;
+}
+
+static int x_rmdir_r(const char *src)
+{
+ wchar_t path[X_MAX_PATH];
+ int r;
+ int full = 0;
+ char *loc = x_fulldir(src);
+ SHFILEOPSTRUCTW op;
+
+ if ((r = utf8_to_unicode_path(path, X_MAX_PATH - 4, loc, 0))) {
+ x_free(loc);
+ return r;
+ }
+ if (path[wcslen(path) - 1] == L'\\') {
+ wcscat(path, L"*.*");
+ path[wcslen(path) + 1] = L'\0';
+ full = 1;
+ }
+ op.hwnd = NULL;
+ op.wFunc = FO_DELETE;
+ op.pFrom = path;
+ op.pTo = NULL;
+ op.fFlags = FOF_NOCONFIRMATION |
+ FOF_NOERRORUI |
+ FOF_SILENT;
+
+ r = x_cerror(SHFileOperationW(&op));
+ if (r == 0 && full) {
+ path[wcslen(path) - 4] = L'\0';
+ if (!RemoveDirectoryW(path))
+ r = x_cerror(GetLastError());
+ }
+ if (verbose) {
+ if (r)
+ warnx("cannot remove directory '%s': %s",
+ loc, cstrerror(r));
+ else
+ warnx("removed directory '%s'", loc);
+ }
+ x_free(loc);
+ return r;
+}
+
+static int x_rmfile(const char *src)
+{
+ wchar_t path[X_MAX_PATH];
+ int r;
+ char *loc = x_fullpath(src);
+ SHFILEOPSTRUCTW op;
+
+ if ((r = utf8_to_unicode_path(path, X_MAX_PATH, loc, 0))) {
+ x_free(loc);
+ return r;
+ }
+ op.hwnd = NULL;
+ op.wFunc = FO_DELETE;
+ op.pFrom = path;
+ op.pTo = NULL;
+ op.fFlags = FOF_NOCONFIRMATION |
+ FOF_NOERRORUI |
+ FOF_FILESONLY |
+ FOF_SILENT;
+
+ r = x_cerror(SHFileOperationW(&op));
+ if (verbose) {
+ if (r)
+ warnx("cannot remove file '%s': %s",
+ loc, cstrerror(r));
+ else
+ warnx("removed file '%s'", loc);
+ }
+ x_free(loc);
+ return r;
+}
+
+static int x_fstat(LPWIN32_FILE_ATTRIBUTE_DATA pa,
+ const char *src)
+{
+
+ wchar_t path[X_MAX_PATH];
+ int r = 0;
+
+ if (r = x_wfullpath(path, X_MAX_PATH, src))
+ return r;
+ if (!GetFileAttributesExW(path, GetFileExInfoStandard, pa)) {
+ r = x_cerror(GetLastError());
+ if (verbose && r != ENOENT) {
+ warnx("cannot stat file '%S': %s",
+ path, cstrerror(errno));
+ }
+ }
+ return r;
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * end of file functions
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * ---------------------------------------------------------------------
+ * begin of ini
+ * ---------------------------------------------------------------------
+ */
+
+static void ini_free(ini_section_t *ini)
+{
+ ini_section_t *p;
+ while (p = ini) {
+ ini_node_t *n;
+ while (n = ini->nodes) {
+ ini->nodes = n->next;
+ x_free(n->key);
+ x_free(n->val);
+ x_free(n);
+ }
+ ini = p->next;
+ x_free(p->name);
+ x_free(p);
+ }
+}
+
+static ini_section_t *ini_section_get(ini_section_t *ini, const char *name)
+{
+ ini_section_t *p;
+ for (p = ini; p; p = p->next) {
+ if (p->name && !stricmp(p->name, name))
+ return p;
+ }
+ return NULL;
+}
+
+static ini_section_t *ini_section_new(ini_section_t *top)
+{
+ ini_section_t *ini = x_calloc(sizeof(ini_section_t));
+ if (top) {
+ *top->last = ini;
+ top->last = &ini->next;
+ }
+ else
+ ini->last = &ini->next;
+
+ return ini;
+}
+
+static ini_node_t *ini_node_new(ini_section_t *ini)
+{
+ ini_node_t *node = x_calloc(sizeof(ini_node_t));
+ if (ini->nodes) {
+ *ini->nodes->last = node;
+ ini->nodes->last = &node->next;
+ }
+ else {
+ node->last = &node->next;
+ ini->nodes = node;
+ }
+ return node;
+}
+
+static ini_section_t *ini_load(const char *fname)
+{
+ FILE *fp;
+ ini_section_t *top = NULL;
+ ini_section_t *ini = NULL;
+ ini_node_t *node = NULL;
+ char buffer[X_MAX_PATH];
+ int counter = 0;
+ int nextline = 0;
+
+ if (!(fp = x_fopen(fname, "rt"))) {
+ if (verbose)
+ warnx("'%s' %s", fname, cstrerror(errno));
+ return NULL;
+ }
+ ini = top = ini_section_new(NULL);
+ while (fgets(buffer, X_MAX_PATH, fp)) {
+ char *section;
+ char *line;
+ /* Trim readed line */
+ counter++;
+ line = rtrim(buffer);
+ if (nextline) {
+ nextline = 0;
+ if (!node || *line == '\0')
+ continue;
+ node->val = x_strcat(node->val, line);
+ if (node->val[strlen(node->val) - 1] == '\\') {
+ node->val[strlen(node->val) - 1] = '\0';
+ nextline = 1;
+ }
+ if (!nextline) {
+ node->val = expand_envars(node->val);
+ }
+ continue;
+ }
+ line = ltrim(buffer);
+ /* Skip comments and empty lines*/
+ if (*line == '\0' || *line == '#' || *line == ';')
+ continue;
+ if (*line == '[') {
+ char *ends = strchr(++line, ']');
+ if (!ends) {
+ if (verbose)
+ warnx("'%s' unterminated section at line %d",
+ fname, counter);
+ goto cleanup;
+ }
+ *ends = '\0';
+ section = rltrim(line);
+ if (!(ini = ini_section_get(top, section))) {
+ ini = ini_section_new(top);
+ ini->name = x_strdup(section);
+ }
+ else {
+ if (verbose > 1)
+ warnx("'%s' duplicate section at line %d",
+ fname, counter);
+ }
+ continue;
+ }
+ else {
+ char *val = NULL;
+ char *equ = line;
+ if (*equ == '=')
+ equ++;
+ if (equ = strchr(equ, '=')) {
+ *equ++ = '\0';
+ val = rltrim(equ);
+ if (val[strlen(val) - 1] == '\\') {
+ val[strlen(val) - 1] = '\0';
+ nextline = 1;
+ }
+ if (!*val)
+ val = NULL;
+ }
+ line = rltrim(line);
+ if (!*line) {
+ /* Skip entries without keys **/
+ if (verbose > 1)
+ warnx("'%s' missing key at line %d",
+ fname, counter);
+ nextline = 0;
+ continue;
+ }
+ node = ini_node_new(ini);
+ node->key = x_strdup(line);
+ node->val = x_strdup(val);
+ if (node->val && !nextline) {
+ node->val = expand_envars(node->val);
+ }
+ }
+ }
+ fclose(fp);
+
+ return top;
+cleanup:
+ fclose(fp);
+ ini_free(top);
+ return NULL;
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * end of ini
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * ---------------------------------------------------------------------
+ * begin of utf-8
+ * ---------------------------------------------------------------------
+ */
+
+static int utf8_to_unicode_path(wchar_t* retstr, size_t retlen,
+ const char* srcstr, size_t unc)
+{
+ /* TODO: The computations could preconvert the string to determine
+ * the true size of the retstr, but that's a memory over speed
+ * tradeoff that isn't appropriate this early in development.
+ *
+ * Allocate the maximum string length based on leading 4
+ * characters of \\?\ (allowing nearly unlimited path lengths)
+ * plus the trailing null, then transform /'s into \\'s since
+ * the \\?\ form doesn't allow '/' path seperators.
+ *
+ * Note that the \\?\ form only works for local drive paths, and
+ * \\?\UNC\ is needed UNC paths.
+ */
+ size_t srcremains = strlen(srcstr) + 1;
+ wchar_t *t = retstr;
+
+ /* leave an extra space for double zero */
+ --retlen;
+ /* This is correct, we don't twist the filename if it is will
+ * definately be shorter than MAX_PATH. It merits some
+ * performance testing to see if this has any effect, but there
+ * seem to be applications that get confused by the resulting
+ * Unicode \\?\ style file names, especially if they use argv[0]
+ * or call the Win32 API functions such as GetModuleName, etc.
+ * Not every application is prepared to handle such names.
+ *
+ * Note that a utf-8 name can never result in more wide chars
+ * than the original number of utf-8 narrow chars.
+ */
+ if (srcremains > unc) {
+ if (srcstr[1] == ':' && (srcstr[2] == '/' || srcstr[2] ==
'\\')) {
+ wcscpy (retstr, L"\\\\?\\");
+ retlen -= 4;
+ t += 4;
+ }
+ else if ((srcstr[0] == '/' || srcstr[0] == '\\')
+ && (srcstr[1] == '/' || srcstr[1] == '\\')
+ && (srcstr[2] != '?')) {
+ /* Skip the slashes */
+ srcstr += 2;
+ srcremains -= 2;
+ wcscpy (retstr, L"\\\\?\\UNC\\");
+ retlen -= 8;
+ t += 8;
+ }
+ }
+ if (!MultiByteToWideChar(CP_UTF8, 0, srcstr, -1, t, retlen))
+ return x_cerror(0);
+ for (; *t; t++) {
+ if (*t == L'/')
+ *t = L'\\';
+ }
+ *t = L'\0';
+ return 0;
+}
+
+static int unicode_to_utf8_path(char* retstr, size_t retlen,
+ const wchar_t* srcstr)
+{
+ /* Skip the leading 4 characters if the path begins \\?\, or substitute
+ * // for the \\?\UNC\ path prefix, allocating the maximum string
+ * length based on the remaining string, plus the trailing null.
+ * then transform \\'s back into /'s since the \\?\ form never
+ * allows '/' path seperators, and APR always uses '/'s.
+ */
+ if (srcstr[0] == L'\\' && srcstr[1] == L'\\' &&
+ srcstr[2] == L'?' && srcstr[3] == L'\\') {
+ if (srcstr[4] == L'U' && srcstr[5] == L'N' &&
+ srcstr[6] == L'C' && srcstr[7] == L'\\') {
+ srcstr += 8;
+ retstr[0] = '\\';
+ retstr[1] = '\\';
+ retlen -= 2;
+ retstr += 2;
+ }
+ else {
+ srcstr += 4;
+ }
+ }
+
+ if (!WideCharToMultiByte(CP_UTF8, 0, srcstr, -1,
+ retstr, retlen, NULL, 0))
+ return x_cerror(0);
+
+ return 0;
+}
+
+/*
+ * An internal function to convert an array of strings (either
+ * a counted or NULL terminated list, such as an argv[argc] or env[]
+ * list respectively) from wide Unicode strings to narrow utf-8 strings.
+ * These are allocated from the MSVCRT's _CRT_BLOCK to trick the system
+ * into trusting our store.
+ */
+int wastrtoastr(char const * const **retarr,
+ wchar_t const * const *arr, int args)
+{
+ size_t elesize = 0;
+ char **newarr;
+ char *elements;
+ char *ele;
+ int arg;
+
+ if (args < 0) {
+ for (args = 0; arr[args]; ++args) {
+ /* Nothing. */
+ }
+ }
+ newarr = _malloc_dbg((args + 1) * sizeof(char *),
+ _CRT_BLOCK, __FILE__, __LINE__);
+
+ for (arg = 0; arg < args; ++arg) {
+ newarr[arg] = (void*)(wcslen(arr[arg]) + 1);
+ elesize += (size_t)newarr[arg];
+ }
+
+ /* This is a safe max allocation, we will realloc after
+ * processing and return the excess to the free store.
+ * 3 ucs bytes hold any single wchar_t value (16 bits)
+ * 4 ucs bytes will hold a wchar_t pair value (20 bits)
+ */
+ elesize = elesize * 3 + 1;
+ ele = elements = _malloc_dbg(elesize * sizeof(char),
+ _CRT_BLOCK, __FILE__, __LINE__);
+
+ for (arg = 0; arg < args; ++arg) {
+ size_t len = (size_t)newarr[arg];
+
+ newarr[arg] = ele;
+ len = WideCharToMultiByte(CP_UTF8, 0, arr[arg], -1,
+ newarr[arg], len, NULL, 0);
+ ele += len;
+ assert(len);
+ }
+
+ newarr[arg] = NULL;
+ *(ele++) = '\0';
+
+ /* Return to the free store if the heap realloc is the least bit optimized
+ */
+ ele = _realloc_dbg(elements, ele - elements,
+ _CRT_BLOCK, __FILE__, __LINE__);
+
+ if (ele != elements) {
+ size_t diff = ele - elements;
+ for (arg = 0; arg < args; ++arg) {
+ newarr[arg] += diff;
+ }
+ }
+
+ *retarr = newarr;
+ return args;
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * end of utf-8
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * ---------------------------------------------------------------------
+ * begin of tests
+ * ---------------------------------------------------------------------
+ */
+
+static void test_getopt(int argc, const char **argv)
+{
+ int ch;
+
+ while ((ch = getopt(argc, argv, "s:V:g:r:qLRS-")) != EOF) {
+ printf("Valid argument = %c [%s]\n", ch, optarg);
+ }
+ argc -= optind;
+ argv += optind;
+ for (ch = 0; ch < argc; ch++)
+ printf("Option %d is %s\n", ch, argv[ch]);
+}
+
+static int test_path()
+{
+ char *test[] = {
+ "test",
+ "\\test",
+ "\\\\?\\UNC\\C:\\..\\test/foo",
+ "//C://../../..\\..\\..\\..\\*/foo",
+
"C:\\W\\tools\\foo\\..\\..\\*/foo/barsalllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll/dddddddddddddddddddddddddddddddddddddddddddddddddddddddddaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+ "./",
+ NULL
+ };
+ char **p;
+ for (p = test; *p; p++) {
+ printf("Full path is: %s\n", x_fulldir(*p));
+ }
+ printf("Wide is %S\n", x_wstrdup_utf8("Ax"));
+ return 0;
+}
+
+static int test_ini()
+{
+
+ ini_section_t *ini = ini_load("test.ini");
+ ini_section_t *top = ini;
+ while (ini) {
+ ini_node_t *node = ini->nodes;
+ printf("Section [%s]\n", ini->name);
+ while (node) {
+ printf(" %s=%s\n", node->key, node->val);
+ node = node->next;
+ }
+ ini = ini->next;
+ }
+ ini_free(top);
+ return 0;
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * end of tests
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * ---------------------------------------------------------------------
+ * begin of user interface
+ * ---------------------------------------------------------------------
+ */
+
+static const char *programs[] = {
+ "mkdir", "Creates a new directory(ies)",
+ "rmdir", "Removes directory(ies)",
+ "touch", "Change file timestamps",
+ NULL, NULL
+};
+
+static const char str_license[] = ""
+"Licensed to the Apache Software Foundation (ASF) under one or more\n"
+"contributor license agreements. See the NOTICE file distributed with\n"
+"this work for additional information regarding copyright ownership.\n"
+"The ASF licenses this file to You under the Apache License, Version 2.0\n"
+"(the \"License\"); you may not use this file except in compliance
with\n"
+"the License. You may obtain a copy of the License at\n"
+"\n"
+"
http://www.apache.org/licenses/LICENSE-2.0\n"
+"\n"
+"Unless required by applicable law or agreed to in writing, software\n"
+"distributed under the License is distributed on an \"AS IS\"
BASIS,\n"
+"WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
+"See the License for the specific language governing permissions and\n"
+"limitations under the License.\n\n";
+
+static int print_banner(int license)
+{
+ fprintf(stdout, "xtools (Windows generic build tools) version 1.0.0\n");
+ fprintf(stdout, "Written by Mladen Turk (mturk(a)redhat.com).\n\n");
+ if (license)
+ fprintf(stdout, "%s", str_license);
+ return 0;
+}
+
+static void print_programs()
+{
+ const char **p;
+ fprintf(stderr, "Where supported commands are:\n\n");
+ for (p = programs; *p; p += 2) {
+ fprintf(stderr, " %-16s%s\n", *p, *(p+1));
+ }
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * end of user interface
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * ---------------------------------------------------------------------
+ * begin of programs usage
+ * ---------------------------------------------------------------------
+ */
+
+static int prog_mkdir_usage(int retval)
+{
+ fprintf(stderr, "Usage: %s [OPTION]... DIRECTORY...\n", progname);
+ fprintf(stderr, "Create the DIRECTORY(ies), if they do not already
exist.\n");
+ fprintf(stderr, "Any intermediate directories in the path are created, if
needed\n\n");
+ fprintf(stderr, " -v, -V, --verbose explain what is being done.\n");
+ fprintf(stderr, " --version output version information and
exit.\n");
+ fprintf(stderr, " -h, -H, --help display this help and exit.\n\n");
+ return retval;
+}
+
+static int prog_rmdir_usage(int retval)
+{
+ fprintf(stderr, "Usage: %s [OPTION]... DIRECTORY...\n", progname);
+ fprintf(stderr, "Remove (unlink) the DIRECTORY(ies).\n\n");
+ fprintf(stderr, " -r, -R, remove the contents of directories
recursively.\n\n");
+ fprintf(stderr, " -v, -V, --verbose explain what is being done.\n");
+ fprintf(stderr, " --version output version information and
exit.\n");
+ fprintf(stderr, " -h, -H, --help display this help and exit.\n\n");
+ return retval;
+}
+
+static int prog_touch_usage(int retval)
+{
+ fprintf(stderr, "Usage: %s [OPTION]... FILE...\n", progname);
+ fprintf(stderr, "Update the access and modification times of each FILE to the
current time\n\n");
+ fprintf(stderr, " -a, -A, change only the access time.\n");
+ fprintf(stderr, " -c, -C, do not create any files.\n");
+ fprintf(stderr, " -d, -D, STRING parse STRING and use it instead of current
time.\n");
+ fprintf(stderr, " -m, -M, change only the modification
time.\n");
+ fprintf(stderr, " -r, -R, FILE use this file time's instead current
time.\n");
+ fprintf(stderr, " -t, -T, STAMP use [[CC]YY]MMDDhhmm[.ss] instead of
current time.\n\n");
+ fprintf(stderr, " -v, -V, --verbose explain what is being done.\n");
+ fprintf(stderr, " --version output version information and
exit.\n");
+ fprintf(stderr, " -h, -H, --help display this help and exit.\n\n");
+ return retval;
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * end of programs usage
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * ---------------------------------------------------------------------
+ * begin of programs
+ * ---------------------------------------------------------------------
+ */
+
+static int prog_mkdir(int argc, const char **argv, const char **env)
+{
+ int i, ch, rv = 0;
+
+ verbose = 0;
+ x_free(__pname);
+ __pname = "mkdir";
+
+ while ((ch = getopt(argc, argv, "hHvV")) != EOF) {
+ switch (ch) {
+ case '.':
+ if (!strcmp(optarg, "verbose"))
+ verbose = 1;
+ else if (!strcmp(optarg, "version"))
+ return print_banner(1);
+ else if (!strcmp(optarg, "help"))
+ return prog_mkdir_usage(0);
+ else
+ return prog_mkdir_usage(EINVAL);
+ break;
+ case 'v':
+ case 'V':
+ verbose = 1;
+ break;
+ case 'h':
+ case 'H':
+ return prog_mkdir_usage(0);
+ break;
+ case '?':
+ return EINVAL;
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc < 1) {
+ return prog_mkdir_usage(EINVAL);
+ }
+
+ for (i = 0; i < argc; i++) {
+ if ((rv = x_createdir_r(argv[0])))
+ break;
+ }
+ return rv;
+}
+
+static int prog_rmdir(int argc, const char **argv, const char **env)
+{
+ int i, ch, rv = 0;
+ int recurse = 0;
+
+ x_free(__pname);
+ __pname = "rmdir";
+ while ((ch = getopt(argc, argv, "hHvVrR")) != EOF) {
+ switch (ch) {
+ case '.':
+ if (!strcmp(optarg, "verbose"))
+ verbose = 1;
+ else if (!strcmp(optarg, "version"))
+ return print_banner(1);
+ else if (!strcmp(optarg, "help"))
+ return prog_rmdir_usage(0);
+ else
+ return prog_rmdir_usage(EINVAL);
+ break;
+ case 'v':
+ case 'V':
+ verbose = 1;
+ break;
+ case 'h':
+ case 'H':
+ return prog_rmdir_usage(0);
+ break;
+ case 'r':
+ case 'R':
+ recurse = 1;
+ break;
+ case '?':
+ return EINVAL;
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc < 1) {
+ return prog_rmdir_usage(EINVAL);
+ }
+ for (i = 0; i < argc; i++) {
+ if (recurse) {
+ if ((rv = x_rmdir_r(argv[i])))
+ break;
+ }
+ else {
+ if ((rv = x_rmdir(argv[i])))
+ break;
+ }
+ }
+ return rv;
+}
+
+static int prog_touch(int argc, const char **argv, const char **env)
+{
+ int i, ch, rv = 0;
+ int force = 0;
+ int flags = 0;
+ DWORD create = OPEN_ALWAYS;
+ const char *from = NULL;
+ const char *tstr = NULL;
+ wchar_t file[X_MAX_PATH];
+ WIN32_FILE_ATTRIBUTE_DATA ad;
+
+ x_free(__pname);
+ __pname = "touch";
+ while ((ch = getopt(argc, argv, "aAcCfFmMr:R:t:hHvV")) != EOF) {
+ switch (ch) {
+ case '.':
+ if (!strcmp(optarg, "verbose"))
+ verbose = 1;
+ else if (!strcmp(optarg, "version"))
+ return print_banner(1);
+ else if (!strcmp(optarg, "help"))
+ return prog_touch_usage(0);
+ else
+ return prog_touch_usage(EINVAL);
+ break;
+ case 'v':
+ case 'V':
+ verbose = 1;
+ break;
+ case 'h':
+ case 'H':
+ return prog_touch_usage(0);
+ break;
+ case 'f':
+ case 'F':
+ force = 1;
+ case 'c':
+ case 'C':
+ create = OPEN_EXISTING;
+ break;
+ case 'a':
+ case 'A':
+ flags |= 1;
+ break;
+ case 'm':
+ case 'M':
+ flags |= 2;
+ break;
+ case 'r':
+ case 'R':
+ from = optarg;
+ break;
+ case 't':
+ case 'T':
+ tstr = optarg;
+ break;
+ case '?':
+ return EINVAL;
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc < 1) {
+ return prog_touch_usage(EINVAL);
+ }
+ if (!flags)
+ flags = 3;
+ if (from) {
+ if (rv = x_fstat(&ad, from)) {
+ if (verbose) {
+ x_wfullpath(file, X_MAX_PATH, from);
+ warnx("'%S' -- %s", file, cstrerror(rv));
+ }
+ return rv;
+ }
+ }
+ else if (tstr) {
+ SYSTEMTIME t;
+ size_t tl = strlen(tstr);
+ char *sp = strchr(tstr, '.');
+ int cen = 0;
+ int r = 0;
+ memset(&t, 0, sizeof(SYSTEMTIME));
+ if (sp)
+ tl -= (size_t)(sp - tstr);
+ if (tl == 12)
+ r = sscanf(tstr, "%4d%2d%2d%2d%2d",
+ &t.wYear, &t.wMonth,
+ &t.wDay, &t.wHour, &t.wMinute);
+ else if (tl == 10)
+ r = sscanf(tstr, "%2d%2d%2d%2d%2d",
+ &t.wYear, &t.wMonth,
+ &t.wDay, &t.wHour, &t.wMinute);
+ else if (tl == 8)
+ r = sscanf(tstr, "%2d%2d%2d%2d",
+ &t.wMonth,
+ &t.wDay, &t.wHour, &t.wMinute);
+
+ else {
+ if (verbose)
+ warnx("invalid time format %s", tstr);
+ return EINVAL;
+ }
+ if (sp)
+ t.wSecond = atoi(sp + 1);
+ if (t.wYear < 100) {
+ SYSTEMTIME n;
+ GetSystemTime(&n);
+ if (t.wYear)
+ t.wYear = (n.wYear - n.wYear % 100) + t.wYear;
+ else
+ t.wYear = n.wYear;
+ }
+ if (!SystemTimeToFileTime(&t, &ad.ftLastAccessTime)) {
+ if (verbose)
+ warnx("invalid time format %04d-%02d-%02d-%02d-%02d.%02d",
+ t.wYear, t.wMonth, t.wDay, t.wHour,
+ t.wMinute, t.wSecond);
+ return EINVAL;
+ }
+ ad.ftLastWriteTime = ad.ftLastAccessTime;
+ }
+ else {
+ GetSystemTimeAsFileTime(&ad.ftLastAccessTime);
+ ad.ftLastWriteTime = ad.ftLastAccessTime;
+ }
+ for (i = 0; i < argc; i++) {
+ HANDLE hf;
+ if ((rv = x_wfullpath(file, X_MAX_PATH, argv[i]))) {
+ if (verbose) {
+ warnx("'%s' -- %s", argv[i], cstrerror(rv));
+ }
+ return rv;
+ }
+ hf = CreateFileW(file, GENERIC_READ | GENERIC_WRITE,
+ 0, NULL, create,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hf == INVALID_HANDLE_VALUE) {
+ rv = x_cerror(0);
+ if (verbose) {
+ warnx("'%S' -- %s", file, cstrerror(rv));
+ }
+ return rv;
+ }
+ else {
+ FILETIME *at = NULL;
+ FILETIME *mt = NULL;
+ FILETIME *ct = NULL;
+ if (flags & 1)
+ at = &ad.ftLastAccessTime;
+ if (flags & 2)
+ mt = &ad.ftLastWriteTime;
+ GetFileTime(hf, &ad.ftCreationTime, NULL, NULL);
+ if (at && CompareFileTime(&ad.ftCreationTime, at) > 0) {
+ /* File creation time is higher then access
+ * time we wish to set
+ */
+ at = NULL;
+ }
+ if (mt && CompareFileTime(&ad.ftCreationTime, mt) > 0) {
+ /* File creation time is higher then modification
+ * time we wish to set
+ */
+ mt = NULL;
+ }
+ if (!SetFileTime(hf, NULL, at, mt)) {
+ rv = x_cerror(0);
+ if (verbose)
+ warnx("'%S' -- %s", file, cstrerror(rv));
+ }
+ if (verbose) {
+ if (at || mt)
+ warnx("'%S' modified.", file);
+ else
+ warnx("'%S' not modified.", file);
+ }
+ CloseHandle(hf);
+ }
+ }
+ return rv;
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * end of programs
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * ---------------------------------------------------------------------
+ * utf-8 main. Arguments passed are utf-8 encoded
+ * ---------------------------------------------------------------------
+ */
+static int umain(int argc, const char **argv, const char **env)
+{
+ const char *name = progname;
+ if (*name == 'x' || *name == 'X')
+ name++;
+ if (!stricmp(name, "mkdir"))
+ return prog_mkdir(argc, argv, env);
+ else {
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s <command>\n",
+ progname);
+ return EINVAL;
+ }
+ if (!stricmp(argv[1], "mkdir"))
+ return prog_mkdir(--argc, ++argv, env);
+ else if (!stricmp(argv[1], "rmdir"))
+ return prog_rmdir(--argc, ++argv, env);
+ else if (!stricmp(argv[1], "touch"))
+ return prog_touch(--argc, ++argv, env);
+ else if (!stricmp(argv[1], "test")) {
+ argc -= 2;
+ argv += 2;
+ printf("Test %d %s\n", argc, *argv);
+ if (argc && !strcmp(*argv, "ini"))
+ return test_ini();
+ if (argc && !strcmp(*argv, "path"))
+ return test_path(--argc, ++argv, env);
+ }
+ else {
+ fprintf(stderr, "Usage: %s <command>\n",
+ progname);
+ print_programs();
+ return EINVAL;
+ }
+ }
+ return 0;
+}
+
+static void setup_env(const char **env)
+{ char *e;
+ if ((e = getenv("XTOOLS_PAUSE")) != NULL)
+ xtools_pause = 1;
+ if ((e = getenv("XTOOLS_VERBOSE")) != NULL) {
+ verbose = atoi(e);
+ if (!verbose)
+ verbose = 1;
+ }
+}
+
+int wmain(int argc, const wchar_t **wargv, const wchar_t **wenv)
+{
+ char **argv;
+ char **env;
+ wchar_t *modname;
+ int dupenv;
+ int rv;
+
+ /* Find on what we are running */
+ GetSystemInfo(&win_osinf);
+ win_osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXA);
+ GetVersionExA((LPOSVERSIONINFOA)&win_osver);
+
+ if (win_osver.dwMajorVersion < 5) {
+ /* Pre WIN2K. bail out */
+ fprintf(stderr, "This program cannot be run on < Windows 2000\n");
+ _exit(EACCES);
+ return EACCES;
+ }
+ wastrtoastr(&argv, wargv, argc);
+ dupenv = wastrtoastr(&env, wenv, -1);
+
+ _environ = _malloc_dbg((dupenv + 1) * sizeof (char *),
+ _CRT_BLOCK, __FILE__, __LINE__);
+ memcpy(_environ, env, (dupenv + 1) * sizeof (char *));
+
+ /*
+ * MSVCRT will attempt to maintain the wide environment calls
+ * on _putenv(), which is bogus if we've passed a non-ascii
+ * string to _putenv(), since they use MultiByteToWideChar
+ * and breaking the implicit utf-8 assumption we've built.
+ *
+ * Reset _wenviron for good measure.
+ */
+ if (_wenviron) {
+ wenv = _wenviron;
+ _wenviron = NULL;
+ free((wchar_t **)wenv);
+ }
+ modname = x_malloc(X_MAX_PATH * 2);
+ __argv0 = x_malloc(X_MAX_PATH);
+ if (!GetModuleFileNameExW(GetCurrentProcess(), NULL,
+ modname, X_MAX_PATH))
+ exit(GetLastError());
+ if ((rv = unicode_to_utf8_path(__argv0, X_MAX_PATH, modname)))
+ exit(rv);
+ x_free(modname);
+ setup_env(env);
+ rv = umain(argc, argv, env);
+ if (xtools_pause) {
+ fprintf(stdout, "\nPress any key to continue...");
+ getch();
+ fprintf(stdout, "\n");
+ }
+ if (verbose)
+ warnx("exit(%d)", rv);
+ exit(rv);
+ /*
+ * Never reached.
+ * Just to make compiler happy
+ */
+ return rv;
+}
Property changes on: trunk/build/install/xtool/xtool.c
___________________________________________________________________
Name: svn:eol-style
+ native
Added: trunk/build/install/xtool/xtool.rc
===================================================================
--- trunk/build/install/xtool/xtool.rc (rev 0)
+++ trunk/build/install/xtool/xtool.rc 2008-03-31 12:14:20 UTC (rev 1489)
@@ -0,0 +1,77 @@
+/*
+ * XTOOL - Windows generic build tools
+ *
+ * Copyright(c) 2007 Red Hat Middleware, LLC,
+ * and individual contributors as indicated by the @authors tag.
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * @author Mladen Turk
+ */
+
+#include <windows.h>
+
+#define STR_COPYRIGHT "Copyright � 2008 Red Hat Middleware, LLC. " \
+ "or its licensors, as applicable."
+
+#define STR_LICENSE "Distributable under LGPL license. " \
+ "See terms of license at gnu.org."
+
+#define STR_COMPANY "Red Hat�, Inc."
+#define STR_TRADEMARK "� Red Hat Inc."
+#define STR_PRODUCT "Xtool"
+#define STR_DESCR "Xtool - Windows generic build tools"
+
+#define STR_VERSION "1.0.0.0"
+
+IDI_MAINICON ICON "jboss.ico"
+IDI_RHELICON ICON "redhat.ico"
+
+1 VERSIONINFO
+ FILEVERSION 1,0,0,0
+ PRODUCTVERSION 1,0,0,0
+ FILEFLAGSMASK 0x3fL
+#if defined(_DEBUG)
+ FILEFLAGS 0x03L
+#else
+ FILEFLAGS 0x02L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "Comments", STR_COPYRIGHT "\0"
+ VALUE "CompanyName", STR_COMPANY "\0"
+ VALUE "FileDescription", STR_PRODUCT "\0"
+ VALUE "FileVersion", STR_VERSION
+ VALUE "InternalName", STR_PRODUCT "\0"
+ VALUE "LegalCopyright", STR_COPYRIGHT "\0"
+ VALUE "OriginalFilename", "xtool.exe\0"
+ VALUE "ProductName", STR_PRODUCT "\0"
+ VALUE "ProductVersion", STR_VERSION
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END