home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR24 / CFF51B.ZIP / CFPORT.CS2 < prev    next >
Text File  |  1993-10-22  |  19KB  |  958 lines

  1. /* CFPORT.CS2 -- cset2 for OS/2 2.x */
  2. /* PORTABILITY FOR CFF -- MODIFY TO SUIT THE COMPILER/OS IN USE */
  3.  
  4. #define ftruncate(a,b) chsize(a,b)
  5.  
  6. #define INCL_BASE
  7. #define INCL_DOSMEMMGR
  8. #define INCL_DOSFILEMGR
  9. #include <os2.h>
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #include <stdlib.h>
  13. #include <fcntl.h>
  14. #include <errno.h>
  15. #include <time.h>
  16. #include <io.h>
  17. #include <direct.h>
  18. #include <share.h>
  19. #include <stdio.h>
  20.  
  21. #include "..\cff.h"
  22.  
  23. extern void *mymemmove(void *, void *, long);
  24. extern int mystrlen(void *);
  25. extern int mystrcpy(void *, void *);
  26.  
  27. #define PCDOS 0
  28. #define CFF_OS2 1
  29. #define HAS_NO_DIRENT 1
  30. #define HAS_NO_SBRK 1
  31.  
  32. #define NIBBLE 128
  33. #define CHUNK_SIZE 8192
  34.  
  35. #ifndef HEAPSTART
  36. #define HEAPSTART 0x50000
  37. #endif
  38.  
  39. unsigned long heapcreep;
  40. void *heapstart = (void *)HEAPSTART;
  41.  
  42.  
  43. static STOR BIGZERO;
  44.  
  45. /* DUMMY ROUTINES TO PREVENT LINKING UNWANTED MALLOC LIKE STUFF */
  46. int getpagesize(void)
  47. {
  48.     return 4096;
  49. }
  50. int _heapchk(void)
  51. {
  52.     return 0;
  53. }
  54.  
  55. int _heapset(unsigned a)
  56. {
  57.     return 0;
  58. }
  59. void *_expand (void *mem, size_t new_size)
  60. {
  61.     return NULL;
  62. }
  63. size_t _msize (const void *mem)
  64. {
  65.     return mallocsize(mem);
  66. }
  67. int _heapmin(void)
  68. {
  69.     return 0;
  70. }
  71. int _debug_heapmin(const char *fn, size_t ln)
  72. {
  73.     return 0;
  74. }
  75. void _debug_free( void *ptr, const char *fn, size_t ln)
  76. {
  77.     free(ptr);
  78. }
  79. void *_debug_calloc(size_t num, size_t size, const char *fn, size_t ln)
  80. {
  81.     return calloc(num, size);
  82. }
  83. void *_debug_malloc(size_t size, const char *fn, size_t ln)
  84. {
  85.     return malloc(size);
  86. }
  87. void *_debug_realloc(void *ptr, size_t size, const char *fn, size_t ln)
  88. {
  89.     return realloc(ptr, size);
  90. }
  91. void *_dump_allocated(int nbytes)
  92. {
  93.     return NULL;
  94. }
  95. void *_heap_check(void)
  96. {
  97.     return NULL;
  98. }
  99.  
  100. /* --------------- END OF MALLOC DUMMYS ------------------ */
  101.  
  102. static unsigned long
  103. round_up(long size, long amt)
  104. {
  105.     return (size&(amt-1)) ? size+(amt-(size&(amt-1))) : size;
  106. }
  107.  
  108.  
  109.  
  110. static int testflags = 0;
  111. void
  112. cfport_settestflags(int flags)
  113. {
  114.     testflags |= flags;
  115. }
  116. void
  117. cfport_clrtestflags(int flags)
  118. {
  119.     testflags &= ~flags;
  120. }
  121.  
  122. static void
  123. fix_statbuf(struct stat *stat, CFSTAT *sbuf)
  124. {
  125.     sbuf->st_atime = stat->st_atime;
  126.     sbuf->st_mtime = stat->st_mtime;
  127.     sbuf->st_ctime = stat->st_ctime;
  128.     sbuf->st_size = stat->st_size;
  129.     sbuf->st_alloc = stat->st_size;
  130.     sbuf->st_filesize = stat->st_size;
  131.     sbuf->st_filealloc = stat->st_size;
  132. #if 0
  133.     sbuf->st_blksize = stat->st_blksize;
  134. #else
  135.     sbuf->st_blksize = 8192;
  136. #endif
  137.     sbuf->st_dev = stat->st_dev;
  138.     sbuf->st_ino = stat->st_ino;
  139.     sbuf->st_nlink = stat->st_nlink;
  140.     sbuf->st_uid = stat->st_uid;
  141.     sbuf->st_gid = stat->st_gid;    
  142.     sbuf->st_rdev = stat->st_rdev;
  143.     sbuf->st_mode = stat->st_mode;
  144. }
  145.  
  146. #if HAS_NO_SBRK == 1
  147. static int sbrk_initted = 0;
  148. void *sbrkmem_base;
  149. static unsigned long mem_alloced;
  150. static unsigned long sbrk_alloced;
  151.  
  152. static int
  153. get_os2_memory(void)
  154. {
  155. void *my_base;
  156. unsigned long my_alloced;
  157.  
  158.     /* Allocate 32 Megabytes of uncommitted memory -- this is the OS2 limit */
  159.     my_alloced = 32*1024*1024;
  160.     while(DosAllocMem(&my_base, my_alloced, PAG_READ|PAG_WRITE))
  161.     {/* Failure -- try smaller allocation */
  162.         if(my_alloced <= 4*1024*1024)
  163.                 return 0;
  164.         my_alloced -= 4*1024*1024;
  165.     }
  166.     /* Check coalesce */
  167.     if(my_base == ((char *)sbrkmem_base + mem_alloced))
  168.         mem_alloced += my_alloced;
  169.     else
  170.     {
  171.         sbrkmem_base = my_base;
  172.         mem_alloced = my_alloced;
  173.         sbrk_alloced = 0;
  174.     }
  175.     return 1;
  176. }
  177.  
  178. void *
  179. sbrk(int amount)
  180. {
  181. int commit = 1;
  182.     if(!sbrk_initted)
  183.     {
  184.         if(!get_os2_memory())
  185.             abort();
  186.         sbrk_initted = 1;
  187.     }
  188.     if(amount < 0)
  189.     {
  190.         amount = -amount;
  191.         commit = 0;
  192.     }
  193.     for(;;)
  194.     {
  195.         if((amount + sbrk_alloced) <= mem_alloced)
  196.         {
  197.         void *return_base = (char *)sbrkmem_base + sbrk_alloced;
  198.             sbrk_alloced += amount;
  199.             if(commit)
  200.                 DosSetMem(return_base, amount, PAG_COMMIT|PAG_READ|PAG_WRITE);
  201.             return return_base;
  202.         }
  203.         if(!get_os2_memory())
  204.             return ((void *)-1);
  205.     }
  206. }
  207. #endif
  208.  
  209. void *
  210. PORTSBRK(unsigned long amt)
  211. {
  212.     return sbrk(amt);
  213. }
  214. void
  215. PORTHEAPSTART(void)
  216. {
  217. void *curstart = sbrk(0);
  218. char  *newstart = NULL;
  219. int amount;
  220.  
  221.     if(curstart > heapstart)
  222.     {
  223.         cfprintf("CFPORT: The heap safety zone was exceeded by %d bytes.\n",
  224.             -((long)((unsigned long)heapstart - (unsigned long)curstart)));
  225.         cfprintf("        Modify 'heapstart' in cfport.c\n");
  226. #if HAS_NO_SBRK == 1
  227.         cfprintf("        sbrkmem_base=%0xlx=%lu sbrk_alloc=%lu\n",
  228.                     sbrkmem_base, mem_alloced);
  229. #endif
  230.         exit(-1);
  231.     }
  232.     amount = heapcreep = (unsigned long)((unsigned long)heapstart - (unsigned long)curstart);
  233.     if((newstart = sbrk(-amount)) == (void *)-1) {
  234.         cfprintf("CFFINIT: failed to set heap: zone=%lu HEAPSTART=%p curstart=%p.\n",
  235.         heapcreep, heapstart, curstart);
  236.         exit(-2);
  237.     }
  238.     else if(heapcreep && newstart+heapcreep != heapstart) {
  239.         cfprintf("Heap was not set properly: desired=%p result=%p zone=%lu\n", 
  240.             heapstart, newstart, heapcreep);
  241.         exit(-3);
  242.     }
  243. }
  244. int
  245. PORTSTAT(void *path, CFSTAT *sbuf)
  246. {
  247. struct stat _stat;
  248. int result = stat(path, &_stat);
  249.     if(result == 0)
  250.         fix_statbuf(&_stat, sbuf);
  251.     return result;
  252. }
  253. void
  254. PORTFSTAT(int handle, CFSTAT *sbuf)
  255. {
  256. struct stat _stat;
  257.  
  258.     fstat(handle, &_stat);
  259.     fix_statbuf(&_stat, sbuf);    
  260. }
  261.  
  262. long
  263. PORTREAD(long handle, void *mem_addr, STOR dsk_addr, long amount)
  264. {
  265.     lseek(handle, dsk_addr.a0, SEEK_SET);  
  266.     return read(handle, mem_addr, amount);
  267.  
  268. }
  269. long
  270. PORTWRITE(long handle, void *mem_addr, STOR dsk_addr, long amount)
  271. {
  272.     lseek(handle, dsk_addr.a0, SEEK_SET);  
  273.     return write(handle, mem_addr, amount);
  274. }
  275. void
  276. PORTSEEK(long handle, STOR spot, int mode, STOR *loc)
  277. {
  278. STOR ret;
  279.     switch(mode)
  280.     {
  281.         case S_END:
  282.             mode = SEEK_END;
  283.             break;
  284.         case S_CUR:
  285.             mode = SEEK_CUR;
  286.             break;
  287.         case S_SET:
  288.             mode = SEEK_SET;
  289.             break;
  290.         default:
  291.             mode = -1;
  292.     }
  293.     ret.a4.s1 = 0;
  294.     ret.a4.s0 = lseek((int)handle, spot.a0, mode);
  295.     if(loc)
  296.         *loc = ret;
  297. }
  298. long
  299. PORTOPEN(void *path, int mode)
  300. {
  301. int omode = O_BINARY;
  302.  
  303.     if(mode & F_STAT)
  304.         omode |= O_RDONLY;
  305.     else if((mode & F_RDWR) == F_RDWR)
  306.         omode |= O_RDWR;
  307.     else if((mode & F_RDWR) == F_WRONLY)
  308.         omode |= O_RDWR;
  309.     else if((mode & F_RDWR) == F_RDONLY)
  310.         omode |= O_RDONLY;
  311.     if(mode & F_TRUNC)
  312.         omode |= O_TRUNC;
  313.     if(mode & F_EXCL)
  314.         omode |= O_EXCL;
  315.     if(mode & F_APPEND)
  316.         omode |= O_APPEND;
  317.  
  318.     return open(path,omode);
  319. }
  320. long
  321. PORTCLOSE(long handle)
  322. {
  323.     return close((int)handle);
  324. }
  325. long
  326. PORTCREATE(void *path, int mode)
  327. {
  328. int shflg;
  329.     if(mode & F_EXCL)
  330.          shflg = SH_DENYRW;
  331.     else shflg = SH_DENYNO;
  332.     return sopen(path,O_BINARY|O_CREAT|O_TRUNC|O_RDWR,shflg,S_IREAD|S_IWRITE);
  333. }
  334. long
  335. PORTUNLINK(void *path)
  336. {
  337.     return unlink(path);
  338. }
  339.  
  340. #if PCDOS == 1
  341. static void
  342. dos_truncate(short handle, long amount)
  343. {
  344. #include <dos.h>
  345. union REGS r;
  346.  
  347.     r.h.al = 0;        /* SEEK_SET */
  348.     r.h.ah = 0x42;    /* seek */
  349.     r.x.bx = handle;
  350.     r.x.dx = (short)amount;
  351.     r.x.cx = (short)(amount>>16);
  352.     _int86(0x21,&r,&r);
  353.  
  354.     r.h.ah = 0x40;    /* write */
  355.     r.x.bx = handle;
  356.     r.x.cx = 0;        /* amount == 0 */
  357.     _int86(0x21,&r,&r);
  358.     
  359.     r.h.ah = 0x3e;    /* close */
  360.     r.x.bx = handle;
  361.     _int86(0x21,&r,&r);
  362. }
  363. #endif
  364. #if HAS_NO_FTRUNCATE == 1
  365. static int
  366. ftruncate(int handle, long size)
  367. {
  368. }
  369. #endif
  370. #if HAS_NO_FSYNC == 1
  371. static int
  372. fsync(int handle)
  373. {
  374. }
  375. #endif
  376. #if HAS_NO_SYNC == 1
  377. static void
  378. sync(void)
  379. {
  380. }
  381. #endif
  382.  
  383. long
  384. PORTTRUNCATE(long handle, char *path, STOR amount)
  385. {
  386. #if PCDOS == 1
  387.     if(_emx_env & 0x200)
  388.     {/* Running under OS2 */
  389.         ftruncate((int)handle, amount.a0);
  390.         return handle;
  391.     }
  392.     else
  393.     {
  394.         dos_truncate((short)handle, amount.a0);
  395.         return PORTOPEN(path, F_RDWR);
  396.     }
  397. #else
  398.     ftruncate((int)handle, amount.a0);
  399.     return handle;
  400. #endif
  401. }
  402. void
  403. PORTCLOSETRUNC(long handle, STOR amount)
  404. {
  405. #if PCDOS == 1
  406.     if(_emx_env & 0x200)
  407.     {/* Running under OS2 */
  408.         ftruncate((int)handle, amount.a0);
  409.         close ((int)handle);
  410.     }
  411.     else
  412.         dos_truncate((short)handle, amount.a0);
  413. #else
  414.     ftruncate((int)handle, amount.a0);
  415.     close((int)handle);
  416. #endif
  417. }
  418.  
  419. void
  420. PORTFLUSH(long handle)
  421. {
  422.     DosResetBuffer((HFILE)handle);
  423. #if 0
  424.     if(handle < 0)
  425.          sync();
  426.     else fsync((int)handle);
  427. #endif
  428. }
  429.  
  430. char *
  431. PORTGETCWD(void *buf, int maxlen)
  432. {
  433. char *result;
  434.  
  435.     result = getcwd((char *)buf, maxlen);
  436.     ((char *)buf)[maxlen] = 0;
  437.     if(result)
  438.     {
  439.     char *cp = buf;
  440.         while(*cp != 0)
  441.         {
  442.             if(*cp == '\\') *cp = '/';
  443.             ++cp;
  444.         }
  445.     }
  446.     return result;
  447. }
  448.  
  449. long
  450. PORTCHDIR(void *path)
  451. {
  452.     return chdir(path);
  453. }
  454. unsigned long
  455. PORTTIME(void)
  456. {
  457.     return time(NULL);
  458. }
  459. unsigned long
  460. PORTCLOCK(void)
  461. {
  462.     return clock();
  463. }
  464. void
  465. PORTABORT(void)
  466. {
  467.  
  468.     abort();
  469. }
  470.  
  471. /* THE BASIC OS DRIVERS */
  472.  
  473. /* Primary Memory driver */
  474. long
  475. pmem_driver(int func, int handle, void *mem_addr, STOR dsk_addr, long amount)
  476. {
  477.     switch(func)
  478.     {
  479.         case    S_GETSPACE:
  480.         {
  481.         unsigned long min, nib, current;
  482.  
  483.             amount = round_up(amount, CHUNK_SIZE);
  484.             min = round_up(amount / 4, CHUNK_SIZE);
  485.             nib = round_up(amount / 16, CHUNK_SIZE);
  486.             current = amount;
  487.             ((STOR *)mem_addr)->a2.size = 0;
  488.             ((STOR *)mem_addr)->a2.type = STO_CHUNK;
  489.  
  490.             while(current >= min) {
  491.               if((((STOR *)mem_addr)->a1 = PORTSBRK(current)) != (void *)-1) {
  492.                 if(((STOR *)mem_addr)->a0 & (NIBBLE-1))
  493.                 {/* Normally the system uses NIBBLE bytes as the alignment */
  494.                   ((STOR *)mem_addr)->a0 = 
  495.                               round_up(((STOR *)mem_addr)->a0, NIBBLE);
  496.                   current -= NIBBLE;
  497.                 }
  498.                 ((STOR *)mem_addr)->a2.size = current;
  499.                 return 0;
  500.               }
  501.               current -= nib;
  502.             }
  503.             return 1;
  504.         }
  505.         case    S_GIVESPACE:
  506.             return 1;
  507.         default:
  508.             return 1;
  509.     }
  510.     return 0;
  511. }
  512.  
  513. /* Secondary Memory driver */
  514. long
  515. smem_driver(int func, int handle, void *mem_addr, STOR dsk_addr, long amount)
  516. {
  517.     if(!(testflags & 1))
  518.     {/* 
  519.         IF SECONDARY MEMORY REALLY EXISTS, THEN PUT A REAL DRIVER HERE.
  520.         The system adapts to a 0 return from S_GETSPACE by mapping 
  521.         secondary memory to primary memory when cfinit is called.
  522.         S_OPEN is never called.
  523.      */
  524.         switch (func)
  525.         {
  526.             case S_GETSPACE:
  527.                 *((long *)mem_addr) = 0;
  528.                 break;
  529.         }
  530.         return -1;
  531.     } /* END: Real driver */
  532.     else {
  533.     /* THIS CODE IS JUST FOR TESTING PURPOSES, IT USES A LOCAL MEMORY BUFFER */
  534.  
  535. #define SMEMMAX (4096*1024)
  536. static char *sbuf = NULL;
  537. static long smemalloc = 0;
  538.  
  539.         if(sbuf == NULL) {
  540.             if((sbuf = PORTSBRK(SMEMMAX)) == (void *)-1) {
  541.                 cfprintf("SMEM_DRIVER: Failed to init test memory block.\n");
  542.                 exit(-1);
  543.             }
  544.         }
  545.         switch(func)
  546.         {
  547.             case    S_CLOSE:
  548.                 return 0;        /* a real driver would do something */            
  549.             case    S_READBLK:
  550.             case    S_WRITEBLK:
  551.             {
  552.             char *smemaddr = sbuf + dsk_addr.a0;
  553.             long xfer = amount;
  554.                 if(dsk_addr.a0 + amount > smemalloc)
  555.                     xfer = smemalloc - dsk_addr.a0;
  556.                 if(xfer < 0) {
  557.                     return -1;
  558.                 }
  559.                 if(func == S_READBLK)
  560.                      mymemmove(mem_addr, smemaddr, xfer);
  561.                 else mymemmove(smemaddr, mem_addr, xfer);
  562.                 return xfer;
  563.             }
  564.             case    S_GETSPACE:
  565.                 amount = round_up(amount, CHUNK_SIZE);
  566.                 ((STOR *)mem_addr)->a0 = smemalloc;
  567.                 ((STOR *)mem_addr)->a2.size = 0;
  568.                 ((STOR *)mem_addr)->a2.type = STO_CHUNK;
  569.                 if(amount + smemalloc < SMEMMAX) {
  570.                     ((STOR *)mem_addr)->a2.size = amount;
  571.                     smemalloc += amount;
  572.                     return 0;
  573.                 } else {/* Not enough space available, return error + avail */
  574.                     ((STOR *)mem_addr)->a2.size = 
  575.                                     (SMEMMAX - smemalloc) & ~CHUNK_SIZE;
  576.                     return 1;
  577.                 }
  578.             case    S_GIVESPACE:
  579. #if 0
  580. cfprintf("SMEM: GIVESPACE at loc=%lx size=%lu curbase=%lx\n",
  581. ((STOR *)mem_addr)->a0, ((STOR *)mem_addr)->a2.size, smemalloc);
  582. #endif
  583.                 if(((STOR *)mem_addr)->a0 == 
  584.                         smemalloc - ((STOR *)mem_addr)->a2.size)
  585.                 {/* Accept returns if they are at the end */
  586.                     smemalloc -= ((STOR *)mem_addr)->a2.size;
  587. #if 0
  588. cfprintf("SMEM: Truncate to %lu bytes\n", smemalloc);
  589. #endif
  590.                     return 0;
  591.                 }
  592.                 break;
  593.             default:
  594.                 break;
  595.         }
  596.         return 1;
  597.     }/* END: test driver */
  598. }
  599.  
  600. /* Internal file driver */
  601. long
  602. cfile_driver(int func, int handle, void *mem_addr, STOR dsk_addr, long amount)
  603. {
  604. long result = 0;
  605.  
  606.     switch(func)
  607.     {
  608.         case S_READBLK:
  609.             result = PORTREAD(handle, mem_addr, dsk_addr, amount);
  610.             break;
  611.         case S_WRITEBLK:
  612.             result = PORTWRITE(handle, mem_addr, dsk_addr, amount);
  613.             break;
  614.         case    S_GETSPACE:
  615.         {
  616.         unsigned long result;
  617.         STOR base;
  618.         STOR end;
  619.             PORTSEEK(handle, BIGZERO, S_END, &base);
  620.             amount = round_up(amount, CHUNK_SIZE);
  621.             end.a4.s0 = base.a0 + amount-1;
  622.             end.a4.s1 = 0;
  623.             PORTWRITE(handle, "0", end, 1);
  624.             PORTSEEK(handle, BIGZERO, S_END, &end);
  625.             result = end.a0 - base.a0;
  626.             ((STOR *)mem_addr)->a0 = base.a0;
  627.             ((STOR *)mem_addr)->a2.size = result;
  628.             ((STOR *)mem_addr)->a2.type = STO_CHUNK;
  629.             return (result == amount) ? 0:1;        
  630.         }
  631.         case    S_GIVESPACE:
  632.         {
  633.         STOR base; 
  634.             PORTSEEK(handle, BIGZERO, S_END, &base);
  635.             if((((STOR *)mem_addr)->a0 + ((STOR *)mem_addr)->a2.size) == base.a0)
  636.             {/* OK to return space if at end */
  637. #if 0
  638.             long result;
  639.                 base.a0 -= ((STOR *)mem_addr)->a2.size;
  640.                 result = PORTTRUNCATE(handle, base);
  641. #endif
  642.                 return 0;
  643.             }
  644.             else return 1;
  645.         }
  646.         case    S_OPEN:
  647.             result = PORTOPEN(mem_addr, handle);
  648.             break;
  649.         case    S_CLOSE:
  650.             result = PORTCLOSE(handle);
  651.             break;
  652.         case    S_CREATE:
  653.             result = PORTCREATE(mem_addr, handle);
  654.             break;
  655.         case    S_UNLINK:
  656.             result = PORTUNLINK(mem_addr);
  657.             break;
  658.         case    S_SEEK:
  659.             PORTSEEK(handle, dsk_addr, amount, mem_addr);
  660.             break;
  661.         case    S_FLUSH:
  662.             PORTFLUSH(handle);
  663.             break;
  664.         case    S_CLOSETRUNC: /* truncate and close, (PCDOS needs this) */
  665.             PORTCLOSETRUNC(handle, dsk_addr);
  666.             break;
  667.         default:
  668.             return 1;
  669.     }
  670.     return result;
  671. }
  672. /* External file driver */
  673. long
  674. xfile_driver(int func, int handle, void *mem_addr, STOR dsk_addr, long amount)
  675. {
  676. long result = 0;
  677.  
  678.     switch(func)
  679.     {
  680.         case    S_GETSPACE:
  681.             ((STOR *)mem_addr)->a2.size = 0;
  682.         case    S_GIVESPACE:
  683.             return 1;
  684.         case    S_OPEN:
  685.             result = PORTOPEN(mem_addr, handle);
  686.             break;
  687.         case    S_CLOSE:
  688.             result = PORTCLOSE(handle);
  689.             break;
  690.         case    S_UNLINK:
  691.             result = PORTUNLINK(mem_addr);
  692.             break;
  693.         case    S_CREATE:
  694.             result = PORTCREATE(mem_addr,handle);
  695.             break;
  696.         case    S_READBLK:
  697.             result = PORTREAD(handle, mem_addr, dsk_addr, amount);
  698.             break;
  699.         case    S_WRITEBLK:
  700.             result = PORTWRITE(handle, mem_addr, dsk_addr, amount);
  701.             break;
  702.         case    S_SEEK:
  703.             PORTSEEK(handle, dsk_addr, amount, mem_addr);
  704.             break;
  705.         case    S_FLUSH:
  706.             PORTFLUSH(handle);
  707.             break;
  708.         default:
  709.             return 1;
  710.     }
  711.     return result;
  712. }
  713. #if HAS_NO_DIRENT == 1
  714. struct dirent {
  715.     int d_namlen;
  716.     char *d_name;
  717. };
  718. typedef struct {
  719.     unsigned long id;
  720.     unsigned long handle;
  721.     long cur_spot;
  722.     char *path;
  723.     struct _FILEFINDBUF3 results;
  724.     struct dirent d;
  725. } DIR;
  726. #define DIRP_ID (0x82018373)
  727.  
  728. static void *
  729. opendir(void *path)
  730. {
  731. DIR *dirp;
  732. unsigned long result = 1;
  733. unsigned long search_count = 1;
  734.  
  735.     if(!path)
  736.         return NULL;
  737.  
  738.     if((dirp = calloc(1,sizeof(DIR))))
  739.     {
  740.         dirp->id = DIRP_ID;
  741.         dirp->handle = 0xffffffff;
  742.         dirp->d.d_name = dirp->results.achName;
  743.         if((dirp->path = malloc(mystrlen(path)+1)))
  744.         {
  745.             mystrcpy(dirp->path, path);
  746.             result = DosFindFirst(
  747.                                 dirp->path,
  748.                                 &dirp->handle,
  749.                                 0x37,
  750.                                 &dirp->results,
  751.                                 sizeof(FILEFINDBUF3),
  752.                                 &search_count,
  753.                                 1
  754.                               );                                
  755.             if(result)
  756.             {
  757.                 free(dirp->path);
  758.             }
  759.         }
  760.         if(result)
  761.         {
  762.             free(dirp);
  763.             dirp = NULL;
  764.         }
  765.     }
  766.     return dirp;
  767. }
  768. static void *
  769. readdir(DIR *dirp)
  770. {
  771. unsigned long result = 1;
  772. unsigned long search_count = 1;
  773.  
  774.     if(!dirp || dirp->id != DIRP_ID)
  775.         return NULL;
  776.  
  777.     if(dirp->cur_spot == 0)
  778.     {
  779.         result = DosFindFirst(
  780.                                 dirp->path,
  781.                                 &dirp->handle,
  782.                                 0x37,
  783.                                 &dirp->results,
  784.                                 sizeof(FILEFINDBUF3),
  785.                                 &search_count,
  786.                                 1
  787.                               );                                
  788.     }
  789.     else if(dirp->cur_spot > 0)
  790.     {
  791.         result = DosFindNext(
  792.                                 dirp->handle,
  793.                                 &dirp->results,
  794.                                 sizeof(FILEFINDBUF3),
  795.                                 &search_count
  796.                             
  797.                             );
  798.     }
  799.     if(result == 0 && search_count > 0)
  800.     {
  801.         dirp->cur_spot += 1;
  802.         dirp->d.d_namlen = dirp->results.cchName;
  803.         return &dirp->d;
  804.     }
  805.     else
  806.         dirp->cur_spot = -1;
  807.  
  808.     return NULL;
  809. }
  810. static long
  811. telldir(DIR *dirp)
  812. {
  813.     if(!dirp || dirp->id != DIRP_ID)
  814.         return -1;
  815.     return dirp->cur_spot;
  816. }
  817. static void
  818. seekdir(DIR *dirp, long spot)
  819. {
  820.     if(dirp && dirp->id == DIRP_ID && spot >= 0)
  821.     {
  822.     long i;
  823.         dirp->cur_spot = 0;
  824.         for(i = 0; i < spot; ++i)
  825.             if(!readdir(dirp))
  826.                 break;
  827.     }
  828. }
  829. static void
  830. rewinddir(DIR *dirp)
  831. {
  832.     if(dirp && dirp->id == DIRP_ID)
  833.     {
  834.         dirp->cur_spot = 0;
  835.     }
  836. }
  837. static void
  838. closedir(DIR *dirp)
  839. {
  840.     if(dirp && dirp->id == DIRP_ID)
  841.     {
  842.         DosFindClose(dirp->handle);
  843.         free(dirp->path);
  844.         free(dirp);
  845.     }
  846. }
  847. #else
  848. #include <dirent.h>
  849. #endif
  850.  
  851. void *
  852. PORTOPENDIR(char *name)
  853. {
  854.     return opendir(name);
  855. }
  856. void *
  857. PORTREADDIR(void *it, CFDIRENT *d)
  858. {
  859. struct dirent *rd;
  860.     if((rd = readdir((DIR *)it))) {
  861.         d->d_namlen = rd->d_namlen;
  862.         d->d_name = rd->d_name;
  863.         d->d_mode = M_EXTRNFILE;
  864.     }
  865.     return rd;
  866. }
  867. void
  868. PORTTELLDIR(void *it, STOR *loc)
  869. {
  870. STOR me;
  871.     me.a4.s0 = 0;
  872.     me.a4.s1 = 0;
  873.     me.a0 = telldir((DIR *)it); 
  874.     if(loc)
  875.         *loc = me;
  876. }
  877. void
  878. PORTSEEKDIR(void *it, STOR *loc)
  879. {
  880.     seekdir((DIR *)it, loc->a0);
  881. }
  882. void
  883. PORTREWINDDIR(void *it)
  884. {
  885.     rewinddir((DIR *)it);
  886. }
  887. void
  888. PORTCLOSEDIR(void *it)
  889. {
  890.     closedir((DIR *)it);
  891. }
  892. int
  893. PORTPRINT(int c)
  894. {
  895.     return write(1, &c, 1);
  896. }
  897.  
  898. #if 0
  899. /* 
  900.     THIS CODE IS FOR SAMPLE PURPOSES ONLY -- THE REAL CODE IS IN THE LIBRARY
  901.     PROGRAMMERS WHO WISH TO CREATE CUSTOM COMPARISON ROUTINES CAN USE THESE
  902.     FUNCTIONS AS MODELS.
  903. */
  904. /*
  905.     default_keycmp - system key comparison
  906.  
  907.     Return:    LESS    if keya <  keyb
  908.             EQUAL    if keya == keyb
  909.             GREATER    if keya >  keyb
  910. */
  911. static __inline__ int
  912. mymemcmp(unsigned char *a, unsigned char *b, int len)
  913. {
  914. int result = 0;
  915.     do {
  916.         if((result = ((int)*a++) - ((int)*b++)))
  917.             return result;
  918.     } while(--len);
  919.     return result;
  920. }
  921. int
  922. default_keycmp (void *keya, int    lena, void *keyb, int lenb)
  923. {
  924. int    result;
  925.  
  926.     if (lena == 0)
  927.         return ( (lenb == 0) ? EQUAL : LESS );
  928.     else if (lenb == 0)
  929.         return (GREATER);
  930.  
  931.  
  932.     result = mymemcmp (keya, keyb, ((lena<lenb)?lena:lenb));
  933.  
  934.     if (result < 0)
  935.         return LESS;
  936.     if (result > 0)
  937.         return GREATER;
  938.  
  939.     return ((lena == lenb) ? EQUAL : ((lena < lenb) ? LESS : GREATER));
  940.  
  941. }
  942. /*
  943.     default_itemcmp - system item comparison
  944.  
  945.     Return:    LESS-1        if itema <  itemb
  946.             EQUAL+1        if itema == itemb
  947.             GREATER+1    if itema >  itemb
  948. */
  949.  
  950. int
  951. default_itemcmp (Item *a, Item *b)
  952. {
  953.     return ( (a->item == b->item) ? 
  954.                 EQUAL+1 : ((a->item < b->item) ? LESS-1 : GREATER+1) );
  955. }
  956.  
  957. #endif
  958.