/*
@(C$)
MAXTEXTLEN      : Lunghezza massima di un file di testo (in righe)
LFLOG           : Numero logico del primo file elaborabile dalla dumpfile
-------------------------------------------------------------------------------
*/
#include				<ccommon.h>
#include				<genconst.h>
#include				<ccustio.h>
#include				<cfiles.h>
#include				<cbpltree.h>
#include				<cbplcre.h>
#include				<cisam.h>
#include				<memory.h>
#include				<progind.h>

#define	MAXTEXTLEN		8096

extern BOOLEAN			dispferr;
HIDDEN int rd = 0;

/*
@($) cupdatefile  ISAM

@(ID)
Aggiorna un file ISAM utilizzando un nuovo tracciato record.
Ritorna il codice di errore.
@(FD)

@(ISV)
ws  = stringa di lavoro.

wisfd    = descrittore del file in esame.

oldrec   = buffer contenente il vecchio record.

newrec   = buffer contenente il nuovo record.

tmpf     = descrittore del file.

tmpname  = nome del file.

filename = nome del file.

nsec     = variabile di lavoro.

i,j,k    = contatori.

junk     = variabile spazzatura per la chiamata di varie funzioni.

d        = descrittore del file.

@(FSV)

*/

int	cupdatefile(logicname,lenr,newrecdes,vis,err)
int						logicname;  /* numero logico del file                       */
unsigned int	lenr;       /* lunghezza nuovo record                       */
RecDes				*newrecdes; /* nuovo tracciato record                       */
BOOLEAN				vis;        /* se true visualizza cio' che sta facendo      */
int						*err;       /* codice errore                                */

	{
		char 			ws[256];
		isfdptr		wisfd;
		RecType		oldrec,newrec;
		SecDef		tmpf;
		PathSt		tmpname, filename;
		RecNoType	nsec,i,k;
		int				junk,j;
		FileDes		d;
		FILE			*fd;
		char			s[81];

		*err = NoErr;
		COpenDir ( ManuLock , NORDIR);
		CGetFile(logicname, &d, NoLock, NORDIR);
		CCloseDir(NORDIR);
		if (d.EOX == 0)
		{
			COpenDir ( ManuLock , NORDIR); 
			CGetFile(logicname, &d, Lock, NORDIR);
			d.LenR = lenr ;
			CPutFile(logicname, &d, NORDIR);
			CCloseDir(NORDIR);
			COpenRecDir(ManuLock, NORDIR);
			CPutRec(logicname, newrecdes, NORDIR);
			CCloseRecDir(NORDIR);
#ifndef DOS
			writelog(FNCHGREC, NULL, (RecType) newrecdes);
#endif
			strcpy(tmpname, CAddPref(d.SysName));
			if ((fd = fopen(tmpname, "r")) == NULL)
				*err = cisbuild(wisfd, logicname, d.EOX, err);
			else fclose(fd);
			return(*err);
		}
		if (cisopen(&wisfd, logicname, &oldrec, ExclLock, err)) return(*err);
		strcpy(tmpname, CInsPref("tmp.dta", NORDIR));
		nsec = ((RecNoType) lenr * wisfd->d->EOX) / BlockLenIO + 1;
		CCreate(&tmpf, tmpname, lenr, 0, nsec);
		COpen(&tmpf, tmpname, lenr, 0, ExclLock);
		if ((*err = tmpf.IOR))
		{
			junk = cisclose(&wisfd, &oldrec, &junk);
			unlink(tmpname) ;
			return(*err);
		}
		newrec = (RecType) malloc(lenr);
		k = 0L;
		i = 0L;
		if (vis)
		{
			sprintf(s, "Aggiorna - %s", wisfd->d->Des);
			progind_create(wisfd->d->EOD, s, FALSE, TRUE, 10);
		}
		dispferr = FALSE;
		while (i < wisfd->d->EOD)
		{
			i++;
			CRead(&wisfd->f, oldrec, i, NoLock);
			if ((*err = wisfd->f.IOR)) break ;
			if ((vis) && ((i % 10) == 0))
				progind_set_status(i);
			if (!IRecIsDeleted(oldrec))
			{
				k++;
				CZeroRec(newrecdes, newrec);
				for (j = 0; j < newrecdes->NFields; j++)
				{
					strcpy(ws, "");
					if (!CGetFieldBuff(newrecdes->Fd[j].Name, wisfd->r, oldrec, ws))
					 junk = CPutFieldBuff(newrecdes->Fd[j].Name, newrecdes, ws, newrec);
				}
				CWrite(&tmpf, newrec, k, NoLock);
			}
		}
		dispferr = TRUE;
		CClose(&tmpf);
		if (vis) progind_set_status(i);
		strcpy(filename, wisfd->d->SysName);
		junk = cisclose(&wisfd, &oldrec, &junk);
		if (!*err)
		{
			COpenDir ( ManuLock , NORDIR);
			CGetFile(logicname, &d, Lock, NORDIR);
			d.LenR = lenr ;
			d.EOD = k;
			CPutFile(logicname, &d, NORDIR);
			CCloseDir(NORDIR);
			COpenRecDir(ManuLock, NORDIR);
			CPutRec(logicname, newrecdes, NORDIR);
			CCloseRecDir(NORDIR);
			if ((unlink(filename) == -1) || (CRenameFil(tmpname,filename) == -1))
			{
				free(newrec);
				return(*err = errno);
			}
#ifndef DOS
			else
				writelog(FNCHGREC, NULL, (RecType) newrecdes);
#endif
		}
		else unlink(tmpname);
		free(newrec);
		if (vis) 
			progind_destroy();
		return(*err);
	}

