Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4758 right-hear 1
 
2
 * uce-dirent.h - operating system independent dirent implementation
3
 *
4
 * Copyright (C) 1998-2002  Toni Ronkko
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining
7
 * a copy of this software and associated documentation files (the
8
 * ``Software''), to deal in the Software without restriction, including
9
 * without limitation the rights to use, copy, modify, merge, publish,
10
 * distribute, sublicense, and/or sell copies of the Software, and to
11
 * permit persons to whom the Software is furnished to do so, subject to
12
 * the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included
15
 * in all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
18
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20
 * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
21
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 *
25
 *
26
 * May 28 1998, Toni Ronkko 
27
 *
28
 * $Id: uce-dirent.h,v 1.7 2002/05/13 10:48:35 tr Exp $
29
 *
30
 * $Log: uce-dirent.h,v $
31
 * Revision 1.7  2002/05/13 10:48:35  tr
32
 * embedded some source code directly to the header so that no source
33
 * modules need to be included in the MS Visual C project using the
34
 * interface, removed all the dependencies to other headers of the `uce'
35
 * library so that the header can be made public
36
 *
37
 * Revision 1.6  2002/04/12 16:22:04  tr
38
 * Unified Compiling Environment (UCE) replaced `std' library
39
 *
40
 * Revision 1.5  2001/07/20 16:33:40  tr
41
 * moved to `std' library and re-named defines accordingly
42
 *
43
 * Revision 1.4  2001/07/10 16:47:18  tronkko
44
 * revised comments
45
 *
46
 * Revision 1.3  2001/01/11 13:16:43  tr
47
 * using ``uce-machine.h'' for finding out defines such as `FREEBSD'
48
 *
49
 * Revision 1.2  2000/10/08 16:00:41  tr
50
 * copy of FreeBSD man page
51
 *
52
 * Revision 1.1  2000/07/10 05:53:16  tr
53
 * Initial revision
54
 *
55
 * Revision 1.2  1998/07/19 18:29:14  tr
56
 * Added error reporting capabilities and some asserts.
57
 *
58
 * Revision 1.1  1998/07/04 16:27:51  tr
59
 * Initial revision
60
 *
61
 *
62
 * MSVC 1.0 scans automatic dependencies incorrectly when your project
63
 * contains this very header.  The problem is that MSVC cannot handle
64
 * include directives inside #if..#endif block those are never entered.
65
 * Since this header ought to compile in many different operating systems,
66
 * there had to be several conditional blocks that are compiled only in
67
 * operating systems for what they were designed for.  MSVC 1.0 cannot
68
 * handle inclusion of sys/dir.h in a part that is compiled only in Apollo
69
 * operating system.  To fix the problem you need to insert DIR.H into
70
 * SYSINCL.DAT located in MSVC\BIN directory and restart visual C++.
71
 * Consult manuals for more informaton about the problem.
72
 *
73
 * Since many UNIX systems have dirent.h we assume to have one also.
74
 * However, if your UNIX system does not have dirent.h you can download one
75
 * for example at: http://ftp.uni-mannheim.de/ftp/GNU/dirent/dirent.tar.gz.
76
 * You can also see if you have one of dirent.h, direct.h, dir.h, ndir.h,
77
 * sys/dir.h and sys/ndir.h somewhere.  Try defining HAVE_DIRENT_H,
78
 * HAVE_DIRECT_H, HAVE_DIR_H, HAVE_NDIR_H, HAVE_SYS_DIR_H and
79
 * HAVE_SYS_NDIR_H according to the files found.
80
 */
81
#ifndef DIRENT_H
82
#define DIRENT_H
83
#define DIRENT_H_INCLUDED
84
85
 
86
#if defined(MSDOS)                             /* MS-DOS */
87
#elif defined(__MSDOS__)                       /* Turbo C/Borland */
88
# define MSDOS
89
#elif defined(__DOS__)                         /* Watcom */
90
# define MSDOS
91
#endif
92
93
 
94
#elif defined(__NT__)                          /* Watcom */
95
# define WIN32
96
#elif defined(_WIN32)                          /* Microsoft */
97
# define WIN32
98
#elif defined(__WIN32__)                       /* Borland */
99
# define WIN32
100
#endif
101
102
 
