Category : Files from Magazines
Archive   : DDJ8603.ZIP
Filename : HOLUBLST.MAR

 
Output of file : HOLUBLST.MAR contained in archive : DDJ8603.ZIP
Listing 6 -- skipto.c
------------------------------------------------------------------------------
1 char *skipto( c, p, esc )
2 register char *p ;
3 register int c, esc ;
4 {
5 /* Skip to c or to end of string. If c is preceeded by
6 * the esc character it is skipped over.
7 */
8
9 while( *p && *p != c )
10 {
11 if ( *p != esc )
12 p++ ;
13
14 else if ( *++p ) /* skip over escaped characters */
15 p++;
16 }
17
18 return(p);
19 }
Listing 7 -- dir.h
------------------------------------------------------------------------------
1 /*
2 * DIR.H
3 * #defines and typedefs needed to talk to the routine dir().
4 * A pointer to the DIRECTORY structure is passed to dir().
5 * DIRECTORY structures are created by mk_dir() and deleted with
6 * del_dir().
7 *
8 * On entry:
9 * dirv is the first of an uninitialized array of character
10 * pointers.
11 * lastdir should be initialized to point at dirv.
12 * maxdirs is the size of the above
13 * nfiles
14 * ndirs
15 * nbytes is the total file count, the total directory count
16 * and the total byte count. These will be incremented
17 * as appropriate and are usually set to 0 before
18 * calling dir().
19 * width should be initialized to 0 before calling dir().
20 * vol_label is undefined on entry to dir().
21 * longf is 1 if entrys are to be printed in long format
22 * files is 1 if files are included in the list.
23 * dirs is 1 if directors are included in the list.
24 * graphics is 1 if directories are highlighted with boldface.
25 * hidden is 1 if hidden files are to be included in the list.
26 * path is 1 if the path name is to be included in the list.
27 * label is 1 if you want to get the volume label
28 * exp is 1 if you want the contents of a subdirectory to
29 * be listed rather than the directory name when. This
30 * is only looked at if no wild cards are present in
31 * the file spec.
32 * sort is 1 if you want the list sorted.
33 *
34 * all other fields are ignored. On exit the structure will have been
35 * updated as follows:
36 *
37 * lastdir will be incremented to point at the last entry added
38 * to the dirv table.
39 * maxdirs will be decremented to reflect the added entries.
40 * nfiles is the number of added entries which are files.
41 * ndirs is the number of added entries which are directories.
42 * Note that the equivalent of argc can be derrived by
43 * adding ndirs and nfiles together.
44 * nbytes will have the total size in bytes of all files added
45 * to dirv. This number is the number of bytes actually
46 * occupied by the file, ie. the size returned by DOS
47 * rounded up to the nearest multiple of the disk's
48 * cluster size.
49 * vol_label will hold the volume lable provided that "label" was
50 * set on entry.
51 * width will hold the length of the widest entry added to dirv
52 *
53 * all other fields will have the same values they had on entry.
54 */
55
56 typedef struct
57 {
58 char **lastdir ; /* Most recent addition to dirv */
59 int maxdirs ; /* # of free slots in dirv */
60 int nfiles ; /* # of used slots that are files */
61 int ndirs ; /* # of used slots that are directories */
62 long nbytes ; /* byte count of files */
63 char vol_label[12]; /* volume lable if requested */
64 unsigned width : 7 ; /* Width of widest element in dirv */
65
66 /* Various flags control how dir works: */
67 unsigned longf : 1 ; /* Use long format for entries */
68 unsigned files : 1 ; /* Include files in list */
69 unsigned dirs : 1 ; /* Include directories in list */
70 unsigned graphics : 1 ; /* Use graphics around directory names */
71 unsigned hidden : 1 ; /* List hidden files */
72 unsigned path : 1 ; /* List complete path if given */
73 unsigned label : 1 ; /* Load vol_label with volume label */
74 unsigned exp : 1 ; /* Expand sub-directories */
75 unsigned sort : 1 ; /* Sort added entries */
76
77 char dirv[1]; /* The first of the dirv entries */
78 }
79 DIRECTORY;
Listing 8 -- dir.c
------------------------------------------------------------------------------
1 #include
2 #include
3 #include
4 #include
5
6 /*----------------------------------------------------------------------+
7 * DIR.C: An MSDOS directory access function. |
8 * |
9 * (c) Copyright 1985, Allen I. Holub. All rights reserved. |
10 *----------------------------------------------------------------------+
11 * 11/22/85 Modified so that the total amount of disk space used |
12 * (ie. # of clusters) is put into the total, rather |
13 * than the file size. |
14 *----------------------------------------------------------------------+
15 */
16
17 /* ROUND(n,u): if n is an even multiple of u, evaluate to n, else
18 * round n up to the next even multiple of u.
19 */
20
21 #define ROUND(n,u) ( !((n) % (u)) ? (n) : (((n) / (u)) + 1) * (u))
22
23
24 #define BOLDFACE "\033[1m" /* Ansi esc sequence to turn bold face on */
25 #define ALL_OFF "\033[0m" /* " attributes off */
26
27 #define ATTRIBUTES (READONLY | DIRTY | SYSTEM | HIDDEN | SUBDIR)
28 #define iswhite(c) ((c) == ' ' || (c) == '\t')
29
30 /*----------------------------------------------------------------------*/
31
32 extern char *calloc (unsigned,unsigned); /* In standard library */
33 extern char *cptolower(char*,char*); /* In /src/tools/cptolow.c */
34 extern char *cpy (char*,char*); /* In /src/tools/cpy.c */
35 extern int dos (REGS *); /* In /src/tools/dos.asm */
36 extern void gregs (REGS *); /* In /src/tools/dos.asm */
37 extern char *malloc (unsigned); /* In standard library */
38 extern char *next (char**,int,int); /* In /src/tools/next.c */
39 extern void ssort (char*,int,int,int(*)());/*in /src/tools/ssort.c */
40 extern int strcmp (char*, char*); /* in standard library */
41
42 /*----------------------------------------------------------------------*/
43
44 static unsigned Longfmt = 0; /* True if we're using long format. This
45 * has to be global for the comparison
46 * routine used for sroting to work.
47 */
48
49 static unsigned Cluster_size; /* Number of bytes per cluster on
50 * requested disk.
51 */
52
53 /*----------------------------------------------------------------------*/
54 /* Do a DOS system call using the dos() routine */
55
56 #define DOSCALL(id,regs) { regs.h.ah = id ; dos( ®s ); }
57
58 /*----------------------------------------------------------------------*/
59
60 static int find_first( filespec, attributes, regp )
61 char *filespec ;
62 short attributes;
63 register REGS *regp;
64 {
65 /* Get directory information for the indicated file.
66 * Ambiguous file references are ok but you have to use
67 * find_next to get the rest of the file references.
68 * In this case, The regs structure used by find_first
69 * must be passed to find_next. 0 is returned on success,
70 * otherwise the DOS error code is returned.
71 */
72
73 regp->h.ah = (char) FINDFIRST ;
74 regp->x.dx = (short) filespec ;
75 regp->x.cx = attributes ;
76
77 return (int)( (dos(regp) & CARRY) ? regp->x.ax : 0 );
78 }
79
80 /*----------------------------------------------------------------------*/
81
82 static int find_next ( regp )
83 REGS *regp;
84 {
85 /* Get the next file in an ambiguous file reference. A
86 * call to this function must be preceded by a
87 * find_first call. The regp argument must be the
88 * same register image used by the find_first call.
89 * 0 is returned on success, otherwise the error code
90 * generated by DOS is returned.
91 */
92
93 regp->h.ah = FINDNEXT ;
94 return (int)( (dos(regp) & CARRY) ? regp->x.ax : 0 );
95 }
96
97 /*----------------------------------------------------------------------*/
98
99 int haswild(s)
100 register char *s;
101 {
102 /* Return true if s has a unix wild card in it. */
103
104 for( ; *s ; s++)
105 if( *s == '*' || *s == '?' )
106 return 1;
107 return 0;
108 }
109
110 /*----------------------------------------------------------------------*/
111
112 static int isrootdir( name )
113 register char *name;
114 {
115 /* return true if name is explicitly specifying the root
116 * directory (ie. is one of: d:/ d:\ / \ where
117 * 'd' can be any disk designator.
118 */
119
120 if( *name && name[1] == ':' )
121 name += 2;
122
123 return( (*name == '\\' || *name == '/') && !name[1] );
124 }
125
126 /*----------------------------------------------------------------------*/
127
128 has_only( str, inclusion_set )
129 register char *str;
130 char *inclusion_set;
131 {
132 /* Return true only if every character in str is also in
133 * inclusion_set. True is returned if str is empty.
134 */
135
136 register char *p;
137
138 for(; *str ; str++)
139 {
140 for( p = inclusion_set ; *p && *p != *str ; p++ )
141 ;
142
143 if( !*p )
144 return 0;
145 }
146
147 return 1;
148 }
149
150 /*----------------------------------------------------------------------*/
151
152 static char *fixup_name( name, regs, info )
153 register char *name;
154 REGS *regs;
155 FILE_INFO *info;
156 {
157 /* If the name specifies an implicit file (ie. it asks for
158 * the directory rather than the files in the directory),
159 * modify it to ask for files (eg. ".." becomes "..\*.*").
160 * If the name is actually modified, a pointer to a modified
161 * copy of the original name is returned. Otherwise the
162 * original buffer is returned.
163 */
164
165 static char buf[80] ; /* Place to put modified name */
166 register char *p = buf ; /* Always points into buf */
167 char *start_name = name; /* Remember start of name */
168
169 if( isrootdir(name) || (name[0] && name[1]==':' && !name[2]) )
170 {
171 /* Handle an explicitly requested root directory or
172 * the current directory on another disk.
173 */
174
175 sprintf(buf, "%s*.*", name );
176 }
177 else if( !find_first( name, ALL, regs) )
178 {
179 /* Look for the indicated name & see if it's a directory.
180 * If so, append slash-*.* to the requested name
181 */
182
183 if( !IS_SUBDIR(info) )
184 return name;
185 else
186 sprintf(buf, "%s/*.*", name );
187 }
188 else
189 {
190 /* If we get here then a non-existant file or directory
191 * was requested.
192 * If the name consists of nothing but the characters
193 * \ / . or a drive designator, assume that the root
194 * directory was requested and adjust the name
195 * accordingly.
196 */
197
198 if( *name && name[1] == ':') /* Copy drive designator if */
199 { /* one's present. */
200 *p++ = *name++ ;
201 *p++ = *name++ ;
202 }
203
204 if( has_only(name, ".\\/") )
205 strcpy( p, "/*.*" );
206 else
207 return( start_name );
208 }
209
210 return( buf );
211 }
212
213 /*----------------------------------------------------------------------*/
214
215 static int dirtoa( target, infop, graphics, pathname )
216 register char *target ;
217 char *pathname ;
218 register FILE_INFO *infop ;
219 unsigned graphics;
220 {
221 /* Convert directory entry held in infop to an ascii string
222 * in target. If Longfmt use a long format, if graphics then
223 * directory names are printed in bold face, else they're
224 * printed as "." If pathname is true then the name
225 * will be preceeded with the full pathname.
226 */
227
228 char *startstr = target;
229 int i;
230
231 if( Longfmt )
232 {
233 *target++ = ( IS_READONLY(infop) ) ? 'r' : '.' ;
234 *target++ = ( IS_HIDDEN (infop) ) ? 'h' : '.' ;
235 *target++ = ( IS_SYSTEM (infop) ) ? 's' : '.' ;
236 *target++ = ( IS_SUBDIR (infop) ) ? 'd' : '.' ;
237 *target++ = ( IS_DIRTY (infop) ) ? 'm' : '.' ;
238
239 sprintf(target, " %6ld %2d/%02d/%02d %2d:%02d:%02d - ",
240 infop->fi_fsize,
241 C_MONTH(infop), C_DAY(infop), C_YEAR(infop)-1900,
242 C_HR(infop), C_MIN(infop), C_SEC(infop) );
243
244 while( *target )
245 target++;
246 }
247
248 if( IS_SUBDIR(infop) && graphics )
249 target = cpy( target, BOLDFACE );
250
251 target = cpy ( target, pathname );
252 target = cptolower( target, infop->fi_name );
253
254 if( IS_SUBDIR(infop) && graphics )
255 target = cpy( target, ALL_OFF );
256
257 return( target - startstr );
258 }
259
260 /*----------------------------------------------------------------------*/
261
262 static int add_entry( infop, dp, path )
263 FILE_INFO *infop ;
264 register DIRECTORY *dp ;
265 char *path ;
266 {
267 /* Add an entry to the DIRECTORY structure. Return 0 if
268 * it was added, one if it wasn't.
269 */
270
271 char buf[128] ;
272 register int len ;
273
274 /*
275 * If we're not printing hidden directories but the current
276 * directory is nonetheless hidden, return immediately.
277 * Similarly, return if the directory is full.
278 */
279
280 if( !dp->hidden && (IS_HIDDEN(infop) || *infop->fi_name == '.') )
281 return 1;
282
283 if( dp->maxdirs <= 0 ) /* No more room in dirv. return */
284 return 0; /* error status */
285
286 /*
287 * Update the directory count or the file count as appropriate
288 * return immeadialy if we're looking at a file and we aren't
289 * supposed to list file. The same with directories.
290 */
291
292 if( IS_SUBDIR(infop) )
293 {
294 if( dp->dirs )
295 dp->ndirs++ ;
296 else
297 return 1;
298 }
299 else
300 {
301 if( dp->files )
302 dp->nfiles++ ;
303 else
304 return 1;
305 }
306
307 /*
308 * Convert the FILE_INFO structure to an ascii string and put
309 * it into buf. Then malloc a chunk of memory the correct size,
310 * copy the ascii string there, and put the malloced memory
311 * into dirv at the correct place.
312 */
313
314 Longfmt = dp->longf;
315
316 len = dirtoa( buf, infop, dp->graphics, path );
317
318 if( len > dp->width )
319 dp->width = len ;
320
321 if( *dp->lastdir = malloc(len + 1) )
322 {
323 strcpy( *dp->lastdir++, buf ) ;
324
325 /* Add file size to total. Note that the actual amount
326 * of space (# of clusters) used by the file on the
327 * disk is used.
328 */
329
330 dp->nbytes += ROUND( infop->fi_fsize, Cluster_size );
331
332 --dp->maxdirs;
333 return 1;
334 }
335
336 fprintf(stderr,"Can't get memory for directory\n");
337 return 0;
338 }
339
340 /*----------------------------------------------------------------------*/
341
342
343 static void copy_path( dest, src )
344 char *dest, *src;
345 {
346 /* Copy only the pathname part of the file spec contained in
347 * src to dest. Path names longer than 64 characters are
348 * truncated so dest must be at least 64 characters long.
349 */
350
351 register char *p, *slash;
352
353 for( p = slash = src ; *p ; p++ )
354 if( *p == '/' || *p == '\\' || *p == ':' )
355 slash = p + 1;
356
357 for(p = src; p < slash && p - src < 64 ; *dest++ = *p++ )
358 ;
359
360 *dest = 0;
361 }
362
363 /*----------------------------------------------------------------------*/
364
365 static void clab( dest, src )
366 register char *dest, *src;
367 {
368 for(; *src ; src++, dest++ )
369 if( *src != '.')
370 *dest = *src ;
371 }
372
373 /*----------------------------------------------------------------------*/
374
375 static int cmp( pp1, pp2 )
376 char **pp1, **pp2;
377 {
378 /* Comparison routine needed for ssort() */
379
380 register char *p1 = *pp1;
381 register char *p2 = *pp2;
382
383 if( Longfmt )
384 {
385 /* Skip forward to the '-' that will preceede
386 * the filename.
387 */
388
389 while( *p1 && *p1 != '-' )
390 p1++;
391
392 while( *p2 && *p2 != '-' )
393 p2++;
394 }
395
396 return( strcmp(p1, p2) );
397 }
398
399 /*----------------------------------------------------------------------*/
400
401 DIRECTORY *mk_dir( size )
402 register unsigned size;
403 {
404 /* Make a DIRECTORY with the indicated number of dirv entries.
405 * Note that since one dirv entry is declared as part of the
406 * DIRECTORY header, we'll actually have size+1 entries
407 * available, though the last one is never used. We allocate
408 * it so that we can terminate the list with a null
409 * entry, even if the list is full.
410 */
411
412 register DIRECTORY *dp;
413
414
415
416
417 if( !( dp = (DIRECTORY *)calloc( (unsigned)1,
418 sizeof(DIRECTORY) + (size * sizeof(char *))) ))
419 return 0;
420
421 dp->maxdirs = size ;
422 dp->lastdir = (char **) dp->dirv;
423 return dp;
424 }
425
426 /*----------------------------------------------------------------------*/
427
428 del_dir( dp )
429 register DIRECTORY *dp;
430 {
431 /* Delete a directory made with a previous mk_dir call.
432 * Note that all the strings pointed to by dirv entries
433 * are assumed to have been gotten from malloc (this is
434 * always true if dir() is used to fill the strings.
435 */
436
437 register char **v;
438
439 for( v = (char **) dp->dirv; v < dp->lastdir ; free( *v++ ) )
440 ;
441
442 free( dp );
443 }
444
445 /*----------------------------------------------------------------------*/
446
447 dir( spec, dp )
448 char *spec;
449 DIRECTORY *dp;
450 {
451 /* Get a directory for the indicated spec. DOS wildcards are
452 * permitted. If the DIRECTORY pointed to by dp already has
453 * entries in it, new ones will be appended onto the existing
454 * ones. If *spec is null, no files will be gotten, this is
455 * useful if all you want is the volume label.
456 *
457 * Note that the DTA is not modified by this routine. It
458 * sets the DTA to its own address, but then restores the
459 * DTA before returning.
460 */
461
462 REGS regs ; /* Needed for DOS calls */
463 FILE_INFO info ; /* DOS puts dirs here */
464 char path[80] ; /* place to put path */
465 char **firstdir; /* Used for sorting */
466 short seg,off ; /* Segment and offset of */
467 /* original DTA */
468 unsigned sec_per_cluster, /* Used to compute number of */
469 bytes_per_sector, /* bytes in a cluster */
470 garbage;
471
472 gregs( ®s ); /* Get the original DTA */
473 DOSCALL( GETDTA, regs );
474
475 seg = regs.x.es ; /* remember it in set:off */
476 off = regs.x.bx ;
477
478 regs.x.dx = (word) &info; /* Change the Disk Transfer Addr */
479 DOSCALL( SETDTA, regs ); /* to point at info structure */
480
481
482 /* Find the number of bytes/cluster on the indicated
483 * disk drive (or on the current drive if none is
484 * specified.
485 */
486
487 if( !diskinfo( (!*spec||spec[1]!=':') ? 0 : (toupper(*spec)-'A')+1,
488 &sec_per_cluster, &bytes_per_sector, &garbage, &garbage))
489 fprintf(stderr,"dir: Can't access indicated disk\n");
490
491 Cluster_size = sec_per_cluster * bytes_per_sector ;
492
493
494 /* If a volume label is requested, get it and copy it into
495 * dp->vol_lab. Any imbedded '.'s are stripped by clab.
496 * If no volume label is present, the string is nulled.
497 */
498
499 if( dp->label )
500 {
501 *dp->vol_label = 0;
502
503 if( spec[1] != ':' )
504 strcpy( path, "/*.*" );
505 else
506 {
507 *path = *spec ;
508 strcpy( path+1, ":/*.*" );
509 }
510
511 if( !find_first(path, LABEL, ®s) )
512 clab( dp->vol_label, info.fi_name );
513 }
514
515 /*
516 * Now get the directories:
517 */
518
519 if( dp->exp && !haswild(spec) )
520 spec = fixup_name( spec, ®s, &info );
521
522 copy_path( path, dp->path ? spec : "" );
523
524 firstdir = dp->lastdir;
525
526 /* Now go look for the file:
527 */
528
529 if( !find_first(spec, ATTRIBUTES, ®s) )
530 if( !add_entry(&info, dp, path) )
531 goto abort;
532
533 if( haswild(spec) )
534 while( !find_next( ®s ) )
535 if( !add_entry(&info, dp, path) )
536 goto abort;
537
538 if( dp->sort )
539 ssort( (char *)firstdir, dp->lastdir - firstdir,
540 sizeof(char*), cmp);
541
542 abort:
543 regs.x.ds = seg ; /* Restore the original disk */
544 regs.x.dx = off ; /* transfer address. */
545 DOSCALL( SETDTA, regs );
546 }
Listing 9 -- reargv.c
------------------------------------------------------------------------------
1 #include
2 #include
3
4 #define MAXARGC (unsigned)128
5 #define isquote(c) ((c)=='"' || (c)=='\'')
6
7 extern char *getenv( char* );
8 extern char *malloc( unsigned );
9
10 /*----------------------------------------------------------------------*/
11
12 static char *nextarg( pp )
13 char **pp;
14 {
15 register char *p;
16 char *start;
17 register int term;
18
19 if( !*(p = *pp) )
20 return (char *) 0;
21
22 while( isspace(*p) )
23 p++;
24
25 if( isquote(*p) ) /* Can't use a conditional because */
26 term = *p++; /* of order of evaluation problems */
27 else
28 term = ' ';
29
30 for( start = p; *p ; p++)
31 {
32 if( *p == term && *(p-1) != '\\' )
33 {
34 *p++ = '\0';
35 break;
36 }
37 }
38
39 *pp = p;
40
41 return start;
42 }
43
44 /*----------------------------------------------------------------------*/
45
46 int reargv( argcp, argvp )
47 char ***argvp;
48 int *argcp;
49 {
50 register int argc = 0 ;
51 register int maxc = MAXARGC ;
52 char **argv, **start_argv ;
53 char *env, *p ;
54
55 if( !(env = getenv("CMDLINE")) || !*env )
56 return 0;
57
58 if( !(p = malloc( strlen(env)+1 )))
59 return 0;
60
61 if( !(argv = (char **) malloc( MAXARGC * sizeof(char *)) ))
62 return 0;
63
64 strcpy(p, env);
65 start_argv = argv;
66 for( maxc=MAXARGC; --maxc >= 0 && (*argv++ = nextarg(&p)); argc++)
67 ;
68
69 if( maxc < 0 )
70 fprintf(stderr, "Command line truncated\n");
71
72 *argcp = argc;
73 *argvp = start_argv;
74 return 1;
75 }
76
77 /*----------------------------------------------------------------------*/
78
79 #ifdef DEBUG
80
81 main( argc, argv )
82 char **argv;
83 {
84 printf("Original command line is: |");
85 while( --argc >= 0 )
86 printf("%s|", *argv++ );
87
88 if( !reargv( &argc, &argv ) )
89 printf("\nCMDLINE not present\n");
90 else
91 {
92 printf("New argc = %d\n", argc );
93 printf("\nModified command line is: |");
94
95 while( --argc >= 0 )
96 printf("%s|", *argv++ );
97
98 printf("\n");
99 }
100 }
101
102 #endif
Listing 10 -- ssort.c
------------------------------------------------------------------------------

1 /* SSORT.C Works just like qsort() except that a shell
2 * sort, rather than a quick sort, is used. This
3 * is more efficient than quicksort for small numbers of elements
4 * and it's not recursive so will use much less stack space.
5 *
6 * Copyright (C) 1985, Allen I. Holub. All rights reserved
7 */
8
9 void ssort( base, nel, width, cmp )
10 char *base;
11 int nel, width;
12 int (*cmp)();
13 {
14 register int i, j;
15 int gap, k, tmp ;
16 char *p1, *p2;
17
18 for( gap = nel >>1 ; gap > 0 ; gap >>=1 )
19 for( i = gap; i < nel; i++ )
20 for( j = i-gap; j >= 0 ; j -= gap )
21 {
22 p1 = base + ( j * width);
23 p2 = base + ((j+gap) * width);
24
25 if( (*cmp)( p1, p2 ) <= 0 )
26 break;
27
28 for( k = width; --k >= 0 😉
29 {
30 tmp = *p1;
31 *p1++ = *p2;
32 *p2++ = tmp;
33 }
34 }
35 }


  3 Responses to “Category : Files from Magazines
Archive   : DDJ8603.ZIP
Filename : HOLUBLST.MAR

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/