/*
@($) dispdata  ISAM

@(ID)
Visualizza i dati e le informazioni relative alla fase di caricamento su file di
testo od alla fase di scarico su file di testo.
@(FD)
*/

void	dispdata(w,inname,outname,fs,fd,rs,vis)
HWND				*w;        /* descrittore finestra di visualizzazione */
char					*inname; /* nome del file di input                  */
char					*outname;/* nome del file di output                 */
char					fs;      /* separatore campi                        */
char					fd;      /* delimitatore campi                      */
char					rs;      /* delimitatore record                     */
BOOLEAN				vis;     /* se true visualizza anche i dati         */

{
#ifdef XVT_OS
/* implementare con xvt */
#else
	if (vis)
	{
		*w = CSetWin(1, 5, 80, 17, 2, FALSE, 0, 0, ATEXT9, "");
		rd = 0;
		CCLEARWIN(*w);
	}
	CGotoXY(stdscrn, 5, 15);
	wprintf(stdscrn,"Input                    = %s", inname);
	CCLEAREOL(stdscrn) ;
	CGotoXY(stdscrn, 5, 16);
	wprintf(stdscrn,"Output                   = %s", outname);
	CCLEAREOL(stdscrn) ;
	CGotoXY(stdscrn, 5, 17);
	wprintf(stdscrn,"Registrazioni lette      = ");
	CCLEAREOL(stdscrn) ;
	CGotoXY(stdscrn, 5, 18);
	wprintf(stdscrn,"Registrazioni scritte    = ");
	CCLEAREOL(stdscrn) ;
	CGotoXY(stdscrn, 5, 19);
	wprintf(stdscrn,"Errori                   = ");
	CCLEAREOL(stdscrn) ;
	CGotoXY(stdscrn, 5, 20);
	wprintf(stdscrn,(isprint(fs) || (!fs)) ? "Separatore di campi      = %c" :
																	"Separatore di campi      = chr(%3d)", fs);
	CCLEAREOL(stdscrn) ;
	CGotoXY(stdscrn, 5, 21);
	wprintf(stdscrn,(isprint(fd) || (!fd)) ? "Delimitatore di campi    = %c" :
																	"Delimitatore di campi    = chr(%3d)", fd);
	CCLEAREOL(stdscrn) ;
	CGotoXY(stdscrn, 5, 22);
	wprintf(stdscrn,(isprint(rs) || (!rs)) ? "Delimitatore di record   = %c" :
																	"Delimitatore di record   = chr(%3d)", rs);
	crefscrn(stdscrn);
#endif
}