103
 * See what kind of dirent interface we have unless autoconf has already
104
 * determinated that.
105
 */
106
#if !defined(HAVE_DIRENT_H) && !defined(HAVE_DIRECT_H) && !defined(HAVE_SYS_DIR_H) && !defined(HAVE_NDIR_H) && !defined(HAVE_SYS_NDIR_H) && !defined(HAVE_DIR_H)
107
# if defined(_MSC_VER)                         /* Microsoft C/C++ */
108
    /* no dirent.h */
109
# elif defined(__BORLANDC__)                   /* Borland C/C++ */
110
#   define HAVE_DIRENT_H
111
#   define VOID_CLOSEDIR
112
# elif defined(__TURBOC__)                     /* Borland Turbo C */
113
    /* no dirent.h */
114
# elif defined(__WATCOMC__)                    /* Watcom C/C++ */
115
#   define HAVE_DIRECT_H
116
# elif defined(__apollo)                       /* Apollo */
117
#   define HAVE_SYS_DIR_H
118
# elif defined(__hpux)                         /* HP-UX */
119
#   define HAVE_DIRENT_H
120
# elif (defined(__alpha) || defined(__alpha__)) && !defined(__linux__)  /* Alpha OSF1 */
121
#   error "not implemented"
122
# elif defined(__sgi)                          /* Silicon Graphics */
123
#   define HAVE_DIRENT_H
124
# elif defined(sun) || defined(_sun)           /* Sun Solaris */
125
#   define HAVE_DIRENT_H
126
# elif defined(__FreeBSD__)                    /* FreeBSD */
127
#   define HAVE_DIRENT_H
128
# elif defined(__linux__)                      /* Linux */
129
#   define HAVE_DIRENT_H
130
# elif defined(__GNUC__)                       /* GNU C/C++ */
131
#   define HAVE_DIRENT_H
132
# else
133
#   error "not implemented"
134
# endif
135
#endif
136
137
 
138
#if defined(HAVE_DIRENT_H)
139
# include 
140
# ifdef FREEBSD
141
#   define NAMLEN(dp) ((int)((dp)->d_namlen))
142
# else
143
#   define NAMLEN(dp) ((int)(strlen((dp)->d_name)))
144
# endif
145
146
 
147
# include 
148
# define NAMLEN(dp) ((int)((dp)->d_namlen))
149
150
 
151
# include 
152
# define NAMLEN(dp) ((int)((dp)->d_namlen))
153
154
 
155
# include 
156
# define NAMLEN(dp) ((int)((dp)->d_namlen))
157
158
 
159
# include 
160
# define NAMLEN(dp) ((int)((dp)->d_namlen))
161
162
 
163
# include 
164
# include 
165
# ifndef dirent
166
#   define dirent direct
167
# endif
168
# define NAMLEN(dp) ((int)((dp)->d_namlen))
169
170
 
171
172
 
173
# if defined(WIN32)
174
#   define DIRENT_WIN32_INTERFACE
175
# elif defined(MSDOS)
176
#   define DIRENT_MSDOS_INTERFACE
177
# else
178
#   error "missing native dirent interface"
179
# endif
180
181
 
182
# if defined(DIRENT_WIN32_INTERFACE)
183
#   include 
184
#   if !defined(DIRENT_MAXNAMLEN)
185
#     define DIRENT_MAXNAMLEN (MAX_PATH)
186
#   endif
187
188
 
189
 
190
# elif defined(DIRENT_MSDOS_INTERFACE)
191
#   include 
192
193
 
194
#   if defined(__BORLANDC__)
195
#     include 
196
#     if !defined(DIRENT_MAXNAMLEN)
197
#       define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT))
198
#     endif
199
#     if !defined(_find_t)
200
#       define _find_t find_t
201
#     endif
202
203
 
204
#   elif defined(__TURBOC__)
205
#     include 
206
#     if !defined(DIRENT_MAXNAMLEN)
207
#       define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT))
208
#     endif
209
#     define DIRENT_USE_FFBLK
210
211
 
