1
2 /***************************************************************************
3 * __ __ _ ___________ *
4 * \ \ / /| |____ ____| *
5 * \ \ / / | | | | *
6 * \ \ /\ / / | | | | *
7 * \ \/ \/ / | | | | *
8 * \ /\ / | | | | *
9 * \/ \/ |_| |_| *
10 * *
11 * Wiimms ISO Tools *
12 * http://wit.wiimm.de/ *
13 * *
14 ***************************************************************************
15 * *
16 * This file is part of the WIT project. *
17 * Visit http://wit.wiimm.de/ for project details and sources. *
18 * *
19 * Copyright (c) 2009-2013 by Dirk Clemens <wiimm@wiimm.de> *
20 * *
21 ***************************************************************************
22 * *
23 * This program is free software; you can redistribute it and/or modify *
24 * it under the terms of the GNU General Public License as published by *
25 * the Free Software Foundation; either version 2 of the License, or *
26 * (at your option) any later version. *
27 * *
28 * This program is distributed in the hope that it will be useful, *
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
31 * GNU General Public License for more details. *
32 * *
33 * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt *
34 * *
35 ***************************************************************************/
36
37 #define _GNU_SOURCE 1
38 #define _XOPEN_SOURCE 1
39
40 #include <sys/time.h>
41 #include <sys/ioctl.h>
42
43 #include <signal.h>
44 #include <time.h>
45 #include <ctype.h>
46 #include <errno.h>
47 #include <fcntl.h>
48
49 #if defined(__CYGWIN__)
50 #include <cygwin/fs.h>
51 #include <io.h>
52 #elif defined(__APPLE__)
53 #include <sys/disk.h>
54 #elif defined(__linux__)
55 #include <linux/fs.h>
56 #endif
57
58 #include "version.h"
59 #include "lib-std.h"
60 #include "lib-sf.h"
61 #include "lib-bzip2.h"
62 #include "lib-lzma.h"
63 #include "wbfs-interface.h"
64 #include "crypt.h"
65 #include "titles.h"
66 #include "dclib-utf8.h"
67
68 //
69 ///////////////////////////////////////////////////////////////////////////////
70 /////////////// Setup ///////////////
71 ///////////////////////////////////////////////////////////////////////////////
72
73 enumProgID prog_id = PROG_UNKNOWN;
74 u32 revision_id = SYSTEMID + REVISION_NUM;
75 ccp progname = "?";
76 ccp search_path[6] = {0};
77 ccp lang_info = 0;
78 volatile int SIGINT_level = 0;
79 volatile int verbose = 0;
80 volatile int logging = 0;
81 int progress = 0;
82 int scan_progress = 0;
83 SortMode sort_mode = SORT_DEFAULT;
84 ShowMode opt_show_mode = SHOW__DEFAULT;
85 wd_size_mode_t opt_unit = WD_SIZE_DEFAULT;
86 RepairMode repair_mode = REPAIR_NONE;
87 char escape_char = '%';
88 int opt_force = 0;
89 bool use_utf8 = true;
90 enumOFT output_file_type = OFT_UNKNOWN;
91 uint opt_wdf_version = WDF_VERSION;
92 uint opt_wdf_align = WDF_ALIGN;
93 int opt_truncate = 0;
94 int opt_split = 0;
95 u64 opt_split_size = 0;
96 ccp opt_patch_file = 0;
97 bool opt_copy_gc = false;
98 bool opt_no_link = false;
99 int testmode = 0;
100 int newmode = 0;
101 ccp opt_dest = 0;
102 bool opt_overwrite = false;
103 bool opt_mkdir = false;
104 int opt_limit = -1;
105 int opt_file_limit = -1;
106 int opt_block_size = -1;
107 int print_old_style = 0;
108 int print_sections = 0;
109 int long_count = 0;
110 int brief_count = 0;
111 int ignore_count = 0;
112 int opt_technical = 0;
113 u32 job_limit = ~(u32)0;
114 enumIOMode io_mode = 0;
115 bool opt_no_expand = false;
116 u32 opt_recurse_depth = DEF_RECURSE_DEPTH;
117 PreallocMode prealloc_mode = PREALLOC_DEFAULT;
118
119 StringField_t source_list;
120 StringField_t recurse_list;
121 StringField_t created_files;
122 char iobuf [0x400000]; // global io buffer
123 const char zerobuf[0x40000] = {0}; // global zero buffer
124
125 // 'tempbuf' is only for short usage
126 // ==> don't call other functions while using tempbuf
127 u8 * tempbuf = 0; // global temp buffer -> AllocTempBuffer()
128 size_t tempbuf_size = 0; // size of 'tempbuf'
129
130 const char sep_79[80] = // 79 * '-' + NULL
131 "----------------------------------------"
132 "---------------------------------------";
133
134 ///////////////////////////////////////////////////////////////////////////////
135
sig_handler(int signum)136 static void sig_handler ( int signum )
137 {
138 static const char usr_msg[] =
139 "\n"
140 "****************************************************************\n"
141 "*** SIGNAL USR%d CATCHED: VERBOSE LEVEL %s TO %-4d ***\n"
142 "*** THE EFFECT IS DELAYED UNTIL BEGINNING OF THE NEXT JOB. ***\n"
143 "****************************************************************\n";
144
145 fflush(stdout);
146 switch(signum)
147 {
148 case SIGINT:
149 case SIGTERM:
150 SIGINT_level++;
151 TRACE("#SIGNAL# INT/TERM, level = %d\n",SIGINT_level);
152
153 switch(SIGINT_level)
154 {
155 case 1:
156 fprintf(stderr,
157 "\n"
158 "****************************************************************\n"
159 "*** PROGRAM INTERRUPTED BY USER (LEVEL=1). ***\n"
160 "*** PROGRAM WILL TERMINATE AFTER CURRENT JOB HAS FINISHED. ***\n"
161 "****************************************************************\n" );
162 break;
163
164 case 2:
165 fprintf(stderr,
166 "\n"
167 "*********************************************************\n"
168 "*** PROGRAM INTERRUPTED BY USER (LEVEL=2). ***\n"
169 "*** PROGRAM WILL TRY TO TERMINATE NOW WITH CLEANUP. ***\n"
170 "*********************************************************\n" );
171 break;
172
173 default:
174 fprintf(stderr,
175 "\n"
176 "*************************************************************\n"
177 "*** PROGRAM INTERRUPTED BY USER (LEVEL>=3). ***\n"
178 "*** PROGRAM WILL TERMINATE IMMEDIATELY WITHOUT CLEANUP. ***\n"
179 "*************************************************************\n" );
180 fflush(stderr);
181 exit(ERR_INTERRUPT);
182 }
183 break;
184
185 case SIGUSR1:
186 if ( verbose >= -1 )
187 verbose--;
188 TRACE("#SIGNAL# USR1: verbose = %d\n",verbose);
189 fprintf(stderr,usr_msg,1,"DECREASED",verbose);
190 break;
191
192 case SIGUSR2:
193 if ( verbose < 4 )
194 verbose++;
195 TRACE("#SIGNAL# USR2: verbose = %d\n",verbose);
196 fprintf(stderr,usr_msg,2,"INCREASED",verbose);
197 break;
198
199 default:
200 TRACE("#SIGNAL# %d\n",signum);
201 }
202 fflush(stderr);
203 }
204
205 ///////////////////////////////////////////////////////////////////////////////
206
SetupLib(int argc,char ** argv,ccp p_progname,enumProgID prid)207 void SetupLib ( int argc, char ** argv, ccp p_progname, enumProgID prid )
208 {
209 #ifdef DEBUG
210 if (!TRACE_FILE)
211 {
212 char fname[100];
213 snprintf(fname,sizeof(fname),"_trace-%s.tmp",p_progname);
214 TRACE_FILE = fopen(fname,"w");
215 if (!TRACE_FILE)
216 fprintf(stderr,"open TRACE_FILE failed: %s\n",fname);
217 }
218 #endif
219
220 #ifdef __BYTE_ORDER
221 TRACE("__BYTE_ORDER=%d\n",__BYTE_ORDER);
222 #endif
223 #ifdef LITTLE_ENDIAN
224 TRACE("LITTLE_ENDIAN=%d\n",LITTLE_ENDIAN);
225 #endif
226 #ifdef BIG_ENDIAN
227 TRACE("BIG_ENDIAN=%d\n",BIG_ENDIAN);
228 #endif
229
230 // numeric types
231
232 TRACE("- int\n");
233 TRACE_SIZEOF(bool);
234 TRACE_SIZEOF(short);
235 TRACE_SIZEOF(int);
236 TRACE_SIZEOF(long);
237 TRACE_SIZEOF(long long);
238 TRACE_SIZEOF(size_t);
239 TRACE_SIZEOF(off_t);
240
241 TRACE_SIZEOF(int8_t);
242 TRACE_SIZEOF(int16_t);
243 TRACE_SIZEOF(int32_t);
244 TRACE_SIZEOF(int64_t);
245 TRACE_SIZEOF(uint8_t);
246 TRACE_SIZEOF(uint16_t);
247 TRACE_SIZEOF(uint32_t);
248 TRACE_SIZEOF(uint64_t);
249
250 TRACE_SIZEOF(u8);
251 TRACE_SIZEOF(u16);
252 TRACE_SIZEOF(u32);
253 TRACE_SIZEOF(u64);
254 TRACE_SIZEOF(s8);
255 TRACE_SIZEOF(s16);
256 TRACE_SIZEOF(s32);
257 TRACE_SIZEOF(s64);
258 TRACE_SIZEOF(be16_t);
259 TRACE_SIZEOF(be32_t);
260 TRACE_SIZEOF(be64_t);
261
262 // base types A-Z
263
264 TRACE("-\n");
265 TRACE_SIZEOF(AWData_t);
266 TRACE_SIZEOF(AWRecord_t);
267 TRACE_SIZEOF(CISO_Head_t);
268 TRACE_SIZEOF(CISO_Info_t);
269 TRACE_SIZEOF(CheckDisc_t);
270 TRACE_SIZEOF(CheckWBFS_t);
271 TRACE_SIZEOF(CommandTab_t);
272 TRACE_SIZEOF(DataArea_t);
273 TRACE_SIZEOF(DataList_t);
274 TRACE_SIZEOF(Diff_t);
275 TRACE_SIZEOF(File_t);
276 TRACE_SIZEOF(FileAttrib_t);
277 TRACE_SIZEOF(FileCache_t);
278 TRACE_SIZEOF(FileIndex_t);
279 TRACE_SIZEOF(FileIndexData_t);
280 TRACE_SIZEOF(FileIndexItem_t);
281 TRACE_SIZEOF(FileMapItem_t);
282 TRACE_SIZEOF(FileMap_t);
283 TRACE_SIZEOF(FilePattern_t);
284 TRACE_SIZEOF(ID_DB_t);
285 TRACE_SIZEOF(ID_t);
286 //TRACE_SIZEOF(InfoCommand_t);
287 //TRACE_SIZEOF(InfoOption_t);
288 //TRACE_SIZEOF(InfoUI_t);
289 TRACE_SIZEOF(IOData_t);
290 TRACE_SIZEOF(IsoMappingItem_t);
291 TRACE_SIZEOF(IsoMapping_t);
292 TRACE_SIZEOF(Iterator_t);
293 TRACE_SIZEOF(MemMapItem_t);
294 TRACE_SIZEOF(MemMap_t);
295 TRACE_SIZEOF(ParamField_t);
296 TRACE_SIZEOF(ParamFieldItem_t);
297 TRACE_SIZEOF(ParamFieldType_t);
298 TRACE_SIZEOF(ParamList_t);
299 TRACE_SIZEOF(PartitionInfo_t);
300 TRACE_SIZEOF(PrintTime_t);
301 TRACE_SIZEOF(ReadPatch_t);
302 TRACE_SIZEOF(RegionInfo_t);
303 TRACE_SIZEOF(StringField_t);
304 TRACE_SIZEOF(IdField_t);
305 TRACE_SIZEOF(IdItem_t);
306 TRACE_SIZEOF(StringList_t);
307 TRACE_SIZEOF(SubstString_t);
308 TRACE_SIZEOF(SuperFile_t);
309 TRACE_SIZEOF(TDBfind_t);
310 TRACE_SIZEOF(Verify_t);
311 TRACE_SIZEOF(WBFS_t);
312 TRACE_SIZEOF(WDF_Chunk_t);
313 TRACE_SIZEOF(WDF_Head_t);
314 TRACE_SIZEOF(WDiscInfo_t);
315 TRACE_SIZEOF(WDiscListItem_t);
316 TRACE_SIZEOF(WDiscList_t);
317 TRACE_SIZEOF(WiiFstFile_t);
318 TRACE_SIZEOF(WiiFstInfo_t);
319 TRACE_SIZEOF(WiiFstPart_t);
320 TRACE_SIZEOF(WiiFst_t);
321 TRACE_SIZEOF(WritePatch_t);
322
323 // base types a-z
324
325 TRACE("-\n");
326 TRACE_SIZEOF(aes_key_t);
327
328 TRACE_SIZEOF(cert_chain_t);
329 TRACE_SIZEOF(cert_data_t);
330 TRACE_SIZEOF(cert_head_t);
331 TRACE_SIZEOF(cert_item_t);
332 TRACE_SIZEOF(cert_stat_flags_t);
333 TRACE_SIZEOF(cert_stat_t);
334
335 TRACE_SIZEOF(dcUnicodeTripel);
336 TRACE_SIZEOF(dol_header_t);
337 TRACE_SIZEOF(id6_t);
338 TRACE_SIZEOF(sha1_hash_t);
339
340 TRACE_SIZEOF(wbfs_disc_info_t);
341 TRACE_SIZEOF(wbfs_disc_t);
342 TRACE_SIZEOF(wbfs_head_t);
343 TRACE_SIZEOF(wbfs_inode_info_t);
344 TRACE_SIZEOF(wbfs_param_t);
345 TRACE_SIZEOF(wbfs_t);
346
347 TRACE_SIZEOF(wd_boot_t);
348 TRACE_SIZEOF(wd_compression_t);
349 TRACE_SIZEOF(wd_disc_t);
350 TRACE_SIZEOF(wd_file_list_t);
351 TRACE_SIZEOF(wd_file_t);
352 TRACE_SIZEOF(wd_fst_item_t);
353 TRACE_SIZEOF(wd_header_128_t);
354 TRACE_SIZEOF(wd_header_t);
355 TRACE_SIZEOF(wd_icm_t);
356 TRACE_SIZEOF(wd_ipm_t);
357 TRACE_SIZEOF(wd_iterator_t);
358 TRACE_SIZEOF(wd_memmap_item_t);
359 TRACE_SIZEOF(wd_memmap_t);
360 TRACE_SIZEOF(wd_modify_t);
361 TRACE_SIZEOF(wd_part_control_t);
362 TRACE_SIZEOF(wd_part_header_t);
363 TRACE_SIZEOF(wd_part_sector_t);
364 TRACE_SIZEOF(wd_part_t);
365 TRACE_SIZEOF(wd_part_type_t);
366 TRACE_SIZEOF(wd_patch_mode_t);
367 TRACE_SIZEOF(wd_pfst_t);
368 TRACE_SIZEOF(wd_pname_mode_t);
369 TRACE_SIZEOF(wd_print_fst_t);
370 TRACE_SIZEOF(wd_ptab_info_t);
371 TRACE_SIZEOF(wd_ptab_entry_t);
372 TRACE_SIZEOF(wd_ptab_t);
373 TRACE_SIZEOF(wd_region_t);
374 TRACE_SIZEOF(wd_reloc_t);
375 TRACE_SIZEOF(wd_scrubbed_t);
376 TRACE_SIZEOF(wd_sector_status_t);
377 TRACE_SIZEOF(wd_select_item_t);
378 TRACE_SIZEOF(wd_select_mode_t);
379 TRACE_SIZEOF(wd_select_t);
380 TRACE_SIZEOF(wd_ticket_t);
381 TRACE_SIZEOF(wd_tmd_content_t);
382 TRACE_SIZEOF(wd_tmd_t);
383 TRACE_SIZEOF(wd_trim_mode_t);
384 TRACE_SIZEOF(wd_usage_t);
385
386 TRACE_SIZEOF(wia_controller_t);
387 TRACE_SIZEOF(wia_segment_t);
388 TRACE_SIZEOF(wia_disc_t);
389 TRACE_SIZEOF(wia_exception_t);
390 TRACE_SIZEOF(wia_except_list_t);
391 TRACE_SIZEOF(wia_file_head_t);
392 TRACE_SIZEOF(wia_group_t);
393 TRACE_SIZEOF(wia_part_data_t);
394 TRACE_SIZEOF(wia_part_t);
395 TRACE_SIZEOF(wia_raw_data_t);
396
397 TRACE_SIZEOF(WIT_PATCH_MAGIC);
398 TRACE_SIZEOF(wpat_magic);
399 TRACE_SIZEOF(wpat_comment_t);
400 TRACE_SIZEOF(wpat_data_t);
401 TRACE_SIZEOF(wpat_filename_t);
402 TRACE_SIZEOF(wpat_filenames_t);
403 TRACE_SIZEOF(wpat_header_t);
404 TRACE_SIZEOF(wpat_patch_file_t);
405 TRACE_SIZEOF(wpat_size_t);
406 TRACE_SIZEOF(wpat_toc_file_t);
407 TRACE_SIZEOF(wpat_toc_header_t);
408 TRACE_SIZEOF(wpat_type_t);
409
410 // assertions
411
412 TRACE("-\n");
413 ASSERT( 1 == sizeof(u8) );
414 ASSERT( 2 == sizeof(u16) );
415 ASSERT( 4 == sizeof(u32) );
416 ASSERT( 8 == sizeof(u64) );
417 ASSERT( 1 == sizeof(s8) );
418 ASSERT( 2 == sizeof(s16) );
419 ASSERT( 4 == sizeof(s32) );
420 ASSERT( 8 == sizeof(s64) );
421
422 ASSERT( Count1Bits32(sizeof(WDF_Hole_t)) == 1 );
423 ASSERT( sizeof(CISO_Head_t) == CISO_HEAD_SIZE );
424
425 ASSERT( 79 == strlen(sep_79) );
426 ASSERT( 200 == strlen(wd_sep_200) );
427
428 TRACE("- file formats:\n");
429 validate_file_format_sizes(1);
430 TRACE("-\n");
431
432 //----- setup textmode for cygwin stdout+stderr
433
434 #if defined(__CYGWIN__)
435 setmode(fileno(stdout),O_TEXT);
436 setmode(fileno(stderr),O_TEXT);
437 //setlocale(LC_ALL,"en_US.utf-8");
438 #endif
439
440
441 //----- setup prog id
442
443 prog_id = prid;
444
445 #ifdef WIIMM_TRUNK
446 revision_id = (prid << 20) + SYSTEMID + REVISION_NUM + REVID_WIIMM_TRUNK;
447 #elif defined(WIIMM)
448 revision_id = (prid << 20) + SYSTEMID + REVISION_NUM + REVID_WIIMM;
449 #else
450 revision_id = (prid << 20) + SYSTEMID + REVISION_NUM + REVID_UNKNOWN;
451 #endif
452
453
454 //----- setup progname
455
456 if ( argc > 0 && *argv && **argv )
457 p_progname = *argv;
458 progname = strrchr(p_progname,'/');
459 progname = progname ? progname+1 : p_progname;
460 argv[0] = (char*)progname;
461
462 TRACE("##PROG## REV-ID=%08x, PROG-ID=%d, PROG-NAME=%s\n",
463 revision_id, prog_id, progname );
464
465
466 //----- setup signals
467
468 static const int sigtab[] = { SIGTERM, SIGINT, SIGUSR1, SIGUSR2, -1 };
469 int i;
470 for ( i = 0; sigtab[i] >= 0; i++ )
471 {
472 struct sigaction sa;
473 memset(&sa,0,sizeof(sa));
474 sa.sa_handler = &sig_handler;
475 sigaction(sigtab[i],&sa,0);
476 }
477
478
479 //----- setup search_path
480
481 ccp *sp = search_path, *sp2;
482 ASSERT( sizeof(search_path)/sizeof(*search_path) > 5 );
483
484 // determine program path
485 char proc_path[30];
486 snprintf(proc_path,sizeof(proc_path),"/proc/%u/exe",getpid());
487 TRACE("PROC-PATH: %s\n",proc_path);
488
489 static char share[] = "/share/wit/";
490 static char local_share[] = "/usr/local/share/wit/";
491
492 char path[PATH_MAX];
493 if (readlink(proc_path,path,sizeof(path)))
494 {
495 // program path found!
496 TRACE("PROG-PATH: %s\n",path);
497
498 char * file_ptr = strrchr(path,'/');
499 if ( file_ptr )
500 {
501 // seems to be a real path -> terminate string behind '/'
502 *++file_ptr = 0;
503
504 #ifdef TEST
505 // for development: append 'share' dir
506 StringCopyE(file_ptr,path+sizeof(path),"share/");
507 *sp = STRDUP(path);
508 TRACE("SEARCH_PATH[%zd] = %s\n",sp-search_path,*sp);
509 sp++;
510 *file_ptr = 0;
511 #endif
512
513 *sp = STRDUP(path);
514 TRACE("SEARCH_PATH[%zd] = %s\n",sp-search_path,*sp);
515 sp++;
516
517 if ( file_ptr-5 >= path && !memcmp(file_ptr-4,"/bin/",5) )
518 {
519 StringCopyS(file_ptr-5,sizeof(path),share);
520 *sp = STRDUP(path);
521 TRACE("SEARCH_PATH[%zd] = %s\n",sp-search_path,*sp);
522 sp++;
523 }
524 }
525 }
526
527 // insert 'local_share' if not already done
528
529 for ( sp2 = search_path; sp2 < sp && strcmp(*sp2,local_share); sp2++ )
530 ;
531 if ( sp2 == sp )
532 {
533 *sp = STRDUP(local_share);
534 TRACE("SEARCH_PATH[%zd] = %s\n",sp-search_path,*sp);
535 sp++;
536 }
537
538 // insert CWD if not already done
539 getcwd(path,sizeof(path)-1);
540 strcat(path,"/");
541 for ( sp2 = search_path; sp2 < sp && strcmp(*sp2,path); sp2++ )
542 ;
543 if ( sp2 == sp )
544 {
545 *sp = STRDUP("./");
546 TRACE("SEARCH_PATH[%zd] = %s\n",sp-search_path,*sp);
547 sp++;
548 }
549
550 *sp = 0;
551 ASSERT( sp - search_path < sizeof(search_path)/sizeof(*search_path) );
552
553
554 //----- setup language info
555
556 char * wit_lang = getenv("WIT_LANG");
557 if ( wit_lang && *wit_lang )
558 {
559 lang_info = STRDUP(wit_lang);
560 TRACE("LANG_INFO = %s [WIT_LANG]\n",lang_info);
561 }
562 else
563 {
564 char * lc_ctype = getenv("LC_CTYPE");
565 if (lc_ctype)
566 {
567 char * lc_ctype_end = lc_ctype;
568 while ( *lc_ctype_end >= 'a' && *lc_ctype_end <= 'z' )
569 lc_ctype_end++;
570 const int len = lc_ctype_end - lc_ctype;
571 if ( len > 0 )
572 {
573 char * temp = MALLOC(len+1);
574 memcpy(temp,lc_ctype,len);
575 temp[len] = 0;
576 lang_info = temp;
577 TRACE("LANG_INFO = %s\n",lang_info);
578 }
579 }
580 }
581
582
583 //----- setup common key
584 {
585 static u8 key_base[] = "Wiimms WBFS Tool";
586 static u8 key_mask[WD_CKEY__N][WII_KEY_SIZE] =
587 {
588 {
589 0x25, 0x00, 0x94, 0x12, 0x2a, 0x3e, 0x4e, 0x1f,
590 0x03, 0x2d, 0xc5, 0xc9, 0x30, 0x2a, 0x58, 0xab
591 },
592 {
593 0xad, 0x5c, 0x95, 0x84, 0x80, 0xda, 0x93, 0xd5,
594 0x58, 0x06, 0xfe, 0x77, 0xf9, 0xe7, 0x69, 0x22
595 },
596 };
597
598 u8 h1[WII_HASH_SIZE], h2[WII_HASH_SIZE], key[WII_KEY_SIZE];
599
600 SHA1(key_base,WII_KEY_SIZE,h1);
601 int ci;
602 for ( ci = 0; ci < WD_CKEY__N; ci++ )
603 {
604 SHA1(wd_get_common_key(ci),WII_KEY_SIZE,h2);
605
606 int i;
607 for ( i = 0; i < WII_KEY_SIZE; i++ )
608 key[i] = key_mask[ci][i] ^ h1[i] ^ h2[i];
609
610 wd_set_common_key(ci,key);
611 }
612 }
613
614 //----- setup data structures
615
616 InitializeAllFilePattern();
617 wd_initialize_select(&part_selector);
618
619
620 //----- verify oft_info
621
622 #if defined(TEST) || defined(DEBUG)
623 {
624 ASSERT( OFT__N + 1 == sizeof(oft_info)/sizeof(*oft_info) );
625 enumOFT oft;
626 for ( oft = 0; oft <= OFT__N; oft++ )
627 {
628 ASSERT( oft_info[oft].oft == oft );
629 }
630 }
631 #endif
632 }
633
634 ///////////////////////////////////////////////////////////////////////////////
635
CloseAll()636 void CloseAll()
637 {
638 CloseWBFSCache();
639 }
640
641 ///////////////////////////////////////////////////////////////////////////////
642
CheckEnvOptions(ccp varname,check_opt_func func)643 enumError CheckEnvOptions ( ccp varname, check_opt_func func )
644 {
645 TRACE("CheckEnvOptions(%s,%p)\n",varname,func);
646
647 ccp env = getenv(varname);
648 if ( !env || !*env )
649 return ERR_OK;
650
651 TRACE("env[%s] = %s\n",varname,env);
652
653 const int envlen = strlen(env);
654 char * buf = MALLOC(envlen+1);
655 char * dest = buf;
656
657 int argc = 1; // argv[0] = progname
658 ccp src = env;
659 while (*src)
660 {
661 while ( *src > 0 && *src <= ' ' ) // skip blanks & control
662 src++;
663
664 if (!*src)
665 break;
666
667 argc++;
668 while ( *(u8*)src > ' ' )
669 *dest++ = *src++;
670 *dest++ = 0;
671 ASSERT( dest <= buf+envlen+1 );
672 }
673 TRACE("argc = %d\n",argc);
674
675 char ** argv = MALLOC((argc+1)*sizeof(*argv));
676 argv[0] = (char*)progname;
677 argv[argc] = 0;
678 dest = buf;
679 int i;
680 for ( i = 1; i < argc; i++ )
681 {
682 TRACE("argv[%d] = %s\n",i,dest);
683 argv[i] = dest;
684 while (*dest)
685 dest++;
686 dest++;
687 ASSERT( dest <= buf+envlen+1 );
688 }
689
690 enumError stat = func(argc,argv,true);
691 if (stat)
692 fprintf(stderr,
693 "Error while scanning the environment variable '%s'\n",varname);
694
695 // don't FREE() because is's possible that there are pointers to arguments
696 //FREE(argv);
697 //FREE(buf);
698
699 return stat;
700 }
701
702 //
703 ///////////////////////////////////////////////////////////////////////////////
704 /////////////// error messages ///////////////
705 ///////////////////////////////////////////////////////////////////////////////
706
GetErrorName(int stat)707 ccp GetErrorName ( int stat )
708 {
709 switch(stat)
710 {
711 case ERR_OK: return "OK";
712 case ERR_DIFFER: return "FILES DIFFER";
713 case ERR_NOTHING_TO_DO: return "NOTHING TO DO";
714 case ERR_NO_SOURCE_FOUND: return "NO SOURCE FOUND";
715 case ERR_JOB_IGNORED: return "JOB IGNORED";
716 case ERR_WARNING: return "WARNING";
717
718 case ERR_INVALID_FILE: return "INVALID FILE";
719 case ERR_INVALID_VERSION: return "INVALID VERSION";
720
721 case ERR_NO_WDF: return "NO WDF";
722 case ERR_WDF_VERSION: return "WDF VERSION NOT SUPPORTED";
723 case ERR_WDF_SPLIT: return "SPLITTED WDF NOT SUPPORTED";
724 case ERR_WDF_INVALID: return "INVALID WDF";
725
726 case ERR_NO_CISO: return "NO WDF";
727 case ERR_CISO_INVALID: return "INVALID WDF";
728
729 case ERR_WPART_INVALID: return "INVALID WII PARTITION";
730 case ERR_WDISC_INVALID: return "INVALID WII DISC";
731 case ERR_WDISC_NOT_FOUND: return "WII DISC NOT FOUND";
732
733 case ERR_NO_WBFS_FOUND: return "NO WBFS FOUND";
734 case ERR_TO_MUCH_WBFS_FOUND: return "TO MUCH WBFS FOUND";
735 case ERR_WBFS_INVALID: return "INVALID WBFS";
736
737 case ERR_NO_WIA: return "NO WIA FOUND";
738 case ERR_WIA_INVALID: return "INVALID WIA";
739 case ERR_BZIP2: return "BZIP2 ERROR";
740 case ERR_LZMA: return "LZMA ERROR";
741
742 case ERR_ALREADY_EXISTS: return "FILE ALREADY EXISTS";
743 case ERR_CANT_OPEN: return "CAN'T OPEN FILE";
744 case ERR_CANT_CREATE: return "CAN'T CREATE FILE";
745 case ERR_CANT_CREATE_DIR: return "CAN'T CREATE DIRECTORY";
746 case ERR_WRONG_FILE_TYPE: return "WRONG FILE TYPE";
747 case ERR_READ_FAILED: return "READ FILE FAILED";
748 case ERR_REMOVE_FAILED: return "REMOVE FILE FAILED";
749 case ERR_WRITE_FAILED: return "WRITE FILE FAILED";
750
751 case ERR_WBFS: return "WBFS ERROR";
752
753 case ERR_MISSING_PARAM: return "MISSING PARAMETERS";
754 case ERR_SEMANTIC: return "SEMANTIC ERROR";
755 case ERR_SYNTAX: return "SYNTAX ERROR";
756
757 case ERR_INTERRUPT: return "INTERRUPT";
758
759 case ERR_ERROR: return "ERROR";
760
761 case ERR_NOT_IMPLEMENTED: return "NOT IMPLEMENTED YET";
762 case ERR_INTERNAL: return "INTERNAL ERROR";
763 case ERR_OUT_OF_MEMORY: return "OUT OF MEMORY";
764 case ERR_FATAL: return "FATAL ERROR";
765 }
766 return "?";
767 }
768
769 ///////////////////////////////////////////////////////////////////////////////
770
GetErrorText(int stat)771 ccp GetErrorText ( int stat )
772 {
773 switch(stat)
774 {
775 case ERR_OK: return "Ok";
776 case ERR_DIFFER: return "Files differ";
777 case ERR_NOTHING_TO_DO: return "Nothing to do";
778 case ERR_NO_SOURCE_FOUND: return "No source file found";
779 case ERR_JOB_IGNORED: return "Job ignored";
780 case ERR_WARNING: return "Unspecific warning";
781
782 case ERR_INVALID_FILE: return "File has invalid content";
783 case ERR_INVALID_VERSION: return "File version not supported";
784
785 case ERR_NO_WDF: return "File is not a WDF";
786 case ERR_WDF_VERSION: return "WDF version not supported";
787 case ERR_WDF_SPLIT: return "Splitted WDF not supported";
788 case ERR_WDF_INVALID: return "File is an invalid WDF";
789
790 case ERR_NO_CISO: return "File is not a CISO";
791 case ERR_CISO_INVALID: return "File is an invalid CISO";
792
793 case ERR_WPART_INVALID: return "Invalid Wii partition";
794 case ERR_WDISC_INVALID: return "Invalid Wii disc";
795 case ERR_WDISC_NOT_FOUND: return "Wii disc not found";
796
797 case ERR_NO_WBFS_FOUND: return "No WBFS found";
798 case ERR_TO_MUCH_WBFS_FOUND: return "To much WBFS found";
799 case ERR_WBFS_INVALID: return "Invalid WBFS";
800
801 case ERR_NO_WIA: return "File is not a WIA";
802 case ERR_WIA_INVALID: return "File is an invalid WIA";
803 case ERR_BZIP2: return "A bzip2 error occurred";
804 case ERR_LZMA: return "A lzma error occurred";
805
806 case ERR_ALREADY_EXISTS: return "File already exists";
807 case ERR_CANT_OPEN: return "Can't open file";
808 case ERR_CANT_CREATE: return "Can't create file";
809 case ERR_CANT_CREATE_DIR: return "Can't create directory";
810 case ERR_WRONG_FILE_TYPE: return "Wrong type of file";
811 case ERR_READ_FAILED: return "Reading from file failed";
812 case ERR_REMOVE_FAILED: return "Removing a file failed";
813 case ERR_WRITE_FAILED: return "Writing to file failed";
814
815 case ERR_WBFS: return "A WBFS error occurred";
816
817 case ERR_MISSING_PARAM: return "Missing ate least one parameter";
818 case ERR_SEMANTIC: return "Semantic error";
819 case ERR_SYNTAX: return "Syntax error";
820
821 case ERR_INTERRUPT: return "Program interrupted by user";
822
823 case ERR_ERROR: return "Unspecific error";
824
825 case ERR_NOT_IMPLEMENTED: return "Not implemented yet";
826 case ERR_INTERNAL: return "Internal error";
827 case ERR_OUT_OF_MEMORY: return "Allocation of dynamic memory failed";
828 case ERR_FATAL: return "Unspecific fatal error";
829 }
830 return "?";
831 }
832
833 ///////////////////////////////////////////////////////////////////////////////
834
835 enumError last_error = ERR_OK;
836 enumError max_error = ERR_OK;
837 u32 error_count = 0;
838
839 ///////////////////////////////////////////////////////////////////////////////
840
PrintError(ccp func,ccp file,uint line,int syserr,enumError err_code,ccp format,...)841 int PrintError ( ccp func, ccp file, uint line,
842 int syserr, enumError err_code, ccp format, ... )
843 {
844 fflush(stdout);
845 char msg[1000];
846 const int plen = strlen(progname)+2;
847
848 if (format)
849 {
850 va_list arg;
851 va_start(arg,format);
852 vsnprintf(msg,sizeof(msg),format,arg);
853 msg[sizeof(msg)-2] = 0;
854 va_end(arg);
855
856 const int mlen = strlen(msg);
857 if ( mlen > 0 && msg[mlen-1] != '\n' )
858 {
859 msg[mlen] = '\n';
860 msg[mlen+1] = 0;
861 }
862 }
863 else
864 StringCat2S(msg,sizeof(msg),GetErrorText(err_code),"\n");
865
866 ccp prefix = err_code == ERR_OK ? "" : err_code <= ERR_WARNING ? "! " : "!! ";
867 const int fw = GetTermWidth(80,40) - 1;
868
869 #ifdef DEBUG
870 TRACE("%s%s #%d [%s] in %s() @ %s#%d\n",
871 prefix, err_code <= ERR_WARNING ? "WARNING" : "ERROR",
872 err_code, GetErrorName(err_code), func, file, line );
873 TRACE("%s%*s%s",prefix,plen,"",msg);
874 if (syserr)
875 TRACE("!! ERRNO=%d: %s\n",syserr,strerror(syserr));
876 fflush(TRACE_FILE);
877 #endif
878
879 #if defined(EXTENDED_ERRORS)
880 if ( err_code > ERR_WARNING )
881 #else
882 if ( err_code >= ERR_NOT_IMPLEMENTED )
883 #endif
884 {
885 if ( err_code > ERR_WARNING )
886 fprintf(stderr,"%s%s: ERROR #%d [%s] in %s() @ %s#%d\n",
887 prefix, progname, err_code, GetErrorName(err_code), func, file, line );
888 else
889 fprintf(stderr,"%s%s: WARNING in %s() @ %s#%d\n",
890 prefix, progname, func, file, line );
891
892 #if defined(EXTENDED_ERRORS) && EXTENDED_ERRORS > 1
893 fprintf(stderr,"%s -> %s/%s?annotate=%d#l%d\n",
894 prefix, URI_VIEWVC, file, REVISION_NEXT, line );
895 #endif
896
897 fputs(prefix,stderr);
898 PutLines(stderr,plen,fw,0,prefix,msg);
899 }
900 else
901 {
902 fprintf(stderr,"%s%s:",prefix,progname);
903 PutLines(stderr,plen,fw,strlen(progname)+1,prefix,msg);
904 }
905
906 if (syserr)
907 {
908 fprintf(stderr,"%s%*s-> ",prefix,plen,"");
909 snprintf(msg,sizeof(msg),"%s [%d]",strerror(syserr),syserr);
910 PutLines(stderr,plen+3,fw,plen+3,prefix,msg);
911 }
912 fflush(stderr);
913
914 if ( err_code > ERR_OK )
915 error_count++;
916
917 last_error = err_code;
918 if ( max_error < err_code )
919 max_error = err_code;
920
921 if ( err_code > ERR_NOT_IMPLEMENTED )
922 exit(err_code);
923
924 return err_code;
925 }
926
927 ///////////////////////////////////////////////////////////////////////////////
928
HexDump16(FILE * f,int indent,u64 addr,const void * data,size_t count)929 void HexDump16 ( FILE * f, int indent, u64 addr,
930 const void * data, size_t count )
931 {
932 HexDump(f,indent,addr,4,16,data,count);
933 }
934
935 //-----------------------------------------------------------------------------
936
HexDump(FILE * f,int indent,u64 addr,int addr_fw,int row_len,const void * p_data,size_t count)937 void HexDump ( FILE * f, int indent, u64 addr, int addr_fw, int row_len,
938 const void * p_data, size_t count )
939 {
940 if ( !f || !p_data || !count )
941 return;
942
943 const int MAX_LEN = 256;
944 char buf[MAX_LEN+1];
945 const u8 * data = p_data;
946
947 indent = NormalizeIndent(indent);
948 addr_fw = NormalizeIndent(addr_fw);
949
950 const bool show_ascii = row_len >= 0;
951 if ( row_len < 0 )
952 row_len = -row_len;
953 else if ( row_len < 1 )
954 row_len = 16;
955 else if ( row_len > MAX_LEN )
956 row_len = MAX_LEN;
957
958
959 if ( (s64)addr != -1 )
960 {
961 const int fw = snprintf(buf,sizeof(buf),"%llx",addr+count-1);
962 if ( addr_fw < fw )
963 addr_fw = fw;
964 }
965
966 while ( count > 0 )
967 {
968 if ( (s64)addr == -1 )
969 fprintf(f,"%*s", indent,"" );
970 else
971 {
972 fprintf(f,"%*s%*llx:", indent,"", addr_fw, addr );
973 addr += row_len;
974 }
975 char * dest = buf;
976
977 int i;
978 for ( i = 0; i < row_len; i++ )
979 {
980 u8 ch = *data++;
981 if ( count > 0 )
982 {
983 count--;
984 fprintf(f,"%s%02x ", i&3 ? "" : " ", ch );
985 *dest++ = ch < ' ' || ch >= 0x7f ? '.' : ch;
986 }
987 else
988 fprintf(f,"%s ", i&3 ? "" : " " );
989 }
990 *dest = 0;
991 if (show_ascii)
992 fprintf(f,":%s:\n",buf);
993 else
994 fputc('\n',f);
995 }
996 }
997
998 //
999 ///////////////////////////////////////////////////////////////////////////////
1000 /////////////// terminal cap ///////////////
1001 ///////////////////////////////////////////////////////////////////////////////
1002
1003 u32 opt_width = 0;
1004
1005 ///////////////////////////////////////////////////////////////////////////////
1006
ScanOptWidth(ccp source)1007 int ScanOptWidth ( ccp source )
1008 {
1009 return ERR_OK != ScanSizeOptU32(
1010 &opt_width, // u32 * num
1011 source, // ccp source
1012 1, // default_factor1
1013 0, // int force_base
1014 "width", // ccp opt_name
1015 40, // u64 min
1016 10000, // u64 max
1017 1, // u32 multiple
1018 0, // u32 pow2
1019 true // bool print_err
1020 );
1021 }
1022
1023 ///////////////////////////////////////////////////////////////////////////////
1024
GetTermWidth(int default_value,int min_value)1025 int GetTermWidth ( int default_value, int min_value )
1026 {
1027 int term_width = opt_width > 0
1028 ? opt_width
1029 : GetTermWidthFD(STDOUT_FILENO,-1,min_value);
1030 if ( term_width <= 0 )
1031 term_width = GetTermWidthFD(STDERR_FILENO,-1,min_value);
1032
1033 return term_width > 0 ? term_width : default_value;
1034 }
1035
1036 ///////////////////////////////////////////////////////////////////////////////
1037
GetTermWidthFD(int fd,int default_value,int min_value)1038 int GetTermWidthFD ( int fd, int default_value, int min_value )
1039 {
1040 TRACE("GetTermWidthFD(%d,%d)\n",fd,default_value);
1041
1042 #ifdef TIOCGSIZE
1043 TRACE(" - have TIOCGSIZE\n");
1044 #endif
1045
1046 #ifdef TIOCGWINSZ
1047 TRACE(" - have TIOCGWINSZ\n");
1048 #endif
1049
1050 if (isatty(fd))
1051 {
1052 #ifdef TIOCGSIZE
1053 {
1054 struct ttysize ts;
1055 if ( !ioctl(fd,TIOCGSIZE,&ts))
1056 {
1057 TRACE(" - TIOCGSIZE = %d*%d\n",ts.ts_cols,ts.ts_lines);
1058 if ( ts.ts_cols > 0 )
1059 return ts.ts_cols > min_value ? ts.ts_cols : min_value;
1060 }
1061 }
1062 #endif
1063
1064 #ifdef TIOCGWINSZ
1065 {
1066 struct winsize ws;
1067 if ( !ioctl(fd,TIOCGWINSZ,&ws))
1068 {
1069 TRACE(" - TIOCGWINSZ = %d*%d\n",ws.ws_col,ws.ws_row);
1070 if ( ws.ws_col > 0 )
1071 return ws.ws_col > min_value ? ws.ws_col : min_value;
1072 }
1073 }
1074 #endif
1075 }
1076
1077 return default_value ? default_value : opt_width;
1078 }
1079
1080 //
1081 ///////////////////////////////////////////////////////////////////////////////
1082 /////////////// timer ///////////////
1083 ///////////////////////////////////////////////////////////////////////////////
1084
GetTimerMSec()1085 u32 GetTimerMSec()
1086 {
1087 struct timeval tval;
1088 gettimeofday(&tval,NULL);
1089
1090 static time_t timebase = 0;
1091 if (!timebase)
1092 timebase = tval.tv_sec;
1093
1094 return ( tval.tv_sec - timebase ) * 1000 + tval.tv_usec/1000;
1095 }
1096
1097 ///////////////////////////////////////////////////////////////////////////////
1098
PrintMSec(char * buf,int bufsize,u32 msec,bool PrintMSec)1099 ccp PrintMSec ( char * buf, int bufsize, u32 msec, bool PrintMSec )
1100 {
1101 if (PrintMSec)
1102 snprintf(buf,bufsize,"%02d:%02d:%02d.%03d",
1103 msec/3600000, msec/60000%60, msec/1000%60, msec%1000 );
1104 else
1105 snprintf(buf,bufsize,"%02d:%02d:%02d",
1106 msec/3600000, msec/60000%60, msec/1000%60 );
1107 ccp ptr = buf;
1108 int colon_counter = 0;
1109 while ( *ptr == '0' || *ptr == ':' && !colon_counter++ )
1110 ptr++;
1111 return *ptr == ':' ? ptr-1 : ptr;
1112 }
1113
1114 //
1115 ///////////////////////////////////////////////////////////////////////////////
1116 /////////////// string functions ///////////////
1117 ///////////////////////////////////////////////////////////////////////////////
1118
PathCatPP(char * buf,size_t bufsize,ccp path1,ccp path2)1119 ccp PathCatPP ( char * buf, size_t bufsize, ccp path1, ccp path2 )
1120 {
1121 // concatenate path + path
1122
1123 if ( !path1 || !*path1 )
1124 return path2 ? path2 : "";
1125
1126 if ( !path2 || !*path2 )
1127 return path1;
1128
1129 char * ptr = StringCopyS(buf,bufsize-1,path1);
1130 DASSERT( ptr > buf );
1131 if ( ptr[-1] != '/' )
1132 *ptr++ = '/';
1133 while ( *path2 == '/' )
1134 path2++;
1135 StringCopyE(ptr,buf+bufsize,path2);
1136 return buf;
1137 }
1138
1139 ///////////////////////////////////////////////////////////////////////////////
1140
PathCatPPE(char * buf,size_t bufsize,ccp path1,ccp path2,ccp ext)1141 ccp PathCatPPE ( char * buf, size_t bufsize, ccp path1, ccp path2, ccp ext )
1142 {
1143 // concatenate path + path + extension
1144
1145 char * ptr = path1 ? StringCopyS(buf,bufsize-1,path1) : buf;
1146 if ( ptr > buf && ptr[-1] != '/' )
1147 *ptr++ = '/';
1148
1149 if (path2)
1150 {
1151 while ( *path2 == '/' )
1152 path2++;
1153 ptr = StringCopyE(ptr,buf+bufsize,path2);
1154 }
1155
1156 if (ext)
1157 StringCopyE(ptr,buf+bufsize,ext);
1158
1159 return buf;
1160 }
1161
1162 ///////////////////////////////////////////////////////////////////////////////
1163
SetupDirPath(char * buf,size_t bufsize,ccp src_path)1164 char * SetupDirPath ( char * buf, size_t bufsize, ccp src_path )
1165 {
1166 DASSERT( buf );
1167 DASSERT( bufsize > 10 );
1168 bufsize--;
1169
1170 char * path_dest = StringCopyS(buf,bufsize,src_path);
1171 if ( path_dest == buf )
1172 path_dest = StringCopyS(buf,bufsize,"./");
1173 else if ( path_dest[-1] != '/' )
1174 {
1175 *path_dest++ = '/';
1176 *path_dest = 0;
1177 }
1178
1179 TRACE(" - dir-path=%s\n",buf);
1180 return path_dest;
1181 }
1182
1183 ///////////////////////////////////////////////////////////////////////////////
1184 ///////////////////////////////////////////////////////////////////////////////
1185
PathCMP(ccp path1,ccp path2)1186 int PathCMP ( ccp path1, ccp path2 )
1187 {
1188 noPRINT("PathCMP( | %s | %s | )\n",path1,path2);
1189
1190 //--- eliminate equal characters
1191
1192 while ( *path1 == *path2 )
1193 {
1194 if (!*path1)
1195 return 0;
1196 path1++;
1197 path2++;
1198 }
1199
1200 //--- start the case+path test
1201
1202 ccp p1 = path1;
1203 ccp p2 = path2;
1204 while ( *p1 || *p2 )
1205 {
1206 int ch1 = (uchar)tolower((int)*p1++);
1207 int ch2 = (uchar)tolower((int)*p2++);
1208 int stat = ch1 - ch2;
1209 noPRINT("%02x,%02x,%c %02x,%02x,%c -> %2d\n",
1210 p1[-1], ch1, ch1, p2[-1], ch2, ch2, stat );
1211 if (stat)
1212 return ch1 == '/' ? -1 : ch2 == '/' ? 1 : stat;
1213
1214 if ( ch1 == '/' )
1215 break;
1216 }
1217 return *path1 - *path2;
1218 }
1219
1220 ///////////////////////////////////////////////////////////////////////////////
1221
NintendoCMP(ccp path1,ccp path2)1222 int NintendoCMP ( ccp path1, ccp path2 )
1223 {
1224 noPRINT("NintendoCMP( | %s | %s | )\n",path1,path2);
1225
1226 // try to sort in a nintendo like way
1227 // 1.) ignoring case but sort carefully directories
1228 // 2.) files before sub directories
1229
1230 static uchar transform[0x100] = {0,0};
1231 if (!transform[1]) // ==> setup needed once!
1232 {
1233 // define some special characters
1234
1235 uint index = 1;
1236 transform[(u8)'/'] = index++;
1237 transform[(u8)'.'] = index++;
1238
1239 // define all characters until and excluding 'A'
1240
1241 uint i;
1242 for ( i = 1; i < 'A'; i++ )
1243 if (!transform[i])
1244 transform[i] = index++;
1245
1246 // define letters
1247
1248 for ( i = 'A'; i <= 'Z'; i++ )
1249 transform[i] = transform[i-'A'+'a'] = index++;
1250
1251 // define all other
1252
1253 for ( i = 1; i < sizeof(transform); i++ )
1254 if (!transform[i])
1255 transform[i] = index++;
1256
1257 DASSERT( index <= sizeof(transform) );
1258 #if defined(TEST) && defined(DEBUG)
1259 //HexDump16(stderr,0,0,transform,sizeof(transform));
1260 #endif
1261 }
1262
1263
1264 //--- eliminate equal characters
1265
1266 while ( *path1 == *path2 )
1267 {
1268 if (!*path1)
1269 return 0;
1270 path1++;
1271 path2++;
1272 }
1273
1274 //--- start the case+path test
1275
1276 const uchar * p1 = (const uchar *)path1;
1277 const uchar * p2 = (const uchar *)path2;
1278 while ( *p1 || *p2 )
1279 {
1280 int ch1 = transform[*p1++];
1281 int ch2 = transform[*p2++];
1282 int stat = ch1 - ch2;
1283 noPRINT("%02x,%02x,%c %02x,%02x,%c -> %2d\n",
1284 p1[-1], ch1, ch1, p2[-1], ch2, ch2, stat );
1285 if (stat)
1286 {
1287 #ifdef WSZST // special case for Wiimms SZS Tools
1288 // sort files before dirs
1289 const bool indir1 = strchr((ccp)p1-1,'/') != 0;
1290 const bool indir2 = strchr((ccp)p2-1,'/') != 0;
1291 return indir1 != indir2 ? indir1 - indir2 : stat;
1292 #else
1293 return stat;
1294 #endif
1295 }
1296
1297 if ( ch1 == 1 )
1298 break;
1299 }
1300 return *path1 - *path2;
1301 }
1302
1303 ///////////////////////////////////////////////////////////////////////////////
1304 ///////////////////////////////////////////////////////////////////////////////
1305
NormalizeIndent(int indent)1306 int NormalizeIndent ( int indent )
1307 {
1308 return indent < 0 ? 0 : indent < 50 ? indent : 50;
1309 }
1310
1311 ///////////////////////////////////////////////////////////////////////////////
1312
CheckIDHelper(const void * id,int max_len,bool allow_any_len,bool ignore_case,bool allow_point)1313 int CheckIDHelper // helper for all other id functions
1314 (
1315 const void * id, // valid pointer to test ID
1316 int max_len, // max length of ID, a NULL terminates ID too
1317 bool allow_any_len, // if false, only length 4 and 6 are allowed
1318 bool ignore_case, // lower case letters are allowed
1319 bool allow_point // the wildcard '.' is allowed
1320 )
1321 {
1322 ASSERT(id);
1323 ccp ptr = id;
1324 ccp end = ptr + max_len;
1325 while ( ptr != end && ( *ptr >= 'A' && *ptr <= 'Z'
1326 || ignore_case && *ptr >= 'a' && *ptr <= 'z'
1327 || *ptr >= '0' && *ptr <= '9'
1328 || allow_point && *ptr == '.'
1329 || *ptr == '_' ))
1330 ptr++;
1331
1332 const int len = ptr - (ccp)id;
1333 return allow_any_len || len == 4 || len == 6 ? len : 0;
1334 }
1335
1336 //-----------------------------------------------------------------------------
1337
CheckID(const void * id,bool ignore_case,bool allow_point)1338 int CheckID // check up to 7 chars for ID4|ID6
1339 (
1340 const void * id, // valid pointer to test ID
1341 bool ignore_case, // lower case letters are allowed
1342 bool allow_point // the wildcard '.' is allowed
1343 )
1344 {
1345 // check up to 7 chars
1346 return CheckIDHelper(id,7,false,ignore_case,allow_point);
1347 }
1348
1349 //-----------------------------------------------------------------------------
1350
CheckID4(const void * id,bool ignore_case,bool allow_point)1351 bool CheckID4 // check exact 4 chars
1352 (
1353 const void * id, // valid pointer to test ID
1354 bool ignore_case, // lower case letters are allowed
1355 bool allow_point // the wildcard '.' is allowed
1356 )
1357 {
1358 // check exact 4 chars
1359 return CheckIDHelper(id,4,false,ignore_case,allow_point) == 4;
1360 }
1361
1362 //-----------------------------------------------------------------------------
1363
CheckID6(const void * id,bool ignore_case,bool allow_point)1364 bool CheckID6 // check exact 6 chars
1365 (
1366 const void * id, // valid pointer to test ID
1367 bool ignore_case, // lower case letters are allowed
1368 bool allow_point // the wildcard '.' is allowed
1369 )
1370 {
1371 // check exact 6 chars
1372 return CheckIDHelper(id,6,false,ignore_case,allow_point) == 6;
1373 }
1374
1375 //-----------------------------------------------------------------------------
1376
CountIDChars(const void * id,bool ignore_case,bool allow_point)1377 int CountIDChars // count number of valid ID chars, max = 1000
1378 (
1379 const void * id, // valid pointer to test ID
1380 bool ignore_case, // lower case letters are allowed
1381 bool allow_point // the wildcard '.' is allowed
1382 )
1383 {
1384 // count number of valid ID chars
1385 return CheckIDHelper(id,1000,true,ignore_case,allow_point);
1386 }
1387
1388 //-----------------------------------------------------------------------------
1389
ScanID(char * destbuf7,int * destlen,ccp source)1390 char * ScanID ( char * destbuf7, int * destlen, ccp source )
1391 {
1392 ASSERT(destbuf7);
1393
1394 memset(destbuf7,0,7);
1395 ccp id_start = 0;
1396 if (source)
1397 {
1398 ccp src = source;
1399
1400 // skip CTRL and SPACES
1401 while ( *src > 0 && *src <= ' ' )
1402 src++;
1403
1404 if ( ( *src == '*' || *src == '+' ) && ( !src[1] || src[1] == '=' ) )
1405 {
1406 if (destlen)
1407 *destlen = 1;
1408 return src[1] == '=' && src[2] ? (char*)src+2 : 0;
1409 }
1410
1411 // scan first word
1412 const int id_len = CheckID(src,false,false);
1413
1414 if ( id_len == 4 )
1415 {
1416 TRACE("4 chars found:%.6s\n",id_start);
1417 id_start = src;
1418 src += id_len;
1419
1420 // skip CTRL and SPACES
1421 while ( *src > 0 && *src <= ' ' )
1422 src++;
1423
1424 if (!*src)
1425 {
1426 memcpy(destbuf7,id_start,4);
1427 if (destlen)
1428 *destlen = 4;
1429 return 0;
1430 }
1431 id_start = 0;
1432 }
1433 else if ( id_len == 6 )
1434 {
1435 // we have found an ID6 canidat
1436 TRACE("6 chars found:%.6s\n",id_start);
1437 id_start = src;
1438 src += id_len;
1439
1440 // skip CTRL and SPACES
1441 while ( *src > 0 && *src <= ' ' )
1442 src++;
1443
1444 if ( !*src || *src == '=' )
1445 {
1446 if ( *src == '=' )
1447 src++;
1448
1449 // pure 'ID6' or 'ID6 = name found
1450 memcpy(destbuf7,id_start,6);
1451 if (destlen)
1452 *destlen = 6;
1453 return *src ? (char*)src : 0;
1454 }
1455 }
1456
1457 // scan for latest '...[ID6]...'
1458 while (*src)
1459 {
1460 while ( *src && *src != '[' ) // ]
1461 src++;
1462
1463 if ( *src == '[' && src[7] == ']' && CheckID(++src,false,false) == 6 )
1464 {
1465 id_start = src;
1466 src += 8;
1467 }
1468 if (*src)
1469 src++;
1470 }
1471 }
1472 if (id_start)
1473 memcpy(destbuf7,id_start,6);
1474 if (destlen)
1475 *destlen = id_start ? 6 : 0;
1476 return 0;
1477 }
1478
1479 //
1480 ///////////////////////////////////////////////////////////////////////////////
1481 /////////////// time printing & scanning ///////////////
1482 ///////////////////////////////////////////////////////////////////////////////
1483
1484 int opt_print_time = PT__DEFAULT;
1485 int opt_time_select = PT__DEFAULT & PT__USE_MASK;
1486
1487 ///////////////////////////////////////////////////////////////////////////////
1488
ScanPrintTimeMode(ccp arg,int prev_mode)1489 int ScanPrintTimeMode ( ccp arg, int prev_mode )
1490 {
1491 #undef E
1492 #undef EM
1493 #undef IT
1494 #undef MT
1495 #undef CT
1496 #undef AT
1497
1498 #define E PT_ENABLED
1499 #define EM PT__ENABLED_MASK
1500 #define IT PT_USE_ITIME|PT_F_ITIME
1501 #define MT PT_USE_MTIME|PT_F_MTIME
1502 #define CT PT_USE_CTIME|PT_F_CTIME
1503 #define AT PT_USE_ATIME|PT_F_ATIME
1504
1505 static const CommandTab_t tab[] =
1506 {
1507 { 0, "RESET", "-", PT__MASK },
1508
1509 { PT_DISABLED, "OFF", 0, EM },
1510 { PT_ENABLED, "ON", 0, EM },
1511
1512 { E|PT_SINGLE, "SINGLE", "1", EM|PT__MULTI_MASK|PT__F_MASK },
1513 { E|PT_MULTI, "MULTI", "+", EM|PT__MULTI_MASK },
1514
1515 { E|PT_MULTI, "NONE", "0", EM|PT__MULTI_MASK|PT__F_MASK },
1516 { E|PT_MULTI|PT__F_MASK,"ALL", "*", EM|PT__MULTI_MASK|PT__F_MASK },
1517
1518 { E|IT, "I", 0, EM|PT__USE_MASK },
1519 { E|MT, "M", 0, EM|PT__USE_MASK },
1520 { E|CT, "C", 0, EM|PT__USE_MASK },
1521 { E|AT, "A", 0, EM|PT__USE_MASK },
1522
1523 { E|PT_PRINT_DATE, "DATE", 0, EM|PT__PRINT_MASK },
1524 { E|PT_PRINT_TIME, "TIME", "MIN", EM|PT__PRINT_MASK },
1525 { E|PT_PRINT_SEC, "SEC", 0, EM|PT__PRINT_MASK },
1526
1527 { E|IT|PT_PRINT_DATE, "IDATE", 0, EM|PT__USE_MASK|PT__PRINT_MASK },
1528 { E|MT|PT_PRINT_DATE, "MDATE", 0, EM|PT__USE_MASK|PT__PRINT_MASK },
1529 { E|CT|PT_PRINT_DATE, "CDATE", 0, EM|PT__USE_MASK|PT__PRINT_MASK },
1530 { E|AT|PT_PRINT_DATE, "ADATE", 0, EM|PT__USE_MASK|PT__PRINT_MASK },
1531
1532 { E|IT|PT_PRINT_TIME, "ITIME", "IMIN", EM|PT__USE_MASK|PT__PRINT_MASK },
1533 { E|MT|PT_PRINT_TIME, "MTIME", "MMIN", EM|PT__USE_MASK|PT__PRINT_MASK },
1534 { E|CT|PT_PRINT_TIME, "CTIME", "CMIN", EM|PT__USE_MASK|PT__PRINT_MASK },
1535 { E|AT|PT_PRINT_TIME, "ATIME", "AMIN", EM|PT__USE_MASK|PT__PRINT_MASK },
1536
1537 { E|IT|PT_PRINT_SEC, "ISEC", 0, EM|PT__USE_MASK|PT__PRINT_MASK },
1538 { E|MT|PT_PRINT_SEC, "MSEC", 0, EM|PT__USE_MASK|PT__PRINT_MASK },
1539 { E|CT|PT_PRINT_SEC, "CSEC", 0, EM|PT__USE_MASK|PT__PRINT_MASK },
1540 { E|AT|PT_PRINT_SEC, "ASEC", 0, EM|PT__USE_MASK|PT__PRINT_MASK },
1541
1542 { 0,0,0,0 }
1543 };
1544
1545 #undef E
1546 #undef EM
1547 #undef IT
1548 #undef MT
1549 #undef CT
1550 #undef AT
1551
1552 const int stat = ScanCommandListMask(arg,tab);
1553 if ( stat >= 0 )
1554 return SetPrintTimeMode(prev_mode,stat);
1555
1556 ERROR0(ERR_SYNTAX,"Illegal time mode (option --time): '%s'\n",arg);
1557 return PT__ERROR;
1558 }
1559
1560 ///////////////////////////////////////////////////////////////////////////////
1561
ScanAndSetPrintTimeMode(ccp argv)1562 int ScanAndSetPrintTimeMode ( ccp argv )
1563 {
1564 const int stat = ScanPrintTimeMode(argv,opt_print_time);
1565 if ( stat >= 0 )
1566 opt_print_time = stat;
1567 return stat;
1568 }
1569
1570 ///////////////////////////////////////////////////////////////////////////////
1571
SetPrintTimeMode(int prev_mode,int new_mode)1572 int SetPrintTimeMode ( int prev_mode, int new_mode )
1573 {
1574 TRACE("SetPrintTimeMode(%x,%x)\n",prev_mode,new_mode);
1575 if ( new_mode & PT__USE_MASK )
1576 prev_mode = prev_mode & ~PT__USE_MASK | new_mode & PT__USE_MASK;
1577
1578 prev_mode |= new_mode & PT__F_MASK;
1579
1580 if ( new_mode & PT__MULTI_MASK )
1581 prev_mode = prev_mode & ~PT__MULTI_MASK | new_mode & PT__MULTI_MASK;
1582
1583 if ( new_mode & PT__PRINT_MASK )
1584 prev_mode = prev_mode & ~PT__PRINT_MASK | new_mode & PT__PRINT_MASK;
1585
1586 if ( new_mode & PT__ENABLED_MASK )
1587 prev_mode = prev_mode & ~PT__ENABLED_MASK | new_mode & PT__ENABLED_MASK;
1588
1589 TRACE(" -> %x\n",prev_mode);
1590 return prev_mode;
1591 }
1592
1593 ///////////////////////////////////////////////////////////////////////////////
1594
EnablePrintTime(int opt_time)1595 int EnablePrintTime ( int opt_time )
1596 {
1597 return SetPrintTimeMode(PT__DEFAULT|PT_PRINT_DATE,opt_time|PT_ENABLED);
1598 }
1599
1600 ///////////////////////////////////////////////////////////////////////////////
1601
SetTimeOpt(int opt_time)1602 void SetTimeOpt ( int opt_time )
1603 {
1604 opt_print_time = SetPrintTimeMode( opt_print_time, opt_time|PT_ENABLED );
1605 }
1606
1607 ///////////////////////////////////////////////////////////////////////////////
1608
SetupPrintTime(PrintTime_t * pt,int opt_time)1609 void SetupPrintTime ( PrintTime_t * pt, int opt_time )
1610 {
1611 TRACE("SetupPrintTime(%p,%x)\n",pt,opt_time);
1612 ASSERT(pt);
1613 memset(pt,0,sizeof(*pt));
1614
1615 if ( opt_time & PT_SINGLE )
1616 {
1617 opt_time &= ~PT__F_MASK;
1618 switch( opt_time & PT__USE_MASK )
1619 {
1620 case PT_USE_ITIME: opt_time |= PT_F_ITIME; break;
1621 case PT_USE_CTIME: opt_time |= PT_F_CTIME; break;
1622 case PT_USE_ATIME: opt_time |= PT_F_ATIME; break;
1623 default: opt_time |= PT_F_MTIME; break;
1624 }
1625 }
1626 else if ( !(opt_time&PT__F_MASK) )
1627 opt_time |= PT_F_MTIME;
1628
1629 ccp head_format;
1630 switch ( opt_time & (PT__ENABLED_MASK|PT__PRINT_MASK) )
1631 {
1632 case PT_ENABLED|PT_PRINT_SEC:
1633 pt->format = " %Y-%m-%d %H:%M:%S";
1634 pt->undef = " ---------- --:--:--";
1635 head_format = " #-date #-time ";
1636 break;
1637
1638 case PT_ENABLED|PT_PRINT_TIME:
1639 pt->format = " %Y-%m-%d %H:%M";
1640 pt->undef = " ---------- --:--";
1641 head_format = " #-date #-time";
1642 break;
1643
1644 case PT_ENABLED|PT_PRINT_DATE:
1645 pt->format = " %Y-%m-%d";
1646 pt->undef = " ----------";
1647 head_format = " #-date ";
1648 break;
1649
1650 default:
1651 pt->format = "";
1652 pt->undef = "";
1653 head_format = "";
1654 opt_time &= ~PT__F_MASK;
1655 break;
1656 }
1657
1658 pt->mode = opt_time & PT__MASK;
1659 pt->wd1 = strlen(head_format);
1660
1661 ASSERT( pt->wd1 < PT_BUF_SIZE );
1662 ASSERT( 4*pt->wd1 < sizeof(pt->head) );
1663 ASSERT( 4*pt->wd1 < sizeof(pt->fill) );
1664 ASSERT( 4*pt->wd1 < sizeof(pt->tbuf) );
1665
1666 pt->nelem = 0;
1667 char *head = pt->head, *fill = pt->fill;
1668 ccp mptr = "imca";
1669 while (*mptr)
1670 {
1671 char ch = *mptr++;
1672 if ( opt_time & PT_F_ITIME )
1673 {
1674 ccp src;
1675 for ( src = head_format; *src; src++ )
1676 {
1677 *head++ = *src == '#' ? ch : *src;
1678 *fill++ = ' ';
1679 }
1680 pt->nelem++;
1681 }
1682 opt_time >>= 1;
1683 }
1684 *head = 0;
1685 *fill = 0;
1686 pt->wd = pt->nelem * pt->wd1;
1687
1688 TRACE(" -> head: |%s|\n",pt->head);
1689 TRACE(" -> fill: |%s|\n",pt->fill);
1690 TRACE(" -> format: |%s|\n",pt->format);
1691 TRACE(" -> undef: |%s|\n",pt->undef);
1692 }
1693
1694 ///////////////////////////////////////////////////////////////////////////////
1695
PrintTime(PrintTime_t * pt,const FileAttrib_t * fa)1696 char * PrintTime ( PrintTime_t * pt, const FileAttrib_t * fa )
1697 {
1698 ASSERT(pt);
1699 ASSERT(fa);
1700
1701 if (!pt->wd)
1702 *pt->tbuf = 0;
1703 else
1704 {
1705 const time_t * timbuf[] = { &fa->itime, &fa->mtime, &fa->ctime, &fa->atime, 0 };
1706 const time_t ** timptr = timbuf;
1707
1708 char *dest = pt->tbuf, *end = dest + sizeof(pt->tbuf);
1709 int mode;
1710 for ( mode = pt->mode; *timptr; timptr++, mode >>= 1 )
1711 if ( mode & PT_F_ITIME )
1712 {
1713 const time_t thetime = **timptr;
1714 if (!thetime)
1715 dest = StringCopyE(dest,end,pt->undef);
1716 else
1717 {
1718 struct tm * tm = localtime(&thetime);
1719 dest += strftime(dest,end-dest,pt->format,tm);
1720 }
1721 }
1722 }
1723 return pt->tbuf;
1724 }
1725
1726 ///////////////////////////////////////////////////////////////////////////////
1727
SelectTime(const FileAttrib_t * fa,int opt_time)1728 time_t SelectTime ( const FileAttrib_t * fa, int opt_time )
1729 {
1730 ASSERT(fa);
1731 switch ( opt_time & PT__USE_MASK )
1732 {
1733 case PT_USE_ITIME: return fa->itime;
1734 case PT_USE_CTIME: return fa->ctime;
1735 case PT_USE_ATIME: return fa->atime;
1736 default: return fa->mtime;
1737 }
1738 }
1739
1740 ///////////////////////////////////////////////////////////////////////////////
1741
SelectSortMode(int opt_time)1742 SortMode SelectSortMode ( int opt_time )
1743 {
1744 switch ( opt_time & PT__USE_MASK )
1745 {
1746 case PT_USE_ITIME: return SORT_ITIME;
1747 case PT_USE_CTIME: return SORT_CTIME;
1748 case PT_USE_ATIME: return SORT_ATIME;
1749 default: return SORT_MTIME;
1750 }
1751 }
1752
1753 ///////////////////////////////////////////////////////////////////////////////
1754 ///////////////////////////////////////////////////////////////////////////////
1755
ScanTime(ccp arg)1756 time_t ScanTime ( ccp arg )
1757 {
1758 static ccp tab[] =
1759 {
1760 "%Y-%m-%d %H:%M:%S",
1761 "%Y-%m-%d %H:%M",
1762 "%Y-%m-%d %H%M%S",
1763 "%Y-%m-%d %H%M",
1764 "%Y-%m-%d %H",
1765 "%Y-%m-%d",
1766 "%Y%m%d %H%M%S",
1767 "%Y%m%d %H%M",
1768 "%Y%m%d %H",
1769 "%Y%m%d",
1770 "%s",
1771 0
1772 };
1773
1774 ccp * tptr;
1775 for ( tptr = tab; *tptr; tptr++ )
1776 {
1777 struct tm tm;
1778 memset(&tm,0,sizeof(tm));
1779 tm.tm_mon = 1;
1780 tm.tm_mday = 1;
1781 ccp res = strptime(arg,*tptr,&tm);
1782 if (res)
1783 {
1784 while (isblank((int)*res))
1785 res++;
1786 if (!*res)
1787 {
1788 time_t tim = mktime(&tm);
1789 if ( tim != (time_t)-1 )
1790 return tim;
1791 }
1792 }
1793 }
1794
1795 ERROR0(ERR_SYNTAX,"Illegal time format: %s",arg);
1796 return (time_t)-1;
1797 }
1798
1799 //
1800 ///////////////////////////////////////////////////////////////////////////////
1801 /////////////// scan number ///////////////
1802 ///////////////////////////////////////////////////////////////////////////////
1803
ScanS32(s32 * res_num,ccp source,uint default_base)1804 char * ScanS32
1805 (
1806 // return 'source' on error
1807
1808 s32 *res_num, // not NULL: store result (only on success)
1809 ccp source, // NULL or source text
1810 uint default_base // base for numbers without '0x' prefix
1811 // 0: C like with octal support
1812 // 10: standard value for decimal numbers
1813 // 16: standard value for hex numbers
1814 )
1815 {
1816 ccp src = source;
1817 while ( *src > 0 && *src <= ' ' )
1818 src++;
1819
1820 const bool minus = *src == '-';
1821 if ( minus || *src == '+' )
1822 {
1823 src++;
1824 while ( *src > 0 && *src <= ' ' )
1825 src++;
1826 }
1827 const uint base = src[0] == '0' && ( src[1] == 'x' || src[1] == 'X' )
1828 ? 16 : default_base;
1829 char *end;
1830 const s32 num = strtoul( src, &end, base );
1831 if ( (ccp)end > src )
1832 {
1833 if (res_num)
1834 *res_num = minus ? -num : num;
1835 return end;
1836 }
1837
1838 return (char*)source;
1839 }
1840
1841 ///////////////////////////////////////////////////////////////////////////////
1842
ScanS64(s64 * res_num,ccp source,uint default_base)1843 char * ScanS64
1844 (
1845 // return 'source' on error
1846
1847 s64 *res_num, // not NULL: store result (only on success)
1848 ccp source, // NULL or source text
1849 uint default_base // base for numbers without '0x' prefix
1850 // 0: C like with octal support
1851 // 10: standard value for decimal numbers
1852 // 16: standard value for hex numbers
1853 )
1854 {
1855 ccp src = source;
1856 while ( *src > 0 && *src <= ' ' )
1857 src++;
1858
1859 const bool minus = *src == '-';
1860 if ( minus || *src == '+' )
1861 {
1862 src++;
1863 while ( *src > 0 && *src <= ' ' )
1864 src++;
1865 }
1866 const uint base = src[0] == '0' && ( src[1] == 'x' || src[1] == 'X' )
1867 ? 16 : default_base;
1868 char *end;
1869 const s64 num = strtoull( src, &end, base );
1870 if ( (ccp)end > src )
1871 {
1872 if (res_num)
1873 *res_num = minus ? -num : num;
1874 return end;
1875 }
1876
1877 return (char*)source;
1878 }
1879
1880 //
1881 ///////////////////////////////////////////////////////////////////////////////
1882 /////////////// scan size ///////////////
1883 ///////////////////////////////////////////////////////////////////////////////
1884
ScanSizeFactor(char ch_factor,int force_base)1885 u64 ScanSizeFactor ( char ch_factor, int force_base )
1886 {
1887 if ( force_base == 1000 )
1888 {
1889 switch (ch_factor)
1890 {
1891 case 'b': case 'c': return 1;
1892 case 'k': case 'K': return KB_SI;
1893 case 'm': case 'M': return MB_SI;
1894 case 'g': case 'G': return GB_SI;
1895 case 't': case 'T': return TB_SI;
1896 case 'p': case 'P': return PB_SI;
1897 case 'e': case 'E': return EB_SI;
1898
1899 case 's': case 'S': return WII_SECTOR_SIZE;
1900 case 'u': case 'U': return GC_DISC_SIZE;
1901 case 'w': case 'W': return WII_SECTORS_SINGLE_LAYER *(u64)WII_SECTOR_SIZE;
1902 }
1903 }
1904 else if ( force_base == 1024 )
1905 {
1906 switch (ch_factor)
1907 {
1908 case 'b': case 'c': return 1;
1909 case 'k': case 'K': return KiB;
1910 case 'm': case 'M': return MiB;
1911 case 'g': case 'G': return GiB;
1912 case 't': case 'T': return TiB;
1913 case 'p': case 'P': return PiB;
1914 case 'e': case 'E': return EiB;
1915
1916 case 's': case 'S': return WII_SECTOR_SIZE;
1917 case 'u': case 'U': return GC_DISC_SIZE;
1918 case 'w': case 'W': return WII_SECTORS_SINGLE_LAYER *(u64)WII_SECTOR_SIZE;
1919 }
1920 }
1921 else
1922 {
1923 switch (ch_factor)
1924 {
1925 case 'b':
1926 case 'c': return 1;
1927
1928 case 'k': return KB_SI;
1929 case 'm': return MB_SI;
1930 case 'g': return GB_SI;
1931 case 't': return TB_SI;
1932 case 'p': return PB_SI;
1933 case 'e': return EB_SI;
1934
1935 case 'K': return KiB;
1936 case 'M': return MiB;
1937 case 'G': return GiB;
1938 case 'T': return TiB;
1939 case 'P': return PiB;
1940 case 'E': return EiB;
1941
1942 case 's':
1943 case 'S': return WII_SECTOR_SIZE;
1944
1945 case 'u':
1946 case 'U': return GC_DISC_SIZE;
1947
1948 case 'w':
1949 case 'W': return WII_SECTORS_SINGLE_LAYER *(u64)WII_SECTOR_SIZE;
1950 }
1951 }
1952 return 0;
1953 }
1954
1955 //-----------------------------------------------------------------------------
1956
ScanSizeTerm(double * num,ccp source,u64 default_factor,int force_base)1957 char * ScanSizeTerm ( double * num, ccp source, u64 default_factor, int force_base )
1958 {
1959 ASSERT(source);
1960
1961 char * end;
1962 double d = strtod(source,&end);
1963 if ( end > source )
1964 {
1965 // something was read
1966
1967 if ( *end == '/' )
1968 {
1969 const double div = strtod(end+1,&end);
1970 if ( div > 0 )
1971 d /= div;
1972 }
1973
1974 u64 factor = ScanSizeFactor(*end,force_base);
1975 if (factor)
1976 end++;
1977 else
1978 factor = default_factor;
1979
1980 if (factor)
1981 d *= factor;
1982 else
1983 end = (char*)source;
1984 }
1985
1986 if (num)
1987 *num = d;
1988
1989 return end;
1990 }
1991
1992 //-----------------------------------------------------------------------------
1993
ScanSize(double * num,ccp source,u64 default_factor1,u64 default_factor2,int force_base)1994 char * ScanSize ( double * num, ccp source,
1995 u64 default_factor1, u64 default_factor2, int force_base )
1996 {
1997 DASSERT(source);
1998 TRACE("ScanSize(df=%llx,%llx, base=%u)\n",
1999 default_factor1, default_factor2, force_base );
2000
2001 double sum = 0.0;
2002 bool add = true;
2003 char * end = 0;
2004 for (;;)
2005 {
2006 double term;
2007 end = ScanSizeTerm(&term,source,default_factor1,force_base);
2008 if ( end == source )
2009 break;
2010 if (add)
2011 sum += term;
2012 else
2013 sum -= term;
2014
2015 while ( *end > 0 && *end <= ' ' )
2016 end++;
2017
2018 if ( *end == '+' )
2019 add = true;
2020 else if ( *end == '-' )
2021 add = false;
2022 else
2023 break;
2024
2025 source = end+1;
2026 while ( *source > 0 && *source <= ' ' )
2027 source++;
2028
2029 if ( !*source && default_factor2 )
2030 {
2031 if (add)
2032 sum += default_factor2;
2033 else
2034 sum -= default_factor2;
2035 end = (char*)source;
2036 break;
2037 }
2038
2039 default_factor1 = default_factor2;
2040 }
2041
2042 if (num)
2043 *num = sum;
2044
2045 return end;
2046 }
2047
2048 //-----------------------------------------------------------------------------
2049
ScanSizeU32(u32 * num,ccp source,u64 default_factor1,u64 default_factor2,int force_base)2050 char * ScanSizeU32 ( u32 * num, ccp source,
2051 u64 default_factor1, u64 default_factor2, int force_base )
2052 {
2053 double d;
2054 char * end = ScanSize(&d,source,default_factor1,default_factor2,force_base);
2055 //d = ceil(d+0.5);
2056 if ( d < 0 || d > ~(u32)0 )
2057 end = (char*)source;
2058 else if (num)
2059 *num = (u32)d;
2060
2061 return end;
2062 }
2063
2064 //-----------------------------------------------------------------------------
2065
ScanSizeU64(u64 * num,ccp source,u64 default_factor1,u64 default_factor2,int force_base)2066 char * ScanSizeU64 ( u64 * num, ccp source,
2067 u64 default_factor1, u64 default_factor2, int force_base )
2068 {
2069 double d;
2070 char * end = ScanSize(&d,source,default_factor1,default_factor2,force_base);
2071 //d = ceil(d+0.5);
2072 if ( d < 0 || d > ~(u64)0 )
2073 end = (char*)source;
2074 else if (num)
2075 *num = (u64)d;
2076
2077 return end;
2078 }
2079
2080 ///////////////////////////////////////////////////////////////////////////////
2081
ScanSizeOpt(double * num,ccp source,u64 default_factor1,u64 default_factor2,int force_base,ccp opt_name,u64 min,u64 max,bool print_err)2082 enumError ScanSizeOpt
2083 ( double * num, ccp source,
2084 u64 default_factor1, u64 default_factor2, int force_base,
2085 ccp opt_name, u64 min, u64 max, bool print_err )
2086 {
2087 double d;
2088 char * end = ScanSize(&d,source,default_factor1,default_factor2,force_base);
2089
2090 #ifdef DEBUG
2091 {
2092 u64 size = d;
2093 TRACE("--%s %8.6g ~ %llu ~ %llu GiB ~ %llu GB\n",
2094 opt_name, d, size, (size+GiB/2)/GiB, (size+500000000)/1000000000 );
2095 }
2096 #endif
2097
2098 enumError err = ERR_OK;
2099
2100 if ( source == end || *end )
2101 {
2102 err = ERR_SYNTAX;
2103 if (print_err)
2104 ERROR0(ERR_SYNTAX,
2105 "Illegal number for option --%s: %s\n",
2106 opt_name, source );
2107 }
2108 else if ( min > 0 && d < min )
2109 {
2110 err = ERR_SYNTAX;
2111 if (print_err)
2112 ERROR0(ERR_SEMANTIC,
2113 "Value of --%s to small (must not <%llu): %s\n",
2114 opt_name, min, source );
2115 }
2116 else if ( max > 0 && d > max )
2117 {
2118 err = ERR_SYNTAX;
2119 if (print_err)
2120 ERROR0(ERR_SEMANTIC,
2121 "Value of --%s to large (must not >%llu): %s\n",
2122 opt_name, max, source );
2123 }
2124
2125 if ( num && !err )
2126 *num = d;
2127 return err;
2128 }
2129
2130 //-----------------------------------------------------------------------------
2131
ScanSizeOptU64(u64 * num,ccp source,u64 default_factor1,int force_base,ccp opt_name,u64 min,u64 max,u32 multiple,u32 pow2,bool print_err)2132 enumError ScanSizeOptU64
2133 ( u64 * num, ccp source, u64 default_factor1, int force_base,
2134 ccp opt_name, u64 min, u64 max, u32 multiple, u32 pow2, bool print_err )
2135 {
2136 if (!max)
2137 max = ~(u64)0;
2138
2139 if ( pow2 && !force_base )
2140 {
2141 // try base 1024 first without error messages
2142 u64 val;
2143 if (!ScanSizeOptU64( &val, source, default_factor1, 1024,
2144 opt_name, min,max, multiple, pow2, false ))
2145 {
2146 if (num)
2147 *num = val;
2148 return ERR_OK;
2149 }
2150 }
2151
2152 double d = 0.0;
2153 enumError err = ScanSizeOpt(&d,source,default_factor1,
2154 multiple ? multiple : 1,
2155 force_base,opt_name,min,max,print_err);
2156
2157 u64 val;
2158 if ( d < 0.0 )
2159 {
2160 val = 0;
2161 err = ERR_SEMANTIC;
2162 if (print_err)
2163 ERROR0(ERR_SEMANTIC, "--%s: negative values not allowed: %s\n",
2164 opt_name, source );
2165 }
2166 else
2167 val = d;
2168
2169 if ( err == ERR_OK && pow2 > 0 && val )
2170 {
2171 int shift_count = 0;
2172 u64 shift_val = val;
2173 if (val)
2174 {
2175 while (!(shift_val&1))
2176 {
2177 shift_count++;
2178 shift_val >>= 1;
2179 }
2180 }
2181
2182 if ( shift_val != 1 || shift_count/pow2*pow2 != shift_count )
2183 {
2184 err = ERR_SEMANTIC;
2185 if (print_err)
2186 ERROR0(ERR_SYNTAX,
2187 "--%s: value must be a power of %d but not %llu\n",
2188 opt_name, 1<<pow2, val );
2189 }
2190 }
2191
2192 if ( err == ERR_OK && multiple > 1 )
2193 {
2194 u64 xval = val / multiple * multiple;
2195 if ( xval != val )
2196 {
2197 if ( min > 0 && xval < min )
2198 xval += multiple;
2199
2200 if (print_err)
2201 ERROR0(ERR_WARNING,
2202 "--%s: value must be a multiple of %u -> use %llu instead of %llu.\n",
2203 opt_name, multiple, xval, val );
2204 val = xval;
2205 }
2206 }
2207
2208 if ( num && !err )
2209 *num = val;
2210 return err;
2211 }
2212
2213 //-----------------------------------------------------------------------------
2214
ScanSizeOptU32(u32 * num,ccp source,u64 default_factor1,int force_base,ccp opt_name,u64 min,u64 max,u32 multiple,u32 pow2,bool print_err)2215 enumError ScanSizeOptU32
2216 ( u32 * num, ccp source, u64 default_factor1, int force_base,
2217 ccp opt_name, u64 min, u64 max, u32 multiple, u32 pow2, bool print_err )
2218 {
2219 if ( !max || max > ~(u32)0 )
2220 max = ~(u32)0;
2221
2222 u64 val;
2223 enumError err = ScanSizeOptU64( &val, source, default_factor1, force_base,
2224 opt_name, min, max, multiple, pow2, print_err );
2225
2226 if ( num && !err )
2227 *num = (u32)val;
2228 return err;
2229 }
2230
2231 ///////////////////////////////////////////////////////////////////////////////
2232
ScanOptSplitSize(ccp source)2233 int ScanOptSplitSize ( ccp source )
2234 {
2235 opt_split++;
2236 return ERR_OK != ScanSizeOptU64(
2237 &opt_split_size, // u64 * num
2238 source, // ccp source
2239 GiB, // default_factor1
2240 0, // int force_base
2241 "split-size", // ccp opt_name
2242 MIN_SPLIT_SIZE, // u64 min
2243 0, // u64 max
2244 DEF_SPLIT_FACTOR, // u32 multiple
2245 0, // u32 pow2
2246 true // bool print_err
2247 );
2248 }
2249
2250 ///////////////////////////////////////////////////////////////////////////////
2251
ScanOptRDepth(ccp source)2252 int ScanOptRDepth ( ccp source )
2253 {
2254 return ERR_OK != ScanSizeOptU32(
2255 &opt_recurse_depth, // u32 * num
2256 source, // ccp source
2257 1, // default_factor1
2258 0, // int force_base
2259 "rdepth", // ccp opt_name
2260 0, // u64 min
2261 MAX_RECURSE_DEPTH, // u64 max
2262 0, // u32 multiple
2263 0, // u32 pow2
2264 true // bool print_err
2265 );
2266 }
2267
2268 //
2269 ///////////////////////////////////////////////////////////////////////////////
2270 /////////////// scan num/range ///////////////
2271 ///////////////////////////////////////////////////////////////////////////////
2272
ScanNumU32(ccp arg,u32 * p_stat,u32 * p_num,u32 min,u32 max)2273 char * ScanNumU32 ( ccp arg, u32 * p_stat, u32 * p_num, u32 min, u32 max )
2274 {
2275 ASSERT(arg);
2276 ASSERT(p_num);
2277 TRACE("ScanNumU32(%s)\n",arg);
2278
2279 while ( *arg > 0 && *arg <= ' ' )
2280 arg++;
2281
2282 char * end;
2283 u32 num = strtoul(arg,&end, arg[1] >= '0' && arg[1] <= '9' ? 10 : 0 );
2284 u32 stat = end > arg;
2285 if (stat)
2286 {
2287 if ( num < min )
2288 num = min;
2289 else if ( num > max )
2290 num = max;
2291
2292 while ( *end > 0 && *end <= ' ' )
2293 end++;
2294 }
2295 else
2296 num = 0;
2297
2298 if (p_stat)
2299 *p_stat = stat;
2300 *p_num = num;
2301
2302 TRACE("END ScanNumU32() stat=%u, n=%u ->%s\n",stat,num,arg);
2303 return end;
2304 }
2305
2306 ///////////////////////////////////////////////////////////////////////////////
2307
ScanRangeU32(ccp arg,u32 * p_stat,u32 * p_n1,u32 * p_n2,u32 min,u32 max)2308 char * ScanRangeU32 ( ccp arg, u32 * p_stat, u32 * p_n1, u32 * p_n2, u32 min, u32 max )
2309 {
2310 ASSERT(arg);
2311 ASSERT(p_n1);
2312 ASSERT(p_n2);
2313 TRACE("ScanRangeU32(%s)\n",arg);
2314
2315 int stat = 0;
2316 u32 n1 = ~(u32)0, n2 = 0;
2317
2318 while ( *arg > 0 && *arg <= ' ' )
2319 arg++;
2320
2321 if ( *arg == '-' )
2322 n1 = min;
2323 else
2324 {
2325 char * end;
2326 u32 num = strtoul(arg,&end,0);
2327 if ( arg == end )
2328 goto abort;
2329
2330 stat = 1;
2331 arg = end;
2332 n1 = num;
2333
2334 while ( *arg > 0 && *arg <= ' ' )
2335 arg++;
2336 }
2337
2338 if ( *arg != '-' )
2339 {
2340 stat = 1;
2341 n2 = n1;
2342 goto abort;
2343 }
2344 arg++;
2345
2346 while ( *arg > 0 && *arg <= ' ' )
2347 arg++;
2348
2349 char * end;
2350 n2 = strtoul(arg,&end,0);
2351 if ( end == arg )
2352 n2 = max;
2353 stat = 2;
2354 arg = end;
2355
2356 abort:
2357
2358 if ( stat > 0 )
2359 {
2360 if ( n1 < min )
2361 n1 = min;
2362 if ( n2 > max )
2363 n2 = max;
2364 }
2365
2366 if ( !stat || n1 > n2 )
2367 {
2368 stat = 0;
2369 n1 = ~(u32)0;
2370 n2 = 0;
2371 }
2372
2373 if (p_stat)
2374 *p_stat = stat;
2375 *p_n1 = n1;
2376 *p_n2 = n2;
2377
2378 while ( *arg > 0 && *arg <= ' ' )
2379 arg++;
2380
2381 TRACE("END ScanRangeU32() stat=%u, n=%u..%u ->%s\n",stat,n1,n2,arg);
2382 return (char*)arg;
2383 }
2384
2385 //
2386 ///////////////////////////////////////////////////////////////////////////////
2387 /////////////// ScanHex() ///////////////
2388 ///////////////////////////////////////////////////////////////////////////////
2389
2390 // 0..15 : hex digit
2391 // 50 : spaces and control charactzers
2392 // 51 : allowed separators
2393 // 99 : invalid char
2394
2395 const u8 HexTab[256] =
2396 {
2397 99,50,50,50, 50,50,50,50, 50,50,50,50, 50,50,50,50, // 0x00 .. 0x0f
2398 50,50,50,50, 50,50,50,50, 50,50,50,50, 50,50,50,50, // 0x10 .. 0x1f
2399
2400 50,99,99,99, 99,99,99,99, 99,99,99,99, 51,51,51,99, // !"# $%&' ()*+ ,-./
2401 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,51,99, 99,99,99,99, // 0123 4567 89:; <=>?
2402 99,10,11,12, 13,14,15,99, 99,99,99,99, 99,99,99,99, // @ABC DEFG HIJK LMNO
2403 99,99,99,99, 99,99,99,99, 99,99,99,99, 99,99,99,99, // PQRS TUVW XYZ[ \]^_
2404 99,10,11,12, 13,14,15,99, 99,99,99,99, 99,99,99,99, // `abc defg hijk lmno
2405 99,99,99,99, 99,99,99,99, 99,99,99,99, 99,99,99,99, // PQRS TUVW xyz {|}~
2406
2407 99,99,99,99, 99,99,99,99, 99,99,99,99, 99,99,99,99, // 0x80 .. 0x8f
2408 99,99,99,99, 99,99,99,99, 99,99,99,99, 99,99,99,99, // 0x90 .. 0x9f
2409 99,99,99,99, 99,99,99,99, 99,99,99,99, 99,99,99,99, // 0xa0 .. 0xaf
2410 99,99,99,99, 99,99,99,99, 99,99,99,99, 99,99,99,99, // 0xb0 .. 0xbf
2411 99,99,99,99, 99,99,99,99, 99,99,99,99, 99,99,99,99, // 0xc0 .. 0xcf
2412 99,99,99,99, 99,99,99,99, 99,99,99,99, 99,99,99,99, // 0xd0 .. 0xdf
2413 99,99,99,99, 99,99,99,99, 99,99,99,99, 99,99,99,99, // 0xe0 .. 0xef
2414 99,99,99,99, 99,99,99,99, 99,99,99,99, 99,99,99,99, // 0xf0 .. 0xff
2415 };
2416
2417 ///////////////////////////////////////////////////////////////////////////////
2418
ScanHexHelper(void * buf,int buf_size,int * bytes_read,ccp arg,int err_level)2419 char * ScanHexHelper
2420 (
2421 void * buf, // valid pointer to result buf
2422 int buf_size, // number of byte to read
2423 int * bytes_read, // NULL or result: number of read bytes
2424 ccp arg, // source string
2425 int err_level // error level (print message):
2426 // = 0: don't print errors
2427 // >= 1: print syntax errors
2428 // >= 2: msg if bytes_read<buf_size
2429 // >= 3: msg if arg contains more characters
2430 )
2431 {
2432 DASSERT( buf );
2433 DASSERT( buf_size > 0 );
2434 DASSERT( arg );
2435 u8 * dest = buf;
2436 memset(dest,0,buf_size);
2437
2438 const u8 * src = (const u8*)arg;
2439 int read_count = 0;
2440 while ( HexTab[*src] < 99 && read_count < buf_size )
2441 {
2442 while ( HexTab[*src] >= 50 && HexTab[*src] <= 99 )
2443 src++;
2444
2445 if ( *src == '0' && ( src[1] == 'x' || src[1] == 'X' ))
2446 src += 2;
2447
2448 const u8 * end = src;
2449 while ( HexTab[*end] < 16 )
2450 end++;
2451
2452 if ( (end-src) & 1 )
2453 {
2454 *dest++ = HexTab[*src++];
2455 read_count++;
2456 }
2457
2458 while ( src < end && read_count < buf_size )
2459 {
2460 *dest = HexTab[*src++] << 4;
2461 *dest++ |= HexTab[*src++];
2462 read_count++;
2463 }
2464 }
2465 // [[2do]] What 2do?? Is this a forgotten marker?
2466
2467 while ( HexTab[*src] == 50 )
2468 src++;
2469
2470 if ( err_level > 0 )
2471 {
2472 if ( read_count < buf_size && *src )
2473 ERROR0(ERR_SYNTAX,"Illegal character for hex input: %.20s\n",src);
2474 else if ( err_level > 1 && read_count < buf_size )
2475 ERROR0(ERR_SYNTAX,"Missing %d hex characters: %.20s\n",
2476 buf_size - read_count, arg);
2477 else if ( err_level > 2 && *src )
2478 ERROR0(ERR_SYNTAX,"Unexpected characters: %.20s\n",src);
2479 }
2480
2481 if (bytes_read)
2482 *bytes_read = read_count;
2483 return (char*)src;
2484 }
2485
2486 ///////////////////////////////////////////////////////////////////////////////
2487
ScanHex(void * buf,int buf_size,ccp arg)2488 enumError ScanHex
2489 (
2490 void * buf, // valid pointer to result buf
2491 int buf_size, // number of byte to read
2492 ccp arg // source string
2493 )
2494 {
2495 int count;
2496 arg = ScanHexHelper(buf,buf_size,&count,arg,99);
2497
2498 return count == buf_size && !*arg ? ERR_OK : ERR_SYNTAX;
2499 }
2500
2501 ///////////////////////////////////////////////////////////////////////////////
2502
ScanHexSilent(void * buf,int buf_size,ccp arg)2503 enumError ScanHexSilent
2504 (
2505 void * buf, // valid pointer to result buf
2506 int buf_size, // number of byte to read
2507 ccp arg // source string
2508 )
2509 {
2510 int count;
2511 arg = ScanHexHelper(buf,buf_size,&count,arg,0);
2512
2513 return count == buf_size && !*arg ? ERR_OK : ERR_SYNTAX;
2514 }
2515
2516 ///////////////////////////////////////////////////////////////////////////////
2517 ///////////////////////////////////////////////////////////////////////////////
2518
PutLines(FILE * f,int indent,int fw,int first_line,ccp prefix,ccp text)2519 void PutLines
2520 (
2521 FILE * f, // valid output stream
2522 int indent, // indent of output
2523 int fw, // field width of output
2524 int first_line, // length without prefix of already printed first line
2525 ccp prefix, // NULL or prefix for each line
2526 ccp text // text to print
2527 )
2528 {
2529 DASSERT(f);
2530 DASSERT( indent >= 0 );
2531
2532 if (!prefix)
2533 prefix = "";
2534 TRACE("PutLines(,%d,%d,%d,%.10s,%.20s)\n",indent,fw,first_line,prefix,text);
2535 fw -= strlen(prefix);
2536 if ( fw < 10 )
2537 fw = 10;
2538
2539 ccp prefix1 = "";
2540 int indent1, fw1;
2541 if ( indent > first_line )
2542 {
2543 indent1 = indent - first_line;
2544 fw1 = fw - indent;
2545 }
2546 else
2547 {
2548 indent1 = 0;
2549 fw1 = fw - first_line;
2550 }
2551
2552 fw -= indent;
2553 if ( fw < 20 )
2554 fw = 20;
2555
2556 if ( fw1 < 20 )
2557 {
2558 fputc('\n',f);
2559 indent1 = indent;
2560 fw1 = fw;
2561 prefix1 = prefix;
2562 }
2563
2564 while ( *text )
2565 {
2566 // skip blank and control
2567 if ( *text == '\n' )
2568 {
2569 // don't skip spaces behind a LF ==> needed for tables
2570 while ( *text > 0 && *text < ' ' )
2571 text++;
2572 }
2573 else
2574 {
2575 // but ignore spaces on an automatic line break
2576 while ( *text > 0 && *text <= ' ' )
2577 text++;
2578 }
2579
2580 // setup
2581 ccp start = text, last_blank = text;
2582 ccp max = text + fw1;
2583
2584 while ( text < max && *text && *text != '\n' )
2585 {
2586 if ( *text > 0 && *text <= ' ' )
2587 last_blank = text;
2588 text++;
2589 }
2590
2591 // set back to last blank
2592 if ( last_blank > start && (u8)*text > ' ' )
2593 text = last_blank;
2594
2595 // print out
2596 if ( *text || text > start )
2597 fprintf(f,"%s%*s%.*s\n", prefix1, indent1, "", (int)(text-start), start );
2598
2599 // use standard values for next lines
2600 indent1 = indent;
2601 fw1 = fw;
2602 prefix1 = prefix;
2603 }
2604 }
2605
2606 ///////////////////////////////////////////////////////////////////////////////
2607
PrintLines(FILE * f,int indent,int fw,int first_line,ccp prefix,ccp format,...)2608 void PrintLines
2609 (
2610 FILE * f, // valid output stream
2611 int indent, // indent of output
2612 int fw, // field width of output
2613 int first_line, // length without prefix of already printed first line
2614 ccp prefix, // NULL or prefix for each line
2615 ccp format, // format string for vsnprintf()
2616 ... // arguments for 'vsnprintf(format,...)'
2617 )
2618 {
2619 DASSERT(f);
2620 DASSERT(format);
2621
2622 char msg[5000];
2623
2624 va_list arg;
2625 va_start(arg,format);
2626 vsnprintf(msg,sizeof(msg),format,arg);
2627 va_end(arg);
2628
2629 PutLines(f,indent,fw,first_line,prefix,msg);
2630 }
2631
2632 //
2633 ///////////////////////////////////////////////////////////////////////////////
2634 /////////////// scan compression option ///////////////
2635 ///////////////////////////////////////////////////////////////////////////////
2636
2637 wd_compression_t opt_compr_method = WD_COMPR__DEFAULT;
2638 int opt_compr_level = 0; // 0=default, 1..9=valid
2639 u32 opt_compr_chunk_size = 0; // 0=default
2640
2641 ///////////////////////////////////////////////////////////////////////////////
2642
ScanCompression_helper(ccp arg,bool silent,int * level,u32 * chunk_size)2643 static wd_compression_t ScanCompression_helper
2644 (
2645 ccp arg, // argument to scan
2646 bool silent, // don't print error message
2647 int * level, // not NULL: appendix '.digit' allowed
2648 // The level will be stored in '*level'
2649 u32 * chunk_size // not NULL: appendix '@size' allowed
2650 // The size will be stored in '*chunk_size'
2651 )
2652 {
2653 enum
2654 {
2655 COMPR_MEM = WD_COMPR__N+1
2656 };
2657
2658 static const CommandTab_t tab[] =
2659 {
2660 { WD_COMPR_NONE, "NONE", 0, 0 },
2661 { WD_COMPR_PURGE, "PURGE", "WDF", 0 },
2662 { WD_COMPR_BZIP2, "BZIP2", "BZ2", 0 },
2663 { WD_COMPR_LZMA, "LZMA", "LZ", 0 },
2664 { WD_COMPR_LZMA2, "LZMA2", "LZ2", 0 },
2665
2666 { WD_COMPR__DEFAULT, "DEFAULT", "D", 0 },
2667 { WD_COMPR__FAST, "FAST", "F", 0x300 + 10 },
2668 { WD_COMPR__GOOD, "GOOD", "G", 0 },
2669 { WD_COMPR__BEST, "BEST", "B", 0x900 + 50 },
2670
2671 { COMPR_MEM, "MEM", "M", 0 },
2672
2673 { WD_COMPR_NONE, "0", 0, 0 },
2674 { WD_COMPR_LZMA, "1", 0, 0x100 + 5 },
2675 { WD_COMPR_LZMA, "2", 0, 0x200 + 10 },
2676 { WD_COMPR_LZMA, "3", 0, 0x300 + 30 },
2677 { WD_COMPR_LZMA, "4", 0, 0x400 + 30 },
2678 { WD_COMPR_LZMA, "5", 0, 0x400 + 50 },
2679 { WD_COMPR_LZMA, "6", 0, 0x500 + 20 },
2680 { WD_COMPR_LZMA, "7", 0, 0x500 + 50 },
2681 { WD_COMPR_LZMA, "8", 0, 0x600 + 50 },
2682 { WD_COMPR_LZMA, "9", 0, 0x900 + 50 },
2683
2684 { 0,0,0,0 }
2685 };
2686
2687 char argbuf[100];
2688 ccp scan_arg = arg ? arg : "";
2689 while ( *scan_arg > 0 && *scan_arg <= ' ' )
2690 scan_arg++;
2691
2692 if ( level || chunk_size )
2693 {
2694 if (level)
2695 *level = -1; // -1 = mark as 'not set'
2696 if (chunk_size)
2697 *chunk_size = 0;
2698
2699 const int len = strlen(scan_arg);
2700 if ( len < sizeof(argbuf) )
2701 {
2702 strcpy(argbuf,scan_arg);
2703 scan_arg = argbuf;
2704
2705 if (chunk_size)
2706 {
2707 char * found = strchr(argbuf,'@');
2708 if (found)
2709 {
2710 *found++ = 0;
2711 char * end;
2712 unsigned num = strtoul(found,&end,10);
2713 if (*end)
2714 {
2715 if (!silent)
2716 ERROR0(ERR_SYNTAX,
2717 "Unsigned number expected: --compression @%s\n",found);
2718 return -1;
2719 }
2720 *chunk_size = ( num ? num : WIA_DEF_CHUNK_FACTOR ) * WII_GROUP_SIZE;
2721 }
2722 }
2723 if (level)
2724 {
2725 char * found = strchr(argbuf,'.');
2726 if ( found && found[1] >= '0' && found[1] <= '9' && !found[2] )
2727 {
2728 *level = found[1] - '0';
2729 *found = 0;
2730 }
2731 }
2732
2733 if (!*argbuf)
2734 return WD_COMPR__DEFAULT;
2735 }
2736 }
2737
2738 const CommandTab_t * cmd = ScanCommand(0,scan_arg,tab);
2739 if (cmd)
2740 {
2741 wd_compression_t compr = cmd->id;
2742 u32 opt = cmd->opt;
2743
2744 if ( compr == (wd_compression_t)COMPR_MEM )
2745 {
2746 compr = WD_COMPR__DEFAULT;
2747 u32 memlimit = GetMemLimit();
2748 if (memlimit)
2749 {
2750 typedef struct tripel
2751 {
2752 wd_compression_t compr;
2753 int level;
2754 u32 csize;
2755 } tripel;
2756
2757 static const tripel tab[] =
2758 {
2759 { WD_COMPR_LZMA, 7, 50 * WIA_BASE_CHUNK_SIZE },
2760 { WD_COMPR_LZMA, 7, 40 * WIA_BASE_CHUNK_SIZE },
2761 { WD_COMPR_LZMA, 6, 50 * WIA_BASE_CHUNK_SIZE },
2762 { WD_COMPR_LZMA, 6, 40 * WIA_BASE_CHUNK_SIZE },
2763 { WD_COMPR_LZMA, 6, 30 * WIA_BASE_CHUNK_SIZE },
2764 { WD_COMPR_LZMA, 5, 50 * WIA_BASE_CHUNK_SIZE },
2765 { WD_COMPR_LZMA, 5, 40 * WIA_BASE_CHUNK_SIZE },
2766 { WD_COMPR_LZMA, 5, 30 * WIA_BASE_CHUNK_SIZE },
2767 { WD_COMPR_LZMA, 5, 20 * WIA_BASE_CHUNK_SIZE },
2768 { WD_COMPR_LZMA, 4, 50 * WIA_BASE_CHUNK_SIZE },
2769 { WD_COMPR_LZMA, 4, 40 * WIA_BASE_CHUNK_SIZE },
2770 { WD_COMPR_LZMA, 4, 30 * WIA_BASE_CHUNK_SIZE },
2771 { WD_COMPR_LZMA, 4, 20 * WIA_BASE_CHUNK_SIZE },
2772 { WD_COMPR_LZMA, 4, 10 * WIA_BASE_CHUNK_SIZE },
2773
2774 #ifndef NO_BZIP2
2775 { WD_COMPR_BZIP2, 9, 50 * WIA_BASE_CHUNK_SIZE },
2776 { WD_COMPR_BZIP2, 8, 40 * WIA_BASE_CHUNK_SIZE },
2777 { WD_COMPR_BZIP2, 7, 30 * WIA_BASE_CHUNK_SIZE },
2778 { WD_COMPR_BZIP2, 6, 25 * WIA_BASE_CHUNK_SIZE },
2779 { WD_COMPR_BZIP2, 5, 20 * WIA_BASE_CHUNK_SIZE },
2780 { WD_COMPR_BZIP2, 4, 15 * WIA_BASE_CHUNK_SIZE },
2781 { WD_COMPR_BZIP2, 3, 10 * WIA_BASE_CHUNK_SIZE },
2782 { WD_COMPR_BZIP2, 2, 5 * WIA_BASE_CHUNK_SIZE },
2783 { WD_COMPR_BZIP2, 1, 1 * WIA_BASE_CHUNK_SIZE },
2784 #endif
2785
2786 { WD_COMPR_LZMA, 4, 5 * WIA_BASE_CHUNK_SIZE },
2787 { WD_COMPR_LZMA, 3, 5 * WIA_BASE_CHUNK_SIZE },
2788 { WD_COMPR_LZMA, 2, 5 * WIA_BASE_CHUNK_SIZE },
2789 { WD_COMPR_LZMA, 1, 5 * WIA_BASE_CHUNK_SIZE },
2790 { WD_COMPR_LZMA, 1, 1 * WIA_BASE_CHUNK_SIZE },
2791
2792 { 0,0,0 } // end marker
2793 };
2794
2795 const tripel * p;
2796 for ( p = tab; p->level; p++ )
2797 {
2798 if ( CalcMemoryUsageWIA(p->compr,p->level,p->csize,true) <= memlimit )
2799 {
2800 compr = p->compr;
2801 opt = p->level << 8 | p->csize / WIA_BASE_CHUNK_SIZE;
2802 break;
2803 }
2804 }
2805 }
2806 }
2807
2808 if (opt)
2809 {
2810 if ( level && *level < 1 )
2811 *level = opt >> 8;
2812 if ( chunk_size && *chunk_size <= 1 )
2813 *chunk_size = ( opt & 0xff ) * WIA_BASE_CHUNK_SIZE;
2814 }
2815
2816 return compr;
2817 }
2818
2819 #if 0 // [[obsolete]]
2820 char * end;
2821 u32 val = strtoul(scan_arg,&end,10);
2822 #ifdef TEST
2823 if ( end > scan_arg && !*end )
2824 return val;
2825 #else
2826 if ( end > scan_arg && !*end && val < WD_COMPR__N )
2827 return val;
2828 #endif
2829 #endif
2830
2831 if (!silent)
2832 ERROR0(ERR_SYNTAX,"Illegal compression method: '%s'\n",scan_arg);
2833 return -1;
2834 }
2835
2836 ///////////////////////////////////////////////////////////////////////////////
2837
ScanCompression(ccp arg,bool silent,int * level,u32 * chunk_size)2838 wd_compression_t ScanCompression
2839 (
2840 ccp arg, // argument to scan
2841 bool silent, // don't print error message
2842 int * level, // not NULL: appendix '.digit' allowed
2843 // The level will be stored in '*level'
2844 u32 * chunk_size // not NULL: appendix '@size' allowed
2845 // The size will be stored in '*chunk_size'
2846 )
2847 {
2848 wd_compression_t compr = ScanCompression_helper(arg,silent,level,chunk_size);
2849 if (level)
2850 {
2851 if ( *level < 0 )
2852 *level = 0;
2853 else switch(compr)
2854 {
2855 case WD_COMPR__N:
2856 case WD_COMPR_NONE:
2857 case WD_COMPR_PURGE:
2858 *level = 0;
2859 break;
2860
2861 case WD_COMPR_BZIP2:
2862 #ifdef NO_BZIP2
2863 *level = 0;
2864 #else
2865 *level = CalcCompressionLevelBZIP2(*level);
2866 #endif
2867 break;
2868 case WD_COMPR_LZMA:
2869 case WD_COMPR_LZMA2:
2870 *level = CalcCompressionLevelLZMA(*level);
2871 break;
2872 }
2873 }
2874
2875 return compr;
2876 }
2877
2878 ///////////////////////////////////////////////////////////////////////////////
2879
ScanOptCompression(bool set_oft_wia,ccp arg)2880 int ScanOptCompression
2881 (
2882 bool set_oft_wia, // true: output_file_type := OFT_WIA
2883 ccp arg // argument to scan
2884 )
2885 {
2886 if (set_oft_wia)
2887 output_file_type = OFT_WIA;
2888 if (arg)
2889 {
2890 int new_level = 0;
2891 u32 new_chunk_size;
2892 const int new_compr = ScanCompression(arg,false,&new_level,&new_chunk_size);
2893 if ( new_compr == -1 )
2894 return 1;
2895 opt_compr_method = new_compr;
2896 opt_compr_level = new_level;
2897 opt_compr_chunk_size = new_chunk_size;
2898 }
2899 return 0;
2900 }
2901
2902 //
2903 ///////////////////////////////////////////////////////////////////////////////
2904 /////////////// scan mem option ///////////////
2905 ///////////////////////////////////////////////////////////////////////////////
2906
2907 u64 opt_mem = 0;
2908
2909 ///////////////////////////////////////////////////////////////////////////////
2910
ScanOptMem(ccp arg,bool print_err)2911 int ScanOptMem
2912 (
2913 ccp arg, // argument to scan
2914 bool print_err // true: print error messages
2915 )
2916 {
2917 u64 num;
2918 enumError err = ScanSizeOptU64
2919 ( &num, // u64 * num,
2920 arg, // ccp source,
2921 MiB, // u64 default_factor1,
2922 0, // int force_base,
2923 "mem", // ccp opt_name,
2924 0, // u64 min,
2925 0, // u64 max,
2926 0, // u32 multiple,
2927 0, // u32 pow2,
2928 print_err // bool print_err
2929 );
2930
2931 if (err)
2932 return 1;
2933
2934 opt_mem = num;
2935 return 0;
2936 }
2937
2938 ///////////////////////////////////////////////////////////////////////////////
2939
GetMemLimit()2940 u64 GetMemLimit()
2941 {
2942 static bool done = false;
2943 if ( !done && !opt_mem )
2944 {
2945 done = true;
2946
2947 char * env = getenv("WIT_MEM");
2948 if ( env && *env )
2949 ScanOptMem(env,false);
2950
2951 if (!opt_mem)
2952 {
2953 FILE * f = fopen("/proc/meminfo","r");
2954 if (f)
2955 {
2956 TRACE("SCAN /proc/meminfo\n");
2957 char buf[500];
2958 while (fgets(buf,sizeof(buf),f))
2959 {
2960 if (memcmp(buf,"MemTotal:",9))
2961 continue;
2962
2963 char * ptr;
2964 s64 num = strtoul(buf+9,&ptr,10);
2965 if (num)
2966 {
2967 while ( *ptr && *ptr <= ' ' )
2968 ptr++;
2969 switch (*ptr)
2970 {
2971 case 'k': case 'K': num *= KiB; break;
2972 case 'm': case 'M': num *= MiB; break;
2973 case 'g': case 'G': num *= GiB; break;
2974 }
2975 num -= 50 * MiB + num/5;
2976 opt_mem = num < 1 ? 1 : num;
2977 }
2978 break;
2979 }
2980 fclose(f);
2981 }
2982 }
2983 }
2984
2985 return opt_mem;
2986 }
2987
2988 //
2989 ///////////////////////////////////////////////////////////////////////////////
2990 /////////////// CommandTab_t ///////////////
2991 ///////////////////////////////////////////////////////////////////////////////
2992
ScanCommand(int * res_abbrev,ccp arg,const CommandTab_t * cmd_tab)2993 const CommandTab_t * ScanCommand
2994 (
2995 int * res_abbrev, // NULL or pointer to result 'abbrev_count'
2996 ccp arg, // argument to scan
2997 const CommandTab_t * cmd_tab // valid pointer to command table
2998 )
2999 {
3000 ASSERT(arg);
3001 char cmd_buf[COMMAND_NAME_MAX];
3002
3003 char *dest = cmd_buf;
3004 char *end = cmd_buf + sizeof(cmd_buf) - 1;
3005 while ( *arg && dest < end )
3006 *dest++ = toupper((int)*arg++);
3007 *dest = 0;
3008 const int cmd_len = dest - cmd_buf;
3009
3010 int abbrev_count = 0;
3011 const CommandTab_t *ct, *cmd_ct = 0, *abbrev_ct = 0;
3012 for ( ct = cmd_tab; ct->name1; ct++ )
3013 {
3014 if ( !strcmp(ct->name1,cmd_buf) || ct->name2 && !strcmp(ct->name2,cmd_buf) )
3015 {
3016 cmd_ct = ct;
3017 break;
3018 }
3019
3020 if ( *cmd_buf == '_' ) // no abbreviations for commands beginning with '_'
3021 continue;
3022
3023 if ( !memcmp(ct->name1,cmd_buf,cmd_len)
3024 || ct->name2 && !memcmp(ct->name2,cmd_buf,cmd_len) )
3025 {
3026 if ( !abbrev_ct || abbrev_ct->id != ct->id || abbrev_ct->opt != ct->opt )
3027 {
3028 abbrev_ct = ct;
3029 abbrev_count++;
3030 }
3031 }
3032 }
3033
3034 if (cmd_ct)
3035 abbrev_count = 0;
3036 else if ( abbrev_count == 1 )
3037 cmd_ct = abbrev_ct;
3038 else if (!abbrev_count)
3039 abbrev_count = -1;
3040
3041 if (res_abbrev)
3042 *res_abbrev = abbrev_count;
3043
3044 return cmd_ct;
3045 }
3046
3047 ///////////////////////////////////////////////////////////////////////////////
3048
ScanCommandList(ccp arg,const CommandTab_t * cmd_tab,CommandCallbackFunc func,bool allow_prefix,u32 max_number,s64 result)3049 s64 ScanCommandList
3050 (
3051 ccp arg, // argument to scan
3052 const CommandTab_t * cmd_tab, // valid pointer to command table
3053 CommandCallbackFunc func, // NULL or calculation function
3054 bool allow_prefix, // allow '-' | '+' | '=' as prefix
3055 u32 max_number, // allow numbers < 'max_number' (0=disabled)
3056 s64 result // start value for result
3057 )
3058 {
3059 ASSERT(arg);
3060
3061 char cmd_buf[COMMAND_NAME_MAX];
3062 char *end = cmd_buf + sizeof(cmd_buf) - 1;
3063
3064 for (;;)
3065 {
3066 while ( *arg > 0 && *arg <= ' ' || *arg == ',' )
3067 arg++;
3068
3069 if (!*arg)
3070 return result;
3071
3072 char *dest = cmd_buf;
3073 while ( *arg > ' ' && *arg != ',' &&
3074 ( *arg != '+' || dest == cmd_buf ) && dest < end )
3075 *dest++ = *arg++;
3076 *dest = 0;
3077 char prefix = 0;
3078 int abbrev_count;
3079 const CommandTab_t * cptr = ScanCommand(&abbrev_count,cmd_buf,cmd_tab);
3080 if ( !cptr && allow_prefix && cmd_buf[1]
3081 && ( *cmd_buf == '+' || *cmd_buf == '-' || *cmd_buf == '/' || *cmd_buf == '=' ))
3082 {
3083 prefix = *cmd_buf == '/' ? '-' : *cmd_buf;
3084 cptr = ScanCommand(&abbrev_count,cmd_buf+1,cmd_tab);
3085 }
3086
3087 CommandTab_t ct_num = { 0, cmd_buf, 0, 0 };
3088 if ( max_number && abbrev_count )
3089 {
3090 char * start = cmd_buf + (prefix!=0);
3091 ulong num = strtol(start,&dest,10);
3092 if ( num < max_number && dest > start && !*dest )
3093 {
3094 ct_num.id = num;
3095 cptr = &ct_num;
3096 }
3097 }
3098
3099 if ( !cptr || cptr->opt && prefix && prefix != '+' )
3100 return -1;
3101
3102
3103 if (func)
3104 {
3105 result = func(0,cmd_buf,cmd_tab,cptr,prefix,result);
3106 if ( result == -(s64)1 )
3107 return result;
3108 }
3109 else
3110 {
3111 switch (prefix)
3112 {
3113 case 0:
3114 case '+': result = result & ~cptr->opt | cptr->id; break;
3115 case '-': result &= ~cptr->id; break;
3116 case '=': result = cptr->id; break;
3117 }
3118 }
3119 }
3120 }
3121
3122 ///////////////////////////////////////////////////////////////////////////////
3123
ScanCommandListFunc(ccp arg,const CommandTab_t * cmd_tab,CommandCallbackFunc func,void * param,bool allow_prefix)3124 enumError ScanCommandListFunc
3125 (
3126 ccp arg, // argument to scan
3127 const CommandTab_t * cmd_tab, // valid pointer to command table
3128 CommandCallbackFunc func, // calculation function
3129 void * param, // used define parameter for 'func'
3130 bool allow_prefix // allow '-' | '+' | '=' as prefix
3131 )
3132 {
3133 ASSERT(arg);
3134 ASSERT(func);
3135
3136 char cmd_buf[COMMAND_NAME_MAX];
3137 char *end = cmd_buf + sizeof(cmd_buf) - 1;
3138
3139 for (;;)
3140 {
3141 while ( *arg > 0 && *arg <= ' ' || *arg == ',' )
3142 arg++;
3143
3144 if (!*arg)
3145 return ERR_OK;
3146
3147 char *dest = cmd_buf;
3148 while ( *arg > ' ' && *arg != ',' &&
3149 ( *arg != '+' || dest == cmd_buf ) && dest < end )
3150 *dest++ = *arg++;
3151 *dest = 0;
3152 char prefix = 0;
3153 int abbrev_count;
3154 const CommandTab_t * cptr = ScanCommand(&abbrev_count,cmd_buf,cmd_tab);
3155 if ( !cptr && allow_prefix && cmd_buf[1]
3156 && ( *cmd_buf == '+' || *cmd_buf == '-' || *cmd_buf == '/' || *cmd_buf == '=' ))
3157 {
3158 prefix = *cmd_buf == '/' ? '-' : *cmd_buf;
3159 cptr = ScanCommand(&abbrev_count,cmd_buf+1,cmd_tab);
3160 }
3161
3162 const enumError err = func(param,cmd_buf,cmd_tab,cptr,prefix,0);
3163 if (err)
3164 return err;
3165 }
3166 }
3167
3168 ///////////////////////////////////////////////////////////////////////////////
3169
ScanCommandListMaskHelper(void * param,ccp name,const CommandTab_t * cmd_tab,const CommandTab_t * cmd,char prefix,s64 result)3170 static s64 ScanCommandListMaskHelper
3171 (
3172 void * param, // NULL or user defined parameter
3173 ccp name, // normalized name of option
3174 const CommandTab_t * cmd_tab, // valid pointer to command table
3175 const CommandTab_t * cmd, // valid pointer to found command
3176 char prefix, // 0 | '-' | '+' | '='
3177 s64 result // current value of result
3178 )
3179 {
3180 return cmd->opt
3181 ? result & ~cmd->opt | cmd->id
3182 : cmd->id;
3183 }
3184
3185 //-----------------------------------------------------------------------------
3186
ScanCommandListMask(ccp arg,const CommandTab_t * cmd_tab)3187 s64 ScanCommandListMask
3188 (
3189 ccp arg, // argument to scan
3190 const CommandTab_t * cmd_tab // valid pointer to command table
3191 )
3192 {
3193 return ScanCommandList(arg,cmd_tab,ScanCommandListMaskHelper,false,0,0);
3194 }
3195
3196 ///////////////////////////////////////////////////////////////////////////////
3197
PrintCommandError(const CommandTab_t * cmd_tab,ccp cmd_arg,int cmd_stat,ccp object)3198 void PrintCommandError
3199 (
3200 const CommandTab_t * cmd_tab, // NULL or pointer to command table
3201 ccp cmd_arg, // analyzed command
3202 int cmd_stat, // status of ScanCommand()
3203 ccp object // NULL or object for error messages
3204 // default= 'command'
3205 )
3206 {
3207 DASSERT(cmd_arg);
3208
3209 if ( !object || !*object )
3210 object = "command";
3211
3212 if ( cmd_stat <= 0 )
3213 {
3214 ERROR0(ERR_SYNTAX,"Unknown %s: %s\n",object,cmd_arg);
3215 return;
3216 }
3217
3218 char buf[100], *dest = buf;
3219 if (cmd_tab)
3220 {
3221 int n = 0;
3222 ccp buf_end = buf + sizeof(buf) - 2;
3223 const int arg_len = strlen(cmd_arg);
3224 const CommandTab_t *ct;
3225 int last_id = -1;
3226
3227 for ( ct = cmd_tab; ct->name1 && dest < buf_end; ct++ )
3228 {
3229 if ( ct->id != last_id )
3230 {
3231 ccp ok = 0;
3232 if (!strncasecmp(cmd_arg,ct->name1,arg_len))
3233 ok = ct->name1;
3234 else if ( ct->name2 && !strncasecmp(cmd_arg,ct->name2,arg_len))
3235 ok = ct->name2;
3236 if (ok)
3237 {
3238 if (!n++)
3239 {
3240 *dest++ = ' ';
3241 *dest++ = '[';
3242 }
3243 else if ( n > 5 )
3244 {
3245 dest = StringCopyE(dest,buf_end,",...");
3246 break;
3247 }
3248 else
3249 *dest++ = ',';
3250 dest = StringCopyE(dest,buf_end,ok);
3251 last_id = ct->id;
3252 }
3253 }
3254 }
3255 if ( dest > buf+1 )
3256 *dest++ = ']';
3257 else
3258 dest = buf;
3259 }
3260 *dest = 0;
3261 ERROR0(ERR_SYNTAX,"%c%s abbreviation is ambiguous: %s%s\n",
3262 toupper((int)*object), object+1, cmd_arg, buf );
3263 }
3264
3265 //
3266 ///////////////////////////////////////////////////////////////////////////////
3267 /////////////// sort mode ///////////////
3268 ///////////////////////////////////////////////////////////////////////////////
3269
ScanSortMode(ccp arg)3270 SortMode ScanSortMode ( ccp arg )
3271 {
3272 static const CommandTab_t tab[] =
3273 {
3274 { SORT_NONE, "NONE", "-", SORT__MASK },
3275
3276 { SORT_ID, "ID", 0, SORT__MODE_MASK },
3277 { SORT_NAME, "NAME", "N", SORT__MODE_MASK },
3278 { SORT_TITLE, "TITLE", "T", SORT__MODE_MASK },
3279 { SORT_PATH, "PATH", "P", SORT__MODE_MASK },
3280 { SORT_NINTENDO,"NINTENDO", "NIN", SORT__MODE_MASK },
3281 { SORT_FILE, "FILE", "F", SORT__MODE_MASK },
3282 { SORT_SIZE, "SIZE", "SZ", SORT__MODE_MASK },
3283 { SORT_OFFSET, "OFFSET", "OF", SORT__MODE_MASK },
3284 { SORT_REGION, "REGION", "R", SORT__MODE_MASK },
3285 { SORT_WBFS, "WBFS", 0, SORT__MODE_MASK },
3286 { SORT_NPART, "NPART", 0, SORT__MODE_MASK },
3287 { SORT_FRAG, "FRAGMENTS", 0, SORT__MODE_MASK },
3288
3289 { SORT_ITIME, "ITIME", "IT", SORT__MODE_MASK },
3290 { SORT_MTIME, "MTIME", "MT", SORT__MODE_MASK },
3291 { SORT_CTIME, "CTIME", "CT", SORT__MODE_MASK },
3292 { SORT_ATIME, "ATIME", "AT", SORT__MODE_MASK },
3293 { SORT_TIME, "TIME", "TI", SORT__MODE_MASK },
3294 { SORT_TIME, "DATE", "D", SORT__MODE_MASK },
3295
3296 { SORT_DEFAULT, "DEFAULT", 0, SORT__MODE_MASK },
3297
3298 { 0, "ASCENDING", 0, SORT_REVERSE },
3299 { SORT_REVERSE, "DESCENDING", "REVERSE", SORT_REVERSE },
3300
3301 { 0,0,0,0 }
3302 };
3303
3304 const int stat = ScanCommandListMask(arg,tab);
3305 if ( stat >= 0 )
3306 return stat;
3307
3308 ERROR0(ERR_SYNTAX,"Illegal sort mode (option --sort): '%s'\n",arg);
3309 return SORT__ERROR;
3310 }
3311
3312 //-----------------------------------------------------------------------------
3313
ScanOptSort(ccp arg)3314 int ScanOptSort ( ccp arg )
3315 {
3316 const SortMode new_mode = ScanSortMode(arg);
3317 if ( new_mode == SORT__ERROR )
3318 return 1;
3319
3320 TRACE("SORT-MODE set: %d -> %d\n",sort_mode,new_mode);
3321 sort_mode = new_mode;
3322 return 0;
3323 }
3324
3325 //
3326 ///////////////////////////////////////////////////////////////////////////////
3327 /////////////// options show + unit ///////////////
3328 ///////////////////////////////////////////////////////////////////////////////
3329
ScanShowMode(ccp arg)3330 ShowMode ScanShowMode ( ccp arg )
3331 {
3332 enum
3333 {
3334 DEC_ALL = SHOW_F_DEC1 | SHOW_F_DEC,
3335 HEX_ALL = SHOW_F_HEX1 | SHOW_F_HEX,
3336 };
3337
3338 static const CommandTab_t tab[] =
3339 {
3340 { SHOW__NONE, "NONE", "-", SHOW__ALL },
3341 { SHOW__ALL, "ALL", 0, 0 },
3342
3343 { SHOW_INTRO, "INTRO", 0, 0 },
3344 { SHOW_FHEADER, "FHEADER", 0, 0 },
3345 { SHOW_SLOT, "SLOTS", 0, 0 },
3346 { SHOW_GEOMETRY, "GEOMETRY", 0, 0 },
3347 { SHOW_D_ID, "D-ID", "DID", 0 },
3348 { SHOW_P_ID, "P-IDS", "PIDS", 0 },
3349 { SHOW_P_TAB, "P-TAB", "PTAB", 0 },
3350 { SHOW_P_INFO, "P-INFO", "PINFO", 0 },
3351 { SHOW_P_MAP, "P-MAP", "PMAP", 0 },
3352 { SHOW_D_MAP, "D-MAP", "DMAP", 0 },
3353 { SHOW_W_MAP, "W-MAP", "WMAP", 0 },
3354 { SHOW_CERT, "CERTIFICATES", 0, 0 },
3355 { SHOW_TICKET, "TICKET", "TIK", 0 },
3356 { SHOW_TMD, "TMD", 0, 0 },
3357 { SHOW_USAGE, "USAGE", 0, 0 },
3358 { SHOW_FILES, "FILES", 0, 0 },
3359 { SHOW_PATCH, "PATCH", 0, 0 },
3360 { SHOW_RELOCATE, "RELOCATE", 0, 0 },
3361 { SHOW_PATH, "PATH", 0, 0 },
3362 { SHOW_CHECK, "CHECK", 0, 0 },
3363
3364 { SHOW_UNUSED, "UNUSED", 0, 0 },
3365 { SHOW_OFFSET, "OFFSET", 0, 0 },
3366 { SHOW_SIZE, "SIZE", 0, 0 },
3367
3368 { SHOW__ID, "IDS", 0, 0 },
3369 { SHOW__PART, "PART", 0, 0 },
3370 { SHOW__DISC, "DISC", 0, 0 },
3371 { SHOW__MAP, "MAP", 0, 0 },
3372
3373 { DEC_ALL, "DEC", 0, SHOW_F_HEX1 },
3374 { 0, "-DEC", 0, SHOW_F_DEC },
3375 { DEC_ALL, "=DEC", 0, HEX_ALL },
3376 { HEX_ALL, "HEX", 0, SHOW_F_DEC1 },
3377 { 0, "-HEX", 0, SHOW_F_HEX },
3378 { HEX_ALL, "=HEX", 0, DEC_ALL },
3379
3380 { SHOW_F_HEAD, "HEADER", 0, 0 },
3381 { SHOW_F_PRIMARY, "PRIMARY", "1", 0 },
3382
3383 { 0,0,0,0 }
3384 };
3385
3386 int stat = ScanCommandList(arg,tab,0,true,0,SHOW_F_HEAD);
3387 if ( stat != -1 )
3388 return stat;
3389
3390 ERROR0(ERR_SYNTAX,"Illegal show mode (option --show): '%s'\n",arg);
3391 return SHOW__ERROR;
3392 }
3393
3394 //-----------------------------------------------------------------------------
3395
ScanOptShow(ccp arg)3396 int ScanOptShow ( ccp arg )
3397 {
3398 const ShowMode new_mode = ScanShowMode(arg);
3399 if ( new_mode == SHOW__ERROR )
3400 return 1;
3401
3402 TRACE("SHOW-MODE set: %d -> %d\n",opt_show_mode,new_mode);
3403 opt_show_mode = new_mode;
3404 return 0;
3405 }
3406
3407 //-----------------------------------------------------------------------------
3408
ConvertShow2PFST(ShowMode show_mode,ShowMode def_mode)3409 int ConvertShow2PFST
3410 (
3411 ShowMode show_mode, // show mode
3412 ShowMode def_mode // default mode
3413 )
3414 {
3415 TRACE("ConvertShow2PFST(%x,%x)\n",show_mode,def_mode);
3416 const ShowMode MASK_OFF_SIZE = SHOW_OFFSET | SHOW_SIZE;
3417 if ( !(show_mode & MASK_OFF_SIZE) )
3418 show_mode |= def_mode & MASK_OFF_SIZE;
3419
3420 const ShowMode MASK_DEC_HEX = SHOW_F_DEC | SHOW_F_HEX;
3421 if ( !(show_mode & MASK_DEC_HEX) )
3422 show_mode |= def_mode & MASK_DEC_HEX;
3423
3424 noTRACE(" --> val=%x, off/size=%x, dec/hex=%x\n",
3425 show_mode, show_mode & MASK_OFF_SIZE, show_mode & MASK_DEC_HEX );
3426
3427 wd_pfst_t pfst = 0;
3428 if ( show_mode & SHOW_F_HEAD )
3429 pfst |= WD_PFST_HEADER;
3430 if ( show_mode & SHOW_UNUSED )
3431 pfst |= WD_PFST_UNUSED;
3432 if ( show_mode & SHOW_OFFSET )
3433 pfst |= WD_PFST_OFFSET;
3434 if ( show_mode & SHOW_SIZE )
3435 {
3436 switch ( show_mode & MASK_DEC_HEX )
3437 {
3438 case SHOW_F_DEC:
3439 pfst |= WD_PFST_SIZE_DEC;
3440 break;
3441
3442 case SHOW_F_HEX:
3443 pfst |= WD_PFST_SIZE_HEX;
3444 break;
3445
3446 default:
3447 pfst |= WD_PFST_SIZE_DEC|WD_PFST_SIZE_HEX; break;
3448 }
3449 }
3450
3451 TRACE(" --> PFST=%x\n",pfst);
3452 return pfst;
3453 }
3454
3455 ///////////////////////////////////////////////////////////////////////////////
3456 ///////////////////////////////////////////////////////////////////////////////
3457
ScanUnit(ccp arg)3458 wd_size_mode_t ScanUnit ( ccp arg )
3459 {
3460 enum
3461 {
3462 F_1000 = WD_SIZE_F_1000,
3463 F_1024 = WD_SIZE_F_1024,
3464 };
3465
3466 static const CommandTab_t tab[] =
3467 {
3468 { WD_SIZE_DEFAULT, "DEFAULT",0, WD_SIZE_M_MODE|WD_SIZE_M_BASE },
3469
3470 { WD_SIZE_F_1000, "1000", "10", WD_SIZE_M_BASE },
3471 { WD_SIZE_F_1024, "1024", "2", WD_SIZE_M_BASE },
3472
3473 { WD_SIZE_AUTO, "AUTO", 0, WD_SIZE_M_MODE },
3474 { WD_SIZE_BYTES, "BYTES",0, WD_SIZE_M_MODE },
3475 { WD_SIZE_K, "K", 0, WD_SIZE_M_MODE },
3476 { WD_SIZE_M, "M", 0, WD_SIZE_M_MODE },
3477 { WD_SIZE_G, "G", 0, WD_SIZE_M_MODE },
3478 { WD_SIZE_T, "T", 0, WD_SIZE_M_MODE },
3479 { WD_SIZE_P, "P", 0, WD_SIZE_M_MODE },
3480 { WD_SIZE_E, "E", 0, WD_SIZE_M_MODE },
3481
3482 { WD_SIZE_K | F_1000, "KB", 0, WD_SIZE_M_MODE|WD_SIZE_M_BASE },
3483 { WD_SIZE_M | F_1000, "MB", 0, WD_SIZE_M_MODE|WD_SIZE_M_BASE },
3484 { WD_SIZE_G | F_1000, "GB", 0, WD_SIZE_M_MODE|WD_SIZE_M_BASE },
3485 { WD_SIZE_T | F_1000, "TB", 0, WD_SIZE_M_MODE|WD_SIZE_M_BASE },
3486 { WD_SIZE_P | F_1000, "PB", 0, WD_SIZE_M_MODE|WD_SIZE_M_BASE },
3487 { WD_SIZE_E | F_1000, "EB", 0, WD_SIZE_M_MODE|WD_SIZE_M_BASE },
3488
3489 { WD_SIZE_K | F_1024, "KIB", 0, WD_SIZE_M_MODE|WD_SIZE_M_BASE },
3490 { WD_SIZE_M | F_1024, "MIB", 0, WD_SIZE_M_MODE|WD_SIZE_M_BASE },
3491 { WD_SIZE_G | F_1024, "GIB", 0, WD_SIZE_M_MODE|WD_SIZE_M_BASE },
3492 { WD_SIZE_T | F_1024, "TIB", 0, WD_SIZE_M_MODE|WD_SIZE_M_BASE },
3493 { WD_SIZE_P | F_1024, "PIB", 0, WD_SIZE_M_MODE|WD_SIZE_M_BASE },
3494 { WD_SIZE_E | F_1024, "EIB", 0, WD_SIZE_M_MODE|WD_SIZE_M_BASE },
3495
3496 { WD_SIZE_HD_SECT, "HDSS", "HSS", WD_SIZE_M_MODE },
3497 { WD_SIZE_WD_SECT, "WDSS", "WSS", WD_SIZE_M_MODE },
3498 { WD_SIZE_GC, "GAMECUBE","GC",WD_SIZE_M_MODE },
3499 { WD_SIZE_WII, "WII", 0, WD_SIZE_M_MODE },
3500
3501 { 0,0,0,0 }
3502 };
3503
3504 int stat = ScanCommandList(arg,tab,0,true,0,0);
3505 if ( stat != -1 )
3506 return stat;
3507
3508 ERROR0(ERR_SYNTAX,"Illegal unit mode (option --unit): '%s'\n",arg);
3509 return -1;
3510 }
3511
3512 //-----------------------------------------------------------------------------
3513
ScanOptUnit(ccp arg)3514 int ScanOptUnit ( ccp arg )
3515 {
3516 const wd_size_mode_t new_mode = ScanUnit(arg);
3517 if ( new_mode == -1 )
3518 return 1;
3519
3520 TRACE("OPT --unit set: %x -> %x\n",opt_unit,new_mode);
3521 opt_unit = new_mode;
3522 return 0;
3523 }
3524
3525 //
3526 ///////////////////////////////////////////////////////////////////////////////
3527 /////////////// repair mode ///////////////
3528 ///////////////////////////////////////////////////////////////////////////////
3529
ScanRepairMode(ccp arg)3530 RepairMode ScanRepairMode ( ccp arg )
3531 {
3532 static const CommandTab_t tab[] =
3533 {
3534 { REPAIR_NONE, "NONE", "-", REPAIR_ALL },
3535
3536 { REPAIR_FBT, "FBT", "F", 0 },
3537 { REPAIR_INODES, "INODES", "I", 0 },
3538 { REPAIR_DEFAULT, "STANDARD", "STD", 0 },
3539
3540 { REPAIR_RM_INVALID, "RM-INVALID", "RI", 0 },
3541 { REPAIR_RM_OVERLAP, "RM-OVERLAP", "RO", 0 },
3542 { REPAIR_RM_FREE, "RM-FREE", "RF", 0 },
3543 { REPAIR_RM_EMPTY, "RM-EMPTY", "RE", 0 },
3544 { REPAIR_RM_ALL, "RM-ALL", "RA", 0 },
3545
3546 { REPAIR_ALL, "ALL", "*", 0 },
3547 { 0,0,0,0 }
3548 };
3549
3550 int stat = ScanCommandList(arg,tab,0,true,0,0);
3551 if ( stat != -1 )
3552 return stat;
3553
3554 ERROR0(ERR_SYNTAX,"Illegal repair mode (option --repair): '%s'\n",arg);
3555 return REPAIR__ERROR;
3556 }
3557
3558 //
3559 ///////////////////////////////////////////////////////////////////////////////
3560 /////////////// IdField_t ///////////////
3561 ///////////////////////////////////////////////////////////////////////////////
3562
InitializeIdField(IdField_t * idf)3563 void InitializeIdField ( IdField_t * idf )
3564 {
3565 ASSERT(idf);
3566 memset(idf,0,sizeof(*idf));
3567 }
3568
3569 ///////////////////////////////////////////////////////////////////////////////
3570
ResetIdField(IdField_t * idf)3571 void ResetIdField ( IdField_t * idf )
3572 {
3573 ASSERT(idf);
3574 if ( idf && idf->field )
3575 {
3576 IdItem_t **ptr = idf->field, **end;
3577 for ( end = ptr + idf->used; ptr < end; ptr++ )
3578 FREE(*ptr);
3579 FREE(idf->field);
3580 }
3581 InitializeIdField(idf);
3582 }
3583
3584 ///////////////////////////////////////////////////////////////////////////////
3585
FindIdFieldHelper(IdField_t * idf,bool * p_found,ccp key)3586 static uint FindIdFieldHelper ( IdField_t * idf, bool * p_found, ccp key )
3587 {
3588 ASSERT(idf);
3589
3590 int beg = 0;
3591 if ( idf && key )
3592 {
3593 int end = idf->used - 1;
3594 while ( beg <= end )
3595 {
3596 uint idx = (beg+end)/2;
3597 int stat = strcmp(key,idf->field[idx]->arg);
3598 if ( stat < 0 )
3599 end = idx - 1 ;
3600 else if ( stat > 0 )
3601 beg = idx + 1;
3602 else
3603 {
3604 TRACE("FindIdFieldHelper(%s) FOUND=%d/%d/%d\n",
3605 key, idx, idf->used, idf->size );
3606 if (p_found)
3607 *p_found = true;
3608 return idx;
3609 }
3610 }
3611 }
3612
3613 TRACE("FindIdFieldHelper(%s) failed=%d/%d/%d\n",
3614 key, beg, idf->used, idf->size );
3615
3616 if (p_found)
3617 *p_found = false;
3618 return beg;
3619 }
3620
3621 ///////////////////////////////////////////////////////////////////////////////
3622
InsertIdFieldHelper(IdField_t * idf,int idx)3623 static IdItem_t ** InsertIdFieldHelper ( IdField_t * idf, int idx )
3624 {
3625 DASSERT(idf);
3626 DASSERT( idf->used <= idf->size );
3627 if ( idf->used == idf->size )
3628 {
3629 idf->size += 0x100;
3630 idf->field = REALLOC(idf->field,idf->size*sizeof(*idf->field));
3631 }
3632 DASSERT( idx <= idf->used );
3633 IdItem_t ** dest = idf->field + idx;
3634 memmove(dest+1,dest,(idf->used-idx)*sizeof(ccp));
3635 idf->used++;
3636 return dest;
3637 }
3638
3639 ///////////////////////////////////////////////////////////////////////////////
3640
FindIdField(IdField_t * idf,ccp key)3641 const IdItem_t * FindIdField ( IdField_t * idf, ccp key )
3642 {
3643 bool found;
3644 int idx = FindIdFieldHelper(idf,&found,key);
3645 return found ? idf->field[idx] : 0;
3646 }
3647
3648 ///////////////////////////////////////////////////////////////////////////////
3649
InsertIdField(IdField_t * idf,void * id6,char flag,time_t mtime,ccp key)3650 bool InsertIdField ( IdField_t * idf, void * id6, char flag, time_t mtime, ccp key )
3651 {
3652 bool found;
3653 int idx = FindIdFieldHelper(idf,&found,key);
3654 IdItem_t ** dest;
3655 if (found)
3656 {
3657 DASSERT( idx < idf->used );
3658 dest = idf->field + idx;
3659 FREE((char*)*dest);
3660 }
3661 else
3662 dest = InsertIdFieldHelper(idf,idx);
3663
3664 const int key_len = key ? strlen(key) : 0;
3665 const int item_size = sizeof(IdItem_t) + key_len + 1;
3666 IdItem_t * item = MALLOC(item_size);
3667 *dest = item;
3668
3669 memset(item,0,item_size);
3670 if (id6)
3671 strncpy(item->id6,id6,6);
3672 item->flag = flag;
3673 item->mtime = mtime;
3674 if (key)
3675 memcpy(item->arg,key,key_len);
3676 return !found;
3677 }
3678
3679 ///////////////////////////////////////////////////////////////////////////////
3680
RemoveIdField(IdField_t * idf,ccp key)3681 bool RemoveIdField ( IdField_t * idf, ccp key )
3682 {
3683 bool found;
3684 uint idx = FindIdFieldHelper(idf,&found,key);
3685 if (found)
3686 {
3687 idf->used--;
3688 ASSERT( idx <= idf->used );
3689 IdItem_t ** dest = idf->field + idx;
3690 FREE(*dest);
3691 memmove(dest,dest+1,(idf->used-idx)*sizeof(ccp));
3692 }
3693 return found;
3694 }
3695
3696 ///////////////////////////////////////////////////////////////////////////////
3697
DumpIdField(FILE * f,int indent,const IdField_t * idf)3698 void DumpIdField ( FILE *f, int indent, const IdField_t * idf )
3699 {
3700 DASSERT(f);
3701 DASSERT(idf);
3702 indent = NormalizeIndent(indent);
3703
3704 int i;
3705 for ( i = 0; i < idf->used; i++ )
3706 {
3707 const IdItem_t * item = idf->field[i];
3708 char timbuf[40];
3709 if (item->mtime)
3710 {
3711 struct tm * tm = localtime(&item->mtime);
3712 strftime(timbuf,sizeof(timbuf),"%F %T",tm);
3713 }
3714 else
3715 strncpy(timbuf," - - ",sizeof(timbuf));
3716
3717 fprintf(f,"%*s%-6s %02x %s %s\n",
3718 indent, "", item->id6, item->flag, timbuf, item->arg );
3719 }
3720 }
3721
3722 //
3723 ///////////////////////////////////////////////////////////////////////////////
3724 /////////////// StringField_t ///////////////
3725 ///////////////////////////////////////////////////////////////////////////////
3726
InitializeStringField(StringField_t * sf)3727 void InitializeStringField ( StringField_t * sf )
3728 {
3729 ASSERT(sf);
3730 memset(sf,0,sizeof(*sf));
3731 }
3732
3733 ///////////////////////////////////////////////////////////////////////////////
3734
ResetStringField(StringField_t * sf)3735 void ResetStringField ( StringField_t * sf )
3736 {
3737 ASSERT(sf);
3738 if ( sf && sf->used > 0 )
3739 {
3740 ASSERT(sf->field);
3741 ccp *ptr = sf->field, *end;
3742 for ( end = ptr + sf->used; ptr < end; ptr++ )
3743 FREE((char*)*ptr);
3744 FREE(sf->field);
3745 }
3746 InitializeStringField(sf);
3747 }
3748
3749 ///////////////////////////////////////////////////////////////////////////////
3750
FindStringField(StringField_t * sf,ccp key)3751 ccp FindStringField ( StringField_t * sf, ccp key )
3752 {
3753 bool found;
3754 int idx = FindStringFieldHelper(sf,&found,key);
3755 return found ? sf->field[idx] : 0;
3756 }
3757
3758 ///////////////////////////////////////////////////////////////////////////////
3759
InsertStringFieldHelper(StringField_t * sf,int idx)3760 static ccp * InsertStringFieldHelper ( StringField_t * sf, int idx )
3761 {
3762 DASSERT(sf);
3763 DASSERT( sf->used <= sf->size );
3764 if ( sf->used == sf->size )
3765 {
3766 sf->size += 0x100;
3767 sf->field = REALLOC(sf->field,sf->size*sizeof(*sf->field));
3768 }
3769 DASSERT( idx <= sf->used );
3770 ccp * dest = sf->field + idx;
3771 memmove(dest+1,dest,(sf->used-idx)*sizeof(ccp));
3772 sf->used++;
3773 return dest;
3774 }
3775
3776 ///////////////////////////////////////////////////////////////////////////////
3777
InsertStringField(StringField_t * sf,ccp key,bool move_key)3778 bool InsertStringField ( StringField_t * sf, ccp key, bool move_key )
3779 {
3780 if (!key)
3781 return 0;
3782
3783 bool found;
3784 int idx = FindStringFieldHelper(sf,&found,key);
3785 if (found)
3786 {
3787 if (move_key)
3788 FREE((char*)key);
3789 }
3790 else
3791 {
3792 ccp * dest = InsertStringFieldHelper(sf,idx);
3793 *dest = move_key ? key : STRDUP(key);
3794 }
3795
3796 return !found;
3797 }
3798
3799 ///////////////////////////////////////////////////////////////////////////////
3800
InsertStringID6(StringField_t * sf,void * id6,char flag,ccp arg)3801 IdItem_t * InsertStringID6 ( StringField_t * sf, void * id6, char flag, ccp arg )
3802 {
3803 if (!id6)
3804 return 0;
3805
3806 bool found;
3807 int idx = FindStringFieldHelper(sf,&found,id6);
3808 ccp * dest;
3809 if (found)
3810 {
3811 DASSERT( idx < sf->used );
3812 dest = sf->field + idx;
3813 FREE((char*)*dest);
3814 }
3815 else
3816 dest = InsertStringFieldHelper(sf,idx);
3817
3818 const int arg_len = arg ? strlen(arg) : 0;
3819 const int item_size = sizeof(IdItem_t) + arg_len + 1;
3820 IdItem_t * item = MALLOC(item_size);
3821
3822 *dest = (ccp)item;
3823 memset(item,0,item_size);
3824 strncpy(item->id6,id6,6);
3825 item->flag = flag;
3826 if (arg)
3827 memcpy(item->arg,arg,arg_len);
3828 return item;
3829 }
3830
3831 ///////////////////////////////////////////////////////////////////////////////
3832
RemoveStringField(StringField_t * sf,ccp key)3833 bool RemoveStringField ( StringField_t * sf, ccp key )
3834 {
3835 bool found;
3836 uint idx = FindStringFieldHelper(sf,&found,key);
3837 if (found)
3838 {
3839 sf->used--;
3840 ASSERT( idx <= sf->used );
3841 ccp * dest = sf->field + idx;
3842 FREE((char*)dest);
3843 memmove(dest,dest+1,(sf->used-idx)*sizeof(ccp));
3844 }
3845 return found;
3846 }
3847
3848 ///////////////////////////////////////////////////////////////////////////////
3849
AppendStringField(StringField_t * sf,ccp key,bool move_key)3850 void AppendStringField ( StringField_t * sf, ccp key, bool move_key )
3851 {
3852 if (key)
3853 {
3854 ASSERT( sf->used <= sf->size );
3855 if ( sf->used == sf->size )
3856 {
3857 sf->size += 0x100;
3858 sf->field = REALLOC(sf->field,sf->size*sizeof(*sf->field));
3859 }
3860 TRACE("AppendStringField(%s,%d) %d/%d\n",key,move_key,sf->used,sf->size);
3861 ccp * dest = sf->field + sf->used++;
3862 *dest = move_key ? key : STRDUP(key);
3863 }
3864 }
3865
3866 ///////////////////////////////////////////////////////////////////////////////
3867
FindStringFieldHelper(StringField_t * sf,bool * p_found,ccp key)3868 uint FindStringFieldHelper ( StringField_t * sf, bool * p_found, ccp key )
3869 {
3870 ASSERT(sf);
3871
3872 int beg = 0;
3873 if ( sf && key )
3874 {
3875 int end = sf->used - 1;
3876 while ( beg <= end )
3877 {
3878 uint idx = (beg+end)/2;
3879 int stat = strcmp(key,sf->field[idx]);
3880 if ( stat < 0 )
3881 end = idx - 1 ;
3882 else if ( stat > 0 )
3883 beg = idx + 1;
3884 else
3885 {
3886 TRACE("FindStringFieldHelper(%s) FOUND=%d/%d/%d\n",
3887 key, idx, sf->used, sf->size );
3888 if (p_found)
3889 *p_found = true;
3890 return idx;
3891 }
3892 }
3893 }
3894
3895 TRACE("FindStringFieldHelper(%s) failed=%d/%d/%d\n",
3896 key, beg, sf->used, sf->size );
3897
3898 if (p_found)
3899 *p_found = false;
3900 return beg;
3901 }
3902
3903 ///////////////////////////////////////////////////////////////////////////////
3904
LoadStringField(StringField_t * sf,bool keep_order,ccp filename,bool silent)3905 enumError LoadStringField
3906 ( StringField_t * sf, bool keep_order, ccp filename, bool silent )
3907 {
3908 ASSERT(sf);
3909 ASSERT(filename);
3910 ASSERT(*filename);
3911
3912 TRACE("LoadStringField(%p,%d,%s,%d)\n",sf,keep_order,filename,silent);
3913
3914 FILE * f = fopen(filename,"rb");
3915 if (!f)
3916 {
3917 if (!silent)
3918 ERROR1(ERR_CANT_OPEN,"Can't open file: %s\n",filename);
3919 return ERR_CANT_OPEN;
3920 }
3921
3922 while (fgets(iobuf,sizeof(iobuf)-1,f))
3923 {
3924 char * ptr = iobuf;
3925 while (*ptr)
3926 ptr++;
3927 if ( ptr > iobuf && ptr[-1] == '\n' )
3928 {
3929 ptr--;
3930 if ( ptr > iobuf && ptr[-1] == '\r' )
3931 ptr--;
3932 }
3933
3934 if ( ptr > iobuf )
3935 {
3936 *ptr++ = 0;
3937 const size_t len = ptr-iobuf;
3938 ptr = MALLOC(len);
3939 memcpy(ptr,iobuf,len);
3940 if (keep_order)
3941 AppendStringField(sf,ptr,true);
3942 else
3943 InsertStringField(sf,ptr,true);
3944 }
3945 }
3946
3947 fclose(f);
3948 return ERR_OK;
3949 }
3950
3951
3952 ///////////////////////////////////////////////////////////////////////////////
3953
SaveStringField(StringField_t * sf,ccp filename,bool rm_if_empty)3954 enumError SaveStringField
3955 ( StringField_t * sf, ccp filename, bool rm_if_empty )
3956 {
3957 ASSERT(sf);
3958 ASSERT(filename);
3959 ASSERT(*filename);
3960
3961 TRACE("SaveStringField(%p,%s,%d)\n",sf,filename,rm_if_empty);
3962
3963 if ( !sf->used && rm_if_empty )
3964 {
3965 unlink(filename);
3966 return ERR_OK;
3967 }
3968 FILE * f = fopen(filename,"wb");
3969 if (!f)
3970 return ERROR1(ERR_CANT_CREATE,"Can't create file: %s\n",filename);
3971
3972 ccp *ptr = sf->field, *end;
3973 for ( end = ptr + sf->used; ptr < end; ptr++ )
3974 fprintf(f,"%s\n",*ptr);
3975 fclose(f);
3976 return ERR_OK;
3977 }
3978
3979 //
3980 ///////////////////////////////////////////////////////////////////////////////
3981 /////////////// ParamField_t ///////////////
3982 ///////////////////////////////////////////////////////////////////////////////
3983
InitializeParamField(ParamField_t * pf,ParamFieldType_t pft)3984 void InitializeParamField ( ParamField_t * pf, ParamFieldType_t pft )
3985 {
3986 DASSERT(pf);
3987 memset(pf,0,sizeof(*pf));
3988 pf->pft = pft;
3989 }
3990
3991 ///////////////////////////////////////////////////////////////////////////////
3992
ResetParamField(ParamField_t * pf)3993 void ResetParamField ( ParamField_t * pf )
3994 {
3995 ASSERT(pf);
3996 if ( pf && pf->used > 0 )
3997 {
3998 ASSERT(pf->list);
3999 ParamFieldItem_t *ptr = pf->list, *end;
4000 for ( end = ptr + pf->used; ptr < end; ptr++ )
4001 FreeString(ptr->key);
4002 FREE(pf->list);
4003 }
4004 InitializeParamField(pf,pf->pft);
4005 }
4006
4007 ///////////////////////////////////////////////////////////////////////////////
4008
MoveParamField(ParamField_t * dest,ParamField_t * src)4009 void MoveParamField ( ParamField_t * dest, ParamField_t * src )
4010 {
4011 DASSERT(src);
4012 DASSERT(dest);
4013 if ( src != dest )
4014 {
4015 ResetParamField(dest);
4016 dest->list = src->list;
4017 dest->used = src->used;
4018 dest->size = src->size;
4019 dest->pft = src->pft;
4020 InitializeParamField(src,src->pft);
4021 }
4022 }
4023
4024 ///////////////////////////////////////////////////////////////////////////////
4025
FindParamFieldHelper(const ParamField_t * pf,bool * p_found,ccp key)4026 static uint FindParamFieldHelper ( const ParamField_t * pf, bool * p_found, ccp key )
4027 {
4028 ASSERT(pf);
4029
4030 int beg = 0;
4031 if ( pf && key )
4032 {
4033 int end = pf->used - 1;
4034 while ( beg <= end )
4035 {
4036 uint idx = (beg+end)/2;
4037 int stat = strcmp(key,pf->list[idx].key);
4038 if ( stat < 0 )
4039 end = idx - 1 ;
4040 else if ( stat > 0 )
4041 beg = idx + 1;
4042 else
4043 {
4044 TRACE("FindParamFieldHelper(%s) FOUND=%d/%d/%d\n",
4045 key, idx, pf->used, pf->size );
4046 if (p_found)
4047 *p_found = true;
4048 return idx;
4049 }
4050 }
4051 }
4052
4053 TRACE("FindParamFieldHelper(%s) failed=%d/%d/%d\n",
4054 key, beg, pf->used, pf->size );
4055
4056 if (p_found)
4057 *p_found = false;
4058 return beg;
4059 }
4060
4061 ///////////////////////////////////////////////////////////////////////////////
4062
FindParamFieldIndex(const ParamField_t * pf,ccp key,int not_found_value)4063 int FindParamFieldIndex ( const ParamField_t * pf, ccp key, int not_found_value )
4064 {
4065 bool found;
4066 const int idx = FindParamFieldHelper(pf,&found,key);
4067 return found ? idx : not_found_value;
4068 }
4069
4070 ///////////////////////////////////////////////////////////////////////////////
4071
FindParamField(const ParamField_t * pf,ccp key)4072 ParamFieldItem_t * FindParamField ( const ParamField_t * pf, ccp key )
4073 {
4074 bool found;
4075 const int idx = FindParamFieldHelper(pf,&found,key);
4076 return found ? pf->list + idx : 0;
4077 }
4078
4079 ///////////////////////////////////////////////////////////////////////////////
4080
InsertParamFieldHelper(ParamField_t * pf,int idx)4081 static ParamFieldItem_t * InsertParamFieldHelper ( ParamField_t * pf, int idx )
4082 {
4083 DASSERT(pf);
4084 DASSERT( pf->used <= pf->size );
4085 noPRINT("+FF: %u/%u/%u\n",idx,pf->used,pf->size);
4086 if ( pf->used == pf->size )
4087 {
4088 pf->size += 0x100;
4089 pf->list = REALLOC(pf->list,pf->size*sizeof(*pf->list));
4090 }
4091 DASSERT( idx <= pf->used );
4092 ParamFieldItem_t * dest = pf->list + idx;
4093 memmove(dest+1,dest,(pf->used-idx)*sizeof(*dest));
4094 pf->used++;
4095 memset(dest,0,sizeof(*dest));
4096 return dest;
4097 }
4098
4099 ///////////////////////////////////////////////////////////////////////////////
4100
RemoveParamField(ParamField_t * pf,ccp key)4101 bool RemoveParamField ( ParamField_t * pf, ccp key )
4102 {
4103 bool found;
4104 uint idx = FindParamFieldHelper(pf,&found,key);
4105 if (found)
4106 {
4107 pf->used--;
4108 ASSERT( idx <= pf->used );
4109 ParamFieldItem_t * dest = pf->list + idx;
4110 FREE((char*)dest);
4111 memmove(dest,dest+1,(pf->used-idx)*sizeof(*dest));
4112 }
4113 return found;
4114 }
4115
4116 ///////////////////////////////////////////////////////////////////////////////
4117
InsertParamField(ParamField_t * pf,ccp key,uint num)4118 ParamFieldItem_t * InsertParamField
4119 (
4120 ParamField_t * pf, // valid param field
4121 ccp key, // key to insert
4122 uint num // value
4123 )
4124 {
4125 if (!key)
4126 return 0;
4127
4128 bool my_found;
4129 const int idx = FindParamFieldHelper(pf,&my_found,key);
4130
4131 ParamFieldItem_t * item;
4132 if (my_found)
4133 item = pf->list + idx;
4134 else
4135 {
4136 item = InsertParamFieldHelper(pf,idx);
4137 item->key = STRDUP(key);
4138 }
4139
4140 item->count++;
4141
4142 if ( pf->pft == PFT_ALIGN )
4143 item->num |= num;
4144 else
4145 item->num = num;
4146 return item;
4147 }
4148
4149 ///////////////////////////////////////////////////////////////////////////////
4150
LoadParamField(ParamField_t * pf,ParamFieldType_t init_pf,ccp filename,bool silent)4151 enumError LoadParamField
4152 (
4153 ParamField_t * pf, // param field
4154 ParamFieldType_t init_pf, // >0: initialize 'pf' with entered type
4155 ccp filename, // filename of source file
4156 bool silent // true: don't print open/read errors
4157 )
4158 {
4159 ASSERT(pf);
4160 ASSERT(filename);
4161 ASSERT(*filename);
4162
4163 TRACE("LoadParamField(%p,%d,%s,%d)\n",pf,init_pf,filename,silent);
4164
4165 if (init_pf)
4166 InitializeParamField(pf,init_pf);
4167
4168 FILE * f = fopen(filename,"rb");
4169 if (!f)
4170 {
4171 if (!silent)
4172 ERROR1(ERR_CANT_OPEN,"Can't open file: %s\n",filename);
4173 return ERR_CANT_OPEN;
4174 }
4175
4176 while (fgets(iobuf,sizeof(iobuf)-1,f))
4177 {
4178 char *ptr = iobuf;
4179
4180 u32 stat, num;
4181 ptr = ScanNumU32(ptr+1,&stat,&num,0,~(u32)0);
4182 if (!stat)
4183 continue;
4184
4185 while ( *ptr > 0 && *ptr <= ' ' )
4186 ptr++;
4187 if ( *ptr != '=' )
4188 continue;
4189 ptr++;
4190
4191 while ( *ptr > 0 && *ptr <= ' ' )
4192 ptr++;
4193 char *key = ptr;
4194
4195 while (*ptr)
4196 ptr++;
4197 while ( ptr > key && (uchar)ptr[-1] <= ' ' )
4198 ptr--;
4199
4200 if ( key < ptr )
4201 {
4202 *ptr = 0;
4203 InsertParamField(pf,key,num);
4204 }
4205 }
4206
4207 fclose(f);
4208 return ERR_OK;
4209 }
4210
4211 ///////////////////////////////////////////////////////////////////////////////
4212
SaveParamField(ParamField_t * pf,ccp filename,bool rm_if_empty)4213 enumError SaveParamField
4214 (
4215 ParamField_t * pf, // valid param field
4216 ccp filename, // filename of dest file
4217 bool rm_if_empty // true: rm dest file if 'pf' is empty
4218 )
4219 {
4220 ASSERT(pf);
4221 ASSERT(filename);
4222 ASSERT(*filename);
4223
4224 TRACE("SaveParamField(%p,%s,%d)\n",pf,filename,rm_if_empty);
4225
4226 if ( !pf->used && rm_if_empty )
4227 {
4228 unlink(filename);
4229 return ERR_OK;
4230 }
4231
4232 FILE * f = fopen(filename,"wb");
4233 if (!f)
4234 return ERROR1(ERR_CANT_CREATE,"Can't create file: %s\n",filename);
4235
4236 enumError err = WriteParamField(f,filename,pf,0,0,0);
4237 fclose(f);
4238 return err;
4239 }
4240
4241 ///////////////////////////////////////////////////////////////////////////////
4242
WriteParamField(FILE * f,ccp filename,ParamField_t * pf,ccp line_prefix,ccp key_prefix,ccp eol)4243 enumError WriteParamField
4244 (
4245 FILE * f, // open destination file
4246 ccp filename, // NULL or filename (needed on write error)
4247 ParamField_t * pf, // valid param field
4248 ccp line_prefix, // not NULL: insert prefix before each line
4249 ccp key_prefix, // not NULL: insert prefix before each key
4250 ccp eol // end of line text (if NULL: use LF)
4251 )
4252 {
4253 if (!key_prefix)
4254 key_prefix = "";
4255 if (!eol)
4256 eol = "\n";
4257
4258 uint max_num = 0;
4259 ParamFieldItem_t *ptr, *end = pf->list + pf->used;
4260 for ( ptr = pf->list; ptr < end; ptr++ )
4261 {
4262 if ( ptr->num && pf->pft == PFT_ALIGN )
4263 {
4264 uint num = 1;
4265 while (!( ptr->num & num ))
4266 num <<= 1;
4267 ptr->num = num;
4268 }
4269
4270 if ( max_num < ptr->num )
4271 max_num = ptr->num;
4272 }
4273
4274 char buf[20];
4275 if ( pf->pft == PFT_ALIGN )
4276 {
4277 uint num_fw = snprintf(buf,sizeof(buf),"%#x",max_num);
4278 for ( ptr = pf->list; ptr < end; ptr++ )
4279 fprintf(f," %#*x = %s\n", num_fw, ptr->num, ptr->key );
4280 }
4281 else
4282 {
4283 uint num_fw = snprintf(buf,sizeof(buf),"%u",max_num);
4284 for ( ptr = pf->list; ptr < end; ptr++ )
4285 fprintf(f," %*u = %s\n", num_fw, ptr->num, ptr->key );
4286 }
4287 return ERR_OK;
4288 }
4289
4290 //
4291 ///////////////////////////////////////////////////////////////////////////////
4292 /////////////// string lists ///////////////
4293 ///////////////////////////////////////////////////////////////////////////////
4294
AtFileHelper(ccp arg,int mode,int mode_expand,int (* func)(ccp arg,int mode))4295 int AtFileHelper
4296 (
4297 ccp arg,
4298 int mode,
4299 int mode_expand,
4300 int (*func) ( ccp arg, int mode )
4301 )
4302 {
4303 if ( !arg || !*arg || !func )
4304 return 0;
4305
4306 TRACE("AtFileHelper(%s,%x,%x)\n",arg,mode,mode_expand);
4307 if ( *arg != '@' )
4308 return func(arg,mode);
4309
4310 FILE * f;
4311 char buf[PATH_MAX];
4312 const bool use_stdin = arg[1] == '-' && !arg[2];
4313
4314 if (use_stdin)
4315 f = stdin;
4316 else
4317 {
4318 #ifdef __CYGWIN__
4319 char buf[PATH_MAX];
4320 NormalizeFilenameCygwin(buf,sizeof(buf),arg+1);
4321 f = fopen(buf,"r");
4322 #else
4323 f = fopen(arg+1,"r");
4324 #endif
4325 if (!f)
4326 return func(arg,mode);
4327 }
4328
4329 ASSERT(f);
4330
4331 u32 max_stat = 0;
4332 while (fgets(buf,sizeof(buf)-1,f))
4333 {
4334 char * ptr = buf;
4335 while (*ptr)
4336 ptr++;
4337 if ( ptr > buf && ptr[-1] == '\n' )
4338 ptr--;
4339 if ( ptr > buf && ptr[-1] == '\r' )
4340 ptr--;
4341 *ptr = 0;
4342 const u32 stat = func(buf,mode_expand);
4343 if ( max_stat < stat )
4344 max_stat = stat;
4345 }
4346 fclose(f);
4347 return max_stat;
4348 }
4349
4350 ///////////////////////////////////////////////////////////////////////////////
4351
4352 uint n_param = 0, id6_param_found = 0;
4353 ParamList_t * first_param = 0;
4354 ParamList_t ** append_param = &first_param;
4355
4356 ///////////////////////////////////////////////////////////////////////////////
4357
GetPoolParam()4358 static ParamList_t* GetPoolParam()
4359 {
4360 static ParamList_t * pool = 0;
4361 static int n_pool = 0;
4362
4363 if (!n_pool)
4364 {
4365 const int alloc_count = 100;
4366 pool = (ParamList_t*) CALLOC(alloc_count,sizeof(ParamList_t));
4367 n_pool = alloc_count;
4368 }
4369
4370 n_pool--;
4371 return pool++;
4372 }
4373
4374 ///////////////////////////////////////////////////////////////////////////////
4375
AppendParam(ccp arg,int is_temp)4376 ParamList_t * AppendParam ( ccp arg, int is_temp )
4377 {
4378 if ( !arg || !*arg )
4379 return 0;
4380
4381 TRACE("ARG#%02d: %s\n",n_param,arg);
4382
4383 ParamList_t * param = GetPoolParam();
4384 if (is_temp)
4385 param->arg = STRDUP(arg);
4386 else
4387 param->arg = (char*)arg;
4388
4389 while (*append_param)
4390 append_param = &(*append_param)->next;
4391
4392 noTRACE("INS: A=%p->%p P=%p &N=%p->%p\n",
4393 append_param, *append_param,
4394 param, ¶m->next, param->next );
4395 *append_param = param;
4396 append_param = ¶m->next;
4397 noTRACE(" => A=%p->%p\n", append_param, *append_param );
4398 n_param++;
4399
4400 return param;
4401 }
4402
4403 ///////////////////////////////////////////////////////////////////////////////
4404
AddParam(ccp arg,int is_temp)4405 int AddParam ( ccp arg, int is_temp )
4406 {
4407 return AppendParam(arg,is_temp) ? 0 : 1;
4408 }
4409
4410 ///////////////////////////////////////////////////////////////////////////////
4411
AtExpandParam(ParamList_t ** p_param)4412 void AtExpandParam ( ParamList_t ** p_param )
4413 {
4414 if ( !p_param || !*p_param )
4415 return;
4416
4417 ParamList_t * param = *p_param;
4418 if ( param->is_expanded || !param->arg || *param->arg != '@' )
4419 return;
4420
4421 FILE * f;
4422 char buf[PATH_MAX];
4423 const bool use_stdin = param->arg[1] == '-' && !param->arg[2];
4424 if (use_stdin)
4425 f = stdin;
4426 else
4427 {
4428 #ifdef __CYGWIN__
4429 NormalizeFilenameCygwin(buf,sizeof(buf),param->arg+1);
4430 f = fopen(buf,"r");
4431 #else
4432 f = fopen(param->arg+1,"r");
4433 #endif
4434 if (!f)
4435 return;
4436 }
4437
4438 ASSERT(f);
4439
4440 u32 count = 0;
4441 while (fgets(buf,sizeof(buf)-1,f))
4442 {
4443 char * ptr = buf;
4444 while (*ptr)
4445 ptr++;
4446 if ( ptr > buf && ptr[-1] == '\n' )
4447 ptr--;
4448 if ( ptr > buf && ptr[-1] == '\r' )
4449 ptr--;
4450 *ptr = 0;
4451
4452 if (count++)
4453 {
4454 // insert a new item
4455 ParamList_t * new_param = GetPoolParam();
4456 new_param->next = param->next;
4457 param->next = new_param;
4458 param = new_param;
4459 n_param++;
4460 }
4461 param->arg = STRDUP(buf);
4462 param->is_expanded = true;
4463 }
4464 fclose(f);
4465
4466 if (!count)
4467 {
4468 *p_param = param->next;
4469 n_param--;
4470 }
4471
4472 append_param = &first_param;
4473 }
4474
4475 ///////////////////////////////////////////////////////////////////////////////
4476
AtExpandAllParam(ParamList_t ** p_param)4477 void AtExpandAllParam ( ParamList_t ** p_param )
4478 {
4479 if (p_param)
4480 for ( ; *p_param; p_param = &(*p_param)->next )
4481 AtExpandParam(p_param);
4482 }
4483
4484 //
4485 ///////////////////////////////////////////////////////////////////////////////
4486 /////////////// string substitutions ///////////////
4487 ///////////////////////////////////////////////////////////////////////////////
4488
SubstString(char * buf,size_t bufsize,SubstString_t * tab,ccp source,int * count)4489 char * SubstString
4490 ( char * buf, size_t bufsize, SubstString_t * tab, ccp source, int * count )
4491 {
4492 ASSERT(buf);
4493 ASSERT(bufsize > 1);
4494 ASSERT(tab);
4495 TRACE("SubstString(%s)\n",source);
4496
4497 char tempbuf[PATH_MAX];
4498 int conv_count = 0;
4499
4500 char *dest = buf;
4501 char *end = buf + bufsize + 1;
4502 if (source)
4503 while ( dest < end && *source )
4504 {
4505 if ( *source != escape_char && *source != 1 )
4506 {
4507 *dest++ = *source++;
4508 continue;
4509 }
4510 if ( source[0] == source[1] )
4511 {
4512 source++;
4513 *dest++ = *source++;
4514 continue;
4515 }
4516 ccp start = source++;
4517
4518 u32 p1, p2, stat;
4519 source = ScanRangeU32(source,&stat,&p1,&p2,0,~(u32)0);
4520 if ( stat == 1 )
4521 p1 = 0;
4522 else if ( stat < 1 )
4523 {
4524 p1 = 0;
4525 p2 = ~(u32)0;
4526 }
4527
4528 char ch = *source++;
4529 int convert = 0;
4530 if ( ch == 'u' || ch == 'U' )
4531 {
4532 convert++;
4533 ch = *source++;
4534 }
4535 else if ( ch == 'l' || ch == 'L' )
4536 {
4537 convert--;
4538 ch = *source++;
4539 }
4540 if (!ch)
4541 break;
4542
4543 size_t count = source - start;
4544
4545 SubstString_t * ptr;
4546 for ( ptr = tab; ptr->c1; ptr++ )
4547 if ( ch == ptr->c1 || ch == ptr->c2 )
4548 {
4549 if (ptr->str)
4550 {
4551 const size_t slen = strlen(ptr->str);
4552 if ( p1 > slen )
4553 p1 = slen;
4554 if ( p2 > slen )
4555 p2 = slen;
4556 count = p2 - p1;
4557 start = ptr->str+p1;
4558 conv_count++;
4559 }
4560 else
4561 count = 0;
4562 break;
4563 }
4564
4565 if (!ptr->c1) // invalid conversion
4566 convert = 0;
4567
4568 if ( count > sizeof(tempbuf)-1 )
4569 count = sizeof(tempbuf)-1;
4570 TRACE("COPY '%.*s' conv=%d\n",(int)count,start,convert);
4571 if ( convert > 0 )
4572 {
4573 char * tp = tempbuf;
4574 while ( count-- > 0 )
4575 *tp++ = toupper((int)*start++);
4576 *tp = 0;
4577 }
4578 else if ( convert < 0 )
4579 {
4580 char * tp = tempbuf;
4581 while ( count-- > 0 )
4582 *tp++ = tolower((int)*start++); // cygwin needs the '(int)'
4583 *tp = 0;
4584 }
4585 else
4586 {
4587 memcpy(tempbuf,start,count);
4588 tempbuf[count] = 0;
4589 }
4590 dest = NormalizeFileName(dest,end,tempbuf,ptr->allow_slash);
4591 }
4592
4593 if (count)
4594 *count = conv_count;
4595 *dest = 0;
4596 return dest;
4597 }
4598
4599 ///////////////////////////////////////////////////////////////////////////////
4600
ScanEscapeChar(ccp arg)4601 int ScanEscapeChar ( ccp arg )
4602 {
4603 if ( arg && strlen(arg) > 1 )
4604 {
4605 ERROR0(ERR_SYNTAX,"Illegal character (option --esc): '%s'\n",arg);
4606 return -1;
4607 }
4608
4609 escape_char = arg ? *arg : 0;
4610 return (unsigned char)escape_char;
4611 }
4612
4613 ///////////////////////////////////////////////////////////////////////////////
4614
HaveEscapeChar(ccp string)4615 bool HaveEscapeChar ( ccp string )
4616 {
4617 if (string)
4618 while(*string)
4619 {
4620 const char ch = *string++;
4621 if ( ch == escape_char || ch == '\1' )
4622 return true;
4623 }
4624 return false;
4625 }
4626
4627 //
4628 ///////////////////////////////////////////////////////////////////////////////
4629 /////////////// Memory Maps ///////////////
4630 ///////////////////////////////////////////////////////////////////////////////
4631
InitializeMemMap(MemMap_t * mm)4632 void InitializeMemMap ( MemMap_t * mm )
4633 {
4634 DASSERT(mm);
4635 memset(mm,0,sizeof(*mm));
4636 }
4637
4638 ///////////////////////////////////////////////////////////////////////////////
4639
ResetMemMap(MemMap_t * mm)4640 void ResetMemMap ( MemMap_t * mm )
4641 {
4642 DASSERT(mm);
4643
4644 uint i;
4645 if (mm->field)
4646 {
4647 for ( i = 0; i < mm->used; i++ )
4648 FREE(mm->field[i]);
4649 FREE(mm->field);
4650 }
4651 memset(mm,0,sizeof(*mm));
4652 }
4653
4654 ///////////////////////////////////////////////////////////////////////////////
4655
FindMemMap(MemMap_t * mm,off_t off,off_t size)4656 MemMapItem_t * FindMemMap ( MemMap_t * mm, off_t off, off_t size )
4657 {
4658 DASSERT(mm);
4659
4660 off_t off_end = off + size;
4661 int beg = 0;
4662 int end = mm->used - 1;
4663 while ( beg <= end )
4664 {
4665 uint idx = (beg+end)/2;
4666 MemMapItem_t * mi = mm->field[idx];
4667 if ( off_end <= mi->off )
4668 end = idx - 1 ;
4669 else if ( off >= mi->off + mi->size )
4670 beg = idx + 1;
4671 else
4672 return mi;
4673 }
4674 return 0;
4675 }
4676
4677 ///////////////////////////////////////////////////////////////////////////////
4678
InsertMemMapIndex(MemMap_t * mm,off_t off,off_t size)4679 uint InsertMemMapIndex
4680 (
4681 // returns the index of the new item
4682
4683 MemMap_t * mm, // mem map pointer
4684 off_t off, // offset of area
4685 off_t size // size of area
4686 )
4687 {
4688 DASSERT(mm);
4689 uint idx = FindMemMapHelper(mm,off,size);
4690
4691 DASSERT( mm->used <= mm->size );
4692 if ( mm->used == mm->size )
4693 {
4694 mm->size += 64;
4695 mm->field = REALLOC(mm->field,mm->size*sizeof(*mm->field));
4696 }
4697
4698 DASSERT( idx <= mm->used );
4699 MemMapItem_t ** dest = mm->field + idx;
4700 memmove(dest+1,dest,(mm->used-idx)*sizeof(MemMapItem_t*));
4701 mm->used++;
4702
4703 MemMapItem_t * mi = MALLOC(sizeof(MemMapItem_t));
4704 mi->off = off;
4705 mi->size = size;
4706 mi->overlap = 0;
4707 *dest = mi;
4708 return idx;
4709 }
4710
4711 ///////////////////////////////////////////////////////////////////////////////
4712
InsertMemMap(MemMap_t * mm,off_t off,off_t size)4713 MemMapItem_t * InsertMemMap
4714 (
4715 // returns a pointer to a new item (never NULL)
4716
4717 MemMap_t * mm, // mem map pointer
4718 off_t off, // offset of area
4719 off_t size // size of area
4720 )
4721 {
4722 const uint idx = InsertMemMapIndex(mm,off,size);
4723 // a C sequence point is important here
4724 return mm->field[idx];
4725 }
4726
4727 ///////////////////////////////////////////////////////////////////////////////
4728
TieMemMap(MemMap_t * mm,uint idx,bool force)4729 static bool TieMemMap
4730 (
4731 // returns true if element are tied togehther
4732
4733 MemMap_t * mm, // mem map pointer
4734 uint idx, // tie element 'idx' and 'idx+1'
4735 bool force // always tie and not only if overlapped
4736 )
4737 {
4738 DASSERT(mm);
4739 DASSERT( idx+1 < mm->used );
4740
4741 MemMapItem_t * i1 = mm->field[idx];
4742 MemMapItem_t * i2 = mm->field[idx+1];
4743 if ( force || i1->off + i1->size >= i2->off )
4744 {
4745 const off_t new_size = i2->off + i2->size - i1->off;
4746 if ( i1->size < new_size )
4747 i1->size = new_size;
4748 FREE(i2);
4749 idx++;
4750 mm->used--;
4751 memmove( mm->field + idx,
4752 mm->field + idx + 1,
4753 ( mm->used - idx ) * sizeof(MemMapItem_t*) );
4754
4755 return true;
4756 }
4757 return false;
4758 }
4759
4760 ///////////////////////////////////////////////////////////////////////////////
4761
InsertMemMapTie(MemMap_t * mm,off_t off,off_t size)4762 MemMapItem_t * InsertMemMapTie
4763 (
4764 // returns a pointer to a new or existing item (never NULL)
4765
4766 MemMap_t * mm, // mem map pointer
4767 off_t off, // offset of area
4768 off_t size // size of area
4769 )
4770 {
4771 uint idx = InsertMemMapIndex(mm,off,size);
4772
4773 if ( idx > 0 && TieMemMap(mm,idx-1,false) )
4774 idx--;
4775
4776 while ( idx + 1 < mm->used && TieMemMap(mm,idx,false) )
4777 ;
4778
4779 return mm->field[idx];
4780 }
4781
4782 ///////////////////////////////////////////////////////////////////////////////
4783
InsertMemMapWrapper(void * param,u64 offset,u64 size,ccp info)4784 void InsertMemMapWrapper
4785 (
4786 void * param, // user defined parameter
4787 u64 offset, // offset of object
4788 u64 size, // size of object
4789 ccp info // info about object
4790 )
4791 {
4792 noTRACE("InsertMemMapWrapper(%p,%llx,%llx,%s)\n",param,offset,size,info);
4793 DASSERT(param);
4794 MemMapItem_t * mi = InsertMemMap(param,offset,size);
4795 StringCopyS(mi->info,sizeof(mi->info),info);
4796 }
4797
4798 ///////////////////////////////////////////////////////////////////////////////
4799
InsertDiscMemMap(MemMap_t * mm,wd_disc_t * disc)4800 void InsertDiscMemMap
4801 (
4802 MemMap_t * mm, // valid memore map pointer
4803 wd_disc_t * disc // valid disc pointer
4804 )
4805 {
4806 noTRACE("InsertDiscMemMap(%p,%p)\n",mm,disc);
4807 DASSERT(mm);
4808 DASSERT(disc);
4809 wd_print_mem(disc,InsertMemMapWrapper,mm);
4810 }
4811
4812 ///////////////////////////////////////////////////////////////////////////////
4813
FindMemMapHelper(MemMap_t * mm,off_t off,off_t size)4814 uint FindMemMapHelper ( MemMap_t * mm, off_t off, off_t size )
4815 {
4816 DASSERT(mm);
4817
4818 int beg = 0;
4819 int end = mm->used - 1;
4820 while ( beg <= end )
4821 {
4822 uint idx = (beg+end)/2;
4823 MemMapItem_t * mi = mm->field[idx];
4824 if ( off < mi->off )
4825 end = idx - 1 ;
4826 else if ( off > mi->off )
4827 beg = idx + 1;
4828 else if ( size < mi->size )
4829 end = idx - 1 ;
4830 else if ( size > mi->size )
4831 beg = idx + 1;
4832 else
4833 {
4834 TRACE("FindMemMapHelper(%llx,%llx) FOUND=%d/%d/%d\n",
4835 (u64)off, (u64)size, idx, mm->used, mm->size );
4836 return idx;
4837 }
4838 }
4839
4840 TRACE("FindStringFieldHelper(%llx,%llx) failed=%d/%d/%d\n",
4841 (u64)off, (u64)size, beg, mm->used, mm->size );
4842 return beg;
4843 }
4844
4845 ///////////////////////////////////////////////////////////////////////////////
4846
CalCoverlapMemMap(MemMap_t * mm)4847 uint CalCoverlapMemMap ( MemMap_t * mm )
4848 {
4849 DASSERT(mm);
4850
4851 uint i, count = 0;
4852 MemMapItem_t * prev = 0;
4853 for ( i = 0; i < mm->used; i++ )
4854 {
4855 MemMapItem_t * ptr = mm->field[i];
4856 ptr->overlap = 0;
4857 if ( prev && ptr->off < prev->off + prev->size )
4858 {
4859 ptr ->overlap |= 1;
4860 prev->overlap |= 2;
4861 count++;
4862 }
4863 prev = ptr;
4864 }
4865 return count;
4866 }
4867
4868 ///////////////////////////////////////////////////////////////////////////////
4869
PrintMemMap(MemMap_t * mm,FILE * f,int indent,ccp info_head)4870 void PrintMemMap ( MemMap_t * mm, FILE * f, int indent, ccp info_head )
4871 {
4872 DASSERT(mm);
4873 if ( !f || !mm->used )
4874 return;
4875
4876 CalCoverlapMemMap(mm);
4877 indent = NormalizeIndent(indent);
4878
4879 static char ovl[][3] = { " ", "!.", ".!", "!!" };
4880
4881 if (!info_head)
4882 info_head = "info";
4883 int i, max_ilen = strlen(info_head);
4884 for ( i = 0; i < mm->used; i++ )
4885 {
4886 MemMapItem_t * ptr = mm->field[i];
4887 ptr->info[sizeof(ptr->info)-1] = 0;
4888 const int ilen = strlen(ptr->info);
4889 if ( max_ilen < ilen )
4890 max_ilen = ilen;
4891 }
4892
4893 fprintf(f,"%*s unused : off(beg) .. off(end) : size : %s\n%*s%.*s\n",
4894 indent, "", info_head,
4895 indent, "", max_ilen+52, wd_sep_200 );
4896
4897 off_t max_end = mm->begin;
4898 for ( i = 0; i < mm->used; i++ )
4899 {
4900 MemMapItem_t * ptr = mm->field[i];
4901 if ( !i && max_end > ptr->off )
4902 max_end = ptr->off;
4903 const off_t end = ptr->off + ptr->size;
4904 if ( ptr->off > max_end )
4905 fprintf(f,"%*s%s%10llx :%10llx ..%10llx :%10llx : %s\n",
4906 indent, "", ovl[ptr->overlap&3], (u64)( ptr->off - max_end ),
4907 (u64)ptr->off, (u64)end, (u64)ptr->size, ptr->info );
4908 else
4909 fprintf(f,"%*s%s :%10llx ..%10llx :%10llx : %s\n",
4910 indent, "", ovl[ptr->overlap&3],
4911 (u64)ptr->off, (u64)end, (u64)ptr->size, ptr->info );
4912 if ( max_end < end )
4913 max_end = end;
4914 }
4915 }
4916
4917 //
4918 ///////////////////////////////////////////////////////////////////////////////
4919 /////////////// File Map ///////////////
4920 ///////////////////////////////////////////////////////////////////////////////
4921
InitializeFileMap(FileMap_t * mm)4922 void InitializeFileMap ( FileMap_t * mm )
4923 {
4924 DASSERT(mm);
4925 memset(mm,0,sizeof(*mm));
4926 }
4927
4928 ///////////////////////////////////////////////////////////////////////////////
4929
ResetFileMap(FileMap_t * mm)4930 void ResetFileMap ( FileMap_t * mm )
4931 {
4932 DASSERT(mm);
4933 FREE(mm->field);
4934 memset(mm,0,sizeof(*mm));
4935 }
4936
4937 ///////////////////////////////////////////////////////////////////////////////
4938
AppendFileMap(FileMap_t * fm,u64 src_off,u64 dest_off,u64 size)4939 const FileMapItem_t * AppendFileMap
4940 (
4941 // returns the modified or appended item
4942
4943 FileMap_t * fm, // file map pointer
4944 u64 src_off, // offset of source
4945 u64 dest_off, // offset of dest
4946 u64 size // size
4947 )
4948 {
4949 DASSERT(fm);
4950 if (!size)
4951 return 0;
4952
4953 if (fm->used)
4954 {
4955 FileMapItem_t *mi = fm->field + fm->used - 1;
4956 if ( mi->src_off + mi->size == src_off
4957 && mi->dest_off + mi->size == dest_off )
4958 {
4959 mi->size += size;
4960 return mi;
4961 }
4962 }
4963
4964 DASSERT( fm->used <= fm->size );
4965 if ( fm->used == fm->size )
4966 {
4967 fm->size += fm->size/2 + 50;
4968 fm->field = REALLOC(fm->field,fm->size*sizeof(*fm->field));
4969 }
4970 DASSERT( fm->used < fm->size );
4971
4972 FileMapItem_t *mi = fm->field + fm->used++;
4973 mi->src_off = src_off;
4974 mi->dest_off = dest_off;
4975 mi->size = size;
4976 return mi;
4977 }
4978
4979 ///////////////////////////////////////////////////////////////////////////////
4980
CombineFileMaps(FileMap_t * fm,bool init_fm,const FileMap_t * fm1,const FileMap_t * fm2)4981 uint CombineFileMaps
4982 (
4983 FileMap_t *fm, // resulting filemap
4984 bool init_fm, // true: initialize 'fm', false: reset 'fm'
4985 const FileMap_t *fm1, // first source filemap
4986 const FileMap_t *fm2 // second source filemap
4987 )
4988 {
4989 DASSERT(fm);
4990 DASSERT(fm1);
4991 DASSERT(fm2);
4992
4993 if (init_fm)
4994 InitializeFileMap(fm);
4995 else
4996 ResetFileMap(fm);
4997
4998
4999 const FileMapItem_t *i1 = fm1->field;
5000 const FileMapItem_t *e1 = i1 + fm1->used;
5001
5002 const FileMapItem_t *i2 = fm2->field;
5003 const FileMapItem_t *e2 = i2 + fm2->used;
5004
5005 u64 fm2_off1 = 0;
5006 u64 fm2_off2 = 0;
5007 u64 fm2_size = 0;
5008
5009 while ( i1 < e1 )
5010 {
5011 u64 fm1_off1 = i1->src_off;
5012 u64 fm1_off2 = i1->dest_off;
5013 u64 fm1_size = i1->size;
5014 i1++;
5015 noPRINT("%4zu %9llx %11llx %9llx | %4zu %9llx %11llx %9llx | NEXT FM-1\n",
5016 i1-fm1->field, fm1_off1, fm1_off2, fm1_size,
5017 i2-fm2->field, fm2_off1, fm2_off2, fm2_size );
5018
5019 while ( fm1_size )
5020 {
5021 while ( fm1_off2 >= fm2_off1 + fm2_size )
5022 {
5023 if ( i2 == e2 )
5024 return fm->used;
5025
5026 fm2_off1 = i2->src_off;
5027 fm2_off2 = i2->dest_off;
5028 fm2_size = i2->size;
5029 i2++;
5030 noPRINT("%4zu %9llx %11llx %9llx | %4zu %9llx %11llx %9llx | NEXT FM-2\n",
5031 i1-fm1->field, fm1_off1, fm1_off2, fm1_size,
5032 i2-fm2->field, fm2_off1, fm2_off2, fm2_size );
5033 }
5034 DASSERT( fm1_off2 < fm2_off1 + fm2_size );
5035 noPRINT("%9llx + %9llx = %9llx < %9llx\n",
5036 fm1_off2, fm1_size, fm1_off2 + fm1_size, fm2_off1 );
5037 if ( fm1_off2 + fm1_size < fm2_off1 )
5038 break;
5039
5040 if ( fm1_off2 < fm2_off1 )
5041 {
5042 const u64 delta = fm2_off1 - fm1_off2;
5043 DASSERT( delta <= fm1_size );
5044 fm1_off1 += delta;
5045 fm1_off2 += delta;
5046 fm1_size -= delta;
5047 }
5048 else
5049 {
5050 const u64 delta = fm1_off2 - fm2_off1;
5051 DASSERT( delta <= fm2_size );
5052 fm2_off1 += delta;
5053 fm2_off2 += delta;
5054 fm2_size -= delta;
5055 }
5056 DASSERT( fm1_off2 == fm2_off1 );
5057
5058 const u64 size = fm1_size < fm2_size ? fm1_size : fm2_size;
5059 AppendFileMap(fm,fm1_off1,fm2_off2,size);
5060 fm1_off1 += size;
5061 fm1_off2 += size;
5062 fm1_size -= size;
5063 fm2_off1 += size;
5064 fm2_off2 += size;
5065 fm2_size -= size;
5066 noPRINT("%4zu %9llx %11llx %9llx | %4zu %9llx %11llx %9llx | ADD %llx\n",
5067 i1-fm1->field, fm1_off1, fm1_off2, fm1_size,
5068 i2-fm2->field, fm2_off1, fm2_off2, fm2_size,
5069 size );
5070 }
5071 }
5072 return fm->used;
5073 }
5074
5075 //
5076 ///////////////////////////////////////////////////////////////////////////////
5077 /////////////// setup files ///////////////
5078 ///////////////////////////////////////////////////////////////////////////////
5079
ResetSetup(SetupDef_t * list)5080 size_t ResetSetup
5081 (
5082 SetupDef_t * list // object list terminated with an element 'name=NULL'
5083 )
5084 {
5085 DASSERT(list);
5086 size_t count;
5087 for ( count = 0; list->name; list++, count++ )
5088 {
5089 FreeString(list->param);
5090 list->param = 0;
5091 list->value = 0;
5092 }
5093 return count;
5094 }
5095
5096 ///////////////////////////////////////////////////////////////////////////////
5097
ScanSetupFile(SetupDef_t * list,ccp path1,ccp path2,bool silent)5098 enumError ScanSetupFile
5099 (
5100 SetupDef_t * list, // object list terminated with an element 'name=NULL'
5101 ccp path1, // filename of text file, part 1
5102 ccp path2, // filename of text file, part 2
5103 bool silent // true: suppress error message if file not found
5104 )
5105 {
5106 DASSERT(list);
5107 DASSERT(path1||path2);
5108
5109 ResetSetup(list);
5110
5111 char pathbuf[PATH_MAX];
5112 ccp path = PathCatPP(pathbuf,sizeof(pathbuf),path1,path2);
5113 TRACE("ScanSetupFile(%s,%d)\n",path,silent);
5114
5115 FILE * f = fopen(path,"rb");
5116 if (!f)
5117 {
5118 if (!silent)
5119 ERROR1(ERR_CANT_OPEN,"Can't open file: %s\n",path);
5120 return ERR_CANT_OPEN;
5121 }
5122
5123 while (fgets(iobuf,sizeof(iobuf)-1,f))
5124 {
5125 //----- skip spaces
5126
5127 char * ptr = iobuf;
5128 while ( *ptr > 0 && *ptr <= ' ' )
5129 ptr++;
5130
5131 if ( *ptr == '!' || *ptr == '#' )
5132 continue;
5133
5134 //----- find end of name
5135
5136 char * name = ptr;
5137 while ( isalnum((int)*ptr) || *ptr == '-' )
5138 ptr++;
5139 if (!*ptr)
5140 continue;
5141
5142 char * name_end = ptr;
5143
5144 //----- skip spaces and check for '='
5145
5146 while ( *ptr > 0 && *ptr <= ' ' )
5147 ptr++;
5148
5149 if ( *ptr != '=' )
5150 continue;
5151
5152 *name_end = 0;
5153
5154 //----- check if name is a known parameter
5155
5156 SetupDef_t * item;
5157 for ( item = list; item->name; item++ )
5158 if (!strcmp(item->name,name))
5159 break;
5160 if (!item->name)
5161 continue;
5162
5163 //----- trim parameter
5164
5165 ptr++; // skip '='
5166 while ( *ptr > 0 && *ptr <= ' ' )
5167 ptr++;
5168
5169 char * param = ptr;
5170
5171 while (*ptr)
5172 ptr++;
5173
5174 ptr--;
5175 while ( *ptr > 0 && *ptr <= ' ' )
5176 ptr--;
5177 ptr[1] = 0;
5178
5179 item->param = STRDUP(param);
5180 if (item->factor)
5181 {
5182 ScanSizeU64(&item->value,param,1,1,0);
5183 if ( item->factor > 1 )
5184 item->value = item->value / item->factor * item->factor;
5185 }
5186 }
5187 fclose(f);
5188 return ERR_OK;
5189 }
5190
5191 //
5192 ///////////////////////////////////////////////////////////////////////////////
5193 /////////////// data area & list ///////////////
5194 ///////////////////////////////////////////////////////////////////////////////
5195
SetupDataList(DataList_t * dl,const DataArea_t * da)5196 void SetupDataList
5197 (
5198 DataList_t * dl, // Object for setup
5199 const DataArea_t * da // Source list,
5200 // terminated with an element where addr==NULL
5201 // The content of this area must not changed
5202 // while accessing the data list
5203 )
5204 {
5205 DASSERT(dl);
5206 memset(dl,0,sizeof(*dl));
5207 dl->area = da;
5208 }
5209
5210 ///////////////////////////////////////////////////////////////////////////////
5211
ReadDataList(DataList_t * dl,void * buf,size_t size)5212 size_t ReadDataList // returns number of writen bytes
5213 (
5214 DataList_t * dl, // NULL or pointer to data list
5215 void * buf, // destination buffer
5216 size_t size // size of destination buffer
5217 )
5218 {
5219 u8 * dest = buf;
5220 size_t written = 0;
5221 if ( dl && dl->area )
5222 {
5223 while ( size > 0 )
5224 {
5225 if (!dl->current.size)
5226 {
5227 noPRINT("NEXT AREA: %p, %p, %zu\n",
5228 dl->area, dl->area->data, dl->area->size );
5229 if (!dl->area->data)
5230 break;
5231 memcpy(&dl->current,dl->area++,sizeof(dl->current));
5232 }
5233
5234 const size_t copy_size = size < dl->current.size ? size : dl->current.size;
5235 noPRINT("COPY AREA: %p <- %p, size = %zu=%zx\n",
5236 dest,dl->current.data,copy_size,copy_size);
5237 memcpy(dest,dl->current.data,copy_size);
5238 written += copy_size;
5239 dest += copy_size;
5240 dl->current.data += copy_size;
5241 dl->current.size -= copy_size;
5242 size -= copy_size;
5243 }
5244 }
5245 return written;
5246 }
5247
5248 //
5249 ///////////////////////////////////////////////////////////////////////////////
5250 /////////////// random mumbers ///////////////
5251 ///////////////////////////////////////////////////////////////////////////////
5252 // thanx to Donald Knuth
5253
5254 const u32 RANDOM32_C_ADD = 2 * 197731421; // 2 Primzahlen
5255 const u32 RANDOM32_COUNT_BASE = 4294967; // Primzahl == ~UINT_MAX32/1000;
5256
5257 static int random32_a_index = -1; // Index in die a-Tabelle
5258 static u32 random32_count = 1; // Abwaerts-Zähler bis zum Wechsel von a,c
5259 static u32 random32_a,
5260 random32_c,
5261 random32_X; // Die letzten Werte
5262
5263 static u32 random32_a_tab[] = // Init-Tabelle
5264 {
5265 0xbb40e62d, 0x3dc8f2f5, 0xdc024635, 0x7a5b6c8d,
5266 0x583feb95, 0x91e06dbd, 0xa7ec03f5, 0
5267 };
5268
5269 //-----------------------------------------------------------------------------
5270
Random32(u32 max)5271 u32 Random32 ( u32 max )
5272 {
5273 if (!--random32_count)
5274 {
5275 // Neue Berechnung von random32_a und random32_c faellig
5276
5277 if ( random32_a_index < 0 )
5278 {
5279 // allererste Initialisierung auf Zeitbasis
5280 Seed32Time();
5281 }
5282 else
5283 {
5284 random32_c += RANDOM32_C_ADD;
5285 random32_a = random32_a_tab[++random32_a_index];
5286 if (!random32_a)
5287 {
5288 random32_a_index = 0;
5289 random32_a = random32_a_tab[0];
5290 }
5291
5292 random32_count = RANDOM32_COUNT_BASE;
5293 }
5294 }
5295
5296 // Jetzt erfolgt die eigentliche Berechnung
5297
5298 random32_X = random32_a * random32_X + random32_c;
5299
5300 if (!max)
5301 return random32_X;
5302
5303 return ( (u64)max * random32_X ) >> 32;
5304 }
5305
5306 //-----------------------------------------------------------------------------
5307
Seed32Time()5308 u64 Seed32Time ()
5309 {
5310 struct timeval tval;
5311 gettimeofday(&tval,NULL);
5312 const u64 random_time_bits = (u64) tval.tv_usec << 16 ^ tval.tv_sec;
5313 return Seed32( ( random_time_bits ^ getpid() ) * 197731421u );
5314 }
5315
5316 //-----------------------------------------------------------------------------
5317
Seed32(u64 base)5318 u64 Seed32 ( u64 base )
5319 {
5320 uint a_tab_len = 0;
5321 while (random32_a_tab[a_tab_len])
5322 a_tab_len++;
5323 const u32 base32 = base / a_tab_len;
5324
5325 random32_a_index = base % a_tab_len;
5326 random32_a = random32_a_tab[random32_a_index];
5327 random32_c = ( base32 & 15 ) * RANDOM32_C_ADD + 1;
5328 random32_X = base32 ^ ( base >> 32 );
5329 random32_count = RANDOM32_COUNT_BASE;
5330
5331 return base;
5332 }
5333
5334 //-----------------------------------------------------------------------------
5335
RandomFill(void * buf,size_t size)5336 void RandomFill ( void * buf, size_t size )
5337 {
5338 size_t xsize = size / sizeof(u32);
5339 if (xsize)
5340 {
5341 size -= xsize * sizeof(u32);
5342 u32 * ptr = buf;
5343 while ( xsize-- > 0 )
5344 *ptr++ = Random32(0);
5345 buf = ptr;
5346 }
5347
5348 u8 * ptr = buf;
5349 while ( size-- > 0 )
5350 *ptr++ = Random32(0);
5351 }
5352
5353 //
5354 ///////////////////////////////////////////////////////////////////////////////
5355 /////////////// bit handling ///////////////
5356 ///////////////////////////////////////////////////////////////////////////////
5357
5358 const uchar TableBitCount[0x100] =
5359 {
5360 0,1,1,2, 1,2,2,3, 1,2,2,3, 2,3,3,4,
5361 1,2,2,3, 2,3,3,4, 2,3,3,4, 3,4,4,5,
5362 1,2,2,3, 2,3,3,4, 2,3,3,4, 3,4,4,5,
5363 2,3,3,4, 3,4,4,5, 3,4,4,5, 4,5,5,6,
5364
5365 1,2,2,3, 2,3,3,4, 2,3,3,4, 3,4,4,5,
5366 2,3,3,4, 3,4,4,5, 3,4,4,5, 4,5,5,6,
5367 2,3,3,4, 3,4,4,5, 3,4,4,5, 4,5,5,6,
5368 3,4,4,5, 4,5,5,6, 4,5,5,6, 5,6,6,7,
5369
5370 1,2,2,3, 2,3,3,4, 2,3,3,4, 3,4,4,5,
5371 2,3,3,4, 3,4,4,5, 3,4,4,5, 4,5,5,6,
5372 2,3,3,4, 3,4,4,5, 3,4,4,5, 4,5,5,6,
5373 3,4,4,5, 4,5,5,6, 4,5,5,6, 5,6,6,7,
5374
5375 2,3,3,4, 3,4,4,5, 3,4,4,5, 4,5,5,6,
5376 3,4,4,5, 4,5,5,6, 4,5,5,6, 5,6,6,7,
5377 3,4,4,5, 4,5,5,6, 4,5,5,6, 5,6,6,7,
5378 4,5,5,6, 5,6,6,7, 5,6,6,7, 6,7,7,8
5379 };
5380
5381 ///////////////////////////////////////////////////////////////////////////////
5382
Count1Bits(const void * data,size_t len)5383 uint Count1Bits ( const void * data, size_t len )
5384 {
5385 uint count = 0;
5386 const uchar * d = data;
5387 while ( len-- > 0 )
5388 count += TableBitCount[*d++];
5389 return count;
5390 }
5391
5392 ///////////////////////////////////////////////////////////////////////////////
5393
Count1Bits8(u8 data)5394 uint Count1Bits8 ( u8 data )
5395 {
5396 return TableBitCount[data];
5397 }
5398
5399 ///////////////////////////////////////////////////////////////////////////////
5400
Count1Bits16(u16 data)5401 uint Count1Bits16 ( u16 data )
5402 {
5403 const u8 * d = (u8*)&data;
5404 return TableBitCount[d[0]]
5405 + TableBitCount[d[1]];
5406 }
5407
5408 ///////////////////////////////////////////////////////////////////////////////
5409
Count1Bits32(u32 data)5410 uint Count1Bits32 ( u32 data )
5411 {
5412 const u8 * d = (u8*)&data;
5413 return TableBitCount[d[0]]
5414 + TableBitCount[d[1]]
5415 + TableBitCount[d[2]]
5416 + TableBitCount[d[3]];
5417 }
5418
5419 ///////////////////////////////////////////////////////////////////////////////
5420
Count1Bits64(u64 data)5421 uint Count1Bits64 ( u64 data )
5422 {
5423 const u8 * d = (u8*)&data;
5424 return TableBitCount[d[0]]
5425 + TableBitCount[d[1]]
5426 + TableBitCount[d[2]]
5427 + TableBitCount[d[3]]
5428 + TableBitCount[d[4]]
5429 + TableBitCount[d[5]]
5430 + TableBitCount[d[6]]
5431 + TableBitCount[d[7]];
5432 }
5433
5434 ///////////////////////////////////////////////////////////////////////////////
5435
FindLowest1Bit64(u64 data)5436 int FindLowest1Bit64 ( u64 data )
5437 {
5438 if (!data)
5439 return -1;
5440
5441 uint index;
5442 for ( index = 0; !(data&1); data >>= 1, index++ )
5443 ;
5444 return index;
5445 }
5446
5447 ///////////////////////////////////////////////////////////////////////////////
5448
GetAlign64(u64 data)5449 u64 GetAlign64 ( u64 data )
5450 {
5451 const int index = FindLowest1Bit64 (data);
5452 return index < 0 ? 0 : 1 << index;
5453 }
5454
5455 //
5456 ///////////////////////////////////////////////////////////////////////////////
5457 /////////////// etc ///////////////
5458 ///////////////////////////////////////////////////////////////////////////////
5459
AllocTempBuffer(size_t needed_size)5460 size_t AllocTempBuffer ( size_t needed_size )
5461 {
5462 // 'tempbuf' is only for short usage
5463 // ==> don't call other functions while using tempbuf
5464
5465 // align to 4K
5466 needed_size = needed_size + 0xfff & ~(size_t)0xfff;
5467
5468 if ( tempbuf_size < needed_size )
5469 {
5470 noPRINT("$$$ ALLOC TEMPBUF, SIZE: %zx > %zx (%s -> %s)\n",
5471 tempbuf_size, needed_size,
5472 wd_print_size_1024(0,0,tempbuf_size,false),
5473 wd_print_size_1024(0,0,needed_size,false) );
5474 tempbuf_size = needed_size;
5475 FREE(tempbuf);
5476 tempbuf = MALLOC(needed_size);
5477 }
5478 return tempbuf_size;
5479 }
5480
5481 ///////////////////////////////////////////////////////////////////////////////
5482
ScanPreallocMode(ccp arg)5483 int ScanPreallocMode ( ccp arg )
5484 {
5485 #ifdef NO_PREALLOC
5486 static char errmsg[] = "Preallocation not supported and option --prealloc is ignored!\n";
5487 #endif
5488
5489 if ( !arg || !*arg )
5490 {
5491 #ifdef NO_PREALLOC
5492 ERROR0(ERR_WARNING,errmsg);
5493 #else
5494 prealloc_mode = PREALLOC_OPT_DEFAULT;
5495 #endif
5496 return 0;
5497 }
5498
5499 static const CommandTab_t tab[] =
5500 {
5501 { PREALLOC_OFF, "OFF", "0", 0 },
5502 { PREALLOC_SMART, "SMART", "1", 0 },
5503 { PREALLOC_ALL, "ALL", "2", 0 },
5504
5505 { 0,0,0,0 }
5506 };
5507
5508 const CommandTab_t * cmd = ScanCommand(0,arg,tab);
5509 if (cmd)
5510 {
5511 #ifdef NO_PREALLOC
5512 if ( cmd->id != PREALLOC_OFF )
5513 ERROR0(ERR_WARNING,errmsg);
5514 #else
5515 prealloc_mode = cmd->id;
5516 #endif
5517 return 0;
5518 }
5519
5520 ERROR0(ERR_SYNTAX,"Illegal preallocation mode (option --prealloc): '%s'\n",arg);
5521 return 1;
5522 }
5523
5524 ///////////////////////////////////////////////////////////////////////////////
5525
AllocRealPath(ccp source)5526 char * AllocRealPath ( ccp source )
5527 {
5528 // Mac does not support: realpath(src,0)
5529
5530 char fname[PATH_MAX];
5531 realpath(source,fname);
5532 return STRDUP(fname);
5533 }
5534
5535 ///////////////////////////////////////////////////////////////////////////////
5536
mark_used(ccp name,...)5537 void mark_used ( ccp name, ... )
5538 {
5539 }
5540
5541 ///////////////////////////////////////////////////////////////////////////////
5542
option_deprecated(ccp name)5543 void option_deprecated ( ccp name )
5544 {
5545 ERROR0(ERR_WARNING,
5546 "Option --%s is deprecated! Don't use it any longer!\n",
5547 name);
5548 }
5549
5550 ///////////////////////////////////////////////////////////////////////////////
5551
option_ignored(ccp name)5552 void option_ignored ( ccp name )
5553 {
5554 ERROR0(ERR_WARNING,
5555 "Option --%s is deprecated and ignored! Don't use it any longer!\n",
5556 name);
5557 }
5558
5559 //
5560 ///////////////////////////////////////////////////////////////////////////////
5561 /////////////// END ///////////////
5562 ///////////////////////////////////////////////////////////////////////////////
5563
5564