/*
@($) getinrec  ISAM

@(ID)
Legge un record da un file di testo.
Ritorna il numero di caratteri che ha letto, 0 se non ha letto nulla.
@(FD)

@(ISV)
nread = numero di caratteri letti.
@(FSV)

*/

int	getinrec(fd,buffer,rs,vis,err)
FILE					*fd;     /* puntatore al file                         */
char					*buffer; /* buffer contenente i record                */
char					rs;      /* separatore records                        */
BOOLEAN				vis;     /* se true visualizza i dati mentre li legge */
int						*err;    /* codice errore                             */

{
	int	nread = 0;

	buffer[nread] = (uchar) fgetc(fd) ;
	while (!feof(fd))
	{
		if (buffer[nread] == rs) break;
		nread++;
		buffer[nread] = (uchar) fgetc(fd) ;
	}
	buffer[nread + 1] = '\0';
	return(nread);
}

/*
@($) getnextfield  ISAM

@(ID)
Restituisce il contenuto del prossimo campo.
Restituisce il carattere di partenza.
@(FD)

@(ISV)
i    = posizione corrente all' interno del buffer.

done = flag di completamento.

s    = stringa di lavoro.

s1   = stringa di lavoro.
@(FSV)

*/

char *getnextfield(isfd,buffer,cnt,len,fs,fd,rs,err)
isfdptr				isfd;    /* descrittore del file ISAM */
char 					*buffer; /* buffer per il record                   */
int						*cnt;    /* carattere di partenza                  */
int						len;     /* lunghezza del campo                    */
char					fs;      /* separatore campi                       */
char					fd;      /* delimitatore campi                     */
char					rs;      /* separatore records                     */
int						*err;    /* codice errore                          */

{
	int					i = *cnt;
	BOOLEAN			done = FALSE;
	char 				*s;
	static char	s1[256];

	if ((fd) && (buffer[i] != fd))
	{
		*err = IsFieldErr;
		return(NULL);
	}
	if (fd) i++;
	s = buffer + i;
	while ((!done) && (i <= len))
	{
		if ((fd) && (buffer[i] == fd)) done = TRUE;
		else
			if ((!fd) && ((buffer[i] == fs) || (buffer[i] == rs))) done = TRUE;
			else i++;
	}
	if (!done)
	{
		*err = IsFieldErr;
		return(NULL);
	}
	buffer[i] = '\0';
	*cnt = i + 1;
	if ((fd) && (fs))
	{
		if (buffer[*cnt] == fs) (*cnt)++;
		else
			if (buffer[*cnt] != rs)
			{
				*err = IsFieldErr;
				return(NULL);
			}
	}
	strcpy(s1, s);
	return(s1);
}

/*
@($) loadrec  ISAM

@(ID)
Carica un record nel file ISAM.
@(FD)

@(ISV)
j = contatore.

s = stringa di lavoro.
@(FSV)
*/

int loadrec(isfd,buffer,rec,fs,fd,rs,len,w,vis,err)
isfdptr				isfd;    /* descrittore del file ISAM */
char 					*buffer; /* buffer dati del file di testo          */
RecType				rec;     /* buffer record (output)                 */
char					fs;      /* separatore campi                       */
char					fd;      /* delimitatore campi                     */
char					rs;      /* separatore record                      */
int						len;     /* lunghezza buffer                       */
HWND					w;       /* finestra di visualizzazione            */
BOOLEAN				vis;     /* se true visualizza                     */
int						*err;    /* codice errore                          */

{
	int				j = 0, i = 0;
	char 			*s;

	*err = NoErr;
	while ((j < isfd->r->NFields) && (!*err))
	{
		s = getnextfield(isfd, buffer, &i, len, fs, fd, rs, err);
		if (!*err)
		{
			if (vis)
			{
#ifdef XVT_OS
/* implementare con xvt */
#else
				wprintf(w, " %-10s : %s\n", isfd->r->Fd[j].Name, (s != NULL) ? s : "");
				crefscrn(stdscrn);
#endif
			}
			if (s != NULL)
				*err = CPutFieldBuff(isfd->r->Fd[j].Name, isfd->r, s, rec);
			j++;
		}
	}
	if ((j != isfd->r->NFields) && (!*err)) *err = IsNFieldsErr;
	return(*err);
}

