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