]> git.sur5r.net Git - cc65/blob - libsrc/cbm/cbm_dir.c
0b97e980390a0ba8896958adc6dc38e6f9775229
[cc65] / libsrc / cbm / cbm_dir.c
1 /* This is a very simplified version of the POSIX opendir(),  */
2 /* readdir(), and closedir() -- for Commodore computers.      */
3 /* Created by Josef Soucek, 2003.  E-mail: josef.soucek@ct.cz */
4
5 /* 2003-01-21 -- Version 0.1 */
6 /* 2009-10-10 -- Version 0.3 */
7 /* 2011-04-07 -- Version 0.4, groepaz */
8 /* 2011-04-14 -- Version 0.5, Greg King */
9
10 /* Tested with floppy-drive and IDE64 devices.        */
11 /* Not tested with messed (buggy) directory listings. */
12 /* Limits filenames to 16 chars. (VICE supports more  */
13 /* in directory listings).                            */
14
15
16 #include <cbm.h>
17 #include <errno.h>
18
19
20
21 /* Opens directory listing.
22 ** Returns 0 if openning directory was successful;
23 ** otherwise, an error-code corresponding to cbm_open().
24 */
25 unsigned char __fastcall__ cbm_opendir (unsigned char lfn, unsigned char device)
26 {
27     if (cbm_open (lfn, device, CBM_READ, "$") == 0) {
28         if ((_oserror = cbm_k_chkin (lfn)) == 0) {
29             /* Ignore start address */
30             cbm_k_basin();
31             cbm_k_basin();
32             cbm_k_clrch();
33             if (cbm_k_readst()) {
34                 cbm_close(lfn);
35                 _oserror = 4;           /* directory cannot be read */
36             }
37         }
38     }
39     return _oserror;
40 }
41
42
43
44 /* Reads one directory line into cbm_dirent structure.
45 ** Returns 0 if reading directory-line was successful.
46 ** Returns non-zero if reading directory failed, or no more file-names to read.
47 ** Returns 2 on last line.  Then, l_dirent->size = the number of "blocks free."
48 */
49 unsigned char __fastcall__ cbm_readdir (unsigned char lfn, register struct cbm_dirent* l_dirent)
50 {
51     unsigned char byte, i = 0;
52     unsigned char is_header = 0;
53     unsigned char rv = 1;
54     static const unsigned char types[] = {
55         CBM_T_CBM,   CBM_T_DEL,   CBM_T_OTHER, CBM_T_OTHER, /* c d e f */
56         CBM_T_OTHER, CBM_T_OTHER, CBM_T_OTHER, CBM_T_OTHER, /* g h i j */
57         CBM_T_OTHER, CBM_T_LNK,   CBM_T_OTHER, CBM_T_OTHER, /* k l m n */
58         CBM_T_OTHER, CBM_T_PRG,   CBM_T_OTHER, CBM_T_REL,   /* o p q r */
59         CBM_T_SEQ,   CBM_T_OTHER, CBM_T_USR,   CBM_T_VRP    /* s t u v */
60     };
61
62     if (!cbm_k_chkin(lfn)) {
63         if (!cbm_k_readst()) {
64             /* skip 2 bytes, next-BASIC-line pointer */
65             cbm_k_basin();
66             cbm_k_basin();
67
68             /* File-size or drive/partition number */
69             l_dirent->size = cbm_k_basin() | (cbm_k_basin() << 8);
70
71             byte = cbm_k_basin();
72             switch (byte) {
73
74                 /* "B" BLOCKS FREE. */
75               case 'b':
76                 /* Read until end; careless callers might call us again. */
77                 while (!cbm_k_readst()) {
78                     cbm_k_basin();
79                 }
80                 rv = 2; /* EOF */
81                 goto ret_val;
82
83                 /* Reverse-text shows when this is the directory header. */
84               case 0x12:  /* RVS_ON */
85                 is_header = 1;
86             }
87
88             while (byte != '\"') {
89                 /* prevent endless loop */
90                 if (cbm_k_readst()) {
91                     rv = 3;
92                     goto ret_val;
93                 }
94                 byte = cbm_k_basin();
95             }
96
97             while ((byte = cbm_k_basin()) != '\"') {
98                 /* prevent endless loop */
99                 if (cbm_k_readst()) {
100                     rv = 4;
101                     goto ret_val;
102                 }
103
104                 if (i < sizeof (l_dirent->name) - 1) {
105                     l_dirent->name[i] = byte;
106                     ++i;
107                 }
108             }
109             l_dirent->name[i] = '\0';
110
111             if (is_header) {
112                 l_dirent->type = CBM_T_HEADER;
113
114                 /* Get the disk-format code. */
115                 i = 6;
116                 do {
117                     l_dirent->access = byte = cbm_k_basin();
118                 } while (--i != 0);
119
120             } else {
121                 /* Go to the file-type column. */
122                 while ((byte = cbm_k_basin()) == ' ') {
123                     /* prevent endless loop */
124                     if (cbm_k_readst()) {
125                         rv = 5;
126                         goto ret_val;
127                     }
128                 }
129
130                 l_dirent->access = CBM_A_RW;
131
132                 /* "Splat" files shouldn't be read. */
133                 if (byte == '*') {
134                     l_dirent->access = CBM_A_WO;
135                     byte = cbm_k_basin();
136                 }
137
138                 if (byte >= 'c' && byte < 'c' + sizeof types) {
139                     l_dirent->type = types[byte - 'c'];
140                 } else {
141                     l_dirent->type = CBM_T_OTHER;
142                 }
143
144                 /* Notice whether it's a directory or a deleted file. */
145                 if (cbm_k_basin() == 'i' && byte == 'd') {
146                     l_dirent->type = CBM_T_DIR;
147                 }
148                 cbm_k_basin();
149
150                 /* Locked files shouldn't be written. */
151                 if ((byte = cbm_k_basin()) == '<') {
152                     l_dirent->access = (l_dirent->access == CBM_A_WO)
153                         ? 0 : CBM_A_RO;
154                 }
155             }
156
157             /* Read to the end of the line. */
158             while (byte != 0) {
159                 /* prevent endless loop */
160                 if (cbm_k_readst()) {
161                     rv = 6;
162                     goto ret_val;
163                 }
164                 byte = cbm_k_basin();
165             }
166
167             rv = 0;
168             goto ret_val;
169         }
170     }
171
172 ret_val:
173     cbm_k_clrch();
174     return rv;
175 }
176
177
178
179 void __fastcall__ cbm_closedir (unsigned char lfn)
180 {
181     cbm_close(lfn);
182 }
183
184