/*
@(#) cloadfile  ISAM

@(ID)
Aggiunge al file ISAM il contenuto del file di testo.
@(FD)

@(ISV)
wisfd = identificatore file isam.

rec   = buffer per un record isam.

buffer = buffer di input.

junk   = variabile spazzatura.

len    = lunghezza attuale del buffer di input.

w      = finestra di visualizzazione.

rl     = numero di record letti.

rt     = numero di record caricati.

er     = numero di record errati.

fin    = identificatore file di input.
@(FSV)
*/

int	cloadfile(inname,logicname,fs,fd,rs,vis,err)
char					*inname;   /* nome del file di testo */
int						logicname; /* numero logico del file */
char					fs;        /* separatore campi       */
char					fd;        /* delimitatore campi     */
char					rs;        /* separatore record      */
BOOLEAN				vis;       /* se true visualizza     */
int						*err;      /* codice di errore       */

	{
		isfdptr		wisfd;
		RecType		rec;
		char 			*buffer;
		int				junk,len;
		HWND		w;
		RecNoType	rl = 0,rt = 0,er = 0;
		FILE			*fin;

		*err = NoErr;
		if (cisopen(&wisfd, logicname, &rec, ExclLock, err)) return(*err);
		if ((fin = fopen(inname, "r")) == NULL)
		{
			*err = CIOResult();
			junk = cisclose(&wisfd, &rec, &junk);
			return(*err);
		}
		buffer = malloc(MAXTEXTLEN);
		dispdata(&w, inname, wisfd->d->SysName, fs, fd, rs, vis);
		if (rs == '\r') rs = '\n';
		while ((len = getinrec(fin, buffer, rs)) && (!*err))
		{
			if ((++rl % 10) == 0)
			{
#ifdef XVT_OS
/* implementare con xvt */
#else
				CGotoXY(stdscrn, 32, 17);
				wprintf(stdscrn,"%10ld", rl);
#endif
			}
			CZeroRec(wisfd->r,rec);
			if (vis)
			{
#ifdef XVT_OS
/* implementare con xvt */
#else
				if (rd < 12) rd++;
				else CScroll(w, 1);
				CGotoXY(w, 1, rd);
				wprintf(w,"Registrazione N. %ld", wisfd->d->EOD + 1);
				CCLEAREOL(w);
				crefscrn(w);
#endif
			}
			if (!loadrec(wisfd, buffer, rec, fs, fd, rs, len, w ,vis ,err))
			{
				if (ciswrite(wisfd, rec, err))
				{
#ifdef XVT_OS
/* implementare con xvt */
#else
					CGotoXY(stdscrn, 32, 17);
					wprintf(stdscrn,"%10ld", rl);
					CGotoXY(stdscrn, 32, 18);
					wprintf(stdscrn,"%10ld", rt);
					CGotoXY(stdscrn, 32, 19);
					wprintf(stdscrn,"%10ld (%d)", ++er, *err);
					beep();
					crefscrn(stdscrn);
#endif

				}
				else
				{
					rt++;
					if ((rl % 10) == 0)
					{
#ifdef XVT_OS
/* implementare con xvt */
#else
						CGotoXY(stdscrn, 32, 18);
						wprintf(stdscrn,"%10ld", rt);
						crefscrn(stdscrn);
#endif
					}
				}
			}
			else
			{
#ifdef XVT_OS
/* implementare con xvt */
#else
				CGotoXY(stdscrn, 32, 17);
				wprintf(stdscrn,"%10ld", rl);
				CGotoXY(stdscrn, 32, 18);
				wprintf(stdscrn,"%10ld", rt);
				CGotoXY(stdscrn, 32, 19);
				wprintf(stdscrn,"%10ld (%d)", ++er, *err);
				beep();
				crefscrn(stdscrn);

#endif
			}
#ifdef XVT_OS
/* implementare con xvt */
#else
			if ((ckeypress()) && (CReadKeyb() == Esc) && (!CInputOk(stdscrn,"Continuo")))
			{
				junk = fclose(fin);
				junk = cisclose(&wisfd, &rec, &junk);
				free(buffer);
				return(*err);
			}
			else *err = NoErr;
#endif
		}
#ifdef XVT_OS
/* implementare con xvt */
#else
		CGotoXY(stdscrn, 32, 17);
		wprintf(stdscrn,"%10ld", rl);
		CGotoXY(stdscrn, 32, 18);
		wprintf(stdscrn,"%10ld", rt);
		crefscrn(stdscrn);
		if (vis) CDelWin(w);
#endif
		junk = fclose(fin);
		junk = cisclose(&wisfd, &rec, &junk);
		free(buffer);
		return(*err);
	}

