1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Datafile archiving utility for the Allegro library.
12  *
13  *      By Shawn Hargreaves.
14  *
15  *      Nathan Smith added the recursive handling of directories.
16  *
17  *      See readme.txt for copyright information.
18  */
19 
20 
21 #define ALLEGRO_USE_CONSOLE
22 
23 #include <stdio.h>
24 #include <string.h>
25 #include <time.h>
26 
27 #include "allegro.h"
28 #include "datedit.h"
29 
30 #if ((defined ALLEGRO_DOS) || (defined ALLEGRO_WINDOWS)) && (!defined SCAN_DEPEND)
31    #define DAT_HAVE_CONIO_H
32    #include <conio.h>
33 #endif
34 
35 
36 
37 static int err = 0;
38 static int changed = 0;
39 
40 static int opt_command = 0;
41 static int opt_compression = -1;
42 static int opt_strip = -1;
43 static int opt_sort = -1;
44 static int opt_relf = FALSE;
45 static int opt_verbose = FALSE;
46 static int opt_keepnames = FALSE;
47 static int opt_colordepth = -1;
48 static int opt_gridx = -1;
49 static int opt_gridy = -1;
50 static int opt_gridw = -1;
51 static int opt_gridh = -1;
52 static char *opt_datafilename = NULL;
53 static char *opt_outputname = NULL;
54 static char *opt_headername = NULL;
55 static char *opt_dependencyfile = NULL;
56 static char *opt_objecttype = NULL;
57 static char *opt_prefixstring = NULL;
58 static char *opt_password = NULL;
59 static char *opt_palette = NULL;
60 
61 static int attrib_ok = FA_ARCH|FA_RDONLY;
62 
63 static char canonical_datafilename[1024];
64 
65 static char **opt_proplist = NULL;
66 static int opt_numprops = 0;
67 
68 static char **opt_fixedproplist = NULL;
69 static int opt_numfixedprops = 0;
70 
71 static char **opt_namelist = NULL;
72 static int opt_numnames = 0;
73 
74 static int *opt_usedname = NULL;
75 
76 
77 
allocate(int n)78 static void allocate(int n)
79 {
80    static int max = 0;
81    if (n <= max)
82       return;
83    opt_proplist = realloc(opt_proplist, n * sizeof *opt_proplist);
84    opt_fixedproplist = realloc(opt_fixedproplist, n * sizeof *opt_fixedproplist);
85    opt_namelist = realloc(opt_namelist, n * sizeof *opt_namelist);
86    opt_usedname = realloc(opt_usedname, n * sizeof *opt_usedname);
87    max = n;
88 }
89 
90 
91 
92 /* display help on the command syntax */
usage(void)93 static void usage(void)
94 {
95    printf("\nDatafile archiving utility for Allegro " ALLEGRO_VERSION_STR ", " ALLEGRO_PLATFORM_STR "\n");
96    printf("By Shawn Hargreaves, " ALLEGRO_DATE_STR "\n\n");
97    printf("Usage: dat [options] filename.dat [names]\n\n");
98    printf("Options:\n");
99    printf("\t'-a' adds the named files to the datafile\n");
100    printf("\t'-bpp colordepth' grabs bitmaps in the specified format\n");
101    printf("\t'-c0' no compression\n");
102    printf("\t'-c1' compress objects individually\n");
103    printf("\t'-c2' global compression on the entire datafile\n");
104    printf("\t'-d' deletes the named objects from the datafile\n");
105    printf("\t'-dither' dithers when reducing color depths\n");
106    printf("\t'-e' extracts the named objects from the datafile\n");
107    printf("\t'-f' store references to original files as relative filenames\n");
108    printf("\t'-g x y w h' grabs bitmap data from a specific grid location\n");
109    printf("\t'-h outputfile.h' sets the output header file\n");
110    printf("\t'-k' keeps the original filenames when grabbing objects\n");
111    printf("\t'-l' lists the contents of the datafile\n");
112    printf("\t'-m dependencyfile' outputs makefile dependencies\n");
113    printf("\t'-n0' no sort: list the objects in the order they were added\n");
114    printf("\t'-n1' sort the objects of the datafile alphabetically by name\n");
115    printf("\t'-o output' sets the output file or directory when extracting data\n");
116    printf("\t'-p prefixstring' sets the prefix for the output header file\n");
117    printf("\t'-pal objectname' specifies which palette to use\n");
118    printf("\t'-r' recursively adds directories as nested datafiles\n");
119    printf("\t'-s0' no strip: save everything\n");
120    printf("\t'-s1' strip grabber specific information from the file\n");
121    printf("\t'-s2' strip all object properties and names from the file\n");
122    printf("\t'-s-PROP' do not strip object property PROP from the file\n");
123    printf("\t'-t type' sets the object type when adding files\n");
124    printf("\t'-transparency' preserves transparency through color conversion\n");
125    printf("\t'-u' updates the contents of the datafile\n");
126    printf("\t'-v' selects verbose mode\n");
127    printf("\t'-w' always updates the entire contents of the datafile\n");
128    printf("\t'-x' alias for -e\n");
129    printf("\t'-007 password' sets the file encryption key\n");
130    printf("\t'PROP=value' sets object properties\n");
131 }
132 
133 
134 
135 /* callback for outputting messages */
datedit_msg(AL_CONST char * fmt,...)136 void datedit_msg(AL_CONST char *fmt, ...)
137 {
138    va_list args;
139    char buf[1024];
140 
141    va_start(args, fmt);
142    vsprintf(buf, fmt, args);
143    va_end(args);
144 
145    printf("%s\n", buf);
146 }
147 
148 
149 
150 /* callback for starting a 2-part message output */
datedit_startmsg(AL_CONST char * fmt,...)151 void datedit_startmsg(AL_CONST char *fmt, ...)
152 {
153    va_list args;
154    char buf[1024];
155 
156    va_start(args, fmt);
157    vsprintf(buf, fmt, args);
158    va_end(args);
159 
160    printf("%s", buf);
161    fflush(stdout);
162 }
163 
164 
165 
166 /* callback for ending a 2-part message output */
datedit_endmsg(AL_CONST char * fmt,...)167 void datedit_endmsg(AL_CONST char *fmt, ...)
168 {
169    va_list args;
170    char buf[1024];
171 
172    va_start(args, fmt);
173    vsprintf(buf, fmt, args);
174    va_end(args);
175 
176    printf("%s\n", buf);
177 }
178 
179 
180 
181 /* callback for printing errors */
datedit_error(AL_CONST char * fmt,...)182 void datedit_error(AL_CONST char *fmt, ...)
183 {
184    va_list args;
185    char buf[1024];
186 
187    va_start(args, fmt);
188    vsprintf(buf, fmt, args);
189    va_end(args);
190 
191    fprintf(stderr, "%s\n", buf);
192 
193    err = 1;
194 }
195 
196 
197 
198 /* callback for asking questions */
datedit_ask(AL_CONST char * fmt,...)199 int datedit_ask(AL_CONST char *fmt, ...)
200 {
201    va_list args;
202    char buf[1024];
203    int c;
204 
205    static int all = FALSE;
206 
207    if (all)
208       return 'y';
209 
210    va_start(args, fmt);
211    vsprintf(buf, fmt, args);
212    va_end(args);
213 
214    printf("%s? (y/n/a/q) ", buf);
215    fflush(stdout);
216 
217    for (;;) {
218       #ifdef DAT_HAVE_CONIO_H
219 
220 	 /* raw keyboard input for platforms that have conio functions */
221 	 c = getch();
222 	 if ((c == 0) || (c == 0xE0))
223 	    getch();
224 
225       #else
226 
227 	 /* stdio version for other systems */
228 	 fflush(stdin);
229 	 c = getchar();
230 
231       #endif
232 
233       switch (c) {
234 
235 	 case 'y':
236 	 case 'Y':
237 	    #ifdef DAT_HAVE_CONIO_H
238 	       printf("%c\n", c);
239 	    #endif
240 	    return 'y';
241 
242 	 case 'n':
243 	 case 'N':
244 	    #ifdef DAT_HAVE_CONIO_H
245 	       printf("%c\n", c);
246 	    #endif
247 	    return 'n';
248 
249 	 case 'a':
250 	 case 'A':
251 	    #ifdef DAT_HAVE_CONIO_H
252 	       printf("%c\n", c);
253 	    #endif
254 	    all = TRUE;
255 	    return 'y';
256 
257 	 case 'q':
258 	 case 'Q':
259 	    #ifdef DAT_HAVE_CONIO_H
260 	       printf("%c\n", c);
261 	    #endif
262 	    return 27;
263 
264 	 case 27:
265 	    #ifdef DAT_HAVE_CONIO_H
266 	       printf("\n");
267 	    #endif
268 	    return 27;
269       }
270    }
271 }
272 
273 
274 
275 /* callback for the datedit functions to show a list of options */
276 /* Returns -1 if canceled */
datedit_select(AL_CONST char * (* list_getter)(int index,int * list_size),AL_CONST char * fmt,...)277 int datedit_select(AL_CONST char *(*list_getter)(int index, int *list_size), AL_CONST char *fmt, ...)
278 {
279    va_list args;
280    char buf[1024];
281    int c, num;
282 
283    va_start(args, fmt);
284    vsprintf(buf, fmt, args);
285    va_end(args);
286 
287    /* If there is only one choice, select it automatically. If the list is */
288    /*  empty, return immediately. */
289    list_getter(-1, &num);
290    if (num<=1) return num-1;
291 
292    printf("%s:\n", buf);
293    for (c=0; c<num; c++) {
294       printf("% 2d %s\n", c, list_getter(c, NULL));
295    }
296    printf("% 2d %s\n", -1, "Cancel");
297    fflush(stdout);
298    fscanf(stdin, "%d", &c);
299    if (c>num)
300       c = num-1;
301    return c;
302 }
303 
304 
305 
306 /* checks if a string is one of the names specified on the command line */
is_name(AL_CONST char * name)307 static int is_name(AL_CONST char *name)
308 {
309    char str1[256], str2[256];
310    int i, e;
311 
312    for (i=0; i<opt_numnames; i++) {
313       if ((stricmp(name, opt_namelist[i]) == 0) ||
314 	  (strcmp(opt_namelist[i], "*") == 0)) {
315 	 opt_usedname[i] = TRUE;
316 	 return TRUE;
317       }
318       else {
319 	 for (e=0; e<(int)strlen(opt_namelist[i]); e++) {
320 	    if (opt_namelist[i][e] == '*') {
321 	       strncpy(str1, opt_namelist[i], e);
322 	       str1[e] = 0;
323 	       strncpy(str2, name, e);
324 	       str2[e] = 0;
325 	       if (strcmp(str1, str2) == 0) {
326 		  opt_usedname[i] = TRUE;
327 		  return TRUE;
328 	       }
329 	    }
330 	 }
331       }
332    }
333 
334    return FALSE;
335 }
336 
337 
338 
339 /* does a view operation */
do_view(AL_CONST DATAFILE * dat,AL_CONST char * parentname)340 static void do_view(AL_CONST DATAFILE *dat, AL_CONST char *parentname)
341 {
342    int i, j;
343    AL_CONST char *name;
344    DATAFILE_PROPERTY *prop;
345    char tmp[256];
346 
347    for (i=0; dat[i].type != DAT_END; i++) {
348       name = get_datafile_property(dat+i, DAT_NAME);
349       strcpy(tmp, parentname);
350       strcat(tmp, name);
351 
352       if ((opt_numnames <= 0) || (is_name(tmp))) {
353 	 if (opt_verbose)
354 	    printf("\n");
355 
356 	 printf("- %c%c%c%c - %s%-*s - %s\n",
357 		  (dat[i].type>>24)&0xFF, (dat[i].type>>16)&0xFF,
358 		  (dat[i].type>>8)&0xFF, dat[i].type&0xFF,
359 		  parentname, 28-(int)strlen(parentname), name,
360 		  datedit_desc(dat+i));
361 
362 	 if (opt_verbose) {
363 	    prop = dat[i].prop;
364 	    if (prop) {
365 	       for (j=0; prop[j].type != DAT_END; j++) {
366 		  printf("  . %c%c%c%c '%s'\n",
367 			   (prop[j].type>>24)&0xFF, (prop[j].type>>16)&0xFF,
368 			   (prop[j].type>>8)&0xFF, prop[j].type&0xFF,
369 			   prop[j].dat);
370 	       }
371 	    }
372 	 }
373       }
374 
375       if (dat[i].type == DAT_FILE) {
376 	 strcat(tmp, "/");
377 	 do_view((DATAFILE *)dat[i].dat, tmp);
378       }
379    }
380 }
381 
382 
383 
384 /* does an export operation */
do_export(DATAFILE * dat,char * parentname)385 static void do_export(DATAFILE *dat, char *parentname)
386 {
387    int i;
388    AL_CONST char *name;
389    char tmp[256];
390 
391    for (i=0; dat[i].type != DAT_END; i++) {
392       name = get_datafile_property(dat+i, DAT_NAME);
393       strcpy(tmp, parentname);
394       strcat(tmp, name);
395 
396       if (is_name(tmp)) {
397 	 if (!datedit_export(dat+i, opt_outputname)) {
398 	    err = 1;
399 	    return;
400 	 }
401       }
402       else {
403 	 if (dat[i].type == DAT_FILE) {
404 	    strcat(tmp, "/");
405 	    do_export((DATAFILE *)dat[i].dat, tmp);
406 	    if (err)
407 	       return;
408 	 }
409       }
410    }
411 }
412 
413 
414 
415 /* deletes objects from the datafile */
do_delete(DATAFILE ** dat,char * parentname)416 static void do_delete(DATAFILE **dat, char *parentname)
417 {
418    int i;
419    AL_CONST char *name;
420    char tmp[256];
421 
422    for (i=0; (*dat)[i].type != DAT_END; i++) {
423       name = get_datafile_property((*dat)+i, DAT_NAME);
424       strcpy(tmp, parentname);
425       strcat(tmp, name);
426 
427       if (is_name(tmp)) {
428 	 printf("Deleting %s\n", tmp);
429 	 *dat = datedit_delete(*dat, i);
430 	 changed = TRUE;
431 	 i--;
432       }
433       else {
434 	 if ((*dat)[i].type == DAT_FILE) {
435 	    DATAFILE *dattmp = (*dat)[i].dat;
436 	    strcat(tmp, "/");
437 	    do_delete(&dattmp, tmp);
438 	    (*dat)[i].dat = dattmp;
439 	 }
440       }
441    }
442 }
443 
444 
445 
446 /* open a sub-datafile in the parent datafile */
open_sub_datafile(DATAFILE * parent,AL_CONST char * name)447 static DATAFILE *open_sub_datafile(DATAFILE *parent, AL_CONST char *name)
448 {
449    DATAFILE *dat;
450    int c;
451 
452    /* Return the datafile if it already exists. */
453    for (c=0; parent[c].type != DAT_END; c++) {
454       if ((parent[c].type == DAT_FILE) && (stricmp(name, get_datafile_property(parent+c, DAT_NAME)) == 0))
455 	 return parent[c].dat;
456    }
457 
458    /* Otherwise create a new datafile. */
459    printf("Creating sub-datafile %s\n", name);
460 
461    dat = malloc(sizeof(DATAFILE));
462    dat->dat = NULL;
463    dat->type = DAT_END;
464    dat->size = 0;
465    dat->prop = NULL;
466 
467    return dat;
468 }
469 
470 
471 
472 /* close a sub-datafile from the parent datafile */
close_sub_datafile(DATAFILE * parent,AL_CONST char * name,DATAFILE * dat)473 static DATAFILE *close_sub_datafile(DATAFILE *parent, AL_CONST char *name, DATAFILE *dat)
474 {
475    int c;
476 
477    /* Adjust the datafile if it already exists. */
478    for (c=0; parent[c].type != DAT_END; c++) {
479       if ((parent[c].type == DAT_FILE) && (stricmp(name, get_datafile_property(parent+c, DAT_NAME)) == 0)) {
480 	 parent[c].dat = dat;
481 	 return parent;
482       }
483    }
484 
485    /* Otherwise insert the datafile. */
486    return datedit_insert(parent, NULL, name, DAT_FILE, dat, 0);
487 }
488 
489 
490 
491 /* adds a file to the archive */
do_add_file(AL_CONST char * filename,int attrib,void * param)492 static int do_add_file(AL_CONST char *filename, int attrib, void *param)
493 {
494    DATEDIT_GRAB_PARAMETERS params;
495    DATAFILE **dat = param;
496    DATAFILE *d;
497    char fname[256];
498    char name[256];
499    int c;
500 
501    canonicalize_filename(fname, filename, sizeof(fname));
502 
503    strcpy(name, get_filename(fname));
504 
505    if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0))
506       return 0;
507 
508    if (!opt_keepnames) {
509       strupr(name);
510 
511       for (c=0; name[c]; c++)
512 	 if (name[c] == '.')
513 	    name[c] = '_';
514    }
515 
516    if (attrib & FA_DIREC) {
517       DATAFILE *sub_dat = open_sub_datafile(*dat, name);
518 
519       if (!sub_dat) {
520 	 fprintf(stderr, "Error: failed to create sub-datafile %s\n", name);
521 	 err = 1;
522 	 return -1;
523       }
524 
525       append_filename(fname, fname, "*", sizeof(fname));
526 
527       if (for_each_file_ex(fname, 0, ~attrib_ok, do_add_file, &sub_dat) <= 0) {
528 	 fprintf(stderr, "Error: failed to add objects to %s\n", name);
529 	 err = 1;
530 	 return -1;
531       }
532 
533       *dat = close_sub_datafile(*dat, name, sub_dat);
534       changed = TRUE;
535       return 0;
536    }
537 
538    params.datafile = canonical_datafilename;
539    params.filename = fname;
540    params.name = name;
541    params.type = datedit_clean_typename(opt_objecttype);
542    params.x = opt_gridx;
543    params.y = opt_gridy;
544    params.w = opt_gridw;
545    params.h = opt_gridh;
546    params.colordepth = opt_colordepth;
547    params.relative = opt_relf;
548 
549    for (c=0; (*dat)[c].type != DAT_END; c++) {
550       if (stricmp(name, get_datafile_property(*dat+c, DAT_NAME)) == 0) {
551 	 printf("Replacing %s -> %s\n", fname, name);
552 	 if (!datedit_grabreplace(*dat+c, &params)) {
553 	    err = 1;
554 	    return -1;
555 	 }
556 	 else {
557 	    changed = TRUE;
558 	    return 0;
559 	 }
560       }
561    }
562 
563    printf("Inserting %s -> %s\n", fname, name);
564    d = datedit_grabnew(*dat, &params);
565    if (!d) {
566       err = 1;
567       return -1;
568    }
569    else {
570       *dat = d;
571       changed = TRUE;
572       return 0;
573    }
574 }
575 
576 
577 
578 /* does an update operation */
do_update(DATAFILE * dat,int force,char * parentname)579 static void do_update(DATAFILE *dat, int force, char *parentname)
580 {
581    int i;
582    AL_CONST char *name;
583    char tmp[256];
584 
585    for (i=0; dat[i].type != DAT_END; i++) {
586       name = get_datafile_property(dat+i, DAT_NAME);
587       strcpy(tmp, parentname);
588       strcat(tmp, name);
589 
590       if (dat[i].type == DAT_FILE) {
591 	 strcat(tmp, "/");
592 	 do_update((DATAFILE *)dat[i].dat, force, tmp);
593 	 if (err)
594 	    return;
595       }
596       else if ((opt_numnames <= 0) || (is_name(tmp))) {
597 	 if (!datedit_update(dat+i, canonical_datafilename, force, opt_verbose, &changed)) {
598 	    err = 1;
599 	    return;
600 	 }
601       }
602    }
603 }
604 
605 
606 
607 /* changes object properties */
do_set_props(DATAFILE * dat,char * parentname)608 static void do_set_props(DATAFILE *dat, char *parentname)
609 {
610    int i, j;
611    AL_CONST char *name;
612    char tmp[256];
613    char propname[256], *propvalue;
614    int type;
615 
616    for (i=0; dat[i].type != DAT_END; i++) {
617       name = get_datafile_property(dat+i, DAT_NAME);
618       strcpy(tmp, parentname);
619       strcat(tmp, name);
620 
621       if (is_name(tmp)) {
622 	 for (j=0; j<opt_numprops; j++) {
623 	    strcpy(propname, opt_proplist[j]);
624 	    propvalue = strchr(propname, '=');
625 	    if (propvalue) {
626 	       *propvalue = 0;
627 	       propvalue++;
628 	    }
629 	    else
630 	       propvalue = "";
631 
632 	    type = datedit_clean_typename(propname);
633 
634 	    if (opt_verbose) {
635 	       if (*propvalue) {
636 		  printf("%s: setting property %c%c%c%c = '%s'\n",
637 			 tmp, type>>24, (type>>16)&0xFF,
638 			 (type>>8)&0xFF, type&0xFF, propvalue);
639 	       }
640 	       else {
641 		  printf("%s: clearing property %c%c%c%c\n",
642 			 tmp, type>>24, (type>>16)&0xFF,
643 			 (type>>8)&0xFF, type&0xFF);
644 	       }
645 	    }
646 
647 	    datedit_set_property(dat+i, type, propvalue);
648 	    changed = TRUE;
649 	 }
650       }
651 
652       if (dat[i].type == DAT_FILE) {
653 	 strcat(tmp, "/");
654 	 do_set_props((DATAFILE *)dat[i].dat, tmp);
655       }
656    }
657 }
658 
659 
660 
661 /* selects a specific palette */
do_setpal(DATAFILE ** dat,char * parentname)662 static void do_setpal(DATAFILE **dat, char *parentname)
663 {
664    int i;
665    AL_CONST char *name;
666    char tmp[256];
667 
668    for (i=0; (*dat)[i].type != DAT_END; i++) {
669       name = get_datafile_property((*dat)+i, DAT_NAME);
670       strcpy(tmp, parentname);
671       strcat(tmp, name);
672 
673       if (stricmp(tmp, opt_palette) == 0) {
674 	 if ((*dat)[i].type != DAT_PALETTE) {
675 	    printf("Error: %s is not a palette object\n", tmp);
676 	    err = 1;
677 	    return;
678 	 }
679 	 printf("Using palette %s\n", tmp);
680 	 memcpy(datedit_current_palette, (*dat)[i].dat, sizeof(PALETTE));
681 	 select_palette(datedit_current_palette);
682 	 return;
683       }
684       else {
685 	 if ((*dat)[i].type == DAT_FILE) {
686 	    DATAFILE *dattmp = (*dat)[i].dat;
687 	    strcat(tmp, "/");
688 	    do_setpal(&dattmp, tmp);
689 	    (*dat)[i].dat = dattmp;
690 	 }
691       }
692    }
693 
694    printf("Error: %s not found\n", opt_palette);
695    err = 1;
696 }
697 
698 
699 
700 /* recursive helper for writing out datafile dependencies */
save_dependencies(DATAFILE * dat,FILE * f,int * depth)701 static void save_dependencies(DATAFILE *dat, FILE *f, int *depth)
702 {
703    AL_CONST char *orig;
704    int c, i;
705    int hasspace;
706 
707    for (c=0; dat[c].type != DAT_END; c++) {
708       orig = get_datafile_property(dat+c, DAT_ORIG);
709 
710       if ((orig) && (orig[0])) {
711 	 if (*depth + strlen(orig) > 56) {
712 	    fprintf(f, " \\\n\t\t");
713 	    *depth = 0;
714 	 }
715 	 else {
716 	    fprintf(f, " ");
717 	    (*depth)++;
718 	 }
719 
720 	 if (strchr(orig, ' ')) {
721 	    hasspace = TRUE;
722 	    fputc('"', f);
723 	    (*depth) += 2;
724 	 }
725 	 else
726 	    hasspace = FALSE;
727 
728 	 for (i=0; orig[i]; i++) {
729 	    if (orig[i] == '\\')
730 	       fputc('/', f);
731 	    else
732 	       fputc(orig[i], f);
733 	    (*depth)++;
734 	 }
735 
736 	 if (hasspace)
737 	    fputc('"', f);
738       }
739 
740       if (dat[c].type == DAT_FILE)
741 	 save_dependencies((DATAFILE *)dat[c].dat, f, depth);
742    }
743 }
744 
745 
746 
747 /* writes out a makefile dependency rule */
do_save_dependencies(DATAFILE * dat,char * srcname,char * depname)748 static int do_save_dependencies(DATAFILE *dat, char *srcname, char *depname)
749 {
750    char *pretty_name;
751    char tm[80];
752    time_t now;
753    FILE *f;
754    int c;
755 
756    pretty_name = datedit_pretty_name(srcname, "dat", FALSE);
757    datedit_msg("Writing makefile dependencies into %s", depname);
758 
759    f = fopen(depname, "w");
760    if (f) {
761       time(&now);
762       strcpy(tm, asctime(localtime(&now)));
763       for (c=0; tm[c]; c++)
764 	 if ((tm[c] == '\r') || (tm[c] == '\n'))
765 	    tm[c] = 0;
766 
767       fprintf(f, "# Allegro datafile make dependencies, produced by dat v" ALLEGRO_VERSION_STR ", " ALLEGRO_PLATFORM_STR "\n");
768       fprintf(f, "# Datafile: %s\n", pretty_name);
769       fprintf(f, "# Date: %s\n", tm);
770       fprintf(f, "# Do not hand edit!\n\n");
771 
772       if (opt_headername)
773 	 fprintf(f, "%s %s :", pretty_name, opt_headername);
774       else
775 	 fprintf(f, "%s :", pretty_name);
776 
777       c = 0xFF;
778       save_dependencies(dat, f, &c);
779 
780       fprintf(f, " \\\n\n\tdat -u %s", pretty_name);
781 
782       if (opt_headername)
783 	 fprintf(f, " -h %s", opt_headername);
784 
785       if (opt_password)
786 	 fprintf(f, " -007 %s", opt_password);
787 
788       fprintf(f, "\n");
789       fclose(f);
790    }
791    else {
792       datedit_error("Error writing %s", depname);
793       return FALSE;
794    }
795 
796    return TRUE;
797 }
798 
799 
800 
main(int argc,char * argv[])801 int main(int argc, char *argv[])
802 {
803    int c, colorconv_mode = 0;
804    int *opt_fixed_prop = NULL;
805    DATAFILE *datafile = NULL;
806 
807    if (install_allegro(SYSTEM_NONE, &errno, atexit) != 0)
808       return 1;
809    datedit_init();
810 
811    for (c=0; c<PAL_SIZE; c++)
812       datedit_current_palette[c] = desktop_palette[c];
813 
814    for (c=1; c<argc; c++) {
815       if (argv[c][0] == '-') {
816 
817 	 switch (utolower(argv[c][1])) {
818 
819 	    case 'd':
820 	       if (stricmp(argv[c]+2, "ither") == 0) {
821 		  colorconv_mode |= COLORCONV_DITHER;
822 		  break;
823 	       }
824 	       /* fall through */
825 
826 	    case 'a':
827 	    case 'e':
828 	    case 'l':
829 	    case 'u':
830 	    case 'w':
831 	    case 'x':
832 	       if (opt_command) {
833 		  usage();
834 		  return 1;
835 	       }
836 	       opt_command = utolower(argv[c][1]);
837 	       break;
838 
839 	    case 'b':
840 	       if ((opt_colordepth > 0) || (c >= argc-1)) {
841 		  usage();
842 		  return 1;
843 	       }
844 	       opt_colordepth = atoi(argv[++c]);
845 	       if ((opt_colordepth != 8) && (opt_colordepth != 15) &&
846 		   (opt_colordepth != 16) && (opt_colordepth != 24) &&
847 		   (opt_colordepth != 32)) {
848 		  usage();
849 		  return 1;
850 	       }
851 	       break;
852 
853 	    case 'c':
854 	       if ((opt_compression >= 0) ||
855 		   (argv[c][2] < '0') || (argv[c][2] > '2')) {
856 		  usage();
857 		  return 1;
858 	       }
859 	       opt_compression = argv[c][2] - '0';
860 	       break;
861 
862 	    case 'f':
863 	       opt_relf = TRUE;
864 	       break;
865 
866 	    case 'g':
867 	       if ((opt_gridx > 0) || (c >= argc-4)) {
868 		  usage();
869 		  return 1;
870 	       }
871 	       opt_gridx = atoi(argv[++c]);
872 	       opt_gridy = atoi(argv[++c]);
873 	       opt_gridw = atoi(argv[++c]);
874 	       opt_gridh = atoi(argv[++c]);
875 	       if ((opt_gridx <  0) || (opt_gridy <  0) ||
876 		   (opt_gridw <= 0) || (opt_gridh <= 0)) {
877 		  usage();
878 		  return 1;
879 	       }
880 	       break;
881 
882 	    case 'h':
883 	       if ((opt_headername) || (c >= argc-1)) {
884 		  usage();
885 		  return 1;
886 	       }
887 	       opt_headername = argv[++c];
888 	       break;
889 
890 	    case 'k':
891 	       opt_keepnames = TRUE;
892 	       break;
893 
894 	    case 'm':
895 	       if ((opt_dependencyfile) || (c >= argc-1)) {
896 		  usage();
897 		  return 1;
898 	       }
899 	       opt_dependencyfile = argv[++c];
900 	       break;
901 
902 	    case 'n':
903 	       if ((opt_sort >= 0) ||
904 		   (argv[c][2] < '0') || (argv[c][2] > '1')) {
905 		  usage();
906 		  return 1;
907 	       }
908 	       opt_sort = argv[c][2] - '0';
909 	       break;
910 
911 	    case 'o':
912 	       if ((opt_outputname) || (c >= argc-1)) {
913 		  usage();
914 		  return 1;
915 	       }
916 	       opt_outputname = argv[++c];
917 	       break;
918 
919 	    case 'p':
920 	       if ((utolower(argv[c][2]) == 'a') &&
921 		   (utolower(argv[c][3]) == 'l') &&
922 		   (argv[c][4] == 0)) {
923 		  if ((opt_palette) || (c >= argc-1)) {
924 		     usage();
925 		     return 1;
926 		  }
927 		  opt_palette = argv[++c];
928 	       }
929 	       else {
930 		  if ((opt_prefixstring) || (c >= argc-1)) {
931 		     usage();
932 		     return 1;
933 		  }
934 		  opt_prefixstring = argv[++c];
935 	       }
936 	       break;
937 
938 	    case 'r':
939 	       attrib_ok |= FA_DIREC;
940 	       break;
941 
942 	    case 's':
943 	       if (argv[c][2] == '-') {
944 		  allocate(opt_numfixedprops + 1);
945 		  opt_fixedproplist[opt_numfixedprops++] = argv[c]+3;
946 	       }
947 	       else {
948 		  if ((opt_strip >= 0) ||
949 		      (argv[c][2] < '0') || (argv[c][2] > '2')) {
950 		     usage();
951 		     return 1;
952 	          }
953 	          opt_strip = argv[c][2] - '0';
954 	       }
955 	       break;
956 
957 	    case 't':
958 	       if (stricmp(argv[c]+2, "ransparency") == 0) {
959 		  colorconv_mode |= COLORCONV_KEEP_TRANS;
960 		  break;
961 	       }
962 
963 	       if ((opt_objecttype) || (c >= argc-1)) {
964 		  usage();
965 		  return 1;
966 	       }
967 	       opt_objecttype = argv[++c];
968 	       break;
969 
970 	    case 'v':
971 	       opt_verbose = TRUE;
972 	       break;
973 
974 	    case '0':
975 	       if ((opt_password) || (c >= argc-1)) {
976 		  usage();
977 		  return 1;
978 	       }
979 	       opt_password = argv[++c];
980 	       break;
981 
982 	    case '-':
983 	       if (stricmp(argv[c]+2, "help") == 0) {
984 	          usage();
985 	          return 1;
986 	       }
987 	       break;
988 
989 	    case '?':
990 	       usage();
991 	       return 1;
992 
993 	    default:
994 	       printf("Unknown option '%s'\n", argv[c]);
995 	       return 1;
996 	 }
997       }
998       else {
999 	 if (strchr(argv[c], '=')) {
1000 	    allocate(opt_numprops + 1);
1001 	    opt_proplist[opt_numprops++] = argv[c];
1002 	 }
1003 	 else {
1004 	    if (!opt_datafilename)
1005 	       opt_datafilename = argv[c];
1006 	    else {
1007 	       allocate(opt_numnames + 1);
1008 	       opt_namelist[opt_numnames] = argv[c];
1009 	       opt_usedname[opt_numnames] = FALSE;
1010 	       opt_numnames++;
1011 	    }
1012 	 }
1013       }
1014    }
1015 
1016    if ((!opt_datafilename) ||
1017        ((!opt_command) &&
1018 	(opt_compression < 0) &&
1019 	(opt_strip < 0) &&
1020 	(opt_sort < 0) &&
1021 	(!opt_numprops) &&
1022 	(!opt_headername) &&
1023 	(!opt_dependencyfile))) {
1024       usage();
1025       return 1;
1026    }
1027 
1028    canonicalize_filename(canonical_datafilename, opt_datafilename, sizeof(canonical_datafilename));
1029 
1030    if (colorconv_mode)
1031       set_color_conversion(colorconv_mode);
1032    else
1033       set_color_conversion(COLORCONV_NONE);
1034 
1035    datafile = datedit_load_datafile(opt_datafilename, FALSE, opt_password);
1036 
1037    if (datafile) {
1038 
1039       if (opt_palette)
1040 	 do_setpal(&datafile, "");
1041 
1042       if (!err) {
1043 	 switch (opt_command) {
1044 
1045 	    case 'a':
1046 	       if (!opt_numnames) {
1047 		  printf("No files specified for addition\n");
1048 		  err = 1;
1049 	       }
1050 	       else {
1051 		  for (c=0; c<opt_numnames; c++) {
1052 		     if (for_each_file_ex(opt_namelist[c], 0, ~attrib_ok, do_add_file, &datafile) <= 0) {
1053 			fprintf(stderr, "Error: %s not found\n", opt_namelist[c]);
1054 			err = 1;
1055 			break;
1056 		     }
1057 		     else
1058 			opt_usedname[c] = TRUE;
1059 		  }
1060 	       }
1061 	       break;
1062 
1063 	    case 'd':
1064 	       if (!opt_numnames) {
1065 		  printf("No objects specified for deletion\n");
1066 		  err = 1;
1067 	       }
1068 	       else
1069 		  do_delete(&datafile, "");
1070 	       break;
1071 
1072 	    case 'e':
1073 	    case 'x':
1074 	       if (!opt_numnames) {
1075 		  printf("No objects specified: use '*' to extract everything\n");
1076 		  err = 1;
1077 	       }
1078 	       else
1079 		  do_export(datafile, "");
1080 	       break;
1081 
1082 	    case 'l':
1083 	       do_view(datafile, "");
1084 	       break;
1085 
1086 	    case 'u':
1087 	       do_update(datafile, FALSE, "");
1088 	       break;
1089 
1090 	    case 'w':
1091 	       do_update(datafile, TRUE, "");
1092 	       break;
1093 	 }
1094       }
1095 
1096       if (!err) {
1097 	 if (opt_command) {
1098 	    for (c=0; c<opt_numnames; c++) {
1099 	       if (!opt_usedname[c]) {
1100 		  fprintf(stderr, "Error: %s not found\n", opt_namelist[c]);
1101 		  err = 1;
1102 	       }
1103 	    }
1104 	 }
1105 
1106 	 if (opt_numprops > 0) {
1107 	    if (!opt_numnames) {
1108 	       printf("No objects specified for setting properties\n");
1109 	       err = 1;
1110 	    }
1111 	    else {
1112 	       for (c=0; c<opt_numnames; c++)
1113 		  opt_usedname[c] = FALSE;
1114 
1115 	       do_set_props(datafile, "");
1116 
1117 	       for (c=0; c<opt_numnames; c++) {
1118 		  if (!opt_usedname[c]) {
1119 		     fprintf(stderr, "Error: %s not found\n", opt_namelist[c]);
1120 		     err = 1;
1121 		  }
1122 	       }
1123 	    }
1124 	 }
1125 
1126 	 if (opt_numfixedprops > 0) {
1127 	    if (opt_strip < 0) {
1128 	       printf("Error: no strip mode\n");
1129 	       err = 1;
1130 	    }
1131 	    else {
1132 	       opt_fixed_prop = malloc((opt_numfixedprops+1)*sizeof(int));
1133 
1134 	       for (c=0; c<opt_numfixedprops; c++)
1135 		  opt_fixed_prop[c] = datedit_clean_typename(opt_fixedproplist[c]);
1136 
1137 	       opt_fixed_prop[c] = 0;  /* end of array delimiter */
1138 	    }
1139 	 }
1140       }
1141 
1142       if ((!err) && ((changed) || (opt_compression >= 0) || (opt_strip >= 0) || (opt_sort >= 0))) {
1143 	 DATEDIT_SAVE_DATAFILE_OPTIONS options;
1144 
1145 	 options.pack = opt_compression;
1146 	 options.strip = opt_strip;
1147 	 options.sort = opt_sort;
1148 	 options.verbose = opt_verbose;
1149 	 options.write_msg = TRUE;
1150 	 options.backup = FALSE;
1151 
1152 	 if (!datedit_save_datafile(datafile, opt_datafilename, opt_fixed_prop, &options, opt_password))
1153 	    err = 1;
1154       }
1155 
1156       if ((!err) && (opt_headername))
1157 	 if (!datedit_save_header(datafile, opt_datafilename, opt_headername, "dat", opt_prefixstring, opt_verbose))
1158 	    err = 1;
1159 
1160       if ((!err) && (opt_dependencyfile))
1161 	 if (!do_save_dependencies(datafile, opt_datafilename, opt_dependencyfile))
1162 	    err = 1;
1163 
1164       if (opt_fixed_prop)
1165 	 free(opt_fixed_prop);
1166 
1167       unload_datafile(datafile);
1168    }
1169 
1170    return err;
1171 }
1172 
1173 END_OF_MAIN()
1174