1 #ifndef __CMDPACK_COMMON_H__
2 #define __CMDPACK_COMMON_H__
3 
4 ////////////////////////////////////////////////////////////////////////////////
5 //
6 // Common headers for Command-Line Pack programs
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation, either version 3 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 //
21 ////////////////////////////////////////////////////////////////////////////////
22 
23 // Disable fopen() warnings on VC++. It means well...
24 #define _CRT_SECURE_NO_WARNINGS
25 
26 // Try to enable 64-bit file offsets on platforms where it's optional
27 #define _LARGEFILE64_SOURCE 1
28 #define __USE_FILE_OFFSET64 1
29 #define __USE_LARGEFILE64 1
30 #define _FILE_OFFSET_BITS 64
31 
32 // Try to enable long filename support on Watcom
33 #define __WATCOM_LFN__ 1
34 
35 // Convince MinGW that we want to glob arguments
36 #ifdef __MINGW32__
37 int _dowildcard = -1;
38 #endif
39 
40 ////////////////////////////////////////////////////////////////////////////////
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <stdarg.h>
46 #include <ctype.h>
47 #include <errno.h>
48 #include <time.h>
49 #include <sys/stat.h>
50 #include <sys/types.h>
51 #include <limits.h>
52 
53 // MSC toolchains use sys/utime.h; everything else uses utime.h
54 #if defined(_MSC_VER)
55 #include <sys/utime.h>
56 #else
57 #include <utime.h>
58 #endif
59 
60 // Try to bring in unistd.h if possible
61 #if !defined(__TURBOC__) && !defined(_MSC_VER)
62 #include <unistd.h>
63 #endif
64 
65 // Bring in direct.h if we need to; sometimes mkdir/rmdir is defined here
66 #if defined(__WATCOMC__) || defined(_MSC_VER)
67 #include <direct.h>
68 #endif
69 
70 // Fill in S_ISDIR
71 #if !defined(_POSIX_VERSION) && !defined(S_ISDIR)
72 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
73 #endif
74 
75 #if defined(__TURBOC__) || defined(__WATCOMC__) || defined(__MINGW32__) || defined(_MSC_VER)
76 //
77 // Already have a single-argument mkdir()
78 //
79 #else
80 //
81 // Provide a single-argument mkdir()
82 //
83 #define mkdir(a) mkdir(a, S_IRWXU | S_IRWXG | S_IRWXO)
84 #endif
85 
86 ////////////////////////////////////////////////////////////////////////////////
87 //
88 // Enforce large memory model for 16-bit DOS targets
89 //
90 #if defined(__MSDOS__) || defined(MSDOS)
91 #if defined(__TURBOC__) || defined(__WATCOMC__)
92 #if !defined(__LARGE__)
93 #error This is not the memory model we should be using!
94 #endif
95 #endif
96 #endif
97 
98 ////////////////////////////////////////////////////////////////////////////////
99 //
100 // Try to figure out integer types
101 //
102 #if defined(_STDINT_H) || defined(_EXACT_WIDTH_INTS)
103 
104 // _STDINT_H_ - presume stdint.h has already been included
105 // _EXACT_WIDTH_INTS - OpenWatcom already provides int*_t in sys/types.h
106 
107 #elif defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L
108 
109 // Assume C99 compliance when the compiler specifically tells us it is
110 #include <stdint.h>
111 
112 #elif defined(_MSC_VER)
113 
114 // On Visual Studio, use its integral types
115 typedef   signed __int8   int8_t;
116 typedef unsigned __int8  uint8_t;
117 typedef   signed __int16  int16_t;
118 typedef unsigned __int16 uint16_t;
119 typedef   signed __int32  int32_t;
120 typedef unsigned __int32 uint32_t;
121 
122 #else
123 
124 // Guess integer sizes from limits.h
125 
126 //
127 // int8_t
128 //
129 #ifndef __int8_t_defined
130 #if SCHAR_MIN == -128 && SCHAR_MAX == 127 && UCHAR_MAX == 255
131 typedef signed char int8_t;
132 #else
133 #error Unknown how to define int8_t!
134 #endif
135 #endif
136 
137 //
138 // uint8_t
139 //
140 #ifndef __uint8_t_defined
141 #if SCHAR_MIN == -128 && SCHAR_MAX == 127 && UCHAR_MAX == 255
142 typedef unsigned char uint8_t;
143 #else
144 #error Unknown how to define uint8_t!
145 #endif
146 #endif
147 
148 //
149 // int16_t
150 //
151 #ifndef __int16_t_defined
152 #if SHRT_MIN == -32768 && SHRT_MAX == 32767 && USHRT_MAX == 65535
153 typedef signed short int16_t;
154 #else
155 #error Unknown how to define int16_t!
156 #endif
157 #endif
158 
159 //
160 // uint16_t
161 //
162 #ifndef __uint16_t_defined
163 #if SHRT_MIN == -32768 && SHRT_MAX == 32767 && USHRT_MAX == 65535
164 typedef unsigned short uint16_t;
165 #else
166 #error Unknown how to define uint16_t!
167 #endif
168 #endif
169 
170 //
171 // int32_t
172 //
173 #ifndef __int32_t_defined
174 #if    INT_MIN == -2147483648 &&  INT_MAX == 2147483647 &&  UINT_MAX == 4294967295
175 typedef signed int int32_t;
176 #elif LONG_MIN == -2147483648 && LONG_MAX == 2147483647 && ULONG_MAX == 4294967295
177 typedef signed long int32_t;
178 #else
179 #error Unknown how to define int32_t!
180 #endif
181 #endif
182 
183 //
184 // uint32_t
185 //
186 #ifndef __uint32_t_defined
187 #if    INT_MIN == -2147483648 &&  INT_MAX == 2147483647 &&  UINT_MAX == 4294967295
188 typedef unsigned int uint32_t;
189 #elif LONG_MIN == -2147483648 && LONG_MAX == 2147483647 && ULONG_MAX == 4294967295
190 typedef unsigned long uint32_t;
191 #else
192 #error Unknown how to define uint32_t!
193 #endif
194 #endif
195 
196 #endif
197 
198 //
199 // There are some places in the code where it's assumed 'long' can hold at least
200 // 32 bits.  Verify that here:
201 //
202 #if LONG_MAX < 2147483647 || ULONG_MAX < 4294967295
203 #error long type must be at least 32 bits!
204 #endif
205 
206 ////////////////////////////////////////////////////////////////////////////////
207 //
208 // Figure out how big file offsets should be
209 //
210 #if defined(_OFF64_T_) || defined(_OFF64_T_DEFINED) || defined(__off64_t_defined)
211 //
212 // We have off64_t
213 // Regular off_t may be smaller, so check this first
214 //
215 
216 #ifdef off_t
217 #undef off_t
218 #endif
219 #ifdef fseeko
220 #undef fseeko
221 #endif
222 #ifdef ftello
223 #undef ftello
224 #endif
225 
226 #define off_t off64_t
227 #define fseeko fseeko64
228 #define ftello ftello64
229 
230 #elif defined(_OFF_T) || defined(__OFF_T_TYPE) || defined(__off_t_defined) || defined(_OFF_T_DEFINED_)
231 //
232 // We have off_t
233 //
234 
235 #else
236 //
237 // Assume offsets are just 'long'
238 //
239 #ifdef off_t
240 #undef off_t
241 #endif
242 #ifdef fseeko
243 #undef fseeko
244 #endif
245 #ifdef ftello
246 #undef ftello
247 #endif
248 
249 #define off_t long
250 #define fseeko fseek
251 #define ftello ftell
252 
253 #endif
254 
255 //
256 // Add the ability to read off_t
257 // (assumes off_t is a signed type)
258 //
strtoofft(const char * s_start,char ** endptr,int base)259 off_t strtoofft(const char* s_start, char** endptr, int base) {
260     off_t max =
261         ((((off_t)1) << ((sizeof(off_t)*8)-2)) - 1) +
262         ((((off_t)1) << ((sizeof(off_t)*8)-2))    );
263     off_t min = ((-1) - max);
264     const char* s = s_start;
265     off_t accumulator;
266     off_t limit_tens;
267     off_t limit_ones;
268     int c;
269     int negative = 0;
270     int anyinput;
271     do {
272         c = *s++;
273     } while(isspace(c));
274     if(c == '-') {
275         negative = 1;
276         c = *s++;
277     } else if (c == '+') {
278         c = *s++;
279     }
280     if(
281         (base == 0 || base == 16) &&
282         c == '0' && (*s == 'x' || *s == 'X')
283     ) {
284         c = s[1];
285         s += 2;
286         base = 16;
287     }
288     if(!base) {
289         base = (c == '0') ? 8 : 10;
290     }
291     limit_ones = max % ((off_t)base);
292     limit_tens = max / ((off_t)base);
293     if(negative) {
294         limit_ones++;
295         if(limit_ones >= base) { limit_ones = 0; limit_tens++; }
296     }
297     for(accumulator = 0, anyinput = 0;; c = *s++) {
298         if(isdigit(c)) {
299             c -= '0';
300         } else if(isalpha(c)) {
301             c -= isupper(c) ? 'A' - 10 : 'a' - 10;
302         } else {
303             break;
304         }
305         if(c >= base) { break; }
306         if(
307             (anyinput < 0) ||
308             (accumulator < 0) ||
309             (accumulator > limit_tens) ||
310             (accumulator == limit_tens && c > limit_ones)
311         ) {
312             anyinput = -1;
313         } else {
314             anyinput = 1;
315             accumulator *= base;
316             accumulator += c;
317         }
318     }
319     if(anyinput < 0) {
320         accumulator = negative ? min : max;
321         errno = ERANGE;
322     } else if(negative) {
323         accumulator = -accumulator;
324     }
325     if(endptr) {
326         *endptr = (char*)(anyinput ? (char*)s - 1 : s_start);
327     }
328     return accumulator;
329 }
330 
331 //
332 // Add the ability to print off_t
333 //
fprinthex(FILE * f,off_t off,int min_digits)334 void fprinthex(FILE* f, off_t off, int min_digits) {
335     unsigned anydigit = 0;
336     int place;
337     for(place = 2 * sizeof(off_t) - 1; place >= 0; place--) {
338         if(sizeof(off_t) > (((size_t)(place)) / 2)) {
339             unsigned digit = (off >> (4 * place)) & 0xF;
340             anydigit |= digit;
341             if(anydigit || place < min_digits) {
342                 fputc("0123456789ABCDEF"[digit], f);
343             }
344         }
345     }
346 }
347 
fprintdec_digit(FILE * f,off_t off)348 static void fprintdec_digit(FILE* f, off_t off) {
349     if(off == 0) { return; }
350     if(off >= 10) {
351         fprintdec_digit(f, off / ((off_t)10));
352         off %= ((off_t)10);
353     }
354     fputc('0' + off, f);
355 }
356 
fprintdec(FILE * f,off_t off)357 void fprintdec(FILE* f, off_t off) {
358     if(off == 0) {
359         fputc('0', f);
360         return;
361     }
362     if(off < 0) {
363         fputc('-', f);
364         off = -off;
365         if(off < 0) {
366             off_t ones = off % ((off_t)10);
367             off /= ((off_t)10);
368             off = -off;
369             fprintdec_digit(f, off);
370             fputc('0' - ones, f);
371             return;
372         }
373     }
374     fprintdec_digit(f, off);
375 }
376 
377 ////////////////////////////////////////////////////////////////////////////////
378 //
379 // Define truncate() for systems that don't have it
380 //
381 #if !defined(_POSIX_VERSION)
382 
383 #if (defined(__MSDOS__) || defined(MSDOS)) && (defined(__TURBOC__) || defined(__WATCOMC__))
384 
385 #include <dos.h>
386 #include <io.h>
387 #include <fcntl.h>
truncate(const char * filename,off_t size)388 int truncate(const char *filename, off_t size) {
389     if(size < 0) {
390         errno = EINVAL;
391         return -1;
392     }
393     //
394     // Extend (or do nothing) if necessary
395     //
396     {   off_t end;
397         FILE* f = fopen(filename, "rb");
398         if(!f) {
399             return -1;
400         }
401         if(fseeko(f, 0, SEEK_END) != 0) {
402             fclose(f);
403             return -1;
404         }
405         end = ftello(f);
406         if(end <= size) {
407             for(; end < size; end++) {
408                 if(fputc(0, f) == EOF) {
409                     fclose(f);
410                     return -1;
411                 }
412             }
413             fclose(f);
414             return 0;
415         }
416         fclose(f);
417     }
418     //
419     // Shrink if necessary (DOS-specific call)
420     //
421     {   int doshandle = 0;
422         unsigned nwritten = 0;
423         if(_dos_open(filename, O_WRONLY, &doshandle)) {
424             return -1;
425         }
426         if(lseek(doshandle, size, SEEK_SET) == -1L) {
427             _dos_close(doshandle);
428             return -1;
429         }
430         if(_dos_write(doshandle, &doshandle, 0, &nwritten)) {
431             _dos_close(doshandle);
432             return -1;
433         }
434         _dos_close(doshandle);
435     }
436     //
437     // Success
438     //
439     return 0;
440 }
441 
442 #elif (defined(_WIN32) && defined(_MSC_VER))
443 
444 #if defined(_MSC_VER)
445 // Disable extension warnings for <windows.h> and friends
446 #pragma warning (disable: 4226)
447 #endif
448 
449 #include <windows.h>
450 
451 #ifndef INVALID_SET_FILE_POINTER
452 #define INVALID_SET_FILE_POINTER ((DWORD)(-1))
453 #endif
454 
truncate(const char * filename,off_t size)455 int truncate(const char *filename, off_t size) {
456     if(size < 0) {
457         errno = EINVAL;
458         return -1;
459     }
460     //
461     // Extend (or do nothing) if necessary
462     //
463     {   off_t end;
464         FILE* f = fopen(filename, "rb");
465         if(!f) {
466             return -1;
467         }
468         if(fseeko(f, 0, SEEK_END) != 0) {
469             fclose(f);
470             return -1;
471         }
472         end = ftello(f);
473         if(end <= size) {
474             for(; end < size; end++) {
475                 if(fputc(0, f) == EOF) {
476                     fclose(f);
477                     return -1;
478                 }
479             }
480             fclose(f);
481             return 0;
482         }
483         fclose(f);
484     }
485     //
486     // Shrink if necessary (Windows-specific call)
487     //
488     {   HANDLE f = CreateFile(
489             filename,
490             GENERIC_WRITE,
491             0,
492             NULL,
493             OPEN_EXISTING,
494             FILE_ATTRIBUTE_NORMAL,
495             NULL
496         );
497         if(f == INVALID_HANDLE_VALUE) {
498             return -1;
499         }
500         if(size > ((off_t)0x7FFFFFFFL)) {
501             // use fancy 64-bit SetFilePointer
502             LONG lo = size;
503             LONG hi = size >> 32;
504             if(SetFilePointer(f, lo, &hi, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
505                 CloseHandle(f);
506                 return -1;
507             }
508         } else {
509             // use plain 32-bit SetFilePointer
510             if(SetFilePointer(f, size, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
511                 CloseHandle(f);
512                 return -1;
513             }
514         }
515         if(!SetEndOfFile(f)) {
516             CloseHandle(f);
517             return -1;
518         }
519     }
520     //
521     // Success
522     //
523     return 0;
524 }
525 
526 #endif
527 
528 #endif // !defined(_POSIX_VERSION)
529 
530 ////////////////////////////////////////////////////////////////////////////////
531 //
532 // Normalize argv[0]
533 //
normalize_argv0(char * argv0)534 void normalize_argv0(char* argv0) {
535     size_t i;
536     size_t start = 0;
537     int c;
538     for(i = 0; argv0[i]; i++) {
539         if(argv0[i] == '/' || argv0[i] == '\\') {
540             start = i + 1;
541         }
542     }
543     i = 0;
544     do {
545         c = ((unsigned char)(argv0[start + i]));
546         if(c == '.') { c = 0; }
547         if(c != 0) { c = tolower(c); }
548         argv0[i++] = c;
549     } while(c != 0);
550 }
551 
552 ////////////////////////////////////////////////////////////////////////////////
553 
printfileerror(FILE * f,const char * name)554 void printfileerror(FILE* f, const char* name) {
555     int e = errno;
556     printf("Error: ");
557     if(name) { printf("%s: ", name); }
558     printf("%s\n", f && feof(f) ? "Unexpected end-of-file" : strerror(e));
559 }
560 
561 ////////////////////////////////////////////////////////////////////////////////
562 
563 #if defined(_WIN32)
564 
565 //
566 // Detect if the user double-clicked on the .exe rather than executing this from
567 // the command line, and if so, display a warning and wait for input before
568 // exiting
569 //
570 #include <windows.h>
571 
getconsolewindow(void)572 static HWND getconsolewindow(void) {
573     HWND hConsoleWindow = NULL;
574     HANDLE k32;
575     //
576     // See if GetConsoleWindow is available (Windows 2000 or later)
577     //
578     k32 = GetModuleHandle(TEXT("kernel32.dll"));
579     if(k32) {
580         typedef HWND (* WINAPI gcw_t)(void);
581         gcw_t gcw = (gcw_t)GetProcAddress(k32, TEXT("GetConsoleWindow"));
582         if(gcw) {
583             hConsoleWindow = gcw();
584         }
585     }
586     //
587     // There is an alternative method that involves FindWindow, but it's too
588     // cumbersome for just printing a warning.
589     //
590     return hConsoleWindow;
591 }
592 
commandlinewarning(void)593 void commandlinewarning(void) {
594     HWND hConsoleWindow;
595     DWORD processId = 0;
596     //
597     // This trick doesn't work in Win9x
598     //
599     if(GetVersion() >= ((DWORD)0x80000000LU)) { return; }
600     //
601     // See if the console window belongs to my own process
602     //
603     hConsoleWindow = getconsolewindow();
604     if(!hConsoleWindow) { return; }
605     GetWindowThreadProcessId(hConsoleWindow, &processId);
606     if(GetCurrentProcessId() == processId) {
607         printf(
608             "\n"
609             "Note: This is a command-line application.\n"
610             "It was meant to run from a Windows command prompt.\n\n"
611             "Press ENTER to close this window..."
612         );
613         fflush(stdout);
614         fgetc(stdin);
615     }
616 }
617 
618 #else
619 
commandlinewarning(void)620 void commandlinewarning(void) {}
621 
622 #endif
623 
624 ////////////////////////////////////////////////////////////////////////////////
625 //
626 // Work around some problems with the Mariko CC toolchain
627 //
628 #ifdef MARIKO_CC
629 
630 // 32-bit signed and unsigned mod seem buggy; this solves it
__umodsi3(unsigned long a,unsigned long b)631 unsigned long __umodsi3(unsigned long a, unsigned long b) { return a - (a / b) * b; }
__modsi3(signed long a,signed long b)632 signed long __modsi3(signed long a, signed long b) { return a - (a / b) * b; }
633 
634 // Some kind of soft float linkage issue?
__cmpdf2(void)635 void __cmpdf2(void) {}
636 
637 #endif
638 
639 ////////////////////////////////////////////////////////////////////////////////
640 
641 #endif
642