/*
@($) dumprec  ISAM

@(ID)
Scrive su di un file di testo un record del file ISAM.
@(FD)

@(ISV)
j = contatore.

i = contatore.

ws = stringa di lavoro.
@(FSV)
*/

int	dumprec(isfd, rec, fout, fs, fd, rs, w, vis, err)
isfdptr				isfd; /* decrittore del file ISAM */
RecType				rec;  /* buffer contenente il record           */
FILE					*fout;/* puntatore al file di testo            */
char					fs;   /* separatore campi                      */
char					fd;   /* delimitatore campi                    */
char					rs;   /* separatore record                     */
HWND				w;      /* descrittore finestra di visualizzaz.  */
BOOLEAN				vis;  /* se true visualizza                    */
int						*err; /* codice di errore                      */

{
	int		j = 0, i = 0;
	char ws[256];

	*err = NoErr;
	while ((j < isfd->r->NFields) && (!*err))
	{
		if (!(*err = CGetFieldBuff(isfd->r->Fd[j].Name, isfd->r, rec, ws)))
		{
			if (vis)
			{
				if (rd < 12) rd++;
#ifdef XVT_OS
/* implementare con xvt */
#else
				else CScroll(w, 1);
#endif
#ifdef XVT_OS
/* implementare con xvt */
#else
				CGotoXY(w, 1, rd);
				wprintf(w, " %-10s : %-s", isfd->r->Fd[j].Name, ws);
				CCLEAREOL(w);
				crefscrn(w);
#endif
			}
			if (fd) fputc(fd, fout);
			fprintf(fout, "%s", ws);
			if (fd) fputc(fd, fout);
			j++;
			if ((fs) && (j < isfd->r->NFields)) fputc(fs, fout);
		}
	}
	if (rs) 
	{
		if (rs == '\r') fprintf(fout, "\n");
	  else fputc(rs, fout);
	}
	return(*err);
}

/*
@(#) cdumpfile  ISAM

@(ID)
Scrive un file ISAM su di un file di testo.
@(FD)

@(ISV)
wisfd = identificatore file isam.

rec   = buffer per un record isam.

junk   = variabile spazzatura.

w      = finestra di visualizzazione.

rl     = numero di record letti.

rt     = numero di record scaricati.

er     = numero di record errati.

eod   = end of data.

fout  = identificatore file di output.
@(FSV)
*/

