Directories

It would be interesting to understand how we became stuck with our awkward file name and directory system. Various attempts have been made to try to create an improved system, but none have really stuck, mainly for reasons of backward compatibility.

Part of the problem is that the file name is attached to a fixed size file header, thus it can never outgrow the maximum length reserved for it, ie 36 characters. And a file name consists not only of the file's name and extension but all the directories and subdirectories it is part of too.

Think about this when making programs for general distribution; you don't know where punters like to keep their stuff, so your carefully crafted program

        dev1_games_SuperDuper_exe

needing to load some auxiliary file, _aux_Background_pic will not work if the punter stores his games in

        dev1_games_adventures_Super_

So keep directory and file names short!

The second issue is the directory structure. A directory is basically a just a file (which from the user's POV is always read-only) that consists of a repetition of all the headers of the files it "contains". Whenever a file needs to be accessed - to be opened, executed or deleted, the driver scans through the directory given, to sequentially search for the desired file. Due to this method, it is wise to keep directories relatively small (ie few files in each directory) where possible.

To delete a file, the system merely zeroes the length of the file name in the directory, leaving the rest of the entry intact.

Directory files grow by 64 bytes for every new file header in it, unless it can re-use a zeroed out slot from a previously deleted file. A directory file can never shrink; it can only grow, which means that if, for example, you needed, as a temporary matter, to add some hundred files to a directory and then delete them again, those hundreds of zombie headers would still be present, potentially slowing down access to that directory even if it later only contained a few files. The only way to shrink a directory is to delete it in its entirety. Now if you were to temporarily dump hundreds of files in the root directory of a device, you might slow down access to the whole drive and permanently reduce the space available on it. There would be no way of fixing it other than reformatting it.

Another awkward aspect of this system is that directories are difficult to rename, copy and even delete. Deletion, however, is the simplest: Starting at the lowest level subdirectory, delete all the files in it, then delete the directory itself. Do this repeatedly as you work your way up the directory tree. Or you could use a S*BASIC program I wrote. (See DelDir. But use great care with this, for obvious reasons!)

Renaming the contents of a directory under this system is pretty much the same as moving files, which is the same as making a new copy and then deleting the old one, and thus it is the most difficult of all. Copying is complicated by the file name length problem.

The final failing of our filing system that I'll touch on here, is that there never was an abstracted method of accessing the directory structure. The lack of this is one of the reasons it is so difficult to fix. Any worthwhile upgrade would involve making low-level changes to the underlying data structures, but since every program that needs directories for something currently accesses those structures directly, all such programs would require a major overhaul, instead of none, or very little, had an abstracted access method been available.

If, for example, you wanted to scan through a whole directory to process all the files in it in some way, you have access the low-level directory structure directly. It isnt hard, but of course, you need to know how. Various methods are possible, most of them require some toolkit. And no toolkit is better, more essential, and luckily, more ubiquitous, than QJump's TK2.

Below are two example programs to do just that. Both only require TK2. They are written for SBASIC, as I find it hard to hobble my own programs for the sake of compatibility with a system that has been dead to me for many years! However, only very slight changes need to be made for them to work with SuperBASIC. Usually it is only a matter of changing a few FOR loop and SELect variables from integer% to floating point. Just RUN the program and SuperBASIC will complain about what you need to change!

The programs

The simplest is this single directory scanner:

DIR

10 dnm$ = 'win1_exe_'
12 DoDir #1; dnm$
14 :
100 DEFine PROCedure DoDir(dc, dir$)
102 LOCal lp, ch, dl, ps, l%, t$(2)
104 LOCal fl, dt, bd, t%, n$(36)
106 ch = FOP_DIR(dir$)
108 n$ = FNAME$(#ch)
110 dl = FLEN(#ch)
112 ps = -64
114 :
116 IF LEN(n$) > 0: n$ = n$ & '_'
118 l% = LEN(n$) + 1
120 :
122 REPeat lp
124  ps = ps + 64: IF ps >= dl: EXIT lp
126  GET#ch\ ps + 14, n$:                   rem Name
128  IF LEN(n$) = 0: NEXT lp:               rem Deleted
130  :
132  BGET#ch\ ps + 5, t%:                   rem Type
134  SELect ON t%
136   = 0: t$ = ' '
138   = 1: t$ = 'E'
140   = 2: t$ = 'r'
142   = 3 TO 9: t$ = t%
144   = 255: t$ = '>'
146   = REMAINDER : t$ = '?'
148  END SELect
150  :
152  LGET#ch\ ps +  0; fl: fl = fl - 64:    rem Length - header
154  LGET#ch\ ps + 52; dt:                  rem Date
156  WGET#ch\ ps + 56; v%:                  rem Version
158  LGET#ch\ ps + 60; bd:                  rem Backup
160  :
162  PRINT#dc; t$! n$(l% TO), 'V'; v%\, DATE$(dt)! CDEC$(fl, 13, 0)
164 END REPeat lp
166 CLOSE#ch
168 END DEFine DoDir
170 :
172 :

Remember, these programs are just scripts, tools for you to shape as you need for what you need them for. See for example my programs DelDir, DotRenDir and DirSize.

This next program is slightly more complex. It scans the directory tree from the top down (as opposed to DelDir which scans directories bottoms up).

DIRr

10 dnm$ = 'win1_bas'
12 ch = FOP_OVER("ram1_dir_txt")
14 DoDir #ch; dnm$
16 CLOSE#ch
18 :
100 DEFine PROCedure DoDir(dc, dir$)
102 LOCal lp, ch, dl, ps, l%, t$(2), v$(5), d$(42)
104 LOCal fl, dt, bd, t%, n$(36)
106 LOCal y$, h$: rem For Qpac2 date formatting
108 :
110 IF LEN(dir$) = 0: d$ = DATAD$: ELSE : d$ = dir$
112 ch = FOP_DIR(d$)
114 n$ = FNAME$(#ch)
116 dl = FLEN(#ch)
118 v$ = d$(1 TO 5)
120 ps = -64
122 :
124 IF LEN(n$) > 0: n$ = n$ & '_'
126 l% = LEN(n$) + 1
128 :
130 REPeat lp
132  ps = ps + 64: IF ps >= dl: EXIT lp
134  GET#ch\ ps + 14, n$:                   rem Name
136  IF LEN(n$) = 0: NEXT lp:               rem Deleted
138  :
140  BGET#ch\ ps + 5, t%:                   rem Type
142  SELect ON t%
144   = 0: t$ = ' '
146   = 1: t$ = 'E'
148   = 2: t$ = 'r'
150   = 3 TO 9: t$ = t%
152   = 255: t$ = '>'
154   = REMAINDER : t$ = '?'
156  END SELect
158  :
160  IF t% = 255 THEN
162   PRINT#dc; t$! d$; '_'; n$(l% TO); '_'
164   DoDir#dc; v$ & n$
166  ELSE
168   LGET#ch\ ps +  0; fl: fl = fl - 64:    rem Length - header
170   LGET#ch\ ps + 52; dt:                  rem Date
172   WGET#ch\ ps + 56; v%:                  rem Version
174   LGET#ch\ ps + 60; bd:                  rem Backup
176   :
178   rem   Alternative output formatting
180   rem PRINT#dc; t$! n$(l% TO), 'V'; v%\, DATE$(dt)! CDEC$(fl, 13, 0)
182   y$ = DATE$(dt): h$ = y$(13 TO 17): y$ = y$(1 TO 12)
184   PRINT#dc; t$! n$(l% TO); TO 20; Sz$(fl)!! h$! y$! 'V'; v%
186  END IF
188 END REPeat lp
190 CLOSE#ch
192 END DEFine DoDir
194 :
196 :
198 rem + ------------------------------------------------------------------------ +
200 rem |<                              Function Sz$                              >|
202 rem + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +
204 rem |          Convert bytes to Kb, Mb, and Gb with 2 decimal points           |
206 rem |                                                                          |
208 rem | Note: Max 999.99 GB! (which is beyond Qdos/SMSQ filesystems anyway!)     |
210 rem + ------------------------------------------------------------------------ +
212 rem | V0.02, pjw, 2026 Jan 10, complete rewrite! SuperBASIC compatible version |
214 rem + ------------------------------------------------------------------------ +
216 :
218 DEFine FuNction Sz$(b)
220 IF b > 1.07373E12: RETurn ' ' & FILL$("*", 6) & ' ?'
222 SELect ON b
224  = 0 TO 1023: RETurn CDEC$(b, 7, 0) & ' b'
226  = 1024 TO 1.048575E6: RETurn CDEC$(100 * b / 1024, 7, 2) & 'Kb'
228  = 1.048576E6 TO 1.073742E9: RETurn CDEC$(100 * b / 1.048576E6, 7, 2) & 'Mb'
230 END SELect
232 RETurn CDEC$(100 * b / 1.073742E9, 7, 2) & 'Gb'
234 END DEFine Sz$
236 :
238 :
  

If you just RUN (or in SMSQ/E EXecute) the program above all it does is produce a file, ram1_dir_txt with a list of all files in the tree, starting at the node you specify (change this to fit your circumstances on the first line). Two alternative output formats are provided; choose one and REM out the other, or add some functional code there instead.

The two routines above are designed for use with simple programs where scanning the directory is at the centre. You need to modify them according to need with your functional code. A different approach is taken with the routines NextFile and NextFileDir. They work more like the kind of abstraction of directory functions that ought to have been built into the system..


Generated with sb2htm on 2026 Jan 10
©pjw 2026