2
Copyright (c) 1990-2003 Info-ZIP. All rights reserved.
4
See the accompanying file LICENSE, version 2000-Apr-09 or later
5
(the contents of which are also included in unzip.h) for terms of use.
6
If, for some reason, all these files are missing, the Info-ZIP license
7
also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
9
/*------------------------------------------------------------------------
13
Amiga-specific routines for use with Info-ZIP's UnZip 5.1 and later.
14
See History.5xx for revision history.
22
_abort() (Aztec C only)
23
[dateformat()] (currently not used)
27
------------------------------------------------------------------------*/
30
#define UNZIP_INTERNAL
37
/* Globular varibundus -- now declared in SYSTEM_SPECIFIC_GLOBALS in amiga.h */
39
/* static int created_dir; */ /* used in mapname(), checkdir() */
40
/* static int renamed_fullpath; */ /* ditto */
43
#define MKDIR(path,mode) mkdir(path)
46
#ifndef S_ISCRIPT /* not having one implies you have none */
47
# define S_IARCHIVE 0020 /* not modified since this bit was last set */
48
# define S_IREAD 0010 /* can be opened for reading */
49
# define S_IWRITE 0004 /* can be opened for writing */
50
# define S_IDELETE 0001 /* can be deleted */
51
#endif /* S_ISCRIPT */
54
# define S_IRWD 0015 /* useful combo of Amiga privileges */
58
# define S_IHIDDEN 0200 /* hidden supported in future AmigaDOS (someday) */
59
#endif /* !S_HIDDEN */
62
/* Make sure the number here matches unzvers.h in the *EXACT* form */
63
/* UZ_MAJORVER "." UZ_MINORVER UZ_PATCHLEVEL vvvv No non-digits! */
64
const char version_id[] = "\0$VER: UnZip " UZ_VER_STRING " ("
65
#include "env:VersionDate"
70
static int ispattern(ZCONST char *p)
77
} else if (c == '?' || c == '*')
93
/**********************/
94
/* Function do_wild() */
95
/**********************/
97
char *do_wild(__G__ wildspec)
99
ZCONST char *wildspec; /* only used first time on a given dir */
101
/* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in amiga.h:
102
static DIR *wild_dir = NULL;
103
static ZCONST char *wildname;
104
static char *dirname, matchname[FILNAMSIZ];
105
static int notfirstcall = FALSE, dirnamelen;
110
/* Even when we're just returning wildspec, we *always* do so in
111
* matchname[]--calling routine is allowed to append four characters
112
* to the returned string, and wildspec may be a pointer to argv[].
114
if (!G.notfirstcall) { /* first call: must initialize everything */
115
G.notfirstcall = TRUE;
117
/* avoid needless readdir() scans: */
118
if (!ispattern(wildspec) ||
119
(lok = Lock((char *)wildspec, ACCESS_READ))) {
120
if (lok) UnLock(lok); /* ^^ we ignore wildcard chars if */
121
G.dirnamelen = 0; /* the name matches a real file */
122
strcpy(G.matchname, wildspec);
126
/* break the wildspec into a directory part and a wildcard filename */
127
if ((G.wildname = (ZCONST char *)strrchr(wildspec, '/')) == NULL &&
128
(G.wildname = (ZCONST char *)strrchr(wildspec, ':')) == NULL) {
129
G.dirname = ""; /* current dir */
131
G.wildname = wildspec;
133
++G.wildname; /* point at character after '/' or ':' */
134
G.dirnamelen = G.wildname - wildspec;
135
if ((G.dirname = (char *)malloc(G.dirnamelen+1)) == NULL) {
136
Info(slide, 1, ((char *)slide,
137
"warning: cannot allocate wildcard buffers\n"));
138
strcpy(G.matchname, wildspec);
139
return G.matchname; /* but maybe filespec was not a wildcard */
141
strncpy(G.dirname, wildspec, G.dirnamelen);
142
G.dirname[G.dirnamelen] = 0;
145
if ((G.wild_dir = opendir(G.dirname)) != NULL) {
146
while ((file = readdir(G.wild_dir)) != NULL) {
147
if (match(file->d_name, G.wildname, 1)) { /* ignore case */
148
strcpy(G.matchname, G.dirname);
149
strcpy(G.matchname + G.dirnamelen, file->d_name);
153
/* if we get to here directory is exhausted, so close it */
154
closedir(G.wild_dir);
158
/* return the raw wildspec in case that works (e.g., directory not
159
* searchable, but filespec was not wild and file is readable) */
160
strcpy(G.matchname, wildspec);
164
/* last time through, might have failed opendir but returned raw wildspec */
165
if (G.wild_dir == NULL) {
166
G.notfirstcall = FALSE; /* nothing left to try -- reset */
167
if (G.dirnamelen > 0)
172
/* If we've gotten this far, we've read and matched at least one entry
173
* successfully (in a previous call), so dirname has been copied into
176
while ((file = readdir(G.wild_dir)) != NULL)
177
if (match(file->d_name, G.wildname, 1)) { /* 1 == ignore case */
178
/* strcpy(G.matchname, dirname); */
179
strcpy(G.matchname + G.dirnamelen, file->d_name);
183
closedir(G.wild_dir); /* have read at least one dir entry; nothing left */
185
G.notfirstcall = FALSE; /* reset for new wildspec */
186
if (G.dirnamelen > 0)
190
} /* end function do_wild() */
195
/**********************/
196
/* Function mapattr() */
197
/**********************/
199
int mapattr(__G) /* Amiga version */
202
ulg tmp = G.crec.external_file_attributes;
205
/* Amiga attributes = hsparwed = hidden, script, pure, archive,
206
* read, write, execute, delete */
208
switch (G.pInfo->hostnum) {
210
if ((tmp & 1) == (tmp>>18 & 1))
211
tmp ^= 0x000F0000; /* PKAZip compatibility kluge */
212
/* turn off archive bit for restored Amiga files */
213
G.pInfo->file_attr = (unsigned)((tmp>>16) & (~S_IARCHIVE));
216
case UNIX_: /* preserve read, write, execute: use logical-OR of */
217
case VMS_: /* user, group, and other; if writable, set delete bit */
224
unsigned uxattr = (unsigned)(tmp >> 16);
227
if (uxattr == 0 && G.extra_field) {
228
/* Some (non-Info-ZIP) implementations of Zip for Unix and
229
VMS (and probably others ??) leave 0 in the upper 16-bit
230
part of the external_file_attributes field. Instead, they
231
store file permission attributes in some extra field.
232
As a work-around, we search for the presence of one of
233
these extra fields and fall back to the MSDOS compatible
234
part of external_file_attributes if one of the known
235
e.f. types has been detected.
236
Later, we might implement extraction of the permission
237
bits from the VMS extra field. But for now, the work-around
238
should be sufficient to provide "readable" extracted files.
239
(For ASI Unix e.f., an experimental remap of the e.f.
240
mode value IS already provided!)
244
uch *ef = G.extra_field;
245
unsigned ef_len = G.crec.extra_field_length;
247
while (!r && ef_len >= EB_HEADSIZE) {
249
ebLen = (unsigned)makeword(ef+EB_LEN);
250
if (ebLen > (ef_len - EB_HEADSIZE))
251
/* discoverd some e.f. inconsistency! */
255
if (ebLen >= (EB_ASI_MODE+2)) {
257
(unsigned)makeword(ef+(EB_HEADSIZE+EB_ASI_MODE));
258
/* force stop of loop: */
259
ef_len = (ebLen + EB_HEADSIZE);
262
/* else: fall through! */
264
/* "found nondecypherable e.f. with perm. attr" */
269
ef_len -= (ebLen + EB_HEADSIZE);
270
ef += (ebLen + EB_HEADSIZE);
274
uxattr = (( uxattr>>6 | uxattr>>3 | uxattr) & 07) << 1;
275
G.pInfo->file_attr = (unsigned)(uxattr&S_IWRITE ?
276
uxattr|S_IDELETE : uxattr);
282
/* all other platforms: assume read-only bit in DOS half of attribute
283
* word is set correctly ==> will become READ or READ+WRITE+DELETE */
285
case FS_HPFS_: /* can add S_IHIDDEN check to MSDOS/OS2/NT eventually */
290
G.pInfo->file_attr = (unsigned)(tmp&1? S_IREAD : S_IRWD);
293
} /* end switch (host-OS-created-by) */
295
G.pInfo->file_attr &= 0xff; /* mask off all but lower eight bits */
298
} /* end function mapattr() */
303
/************************/
304
/* Function mapname() */
305
/************************/
307
int mapname(__G__ renamed)
312
* MPN_OK - no problem detected
313
* MPN_INF_TRUNC - caution (truncated filename)
314
* MPN_INF_SKIP - info "skip entry" (dir doesn't exist)
315
* MPN_ERR_SKIP - error -> skip entry
316
* MPN_ERR_TOOLONG - error -> path is too long
317
* MPN_NOMEM - error (memory allocation failed) -> skip entry
318
* [also MPN_VOL_LABEL, MPN_CREATED_DIR]
321
char pathcomp[FILNAMSIZ]; /* path-component buffer */
322
char *pp, *cp=NULL; /* character pointers */
323
char *lastsemi = NULL; /* pointer to last semi-colon in pathcomp */
324
int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */
326
register unsigned workch; /* hold the character being tested */
329
/*---------------------------------------------------------------------------
330
Initialize various pointers and counters and stuff.
331
---------------------------------------------------------------------------*/
333
if (G.pInfo->vollabel)
334
return MPN_VOL_LABEL; /* can't set disk volume labels in AmigaDOS */
336
/* can create path as long as not just freshening, or if user told us */
337
G.create_dirs = (!uO.fflag || renamed);
339
G.created_dir = FALSE; /* not yet */
341
/* user gave full pathname: don't prepend G.rootpath */
342
#ifndef OLD_AMIGA_RENAMED
343
G.renamed_fullpath = (renamed &&
344
(*G.filename == '/' || *G.filename == ':'));
346
/* supress G.rootpath even when user gave a relative pathname */
348
G.renamed_fullpath = (renamed && strpbrk(G.filename, ":/");
350
G.renamed_fullpath = (renamed &&
351
(strchr(G.filename, ':') || strchr(G.filename, '/')));
355
if (checkdir(__G__ (char *)NULL, INIT) == MPN_NOMEM)
356
return MPN_NOMEM; /* initialize path buffer, unless no memory */
358
*pathcomp = '\0'; /* initialize translation buffer */
359
pp = pathcomp; /* point to translation buffer */
360
if (uO.jflag) /* junking directories */
361
cp = (char *)strrchr(G.filename, '/');
362
if (cp == (char *)NULL) /* no '/' or not junking dirs */
363
cp = G.filename; /* point to internal zipfile-member pathname */
365
++cp; /* point to start of last component of path */
367
/*---------------------------------------------------------------------------
368
Begin main loop through characters in filename.
369
---------------------------------------------------------------------------*/
371
while ((workch = (uch)*cp++) != 0) {
374
case '/': /* can assume -j flag not given */
376
if (strcmp(pathcomp, ".") == 0) {
377
/* don't bother appending "./" to the path */
379
} else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) {
380
/* "../" dir traversal detected, skip over it */
382
killed_ddot = TRUE; /* set "show message" flag */
384
/* when path component is not empty, append it now */
385
if (*pathcomp != '\0' &&
386
((error = checkdir(__G__ pathcomp, APPEND_DIR))
387
& MPN_MASK) > MPN_INF_TRUNC)
389
pp = pathcomp; /* reset conversion buffer for next piece */
390
lastsemi = (char *)NULL; /* leave direct. semi-colons alone */
393
case ';': /* VMS version (or DEC-20 attrib?) */
394
lastsemi = pp; /* keep for now; remove VMS ";##" */
395
*pp++ = (char)workch; /* later, if requested */
399
/* allow ISO European characters in filenames: */
400
if (isprint(workch) || (160 <= workch && workch <= 255))
401
*pp++ = (char)workch;
404
} /* end while loop */
406
/* Show warning when stripping insecure "parent dir" path components */
407
if (killed_ddot && QCOND2) {
408
Info(slide, 0, ((char *)slide,
409
"warning: skipped \"../\" path component(s) in %s\n",
410
FnFilter1(G.filename)));
411
if (!(error & ~MPN_MASK))
412
error = (error & MPN_MASK) | PK_WARN;
415
/*---------------------------------------------------------------------------
416
Report if directory was created (and no file to create: filename ended
417
in '/'), check name to be sure it exists, and combine path and name be-
419
---------------------------------------------------------------------------*/
421
if (G.filename[strlen(G.filename) - 1] == '/') {
422
checkdir(__G__ G.filename, GETPATH);
425
Info(slide, 0, ((char *)slide, " creating: %s\n",
426
FnFilter1(G.filename)));
428
/* set dir time (note trailing '/') */
429
return (error & ~MPN_MASK) | MPN_CREATED_DIR;
431
/* dir existed already; don't look for data to extract */
432
return (error & ~MPN_MASK) | MPN_INF_SKIP;
435
*pp = '\0'; /* done with pathcomp: terminate it */
437
/* if not saving them, remove VMS version numbers (appended ";###") */
438
if (!uO.V_flag && lastsemi) {
440
while (isdigit((uch)(*pp)))
442
if (*pp == '\0') /* only digits between ';' and end: nuke */
446
if (*pathcomp == '\0') {
447
Info(slide, 1, ((char *)slide, "mapname: conversion of %s failed\n",
448
FnFilter1(G.filename)));
449
return (error & ~MPN_MASK) | MPN_ERR_SKIP;
452
error = (error & ~MPN_MASK) | checkdir(__G__ pathcomp, APPEND_NAME);
453
if ((error & MPN_MASK) == MPN_INF_TRUNC) {
454
/* GRR: OK if truncated here: warn and continue */
455
/* (warn in checkdir?) */
457
checkdir(__G__ G.filename, GETPATH);
461
} /* end function mapname() */
466
/***********************/
467
/* Function checkdir() */
468
/***********************/
470
int checkdir(__G__ pathcomp, flag)
476
* MPN_OK - no problem detected
477
* MPN_INF_TRUNC - (on APPEND_NAME) truncated filename
478
* MPN_INF_SKIP - path doesn't exist, not allowed to create
479
* MPN_ERR_SKIP - path doesn't exist, tried to create and failed; or path
480
* exists and is not a directory, but is supposed to be
481
* MPN_ERR_TOOLONG - path is too long
482
* MPN_NOMEM - can't allocate memory for filename buffers
485
/* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in amiga.h: */
486
/* static int rootlen = 0; */ /* length of rootpath */
487
/* static char *rootpath; */ /* user's "extract-to" directory */
488
/* static char *buildpath; */ /* full path (so far) to extracted file */
489
/* static char *end; */ /* pointer to end of buildpath ('\0') */
492
# define FUNCTION (flag & FN_MASK)
495
/*---------------------------------------------------------------------------
496
APPEND_DIR: append the path component to the path being built and check
497
for its existence. If doesn't exist and we are creating directories, do
498
so for this one; else signal success or error as appropriate.
499
---------------------------------------------------------------------------*/
501
/* GRR: check path length after each segment: warn about truncation */
503
if (FUNCTION == APPEND_DIR) {
504
int too_long = FALSE;
506
Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
507
while ((*G.build_end = *pathcomp++) != '\0')
509
/* Truncate components over 30 chars? Nah, the filesystem handles it. */
510
if ((G.build_end-G.buildpath) > FILNAMSIZ-3) /* room for "/a\0" */
511
too_long = TRUE; /* check if extracting dir? */
512
if (SSTAT(G.buildpath, &G.statbuf)) { /* path doesn't exist */
513
if (!G.create_dirs) { /* told not to create (freshening) */
515
return MPN_INF_SKIP; /* path doesn't exist: nothing to do */
518
Info(slide, 1, ((char *)slide,
519
"checkdir error: path too long: %s\n",
520
FnFilter1(G.buildpath)));
522
/* no room for filenames: fatal */
523
return MPN_ERR_TOOLONG;
525
if (MKDIR(G.buildpath, 0777) == -1) { /* create the directory */
526
Info(slide, 1, ((char *)slide,
527
"checkdir error: cannot create %s\n\
528
unable to process %s.\n",
529
FnFilter2(G.buildpath), FnFilter1(G.filename)));
531
/* path didn't exist, tried to create, failed */
534
G.created_dir = TRUE;
535
} else if (!S_ISDIR(G.statbuf.st_mode)) {
536
Info(slide, 1, ((char *)slide,
537
"checkdir error: %s exists but is not directory\n\
538
unable to process %s.\n",
539
FnFilter2(G.buildpath), FnFilter1(G.filename)));
541
/* path existed but wasn't dir */
545
Info(slide, 1, ((char *)slide,
546
"checkdir error: path too long: %s\n", FnFilter1(G.buildpath)));
548
/* no room for filenames: fatal */
549
return MPN_ERR_TOOLONG;
551
*G.build_end++ = '/';
553
Trace((stderr, "buildpath now = [%s]\n", FnFilter1(G.buildpath)));
556
} /* end if (FUNCTION == APPEND_DIR) */
558
/*---------------------------------------------------------------------------
559
GETPATH: copy full path to the string pointed at by pathcomp, and free
560
G.buildpath. Not our responsibility to worry whether pathcomp has room.
561
---------------------------------------------------------------------------*/
563
if (FUNCTION == GETPATH) {
564
strcpy(pathcomp, G.buildpath);
565
Trace((stderr, "getting and freeing path [%s]\n",
566
FnFilter1(pathcomp)));
568
G.buildpath = G.build_end = (char *)NULL;
572
/*---------------------------------------------------------------------------
573
APPEND_NAME: assume the path component is the filename; append it and
574
return without checking for existence.
575
---------------------------------------------------------------------------*/
577
if (FUNCTION == APPEND_NAME) {
578
Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
579
while ((*G.build_end = *pathcomp++) != '\0') {
581
if ((G.build_end-G.buildpath) >= FILNAMSIZ) {
582
*--G.build_end = '\0';
583
Info(slide, 0x201, ((char *)slide,
584
"checkdir warning: path too long; truncating\n\
586
FnFilter1(G.filename), FnFilter2(G.buildpath)));
587
return MPN_INF_TRUNC; /* filename truncated */
590
Trace((stderr, "buildpath now = [%s]\n", FnFilter1(G.buildpath)));
591
/* could check for existence here, prompt for new name... */
595
/*---------------------------------------------------------------------------
596
INIT: allocate and initialize buffer space for the file currently being
597
extracted. If file was renamed with an absolute path, don't prepend the
599
---------------------------------------------------------------------------*/
601
if (FUNCTION == INIT) {
602
Trace((stderr, "initializing buildpath to "));
603
if ((G.buildpath = (char *)malloc(strlen(G.filename)+G.rootlen+1))
606
if ((G.rootlen > 0) && !G.renamed_fullpath) {
607
strcpy(G.buildpath, G.rootpath);
608
G.build_end = G.buildpath + G.rootlen;
611
G.build_end = G.buildpath;
613
Trace((stderr, "[%s]\n", FnFilter1(G.buildpath)));
617
/*---------------------------------------------------------------------------
618
ROOT: if appropriate, store the path in G.rootpath and create it if
619
necessary; else assume it's a zipfile member and return. This path
620
segment gets used in extracting all members from every zipfile specified
622
---------------------------------------------------------------------------*/
624
#if (!defined(SFX) || defined(SFX_EXDIR))
625
if (FUNCTION == ROOT) {
626
Trace((stderr, "initializing root path to [%s]\n",
627
FnFilter1(pathcomp)));
628
if (pathcomp == (char *)NULL) {
632
if (G.rootlen > 0) /* rootpath was already set, nothing to do */
634
if ((G.rootlen = strlen(pathcomp)) > 0) {
635
if (stat(pathcomp, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode)) {
636
/* path does not exist */
637
if (!G.create_dirs) {
639
/* skip (or treat as stored file) */
642
/* create the directory (could add loop here scanning pathcomp
643
* to create more than one level, but why really necessary?) */
644
if (MKDIR(pathcomp, 0777) == -1) {
645
Info(slide, 1, ((char *)slide,
646
"checkdir: cannot create extraction directory: %s\n",
647
FnFilter1(pathcomp)));
649
/* path didn't exist, tried to create, and failed: */
650
/* file exists, or 2+ subdir levels required */
654
if ((G.rootpath = (char *)malloc(G.rootlen+2)) == NULL) {
658
strcpy(G.rootpath, pathcomp);
659
if (G.rootpath[G.rootlen-1] != ':' && G.rootpath[G.rootlen-1] != '/')
660
G.rootpath[G.rootlen++] = '/';
661
G.rootpath[G.rootlen] = '\0';
662
Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath)));
666
#endif /* !SFX || SFX_EXDIR */
668
/*---------------------------------------------------------------------------
669
END: free G.rootpath, immediately prior to program exit.
670
---------------------------------------------------------------------------*/
672
if (FUNCTION == END) {
673
Trace((stderr, "freeing rootpath\n"));
681
return MPN_INVALID; /* should never reach */
683
} /* end function checkdir() */
689
/**************************************/
690
/* Function close_outfile() */
691
/**************************************/
692
/* this part differs slightly with Zip */
693
/*-------------------------------------*/
695
void close_outfile(__G)
699
#ifdef USE_EF_UT_TIME
704
if (uO.cflag) /* can't set time or filenote on stdout */
707
/* close the file *before* setting its time under AmigaDOS */
711
#ifdef USE_EF_UT_TIME
716
(ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
717
G.lrec.last_mod_dos_datetime, &z_utime, NULL)
720
TTrace((stderr, "close_outfile: Unix e.f. modif. time = %ld\n",
722
m_time = z_utime.mtime;
724
/* Convert DOS time to time_t format */
725
m_time = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
727
#else /* !USE_EF_UT_TIME */
728
/* Convert DOS time to time_t format */
729
m_time = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
730
#endif /* ?USE_EF_UT_TIME */
733
Info(slide, 1, ((char *)slide, "\nclose_outfile(): m_time=%s\n",
737
if (!FileDate(G.filename, &m_time))
738
Info(slide, 1, ((char *)slide,
739
"warning: cannot set the time for %s\n", G.filename));
741
/* set file perms after closing (not done at creation)--see mapattr() */
743
chmod(G.filename, G.pInfo->file_attr);
745
/* give it a filenote from the zipfile comment, if appropriate */
747
if (uO.N_flag && G.filenotes[G.filenote_slot]) {
748
SetComment(G.filename, G.filenotes[G.filenote_slot]);
749
free(G.filenotes[G.filenote_slot]);
750
G.filenotes[G.filenote_slot] = NULL;
753
} /* end function close_outfile() */
758
/*************************/
759
/* Function stamp_file() */
760
/*************************/
762
int stamp_file(fname, modtime)
770
return (FileDate((char *)fname, &m_time));
772
} /* end function stamp_file() */
774
#endif /* TIMESTAMP */
778
/********************************************************************/
779
/* Load filedate as a separate external file; it's used by Zip, too.*/
781
# include "amiga/filedate.c" /* */
783
/********************************************************************/
785
/********************* do linewise with stat.c **********************/
787
# include "amiga/stat.c"
788
/* this is the exact same stat.c used by Zip */
790
/* SAS/C makes separate object modules of these; there is less */
791
/* trouble that way when redefining standard library functions. */
795
void _abort(void) /* called when ^C is pressed */
798
close_leftover_open_dirs();
800
fputs("\n^C\n", stderr);
805
/************************************************************/
806
/* function screensize() -- uses sendpkt() from filedate.c: */
807
/************************************************************/
809
#include <devices/conunit.h>
810
#include <dos/dosextens.h>
811
#include <exec/memory.h>
812
#include <clib/exec_protos.h>
814
extern long sendpkt(struct MsgPort *pid, long action, long *args, long nargs);
816
int screensize(int *ttrows, int *ttcols)
819
if (fh && IsInteractive(fh)) {
820
struct ConUnit *conunit = NULL;
821
void *conp = ((struct FileHandle *) (fh << 2))->fh_Type;
822
struct InfoData *ind = AllocMem(sizeof(*ind), MEMF_PUBLIC);
823
long argp = ((unsigned long) ind) >> 2;
825
if (ind && conp && sendpkt(conp, ACTION_DISK_INFO, &argp, 1))
826
conunit = (void *) ((struct IOStdReq *) ind->id_InUse)->io_Unit;
828
FreeMem(ind, sizeof(*ind));
830
if (ttrows) *ttrows = conunit->cu_YMax + 1;
831
if (ttcols) *ttcols = conunit->cu_XMax + 1;
832
return 0; /* success */
835
if (ttrows) *ttrows = INT_MAX;
836
if (ttcols) *ttcols = INT_MAX;
837
return 1; /* failure */
841
#ifdef AMIGA_VOLUME_LABELS
842
/* This function is for if we someday implement -$ on the Amiga. */
843
# include <dos/dosextens.h>
844
# include <dos/filehandler.h>
845
# include <clib/macros.h>
847
BOOL is_floppy(ZCONST char *path)
850
char devname[32], *debna;
852
BPTR lok = Lock((char *)path, ACCESS_READ), pok;
853
struct FileSysStartupMsg *fart;
854
struct DeviceNode *debb, devlist = (void *) BADDR((struct DosInfo *)
855
BADDR(DOSBase->dl_Root->rn_Info)->di_DevInfo);
857
return FALSE; /* should not happen */
858
if (pok = ParentDir((char *)path)) {
861
return FALSE; /* it's not a root directory path */
864
for (debb = devlist; debb; debb = BADDR(debb->dn_Next))
865
if (debb->dn_Type == DLT_DEVICE && (debb->dn_Task == lick->fl_Task))
866
if (fart = BADDR(debb->dn_Startup)) {
867
debna = (char *) BADDR(fart->fssm_Device) + 1;
868
if ((i = debna[-1]) > 31) i = 30;
869
strncpy(devname, debna, i);
871
okay = !strcmp(devname, "trackdisk.device")
872
|| !strcmp(devname, "mfm.device")
873
|| !strcmp(devname, "messydisk.device");
874
break; /* We only support obvious floppy drives, not tricky */
875
} /* things like removable cartrige hard drives, or */
876
Permit(); /* any unusual kind of floppy device driver. */
879
#endif /* AMIGA_VOLUME_LABELS */
885
/* As far as I can tell, all the locales AmigaDOS 2.1 knows about all */
886
/* happen to use DF_MDY ordering, so there's no point in using this. */
888
/*************************/
889
/* Function dateformat() */
890
/*************************/
892
#include <clib/locale_protos.h>
894
# include <pragmas/locale_lib.h>
899
/*---------------------------------------------------------------------------
900
For those operating systems which support it, this function returns a
901
value which tells how national convention says that numeric dates are
902
displayed. Return values are DF_YMD, DF_DMY and DF_MDY (the meanings
903
should be fairly obvious).
904
---------------------------------------------------------------------------*/
905
struct Library *LocaleBase;
907
int result = DF_MDY; /* the default */
909
if ((LocaleBase = OpenLibrary("locale.library", 0))) {
910
if (ll = OpenLocale(NULL)) {
911
uch *f = ll->loc_ShortDateFormat;
912
/* In this string, %y|%Y is year, %b|%B|%h|%m is month, */
913
/* %d|%e is day day, and %D|%x is short for mo/da/yr. */
914
if (!strstr(f, "%D") && !strstr(f, "%x")) {
916
if (!(mo = strstr(f, "%b")) && !(mo = strstr(f, "%B"))
917
&& !(mo = strstr(f, "%h")))
918
mo = strstr(f, "%m");
919
if (!(da = strstr(f, "%d")))
920
da = strstr(f, "%e");
921
if (!(yr = strstr(f, "%y")))
922
yr = strstr(f, "%Y");
925
else if (da && da < mo)
930
CloseLibrary(LocaleBase);
938
/************************/
939
/* Function version() */
940
/************************/
943
/* NOTE: the following include depends upon the environment
944
* variable $Workbench to be set correctly. (Set by
945
* default, by kickstart during startup)
947
int WBversion = (int)
948
#include "ENV:Workbench"
954
/* Define buffers. */
956
char buf1[16]; /* compiler name */
957
char buf2[16]; /* revstamp */
958
char buf3[16]; /* OS */
959
char buf4[16]; /* Date */
960
/* char buf5[16]; /* Time */
962
/* format "with" name strings */
966
strcpy(buf1,"SAS/C ");
969
strcpy(buf1,"Lattice C ");
972
strcpy(buf1,"Manx Aztec C ");
974
strcpy(buf1,"UNKNOWN ");
979
sprintf(buf3,"AmigaDOS v%d",WBversion);
981
strcpy(buf1,"Unknown compiler ");
982
strcpy(buf3,"Unknown OS");
985
/* Define revision, date, and time strings.
986
* NOTE: Do not calculate run time, be sure to use time compiled.
987
* Pass these strings via your makefile if undefined.
990
#if defined(__VERSION__) && defined(__REVISION__)
991
sprintf(buf2,"version %d.%d",__VERSION__,__REVISION__);
994
sprintf(buf2,"version %d",__VERSION__);
996
sprintf(buf2,"unknown version");
1001
sprintf(buf4," on %s",__DATE__);
1003
strcpy(buf4," unknown date");
1008
sprintf(buf5," at %s",__TIME__);
1010
strcpy(buf5," unknown time");
1014
/* Print strings using "CompiledWith" mask defined in unzip.c (used by all).
1015
* ("Compiled with %s%s for %s%s%s%s.")
1018
printf(LoadFarString(CompiledWith),
1023
"", /* buf5 not used */
1024
"" ); /* buf6 not used */
1026
} /* end function version() */