212
#   elif defined(_MSC_VER)
213
#     if !defined(DIRENT_MAXNAMLEN)
214
#       define DIRENT_MAXNAMLEN (12)
215
#     endif
216
217
 
218
#   elif defined(__WATCOMC__)
219
#     if !defined(DIRENT_MAXNAMLEN)
220
#       if defined(__OS2__) || defined(__NT__)
221
#         define DIRENT_MAXNAMLEN (255)
222
#       else
223
#         define DIRENT_MAXNAMLEN (12)
224
#       endif
225
#     endif
226
227
 
228
# endif
229
230
 
231
# if !defined(NAME_MAX) && defined(DIRENT_MAXNAMLEN)
232
#   define NAME_MAX DIRENT_MAXNAMLEN
233
# endif
234
# if NAME_MAX < DIRENT_MAXNAMLEN
235
#   error "assertion failed: NAME_MAX >= DIRENT_MAXNAMLEN"
236
# endif
237
238
 
239
 
240
   * Substitute for real dirent structure.  Note that `d_name' field is a
241
   * true character array although we have it copied in the implementation
242
   * dependent data.  We could save some memory if we had declared `d_name'
243
   * as a pointer refering the name within implementation dependent data.
244
   * We have not done that since some code may rely on sizeof(d_name) to be
245
   * something other than four.  Besides, directory entries are typically so
246
   * small that it takes virtually no time to copy them from place to place.
247
   */
248
  typedef struct dirent {
249
    char d_name[NAME_MAX + 1];
250
251
 
252
# if defined(DIRENT_WIN32_INTERFACE)       /*WIN32*/
253
    WIN32_FIND_DATA data;
254
# elif defined(DIRENT_MSDOS_INTERFACE)     /*MSDOS*/
255
#   if defined(DIRENT_USE_FFBLK)
256
    struct ffblk data;
257
#   else
258
    struct _find_t data;
259
#   endif
260
# endif
261
  } dirent;
262
263
 
264
   * essential for the operation of ``rewinndir'' function. */
265
  typedef struct DIR {
266
    char          *dirname;                    /* directory being scanned */
267
    dirent        current;                     /* current entry */
268
    int           dirent_filled;               /* is current un-processed? */
269
270
 
271
#  if defined(DIRENT_WIN32_INTERFACE)
272
    HANDLE        search_handle;
273
#  elif defined(DIRENT_MSDOS_INTERFACE)
274
#  endif
275
  } DIR;
276
277
 
