1 /* aNetHack 0.0.1 dlb_main.c $ANH-Date: 1432512785 2015/05/25 00:13:05 $ $ANH-Branch: master $:$ANH-Revision: 1.10 $ */
2 /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */
3 /* aNetHack may be freely redistributed. See license for details. */
5 /* data librarian; only useful if you are making the library version, DLBLIB
10 #if !defined(O_WRONLY) && !defined(MAC) && !defined(AZTEC_C)
13 #if defined(__DJGPP__)
17 static void FDECL(grow_ld
, (libdir
**, int *, int));
18 static void FDECL(xexit
, (int));
23 #define DLB_DIRECTORY "Directory" /* name of lib directory */
24 #define LIBLISTFILE "dlb.lst" /* default list file */
26 /* library functions (from dlb.c) */
27 extern boolean
FDECL(open_library
, (const char *, library
*));
28 extern void FDECL(close_library
, (library
*));
30 char *FDECL(eos
, (char *)); /* also used by dlb.c */
31 FILE *FDECL(fopen_datafile
, (const char *, const char *));
33 static void FDECL(Write
, (int, char *, long));
34 static void NDECL(usage
);
35 static void NDECL(verbose_help
);
36 static void FDECL(write_dlb_directory
,
37 (int, int, libdir
*, long, long, long));
39 static char default_progname
[] = "dlb";
40 static char *progname
= default_progname
;
42 /* fixed library and list file names - can be overridden if necessary */
43 static const char *library_file
= DLBFILE
;
44 static const char *list_file
= LIBLISTFILE
;
47 static char origdir
[255] = "";
54 #define DLB_FILES_ALLOC 200 /* initial # of files we'll handle; can grow */
55 #define DLB_VERS 1 /* version of dlb file we will write */
58 * How the file is encoded within the library. Don't use a space
59 * because (at least) the SunOS 4.1.3 C library will eat the white
60 * space instead of preserving it like the man page says it should.
62 #define ENC_NORMAL 'n' /* normal: not compressed in any way */
65 * If you know tar, you have a small clue how to use this (note: - does
66 * NOT mean stdin/stdout).
68 * dlb COMMANDoptions arg... files...
70 * dlb x extract all files
71 * dlb c build the archive
72 * dlb t list the archive
75 * f file specify archive file (default DLBFILE)
76 * I file specify file for list of files (default LIBLISTFILE)
77 * C dir chdir to dir (used ONCE, not like tar's -C)
83 (void) printf("Usage: %s [ctxCIfv] arguments... [files...]\n", progname
);
84 (void) printf(" default library is %s\n", library_file
);
85 (void) printf(" default list file is %s\n", list_file
);
92 static const char *long_help
[] = {
93 "", "dlb COMMANDoptions args... files...", " commands:",
94 " dlb ? print this text", " dlb h ditto",
95 " dlb x extract all files", " dlb c create the archive",
96 " dlb t list table of contents", " options:",
97 " v verbose operation",
98 " f file specify archive file name",
99 " I file specify file for list of file names",
100 " C dir change directory before processing any files", "",
105 for (str
= long_help
; *str
; str
++)
106 (void) printf("%s\n", *str
);
116 #if defined(MSDOS) && !defined(__DJGPP__)
120 printf("%d Length specified for write() too large for 16 bit env.",
124 slen
= (unsigned short) len
;
125 if (write(out
, buf
, slen
) != slen
) {
127 if (write(out
, buf
, len
) != len
) {
129 printf("Write Error in '%s'\n", library_file
);
143 /* open_library(dlb.c) needs this (which normally comes from src/files.c) */
145 fopen_datafile(filename
, mode
)
146 const char *filename
, *mode
;
148 return fopen(filename
, mode
);
162 int ap
= 2; /* argument pointer */
163 int cp
; /* command pointer */
164 int iseen
= 0, fseen
= 0, verbose
= 0; /* flags */
168 if (argc
> 0 && argv
[0] && *argv
[0])
171 progname
= vms_basename(progname
);
179 for (cp
= 0; argv
[1][cp
]; cp
++) {
180 switch (argv
[1][cp
]) {
182 usage(); /* doesn't return */
183 case '-': /* silently ignore */
192 list_file
= argv
[ap
++];
194 printf("Warning: multiple I options. Previous ignored.\n");
200 library_file
= argv
[ap
++];
202 printf("Warning: multiple f options. Previous ignored.\n");
209 if (!getcwd(origdir
, sizeof(origdir
))) {
210 printf("Can't get current directory.\n");
214 if (chdir(argv
[ap
++])) {
215 printf("Can't chdir to %s\n", argv
[--ap
]);
226 printf("Only one of t,x,c may be specified.\n");
229 action
= argv
[1][cp
];
234 if (argv
[ap
] && iseen
) {
235 printf("Too many arguments.\n");
241 printf("Internal error - action.\n");
244 case 't': /* list archive */
245 if (!open_library(library_file
, &lib
)) {
246 printf("Can't open dlb file\n");
250 for (i
= 0; i
< lib
.nentries
; i
++) {
252 printf("%-14s %6ld %6ld\n", lib
.dir
[i
].fname
,
253 lib
.dir
[i
].foffset
, lib
.dir
[i
].fsize
);
255 printf("%s\n", lib
.dir
[i
].fname
);
259 printf("Revision:%ld File count:%ld String size:%ld\n", lib
.rev
,
260 lib
.nentries
, lib
.strsize
);
265 case 'x': { /* extract archive contents */
267 long remainder
, total_read
;
270 if (!open_library(library_file
, &lib
)) {
271 printf("Can't open dlb file\n");
275 for (i
= 0; i
< lib
.nentries
; i
++) {
277 /* if files are listed, see if current is wanted */
279 for (c
= ap
; c
< argc
; c
++)
280 if (!FILENAME_CMP(lib
.dir
[i
].fname
, argv
[c
]))
284 } else if (!FILENAME_CMP(lib
.dir
[i
].fname
, DLB_DIRECTORY
)) {
286 * Don't extract the directory unless the user
287 * specifically asks for it.
289 * Perhaps we should never extract the directory???
293 fseek(lib
.fdata
, lib
.dir
[i
].foffset
, SEEK_SET
);
295 f
= open(lib
.dir
[i
].fname
,
296 O_WRONLY
| O_TRUNC
| O_BINARY
| O_CREAT
, 0640);
298 printf("Can't create '%s'\n", lib
.dir
[i
].fname
);
302 /* read chunks from library and write them out */
305 remainder
= lib
.dir
[i
].fsize
- total_read
;
306 if (remainder
> (long) sizeof(buf
))
307 r
= (int) sizeof(buf
);
311 n
= fread(buf
, 1, r
, lib
.fdata
);
313 printf("Read Error in '%s'\n", lib
.dir
[i
].fname
);
316 if (write(f
, buf
, n
) != n
) {
317 printf("Write Error in '%s'\n", lib
.dir
[i
].fname
);
322 } while (total_read
!= lib
.dir
[i
].fsize
);
327 printf("x %s\n", lib
.dir
[i
].fname
);
334 case 'c': /* create archive */
339 int fd
, out
, nfiles
= 0;
340 long dir_size
, slen
, flen
, fsiz
;
341 boolean rewrite_directory
= FALSE
;
344 * Get names from either/both an argv list and a file
345 * list. This does not do any duplicate checking
348 grow_ld(&ld
, &ldlimit
, DLB_FILES_ALLOC
);
350 /* get file name in argv list */
352 for (; ap
< argc
; ap
++, nfiles
++) {
353 if (nfiles
== ldlimit
)
354 grow_ld(&ld
, &ldlimit
, DLB_FILES_ALLOC
/ 5);
355 ld
[nfiles
].fname
= (char *) alloc(strlen(argv
[ap
]) + 1);
356 Strcpy(ld
[nfiles
].fname
, argv
[ap
]);
361 /* want to do a list file */
362 FILE *list
= fopen(list_file
, "r");
364 printf("Can't open %s\n", list_file
);
368 /* get file names, one per line */
369 for (; fgets(buf
, sizeof(buf
), list
); nfiles
++) {
370 if (nfiles
== ldlimit
)
371 grow_ld(&ld
, &ldlimit
, DLB_FILES_ALLOC
/ 5);
372 *(eos(buf
) - 1) = '\0'; /* strip newline */
373 ld
[nfiles
].fname
= (char *) alloc(strlen(buf
) + 1);
374 Strcpy(ld
[nfiles
].fname
, buf
);
380 printf("No files to archive\n");
385 * Get file sizes and name string length. Don't include
386 * the directory information yet.
388 for (i
= 0, slen
= 0, flen
= 0; i
< nfiles
; i
++) {
389 fd
= open(ld
[i
].fname
, O_RDONLY
| O_BINARY
, 0);
391 printf("Can't open %s\n", ld
[i
].fname
);
394 ld
[i
].fsize
= lseek(fd
, 0, SEEK_END
);
395 ld
[i
].foffset
= flen
;
397 slen
+= strlen(ld
[i
].fname
); /* don't add null (yet) */
402 /* open output file */
404 open(library_file
, O_RDWR
| O_TRUNC
| O_BINARY
| O_CREAT
, FCMASK
);
406 printf("Can't open %s for output\n", library_file
);
410 /* caculate directory size */
411 dir_size
= 40 /* header line (see below) */
412 + ((nfiles
+ 1) * 11) /* handling+file offset+SP+newline */
413 + slen
+ strlen(DLB_DIRECTORY
); /* file names */
415 /* write directory */
416 write_dlb_directory(out
, nfiles
, ld
, slen
, dir_size
, flen
);
419 /* write each file */
420 for (i
= 0; i
< nfiles
; i
++) {
421 fd
= open(ld
[i
].fname
, O_RDONLY
| O_BINARY
, 0);
423 printf("Can't open input file '%s'\n", ld
[i
].fname
);
427 printf("%s\n", ld
[i
].fname
);
430 while ((r
= read(fd
, buf
, sizeof buf
)) != 0) {
432 printf("Read Error in '%s'\n", ld
[i
].fname
);
435 if (write(out
, buf
, r
) != r
) {
436 printf("Write Error in '%s'\n", ld
[i
].fname
);
442 if (fsiz
!= ld
[i
].fsize
)
443 rewrite_directory
= TRUE
;
444 /* in case directory rewrite is needed */
446 ld
[i
].foffset
= flen
;
450 if (rewrite_directory
) {
452 printf("(rewriting dlb directory info)\n");
453 (void) lseek(out
, 0, SEEK_SET
); /* rewind */
454 write_dlb_directory(out
, nfiles
, ld
, slen
, dir_size
, flen
);
457 for (i
= 0; i
< nfiles
; i
++)
458 free((genericptr_t
) ld
[i
].fname
), ld
[i
].fname
= 0;
459 free((genericptr_t
) ld
), ldlimit
= 0;
477 grow_ld(ld_p
, ldlimit_p
, alloc_incr
)
482 static libdir zerolibdir
;
483 int i
= 0, newlimit
= *ldlimit_p
+ alloc_incr
;
484 libdir
*newld
= (libdir
*) alloc(newlimit
* sizeof *newld
);
487 for (; i
< *ldlimit_p
; ++i
)
488 newld
[i
] = (*ld_p
)[i
];
489 free((genericptr_t
) *ld_p
);
491 *ld_p
= newld
, *ldlimit_p
= newlimit
;
492 for (; i
< *ldlimit_p
; ++i
)
493 (*ld_p
)[i
] = zerolibdir
;
497 write_dlb_directory(out
, nfiles
, ld
, slen
, dir_size
, flen
)
500 long slen
, dir_size
, flen
;
505 sprintf(buf
, "%3ld %8ld %8ld %8ld %8ld\n",
506 (long) DLB_VERS
, /* version of dlb file */
507 (long) nfiles
+ 1, /* # of entries (includes directory) */
508 /* string length + room for nulls */
509 (long) slen
+ strlen(DLB_DIRECTORY
) + nfiles
+ 1,
510 (long) dir_size
, /* start of first file */
511 (long) flen
+ dir_size
); /* total file size */
512 Write(out
, buf
, strlen(buf
));
514 /* write each file entry */
515 #define ENTRY_FORMAT "%c%s %8ld\n"
516 sprintf(buf
, ENTRY_FORMAT
, ENC_NORMAL
, DLB_DIRECTORY
, (long) 0);
517 Write(out
, buf
, strlen(buf
));
518 for (i
= 0; i
< nfiles
; i
++) {
519 sprintf(buf
, ENTRY_FORMAT
, ENC_NORMAL
, /* encoding */
520 ld
[i
].fname
, /* name */
521 ld
[i
].foffset
+ dir_size
); /* offset */
522 Write(out
, buf
, strlen(buf
));
544 const char amiga_version_string
[] = AMIGA_VERSION_STRING
;