int	cdumpfile(outname,logicname,knum,fs,fd,rs,vis,err)
char					*outname; /* nome file di testo (out)     */
int						logicname;/* numero logico file ISAM (in) */
int						knum;     /* numero chiave per ordinare i record */
char					fs;       /* separatore campi                    */
char					fd;       /* delimitatore campi                  */
char					rs;       /* separatori campi                    */
BOOLEAN				vis;      /* se true visualizza                  */
int						*err;     /* codice errore                       */

	{
		isfdptr		wisfd;
		RecType		rec;
		int				junk;
		HWND		w;
		RecNoType	rl = 0,rt = 0,er = 0, eod;
		FILE			*fout;

		*err = NoErr;
		if (cisopen(&wisfd, logicname, &rec, ExclLock, err)) return(*err);
		if ((fout = fopen(outname, "w")) == NULL)
		{
			*err = CIOResult();
			junk = cisclose(&wisfd, &rec, &junk);
			return(*err);
		}
		dispdata(&w, wisfd->d->SysName, outname, fs, fd, rs, vis);
		if (knum)
		{
			junk = cisstart(wisfd, knum, rec, IsFirst + NoLock, err);
			while (!*err)
			{
				if ((++rl % 10) == 0)
				{
#ifdef XVT_OS
/* implementare con xvt */
#else
					CGotoXY(stdscrn, 32, 17);
					wprintf(stdscrn,"%10ld", rl);
#endif
				}
				if (vis)
				{
					if (rd < 12) rd++;
#ifdef XVT_OS
/* implementare con xvt */
#else
					else CScroll(w, 1);
#endif
#ifdef XVT_OS
/* implementare con xvt */
#else
					CGotoXY(w, 1, rd);
					wprintf(w, "Registrazione N. %ld", rl);
					CCLEAREOL(w);
					crefscrn(w);
#endif
				}
				if (dumprec(wisfd, rec, fout, fs, fd, rs, w, vis, err)) break;
				rt++;
				if ((rl % 10) == 0)
				{
#ifdef XVT_OS
/* implementare con xvt */
#else
					CGotoXY(stdscrn, 32, 18);
					wprintf(stdscrn,"%10ld", rt);
					crefscrn(stdscrn);
#endif
				}
#ifdef XVT_OS
/* implementare con xvt */
#else
				if ((ckeypress()) && (CReadKeyb() == Esc) && (!CInputOk(stdscrn,"Continuo")))
				{
					junk = fclose(fout);
					junk = cisclose(&wisfd, &rec, &junk);
					return(*err);
				}
#endif
				junk = cisread(wisfd, rec, IsNext + NoLock, err);
			}
			if (*err == BTrEOF) *err = NoErr;
		}
		else
		{
			wisfd->RecNo = 0;
			eod = wisfd->d->EOD;
			while ((wisfd->RecNo < eod) && (!*err))
			{
				wisfd->RecNo++;
				CRead(&wisfd->f, rec, wisfd->RecNo, NoLock);
				if (!IRecIsDeleted(rec))
				{
					if ((++rl % 10) == 0)
					{
#ifdef XVT_OS
/* implementare con xvt */
#else
						CGotoXY(stdscrn, 32, 17);
						wprintf(stdscrn,"%10ld", rl);
#endif
					}
					if (vis)
					{
						if (rd < 12) rd++;
#ifdef XVT_OS
/* implementare con xvt */
#else
						else CScroll(w, 1);
						CGotoXY(w, 1, rd);
						wprintf(w,"Registrazione N. %ld", wisfd->d->EOD + 1);
						CCLEAREOL(w);
						crefscrn(w);
#endif
					}
					if (dumprec(wisfd, rec, fout, fs, fd, rs, w, vis, err)) break;
					rt++;
					if ((rl % 10) == 0)
					{
#ifdef XVT_OS
/* implementare con xvt */
#else
						CGotoXY(stdscrn, 32, 18);
						wprintf(stdscrn,"%10ld", rt);
						crefscrn(stdscrn);
#endif
					}
				}
#ifdef XVT_OS
/* implementare con xvt */
#else
				if ((ckeypress()) && (CReadKeyb() == Esc) && (!CInputOk(stdscrn,"Continuo")))
				{
					junk = fclose(fout);
					junk = cisclose(&wisfd, &rec, &junk);
					return(*err);
				}
#endif
			}
			if (*err == BTrEOF) *err = NoErr;
		}
#ifdef XVT_OS
/* implementare con xvt */
#else
		CGotoXY(stdscrn, 32, 17);
		wprintf(stdscrn,"%10ld", rl);
		CGotoXY(stdscrn, 32, 18);
		wprintf(stdscrn,"%10ld", rt);
		crefscrn(stdscrn);
		if (vis) CDelWin(w);
#endif
		junk = fclose(fout);
		junk = cisclose(&wisfd, &rec, &junk);
		return(*err);
	}
