#ifndef TEST
#include "global.h"
#include "proc.h"
#include "commands.h"
#undef fopen
#undef fclose
#undef tmpfile
#else
#include <stdio.h>
#include <string.h>
#define NULLCHAR ((char *)0)
#define NULLFILE ((FILE *)0)
#define tcmdprintf printf
#define tprintf printf
#define tputs puts
int dofstat (int argc,char *argv[],void *p);
#endif
#include <sys/stat.h>

#ifndef MSDOS
#include <unistd.h>
#include <time.h>
#endif


#undef DEBUG
#define MAXOPENFILES	1024

static int numOpenFiles = 0;
struct fileTable {
	int  active;
#define INACTIVE	0
#define ACTIVE		1
	char *name;
	char *mode;
#ifndef TEST
	struct proc *proc;
#endif
	char *buf;
	time_t when;
	FILE *fp;
};

static struct fileTable files[MAXOPENFILES];

static void register_fopen (FILE *fp, const char *fname, const char *mode);
void tnosfcloseall (struct proc *p);



void
tnosfcloseall (struct proc *p)
{
int k;

	for (k = 0; k < MAXOPENFILES; k++) {
		if (files[k].active == ACTIVE && files[k].proc == p)	{
#ifdef DEBUG
			tcmdprintf ("Closing file '%s' left open by process '%s'\n",
				files[k].name, files[k].proc->name);
#endif
			(void) tnosfclose (files[k].fp);
		}
	}
}



static void
register_fopen (FILE *fp, const char *fname, const char *mode)
{
int k;

	for (k = 0; k < MAXOPENFILES; k++) {
		if (files[k].active == INACTIVE)
			break;
	}

	if (k == MAXOPENFILES)	{
#ifdef DEBUG
		tcmdprintf ("Warning: No space available to add a file to register_fopen\n");
#endif
	} else {
		files[k].active = ACTIVE;
		files[k].name = strdup (fname);
		files[k].mode = strdup (mode);
		files[k].fp = fp;
#ifndef TEST
		files[k].proc = Curproc;
#endif
		files[k].buf = (char *) mallocw (BUFSIZ);
		(void) setvbuf (fp, files[k].buf, _IOFBF, BUFSIZ);
		files[k].when = time ((time_t *)0);
		numOpenFiles++;
	}
}



FILE *
tnostmpfile (void)
{
FILE *fp;

	fp = tmpfile();
	if (fp != NULLFILE)
		register_fopen (fp, "tmpfile", "w+b");
	return fp;
}


FILE *
tnosfopen (const char *fname, const char *mode)
{
FILE *fp;

	fp = fopen (fname, mode);
	if (fp != NULLFILE)
		register_fopen (fp, fname, mode);
	return fp;
}

int
tnosfclose (FILE *stream)
{
int k;
int retval;

	for (k = 0; k < MAXOPENFILES; k++) {
		if (files[k].active == ACTIVE && files[k].fp == stream)
			break;
	}
	if (k == MAXOPENFILES)	{
#ifdef DEBUG
		tcmdprintf ("Warning: Closing a file not opened by tnosfopen\n");
		tcmdprintf ("Proc = %s (%08lx)\n", Curproc->name, (long) stream);
#endif
	} else	{
		files[k].active = INACTIVE;
		free (files[k].name);
		files[k].name = NULLCHAR;
		free (files[k].mode);
		files[k].mode = NULLCHAR;
		files[k].fp = NULLFILE;
#ifndef TEST
		files[k].proc = NULLPROC;
#endif		
		numOpenFiles--;
	}
	retval = fclose (stream);
	if (k != MAXOPENFILES)	{
		free (files[k].buf);
		files[k].buf = NULLCHAR;
	}
	return (retval);
}


int
dofstat (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
int heading = 0;
int k;
struct stat fs;
char *cp;
  
	for (k = 0; k < MAXOPENFILES; k++) {
		/* cycle through all files, quit when we reach an unused entry */
		if (files[k].active == INACTIVE)
			continue;
		if (!heading) {
			tprintf ( "\n                 Listing of Open Files: %d\n\n"
				  "Process          opened at      length position mode name\n"
				  "-------          ------------ -------- -------- ---- ----\n",
				  numOpenFiles);
			heading++;              /* header now printed */
		}

		if (fstat (fileno(files[k].fp), &fs) == -1)
			fs.st_size = 0;
		cp = ctime(&files[k].when);
		
		tprintf("%-16.16s %-12.12s %8ld %8ld %-4.4s %s\n",
#ifdef TEST
			"current",
#else
			files[k].proc->name,
#endif
			&cp[4],	fs.st_size, ftell(files[k].fp),
			files[k].mode, files[k].name);
	}
	tputs ("\n");
	return 0;
}


#ifdef TEST
void
main (void)
{
FILE *fp1, *fp2, *fp3;

	dofstat ();
	fp1 = tnosfopen ("/etc/passwd", "r");
	dofstat ();
	fp2 = tnosfopen ("/tmp/nerffile", "w");
	dofstat ();
	fp3 = tnosfopen ("/tmp/nerffile2", "a+");
	dofstat ();
	tnosfclose (fp1);
	dofstat ();
	tnosfclose (fp2);
	dofstat ();
	tnosfclose (fp3);
	dofstat ();
}
#endif