278
extern "C" {
279
# endif
280
281
 
282
static DIR *opendir (const char *dirname);
283
static struct dirent *readdir (DIR *dirp);
284
static int closedir (DIR *dirp);
285
static void rewinddir (DIR *dirp);
286
287
 
288
 * Implement dirent interface as static functions so that the user does not
289
 * need to change his project in any way to use dirent function.  With this
290
 * it is sufficient to include this very header from source modules using
291
 * dirent functions and the functions will be pulled in automatically.
292
 */
293
#include 
294
#include 
295
#include 
296
#include 
297
#include 
298
299
 
300
#if defined(DIRENT_USE_FFBLK)
301
# define _A_ARCH   (FA_ARCH)
302
# define _A_HIDDEN (FA_HIDDEN)
303
# define _A_NORMAL (0)
304
# define _A_RDONLY (FA_RDONLY)
305
# define _A_SUBDIR (FA_DIREC)
306
# define _A_SYSTEM (FA_SYSTEM)
307
# define _A_VOLID  (FA_LABEL)
308
# define _dos_findnext(dest) findnext(dest)
309
# define _dos_findfirst(name,flags,dest) findfirst(name,dest,flags)
310
#endif
311
312
 
313
static const char *_getdirname (const struct dirent *dp);
314
static void _setdirname (struct DIR *dirp);
315
316
 
317
 * 
318
 * open directory stream for reading
319
 * DIR *opendir (const char *dirname);
320
 *
321
 * Open named directory stream for read and return pointer to the
322
 * internal working area that is used for retrieving individual directory
323
 * entries.  The internal working area has no fields of your interest.
324
 *
325
 * Returns a pointer to the internal working area or NULL in case the
326
 * directory stream could not be opened.  Global `errno' variable will set
327
 * in case of error as follows:
328
 *
329
 * 
330
 * [EACESS  |Permission denied.
331
 * [EMFILE  |Too many open files used by the process.
332
 * [ENFILE  |Too many open files in system.
333
 * [ENOENT  |Directory does not exist.
334
 * [ENOMEM  |Insufficient memory.
335
 * [ENOTDIR |dirname does not refer to directory.  This value is not
336
 *           reliable on MS-DOS and MS-Windows platforms.  Many
337
 *           implementations return ENOENT even when the name refers to a
338
 *           file.]
339
 * 
340
 * 
341
 */
342
static DIR *opendir(const char *dirname)
343
{
344
  DIR *dirp;
345
  assert (dirname != NULL);
346
347
 
348
  if (dirp != NULL) {
349
    char *p;
350
351
 
352
    dirp->dirname = (char*) malloc (strlen (dirname) + 1 + strlen ("\\*.*"));
353
    if (dirp->dirname == NULL) {
354
      /* failed to duplicate directory name.  errno set by malloc() */
355
      free (dirp);
356
      return NULL;
357
    }
358
    /* Copy directory name while appending directory separator and "*.*".
359
     * Directory separator is not appended if the name already ends with
360
     * drive or directory separator.  Directory separator is assumed to be
361
     * '/' or '\' and drive separator is assumed to be ':'. */
362
    strcpy (dirp->dirname, dirname);
363
    p = strchr (dirp->dirname, '\0');
364
    if (dirp->dirname < p  &&
365
        *(p - 1) != '\\'  &&  *(p - 1) != '/'  &&  *(p - 1) != ':')
366
    {
367
      strcpy (p++, "\\");
368
    }
369
# ifdef DIRENT_WIN32_INTERFACE
370
    strcpy (p, "*"); /*scan files with and without extension in win32*/
371
# else
372
    strcpy (p, "*.*"); /*scan files with and without extension in DOS*/
373
# endif
374
375
 
376
    if (_initdir (dirp) == 0) {
377
      /* initialization failed */
378
      free (dirp->dirname);
379
      free (dirp);
380
      return NULL;
381
    }
382
  }
383
  return dirp;
384
}
385
386
 
387
 
388
 * 
389
 * read a directory entry
390
 * struct dirent *readdir (DIR *dirp);
391
 *
392
 * Read individual directory entry and return pointer to a structure
393
 * containing the name of the entry.  Individual directory entries returned
394
 * include normal files, sub-directories, pseudo-directories "." and ".."
395
 * and also volume labels, hidden files and system files in MS-DOS and
396
 * MS-Windows.   You might want to use stat(2) function to determinate which
397
 * one are you dealing with.  Many dirent implementations already contain
398
 * equivalent information in dirent structure but you cannot depend on
399
 * this.
400
 *
401
 * The dirent structure contains several system dependent fields that
402
 * generally have no interest to you.  The only interesting one is char
403
 * d_name[] that is also portable across different systems.  The d_name
404
 * field contains the name of the directory entry without leading path.
405
 * While d_name is portable across different systems the actual storage
406
 * capacity of d_name varies from system to system and there is no portable
407
 * way to find out it at compile time as different systems define the
408
 * capacity of d_name with different macros and some systems do not define
409
 * capacity at all (besides actual declaration of the field). If you really
410
 * need to find out storage capacity of d_name then you might want to try
411
 * NAME_MAX macro. The NAME_MAX is defined in POSIX standard althought
412
 * there are many MS-DOS and MS-Windows implementations those do not define
413
 * it.  There are also systems that declare d_name as "char d_name[1]" and
414
 * then allocate suitable amount of memory at run-time.  Thanks to Alain
415
 * Decamps (Alain.Decamps@advalvas.be) for pointing it out to me.
416
 *
417
 * This all leads to the fact that it is difficult to allocate space
418
 * for the directory names when the very same program is being compiled on
419
 * number of operating systems.  Therefore I suggest that you always
420
 * allocate space for directory names dynamically.
421
 *
422
 * 
423
 * Returns a pointer to a structure containing name of the directory entry
424
 * in `d_name' field or NULL if there was an error.  In case of an error the
425
 * global `errno' variable will set as follows:
426
 *
427
 * 
428
 * [EBADF  |dir parameter refers to an invalid directory stream.  This value
429
 *          is not set reliably on all implementations.]
430
 * 
431
 * 
432
 */
433
static struct dirent *
434
readdir (DIR *dirp)
435
{
436
  assert(dirp != NULL);
437
  if (dirp == NULL) {
438
    errno = EBADF;
439
    return NULL;
440
  }
441
442
 
443
  if (dirp->search_handle == INVALID_HANDLE_VALUE) {
444
    /* directory stream was opened/rewound incorrectly or it ended normally */
445
    errno = EBADF;
446
    return NULL;
447
  }
448
#endif
449
450
 
451
    /*
452
     * Directory entry has already been retrieved and there is no need to
453
     * retrieve a new one.  Directory entry will be retrieved in advance
454
     * when the user calls readdir function for the first time.  This is so
455
     * because real dirent has separate functions for opening and reading
456
     * the stream whereas Win32 and DOS dirents open the stream
457
     * automatically when we retrieve the first file.  Therefore, we have to
458
     * save the first file when opening the stream and later we have to
459
     * return the saved entry when the user tries to read the first entry.
460
     */
461
    dirp->dirent_filled = 0;
462
  } else {
463
    /* fill in entry and return that */
464
#if defined(DIRENT_WIN32_INTERFACE)
465
    if (FindNextFile (dirp->search_handle, &dirp->current.data) == FALSE) {
466
      /* Last file has been processed or an error occured */
467
      FindClose (dirp->search_handle);
468
      dirp->search_handle = INVALID_HANDLE_VALUE;
469
      errno = ENOENT;
470
      return NULL;
471
    }
472
473
 
474
    if (_dos_findnext (&dirp->current.data) != 0) {
475
      /* _dos_findnext and findnext will set errno to ENOENT when no
476
       * more entries could be retrieved. */
477
      return NULL;
478
    }
479
# endif
480
481
 
482
    assert (dirp->dirent_filled == 0);
483
  }
484
  return &dirp->current;
485
}
486
487
 
488
 
489
 * 
490
 * close directory stream.
491
 * int closedir (DIR *dirp);
492
 *
493
 * Close directory stream opened by the `opendir' function.  Close of
494
 * directory stream invalidates the DIR structure as well as previously read
495
 * dirent entry.
496
 *
497
 * The function typically returns 0 on success and -1 on failure but
498
 * the function may be declared to return void on same systems.  At least
499
 * Borland C/C++ and some UNIX implementations use void as a return type.
500
 * The dirent wrapper tries to define VOID_CLOSEDIR whenever closedir is
501
 * known to return nothing.  The very same definition is made by the GNU
502
 * autoconf if you happen to use it.
503
 *
504
 * The global `errno' variable will set to EBADF in case of error.
505
 * 
506
 */
507
static int
508
closedir (DIR *dirp)
509
{
510
  int retcode = 0;
511
512
 
513
  assert (dirp != NULL);
514
  if (dirp == NULL) {
515
    errno = EBADF;
516
    return -1;
517
  }
518
519
 
520
  if (dirp->dirname != NULL) free (dirp->dirname);
521
522
 
523
  if (dirp->search_handle != INVALID_HANDLE_VALUE) {
524
    if (FindClose (dirp->search_handle) == FALSE) {
525
      /* Unknown error */
526
      retcode = -1;
527
      errno = EBADF;
528
    }
529
  }
530
#endif
531
532
 
533
  memset (dirp, 0, sizeof (*dirp));
534
# if defined(DIRENT_WIN32_INTERFACE)
535
  dirp->search_handle = INVALID_HANDLE_VALUE;
536
# endif
537
538
 
539
  return retcode;
540
}
541
542
 
543
 
544
 * 
545
 * rewind directory stream to the beginning
546
 * void rewinddir (DIR *dirp);
547
 *
548
 * Rewind directory stream to the beginning so that the next call of
549
 * readdir() returns the very first directory entry again.  However, note
550
 * that next call of readdir() may not return the same directory entry as it
551
 * did in first time.  The directory stream may have been affected by newly
552
 * created files.
553
 *
554
 * Almost every dirent implementation ensure that rewinddir will update
555
 * the directory stream to reflect any changes made to the directory entries
556
 * since the previous ``opendir'' or ``rewinddir'' call.  Keep an eye on
557
 * this if your program depends on the feature.  I know at least one dirent
558
 * implementation where you are required to close and re-open the stream to
559
 * see the changes.
560
 *
561
 * Returns nothing.  If something went wrong while rewinding, you will
562
 * notice it later when you try to retrieve the first directory entry.
563
 */
564
static void
565
rewinddir (DIR *dirp)
566
{
567
  /* make sure that dirp is legal */
568
  assert (dirp != NULL);
569
  if (dirp == NULL) {
570
    errno = EBADF;
571
    return;
572
  }
573
  assert (dirp->dirname != NULL);
574
575
 
576
#if defined(DIRENT_WIN32_INTERFACE)
577
  if (dirp->search_handle != INVALID_HANDLE_VALUE) {
578
    if (FindClose (dirp->search_handle) == FALSE) {
579
      /* Unknown error */
580
      errno = EBADF;
581
    }
582
  }
583
#endif
584
585
 
586
  if (_initdir (dirp) == 0) {
587
    /* initialization failed but we cannot deal with error.  User will notice
588
     * error later when she tries to retrieve first directory enty. */
589
    /*EMPTY*/;
590
  }
591
}
592
593
 
594
 
595
 * Open native directory stream object and retrieve first file.
596
 * Be sure to close previous stream before opening new one.
597
 */
598
static int
599
_initdir (DIR *dirp)
600
{
601
  assert (dirp != NULL);
602
  assert (dirp->dirname != NULL);
603
  dirp->dirent_filled = 0;
604
605
 
606
  /* Open stream and retrieve first file */
607
  dirp->search_handle = FindFirstFile (dirp->dirname, &dirp->current.data);
608
  if (dirp->search_handle == INVALID_HANDLE_VALUE) {
609
    /* something went wrong but we don't know what.  GetLastError() could
610
     * give us more information about the error, but then we should map
611
     * the error code into errno. */
612
    errno = ENOENT;
613
    return 0;
614
  }
615
616
 
617
  if (_dos_findfirst (dirp->dirname,
618
          _A_SUBDIR | _A_RDONLY | _A_ARCH | _A_SYSTEM | _A_HIDDEN,
619
          &dirp->current.data) != 0)
620
  {
621
    /* _dos_findfirst and findfirst will set errno to ENOENT when no
622
     * more entries could be retrieved. */
623
    return 0;
624
  }
625
# endif
626
627
 
628
  _setdirname (dirp);
629
  dirp->dirent_filled = 1;
630
  return 1;
631
}
632
633
 
634
 
635
 * Return implementation dependent name of the current directory entry.
636
 */
637
static const char *
638
_getdirname (const struct dirent *dp)
639
{
640
#if defined(DIRENT_WIN32_INTERFACE)
641
  return dp->data.cFileName;
642
643
 
644
  return dp->data.ff_name;
645
646
 
647
  return dp->data.name;
648
#endif
649
}
650
651
 
652
 
653
 * Copy name of implementation dependent directory entry to the d_name field.
654
 */
655
static void
656
_setdirname (struct DIR *dirp) {
657
  /* make sure that d_name is long enough */
658
  assert (strlen (_getdirname (&dirp->current)) <= NAME_MAX);
659
660
 
661
      _getdirname (&dirp->current),
662
      NAME_MAX);
663
  dirp->current.d_name[NAME_MAX] = '\0'; /*char d_name[NAME_MAX+1]*/
664
}
665
666
 
667
}
668
# endif
669
# define NAMLEN(dp) ((int)(strlen((dp)->d_name)))
670
671
 
672
# error "missing dirent interface"
673
#endif
674
675
 
676
 
677