#ifndef __CMDPACK_COMMON_H__ #define __CMDPACK_COMMON_H__ //////////////////////////////////////////////////////////////////////////////// // // Common headers for Command-Line Pack programs // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // //////////////////////////////////////////////////////////////////////////////// // Disable fopen() warnings on VC++. It means well... #define _CRT_SECURE_NO_WARNINGS // Try to enable 64-bit file offsets on platforms where it's optional #define _LARGEFILE64_SOURCE 1 #define __USE_FILE_OFFSET64 1 #define __USE_LARGEFILE64 1 #define _FILE_OFFSET_BITS 64 // Try to enable long filename support on Watcom #define __WATCOM_LFN__ 1 // Convince MinGW that we want to glob arguments #ifdef __MINGW32__ int _dowildcard = -1; #endif //////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include // MSC toolchains use sys/utime.h; everything else uses utime.h #if defined(_MSC_VER) #include #else #include #endif // Try to bring in unistd.h if possible #if !defined(__TURBOC__) && !defined(_MSC_VER) #include #endif // Bring in direct.h if we need to; sometimes mkdir/rmdir is defined here #if defined(__WATCOMC__) || defined(_MSC_VER) #include #endif // Fill in S_ISDIR #if !defined(_POSIX_VERSION) && !defined(S_ISDIR) #define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) #endif #if defined(__TURBOC__) || defined(__WATCOMC__) || defined(__MINGW32__) || defined(_MSC_VER) // // Already have a single-argument mkdir() // #else // // Provide a single-argument mkdir() // #define mkdir(a) mkdir(a, S_IRWXU | S_IRWXG | S_IRWXO) #endif //////////////////////////////////////////////////////////////////////////////// // // Enforce large memory model for 16-bit DOS targets // #if defined(__MSDOS__) || defined(MSDOS) #if defined(__TURBOC__) || defined(__WATCOMC__) #if !defined(__LARGE__) #error This is not the memory model we should be using! #endif #endif #endif //////////////////////////////////////////////////////////////////////////////// // // Try to figure out integer types // #if defined(_STDINT_H) || defined(_EXACT_WIDTH_INTS) // _STDINT_H_ - presume stdint.h has already been included // _EXACT_WIDTH_INTS - OpenWatcom already provides int*_t in sys/types.h #elif defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L // Assume C99 compliance when the compiler specifically tells us it is #include #elif defined(_MSC_VER) // On Visual Studio, use its integral types typedef signed __int8 int8_t; typedef unsigned __int8 uint8_t; typedef signed __int16 int16_t; typedef unsigned __int16 uint16_t; typedef signed __int32 int32_t; typedef unsigned __int32 uint32_t; #else // Guess integer sizes from limits.h // // int8_t // #ifndef __int8_t_defined #if SCHAR_MIN == -128 && SCHAR_MAX == 127 && UCHAR_MAX == 255 typedef signed char int8_t; #else #error Unknown how to define int8_t! #endif #endif // // uint8_t // #ifndef __uint8_t_defined #if SCHAR_MIN == -128 && SCHAR_MAX == 127 && UCHAR_MAX == 255 typedef unsigned char uint8_t; #else #error Unknown how to define uint8_t! #endif #endif // // int16_t // #ifndef __int16_t_defined #if SHRT_MIN == -32768 && SHRT_MAX == 32767 && USHRT_MAX == 65535 typedef signed short int16_t; #else #error Unknown how to define int16_t! #endif #endif // // uint16_t // #ifndef __uint16_t_defined #if SHRT_MIN == -32768 && SHRT_MAX == 32767 && USHRT_MAX == 65535 typedef unsigned short uint16_t; #else #error Unknown how to define uint16_t! #endif #endif // // int32_t // #ifndef __int32_t_defined #if INT_MIN == -2147483648 && INT_MAX == 2147483647 && UINT_MAX == 4294967295 typedef signed int int32_t; #elif LONG_MIN == -2147483648 && LONG_MAX == 2147483647 && ULONG_MAX == 4294967295 typedef signed long int32_t; #else #error Unknown how to define int32_t! #endif #endif // // uint32_t // #ifndef __uint32_t_defined #if INT_MIN == -2147483648 && INT_MAX == 2147483647 && UINT_MAX == 4294967295 typedef unsigned int uint32_t; #elif LONG_MIN == -2147483648 && LONG_MAX == 2147483647 && ULONG_MAX == 4294967295 typedef unsigned long uint32_t; #else #error Unknown how to define uint32_t! #endif #endif #endif // // There are some places in the code where it's assumed 'long' can hold at least // 32 bits. Verify that here: // #if LONG_MAX < 2147483647 || ULONG_MAX < 4294967295 #error long type must be at least 32 bits! #endif //////////////////////////////////////////////////////////////////////////////// // // Figure out how big file offsets should be // #if defined(_OFF64_T_) || defined(_OFF64_T_DEFINED) || defined(__off64_t_defined) // // We have off64_t // Regular off_t may be smaller, so check this first // #ifdef off_t #undef off_t #endif #ifdef fseeko #undef fseeko #endif #ifdef ftello #undef ftello #endif #define off_t off64_t #define fseeko fseeko64 #define ftello ftello64 #elif defined(_OFF_T) || defined(__OFF_T_TYPE) || defined(__off_t_defined) || defined(_OFF_T_DEFINED_) // // We have off_t // #else // // Assume offsets are just 'long' // #ifdef off_t #undef off_t #endif #ifdef fseeko #undef fseeko #endif #ifdef ftello #undef ftello #endif #define off_t long #define fseeko fseek #define ftello ftell #endif // // Add the ability to read off_t // (assumes off_t is a signed type) // off_t strtoofft(const char *s_start, char **endptr, int base) { off_t max = ((((off_t)1) << ((sizeof(off_t) * 8) - 2)) - 1) + ((((off_t)1) << ((sizeof(off_t) * 8) - 2))); off_t min = ((-1) - max); const char *s = s_start; off_t accumulator; off_t limit_tens; off_t limit_ones; int c; int negative = 0; int anyinput; do { c = *s++; } while(isspace(c)); if(c == '-') { negative = 1; c = *s++; } else if(c == '+') { c = *s++; } if((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { c = s[1]; s += 2; base = 16; } if(!base) { base = (c == '0') ? 8 : 10; } limit_ones = max % ((off_t)base); limit_tens = max / ((off_t)base); if(negative) { limit_ones++; if(limit_ones >= base) { limit_ones = 0; limit_tens++; } } for(accumulator = 0, anyinput = 0;; c = *s++) { if(isdigit(c)) { c -= '0'; } else if(isalpha(c)) { c -= isupper(c) ? 'A' - 10 : 'a' - 10; } else { break; } if(c >= base) { break; } if((anyinput < 0) || (accumulator < 0) || (accumulator > limit_tens) || (accumulator == limit_tens && c > limit_ones)) { anyinput = -1; } else { anyinput = 1; accumulator *= base; accumulator += c; } } if(anyinput < 0) { accumulator = negative ? min : max; errno = ERANGE; } else if(negative) { accumulator = -accumulator; } if(endptr) { *endptr = (char *)(anyinput ? (char *)s - 1 : s_start); } return accumulator; } // // Add the ability to print off_t // void fprinthex(FILE *f, off_t off, int min_digits) { unsigned anydigit = 0; int place; for(place = 2 * sizeof(off_t) - 1; place >= 0; place--) { if(sizeof(off_t) > (((size_t)(place)) / 2)) { unsigned digit = (off >> (4 * place)) & 0xF; anydigit |= digit; if(anydigit || place < min_digits) { fputc("0123456789ABCDEF"[digit], f); } } } } static void fprintdec_digit(FILE *f, off_t off) { if(off == 0) { return; } if(off >= 10) { fprintdec_digit(f, off / ((off_t)10)); off %= ((off_t)10); } fputc('0' + off, f); } void fprintdec(FILE *f, off_t off) { if(off == 0) { fputc('0', f); return; } if(off < 0) { fputc('-', f); off = -off; if(off < 0) { off_t ones = off % ((off_t)10); off /= ((off_t)10); off = -off; fprintdec_digit(f, off); fputc('0' - ones, f); return; } } fprintdec_digit(f, off); } //////////////////////////////////////////////////////////////////////////////// // // Define truncate() for systems that don't have it // #if !defined(_POSIX_VERSION) #if(defined(__MSDOS__) || defined(MSDOS)) && (defined(__TURBOC__) || defined(__WATCOMC__)) #include #include #include int truncate(const char *filename, off_t size) { if(size < 0) { errno = EINVAL; return -1; } // // Extend (or do nothing) if necessary // { off_t end; FILE *f = fopen(filename, "rb"); if(!f) { return -1; } if(fseeko(f, 0, SEEK_END) != 0) { fclose(f); return -1; } end = ftello(f); if(end <= size) { for(; end < size; end++) { if(fputc(0, f) == EOF) { fclose(f); return -1; } } fclose(f); return 0; } fclose(f); } // // Shrink if necessary (DOS-specific call) // { int doshandle = 0; unsigned nwritten = 0; if(_dos_open(filename, O_WRONLY, &doshandle)) { return -1; } if(lseek(doshandle, size, SEEK_SET) == -1L) { _dos_close(doshandle); return -1; } if(_dos_write(doshandle, &doshandle, 0, &nwritten)) { _dos_close(doshandle); return -1; } _dos_close(doshandle); } // // Success // return 0; } #elif(defined(_WIN32) && defined(_MSC_VER)) #if defined(_MSC_VER) // Disable extension warnings for and friends #pragma warning(disable : 4226) #endif #include #ifndef INVALID_SET_FILE_POINTER #define INVALID_SET_FILE_POINTER ((DWORD)(-1)) #endif int truncate(const char *filename, off_t size) { if(size < 0) { errno = EINVAL; return -1; } // // Extend (or do nothing) if necessary // { off_t end; FILE *f = fopen(filename, "rb"); if(!f) { return -1; } if(fseeko(f, 0, SEEK_END) != 0) { fclose(f); return -1; } end = ftello(f); if(end <= size) { for(; end < size; end++) { if(fputc(0, f) == EOF) { fclose(f); return -1; } } fclose(f); return 0; } fclose(f); } // // Shrink if necessary (Windows-specific call) // { HANDLE f = CreateFile(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(f == INVALID_HANDLE_VALUE) { return -1; } if(size > ((off_t)0x7FFFFFFFL)) { // use fancy 64-bit SetFilePointer LONG lo = size; LONG hi = size >> 32; if(SetFilePointer(f, lo, &hi, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { CloseHandle(f); return -1; } } else { // use plain 32-bit SetFilePointer if(SetFilePointer(f, size, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { CloseHandle(f); return -1; } } if(!SetEndOfFile(f)) { CloseHandle(f); return -1; } } // // Success // return 0; } #endif #endif // !defined(_POSIX_VERSION) //////////////////////////////////////////////////////////////////////////////// // // Normalize argv[0] // void normalize_argv0(char *argv0) { size_t i; size_t start = 0; int c; for(i = 0; argv0[i]; i++) { if(argv0[i] == '/' || argv0[i] == '\\') { start = i + 1; } } i = 0; do { c = ((unsigned char)(argv0[start + i])); if(c == '.') { c = 0; } if(c != 0) { c = tolower(c); } argv0[i++] = c; } while(c != 0); } //////////////////////////////////////////////////////////////////////////////// void printfileerror(FILE *f, const char *name) { int e = errno; printf("Error: "); if(name) { printf("%s: ", name); } printf("%s (%d)\n", f && feof(f) ? "Unexpected end-of-file" : strerror(e), e); } //////////////////////////////////////////////////////////////////////////////// #if defined(_WIN32) // // Detect if the user double-clicked on the .exe rather than executing this from // the command line, and if so, display a warning and wait for input before // exiting // #include static HWND getconsolewindow(void) { HWND hConsoleWindow = NULL; HANDLE k32; // // See if GetConsoleWindow is available (Windows 2000 or later) // k32 = GetModuleHandle(TEXT("kernel32.dll")); if(k32) { typedef HWND (*WINAPI gcw_t)(void); gcw_t gcw = (gcw_t)GetProcAddress(k32, TEXT("GetConsoleWindow")); if(gcw) { hConsoleWindow = gcw(); } } // // There is an alternative method that involves FindWindow, but it's too // cumbersome for just printing a warning. // return hConsoleWindow; } void commandlinewarning(void) { HWND hConsoleWindow; DWORD processId = 0; // // This trick doesn't work in Win9x // if(GetVersion() >= ((DWORD)0x80000000LU)) { return; } // // See if the console window belongs to my own process // hConsoleWindow = getconsolewindow(); if(!hConsoleWindow) { return; } GetWindowThreadProcessId(hConsoleWindow, &processId); if(GetCurrentProcessId() == processId) { printf("\n" "Note: This is a command-line application.\n" "It was meant to run from a Windows command prompt.\n\n" "Press ENTER to close this window..."); fflush(stdout); fgetc(stdin); } } #else void commandlinewarning(void) {} #endif //////////////////////////////////////////////////////////////////////////////// // // Work around some problems with the Mariko CC toolchain // #ifdef MARIKO_CC // 32-bit signed and unsigned mod seem buggy; this solves it unsigned long __umodsi3(unsigned long a, unsigned long b) { return a - (a / b) * b; } signed long __modsi3(signed long a, signed long b) { return a - (a / b) * b; } // Some kind of soft float linkage issue? void __cmpdf2(void) {} #endif //////////////////////////////////////////////////////////////////////////////// #endif