/* 
FHANDLE.C
Alternative to using INT 21h Function 67h (added in DOS 3.3)

cl -qc fhandle.c countf.c
fhandle 40

NOTES:
    -- must have FILES= greater than 20 in CONFIG.SYS to have any effect
    -- (or, can use Quarterdeck FILES.COM program to increase SFT size)
    -- if want to open >20 files simultaneously with high-level function
       like fopen(), may have to increase run-time library tables. For
       example, in Microsoft C the size of table for FILE* is hard-wired
       to 20 in /msc/source/startup/_file.c (#define _NFILE_ 20). So
       would have to increase size of this table as well (and recompile
       startup code) if wanted to use >20 fopen() at once, even after
       using the code below.
*/

#include <stdlib.h>
#include <stdio.h>
#include <dos.h>

typedef unsigned char BYTE;
typedef unsigned WORD;
typedef unsigned long DWORD;
typedef BYTE far *FP;

#ifndef MK_FP
#define MK_FP(seg,ofs)  ((FP)(((DWORD)(seg) << 16) | (ofs)))
#endif

extern unsigned files(void);    // in COUNTF.C

void fail(char *s) { puts(s); exit(1); }

main(int argc, char *argv[])
{
    int f;
    int i;

    BYTE far *tbl = MK_FP(_psp, 0x18);
    WORD far *pmax = (WORD far *) MK_FP(_psp, 0x32);
    BYTE far * far *ptbl = (BYTE far * far *) MK_FP(_psp, 0x34);
    BYTE far *fp, far *p;
    WORD max = *pmax;
    WORD new_max = atoi(argv[1]);
    
    printf("Currently %u max file handles\n", max);
    
    if (new_max <= max)
        fail("nothing to do");

    // make sure proposed JFT size is <= SFT size
	// files() in COUNTF.C
    if (new_max > files())
        fail("FILES= too low: edit CONFIG.SYS and reboot");

    if (! (fp = (BYTE far *) malloc(new_max)))
        fail("insufficient memory");
    if (tbl != *ptbl)
        tbl = *ptbl;
    for (i=0, p=fp; i<max; i++, p++)
        *p = tbl[i];
    for ( ; i < new_max; i++, p++)
        *p = 0xFF;  
    *pmax = new_max;
    *ptbl = fp;
    
    printf("Max file handles increased to %u\n", new_max);

    // now test how many files we can open
    for (i=0; ; i++)
        if (_dos_open(argv[0], 0, &f) != 0)
            break;
    printf("Opened %d files\n", --i);

#ifdef TESTING
    _dos_close(f);  // close last one so we can spawn shell!
    system(getenv("COMSPEC"));
#endif
    
    return 0;
}
