/*
@(SH) Funzioni per la manipolazione dei files in direttorio
------------------------------------------------------------------------------
@(VG$) PRIVATE

fdir            : identificatori per il direttori
rdir            : identificatori per i tracciati record
dispferr        : flag che attiva segnalazione errore per campo inesistente
dirfl           : flags che permettono aperture e chiusure multiple per i direttori
recfl           : flags che permettono aperture e chiusure multiple per i Tr. record
------------------------------------------------------------------------------
*/

#define __CFILES_C /* fv */

#include        "cfiles.h"
#include        "fldtypes.h"
#include        "lffilesc.h"

	int hashfun(char *);
	void setdec(char *, int);
  char *prefname(void);

	HIDDEN BOOLEAN pathpread = FALSE;

	BOOLEAN dispferr = TRUE;
	int  dirfl[2] = {0, 0}, recfl[2] = {0, 0} ;
	char __ptprf[80] = "";

/*
@(#) COpenDir  FILES

@(ID)
Apre il file directory di una ditta.
@(FD)

@(ISV)
name  = percorso per il file di direttorio.

Versione DOS e XENIX.
@(FSV)

@(IN)
NON UTILIZZARE !!.

Se si utilizza spiegare dettagliatamente il motivo.
@(FN)
*/

  void COpenDir(lockmode, dirflg)
  int     lockmode; /* modo di apertura */
  int     dirflg; /* flag per file comuni */

  {
    PathSt          name;

    if (dirfl[dirflg]++) return;
#ifndef DOS
    if ((excllock(CInsPref(glockname, dirflg), (lockmode == ExclLock)) == -1) 
         && (errno == EACCES))
      fatal_box("Locked Directory. Error number : %d ", errno);
#endif
      strcpy(name, CInsPref(directory, dirflg)) ;
      COpen(&fdir[dirflg], name, sizeof(FileDes), 0, lockmode) ;
      if (fdir[dirflg].IOR != NoErr)
        fatal_box("Can't open Directory. Error number : %d ", fdir[dirflg].IOR);
    }

/*
@(#) CCloseDir  FILES

@(ID)
Chiude il file di direttorio di una ditta.
@(FD)

@(ISV)
Versione DOS e XENIX.
@(FSV)

@(IN)
NON UTILIZZARE !!.

Se si utilizza spiegarne dettagliatamente il motivo.
@(FN)
*/

  void CCloseDir(dirflg)
	int     dirflg; /* flag per file comuni */

    {
#ifndef DOS
      exclunlock(CInsPref(glockname, dirflg), (fdir[dirflg].LockMode == ExclLock));
#endif
      if (dirfl[dirflg]) dirfl[dirflg]--;
      if (!dirfl[dirflg]) CClose(&fdir[dirflg]) ;
    }

/*
@(#) COpenFile  FILES

@(ID)
Legge i dati di un archivio dal Direttorio.
@(FD)

@(ISV)
junk  = variabile spazzatura per la chiamata della funzione "sleep".

s = stringa contenente messaggio di attesa.

w     = descrittore finestra di attesa.

Versione DOS e XENIX.
@(FSV)

@(IN)
Sostituisce l'eventuale simbolo "$" con il prefisso corrente.

NON UTILIZZARE !!.

Se si utilizza spiegarne dettagliatamente il motivo.
@(FN)
*/

  void COpenFile(logicname,filed,lockmode,dirflg)
  int                   logicname; /* numero logico file                        */
	FileDes *filed;    /* puntatore alla struttura che contiene i dati letti dal direttorio */
	int                     lockmode;  /* tipo di lock effettuato sul record */
	int                     dirflg; /* flag per file comuni */

{
  do 
  {
    CRead(&fdir[dirflg],(RecType) filed,(long) logicname, lockmode);
       
    if (TESTLOCK(fdir[dirflg].IOR)) 
       message_box("Sono in attesa della directory n.ro %d", logicname);
  } while TESTLOCK(fdir[dirflg].IOR) ;
  strcpy(filed->SysName, CAddPref(filed->SysName)) ;
}

/*
@(#) CCloseFile  FILES

@(ID)
Chiude e Riscrive i dati di un file sul direttorio.
@(FD)

@(ISV)
wd     = descrittore di una riga di direttorio.

junk   = variabile spazzatura per la chiamata della funzione "sleep".

s = messaggio di attesa.

w      = descrittore della finestra di attesa.
@(FSV)

@(IN)
ATTENZIONE : questa funzione aggiorna esclusivamente i campi EOD e Flags .

NON UTILIZZARE !!.

Se si utilizza spiegarne dettagliatamente il motivo.
@(FN)
*/

  void CCloseFile(logicname,filed,dirflg)
  int                   logicname;  /* numero logico file                             */
	FileDes *filed;     /* puntatore al descrittore di un archivio */
	int     dirflg; /* flag per file comuni */

    {
      FileDes   wd;

      CRead(&fdir[dirflg],(RecType) &wd,(long) logicname, NoLock);
      wd.EOD = filed->EOD;
      wd.Flags = filed->Flags;
      CWrite(&fdir[dirflg],(RecType) &wd,(long) logicname, UnLock);
    }
/*
@($) CGetFile  FILES

@(ID)
Legge i dati relativi ad un archivio nel direttorio.
Non sostituisce con il prefisso l'eventuale carattere "$".
@(FD)

@(ISV)
junk   = variabile spazzatura per la chiamata della funzione "sleep".

s = messaggio di attesa.

w      = descrittore finestra di attesa.

Versione DOS e XENIX.
@(FSV)

@(IN)
NON UTILIZZARE !!.

Se si utilizza spiegarne dettagliatamente il motivo.
@(FN)
*/

  void CGetFile(logicname,filed,lockmode,dirflg)
  int                   logicname; /* numero logico file                               */
	FileDes *filed;    /* puntatore al descrittore archivio nel direttorio */
	int                     lockmode;  /* tipo di lock sul record                          */
	int                     dirflg; /* flag per file comuni */
    {

      do
      {
        CRead(&fdir[dirflg],(RecType)    filed,(long) logicname, lockmode);
	if (TESTLOCK(fdir[dirflg].IOR)) 
	  message_box("Sono in attesa della directory n.ro %d", logicname);
      }
      while TESTLOCK(fdir[dirflg].IOR) ;
    }

/*
@($) CPutFile  FILES

@(ID)
Chiude il direttorio e Riscrive i dati relativi ad un archivo.
Aggiorna tutti i campi.
@(FD)

@(IN)
NON UTILIZZARE !!.

Se si utilizza spiegarne dettagliatamente il motivo.
@(FN)
*/

  void CPutFile(logicname,filed,dirflg)
  int                   logicname; /* numero logico file                            */
	FileDes *filed;    /* puntatore al descrittore dell'archivio */
	int                     dirflg; /* flag per file comuni */

    {
      CWrite(&fdir[dirflg],(RecType)   filed,(long) logicname, UnLock);
    }

/*
@($) zerofdes  FILES

@(ID)
Azzera un descrittore di directory.
@(FD)

@(IN)
NON UTILIZZARE !!.

Se si utilizza spiegarne dettagliatamente il motivo.
@(FN)
*/


	void         zerofdes(d) 
  FileDes    *d; /* puntatore al descrittore di un archivio nella direttorio */

	{ 
		strcpy(d->SysName, ""); 
		d->EOD = 0; 
		d->EOX = 0; 
		d->LenR = 0; 
		d->Flags = 0; 
		strcpy(d->Des, ""); 
		strcpy(d->FCalc, ""); 
		strcpy(d->GenPrompt, ""); 
	} 

/*
@(#) COpenRecDir  FILES

@(ID)
Apre l'Archivio dei Tracciati Record.
@(FD)

@(ISV)
name = nome dell'archivio dei Tracciati Record.

Versione DOS e XENIX.
@(FSV)

@(IN)
NON UTILIZZARE !!.

Se si utilizza spiegarne dettagliatamente il motivo.
@(FN)
*/

  void COpenRecDir(lockmode,dirflg)
	int             lockmode;  /* modo di apertura */
	int             dirflg; /* flag per file comuni */

    {
			PathSt          name;

      if (recfl[dirflg]++) return;
      strcpy(name, CInsPref(ntrrec, dirflg)) ;
      COpen(&rdir[dirflg], name, sizeof(RecDes), 0, lockmode) ;
      if (rdir[dirflg].IOR != NoErr)
        fatal_box("Can't open record description file. Error number : %d ", rdir[dirflg].IOR);

    }

/*
@(#) CCloseRecDir  FILES

@(ID)
Chiude l'Archivio dei Tracciati Record
@(FD)

@(IN)
NON UTILIZZARE !!.

Se si utilizza spiegarne dettagliatamente il motivo
@(FN)
*/

  void CCloseRecDir(dirflg)
	int     dirflg; /* flag per file comuni */

    {
      if (recfl[dirflg]) recfl[dirflg]--;
      if (!recfl[dirflg]) CClose(&rdir[dirflg]) ;
    }

/*
@(#) CGetRec  FILES

@(ID)
Legge il tracciato record del file "logicname" e lo mette in "recd".
@(FD)

@(IN)
NON UTILIZZARE !!.

Se si utilizza spiegarne dettagliatamente il motivo.
@(FN)
*/

  void CGetRec(logicname,recd,dirflg)
	int             logicname; /* numero file               */
	RecDes  *recd;   /* descrittore record  */
	int     dirflg; /* flag per file comuni */

    {
      CRead(&rdir[dirflg],(RecType)      recd,(long) logicname, NoLock);
    }


/*
@($) CPutRec  FILES

@(ID)
Aggiorna il file dei Tracciati Record.
@(FD)

*/

  void CPutRec(logicname,recd,dirflg)
	int             logicname; /* numero file                       */
	RecDes  *recd;   /* descrittore record  */
	int     dirflg; /* flag per file comuni */

    {
      CWrite(&rdir[dirflg],(RecType)     recd,(long) logicname, NoLock);
    }

/*
@($) zerodes  FILES

@(ID)
Azzera il Tracciato Record "r".
@(FD)

@(ISV)
i,j = contatori.
@(FSV)

@(IN)
NON UTILIZZARE !!.

Se si utilizza spiegarne dettagliatamente il motivo.
@(FN)
*/

	void                            zerordes(r)
	RecDes          *r; /* descrittore record  */

	{
		int     i,j ;

		r->NFields = 0; 
		for (i = 0; i < MaxFields; i++) 
		{ 
			strcpy(r->Fd[i].Name, ""); 
			r->Fd[i].TypeF = NullF;
			r->Fd[i].Len = 0; 
			r->Fd[i].Dec = 0; 
			r->Fd[i].RecOff = 0; 
		} 
		for (i = 0; i < MaxFields; i++) r->SortFd[i] = INVFLD; 
		r->NKeys = 0; 
		for (i = 1; i < MaxKeys; i++) 
		{ 
			r->Ky[i].DupKeys = FALSE; 
			r->Ky[i].NkFields = 0; 
			for (j = 0; j < MKFields; j++) r->Ky[i].FieldSeq[j] = INVFLD; 
			for (j = 0; j < MKFields; j++) r->Ky[i].FromCh[j] = INVFLD; 
			for (j = 0; j < MKFields; j++) r->Ky[i].ToCh[j] = INVFLD; 
		} 
	} 

/*
@($) setrdes  FILES

@(ID)
Dato il tracciato record crea la struttura HASH (sortFd) per l'accesso veloce
ai campi.
@(FD)

@(ISV)
pos = indirizzo Hash.

i   = contatore.

nf  = variabile di lavoro.

tmppos = indirizzo hash per l'accesso ai campi.
@(FSV)

@(IN)
NON UTILIZZARE !!.

Se si utilizza spiegarne dettagliatamente il motivo.
@(FN)
*/

	word                            setrdes(r)
	RecDes          *r;  /* descrittore record */

	{
		int          pos, tmppos, nf, i;
    
		for (i = 0; i < MaxFields; i++) r->SortFd[i] = INVFLD; 
		if (r->NFields)
		{
			for (i = 0; i < r->NFields; i++) 
			{ 
				nf = i; 
				pos = hashfun(r->Fd[nf].Name);
				while (TRUE)
				{ 
					if (r->SortFd[pos] == INVFLD) 
					{ 
						r->SortFd[pos] = (byte) nf; 
						break; 
					} 
					else 
					{ 
						if (strcmp(r->Fd[r->SortFd[pos]].Name, r->Fd[nf].Name) <= 0) 
						{ 
							pos++;
							if (pos >= MaxFields)
								pos = 0; 
						} 
						else 
						{ 
							tmppos = r->SortFd[pos]; 
							r->SortFd[pos] = (byte) nf; 
							nf = tmppos; 
						} 
					} 
				} 
			}
			r->Fd[0].RecOff = 1; 
			for (i = 1; i < r->NFields; i++) 
				r->Fd[i].RecOff = r->Fd[i - 1].RecOff + r->Fd[i - 1].Len; 
			return(r->Fd[r->NFields - 1].RecOff + r->Fd[r->NFields - 1].Len); 
		}
		return(0);
	} 

/*
@(SHF) Funzioni per la gestione dei campi dei record
@($) setdec  FILES

@(ID)
Data la stringa "s" (contenente un numero) Aggiusta il numero dei decimali in
base a "dec".
@(FD)

@(ISV)
s1 = stringa di lavoro.

i  = contatore.

l  = lunghezza stringa s1.

carry = eventuale riporto approssimazione.

@(FSV)

@(IN)
NON UTILIZZARE !!.

Se si utilizza spiegarne dettagliatamente il motivo.
@(FN)
*/

	void setdec(s,dec) 
	char            *s;  /* stringa che deve contenere un numero        */
	int                     dec; /* numero di decimali che deve avere il numero */

		{
		  char    *s1;
		  int     i, l, carry;
		  
		  if (LENGTH(s) == 0) strcpy(s, "0");
		  if ((s1 = strchr(s, ',')) != NULL) *s1 = '.';
		  s1 = strchr(s, '.');
		  if ((dec) && (s1 == NULL))
		  {
		    strcat(s, ".");
		    s1 = strchr(s, '.');
		  }
		  else
		    if (!dec) 
		    {
		      if (s1 == NULL) return ;
		      l = LENGTH(s1); /* occhio verificare */
		      carry = (s1[1] >= '5');
		      *s1 = '\0';
		      while (carry)
		      {
			s1--;
			if (*s1 == '-') break;
			if (*s1 == '9')
			{
			  *s1 = '0';
			  if (s == s1) break;
			}
			else
		        {
			  (*s1)++;
			  carry = FALSE;
			}
		      }
		      if (carry)
		      {
			for (i = l; i > (*s1 == '-'); i--) s[i] = s[i - 1];
			s[(*s1 == '-')] = '1';
		      }
		      return;
		    }
		  s1++;
		  l = LENGTH(s1);
		  if (l > dec)
		  {
		    carry = (s1[dec] >= '5');
		    s1[dec] = '\0';
		    while (carry)
		    {
		      dec--;
		      if (s1[dec] == '9')
		      {
			s1[dec] = '0';
			if (!dec) break;
		      }
		      else
		      {
			s1[dec]++;
			carry = FALSE;
		      }
		    }
		    s1--;
		    while (carry)
		    {
		      s1--;
		      if (*s1 == '-') break;
		      if (*s1 == '9')
		      {
			*s1 = '0';
			if (s == s1) break;
		      }
		      else
		      {
			(*s1)++;
			carry = FALSE;
		      }
		    }
		    if (carry)
		    {
		      for (i = l; i > (*s1 == '-'); i--) s[i] = s[i - 1];
		      s[(*s1 == '-')] = '1';
		    }
		  }
		  else
		    while (l++ < dec) strcat(s1, "0");
		}

/*
@($) hashfun  FILES

@(ID)
Data la stringa "s" costruisce la chiave Hash.
@(FD)

@(ISV)
l = lunghezza della stringa "s".

w[82] = copia di lavoro della stringa "s".

temp  = variabile di lavoro.

pw    = puntatore ai caratteri della stringa.

Utilizza l'operatore OR Esclusivo.
@(FSV)

@(IN)
Restituisce l'indirizzo HASH.
@(FN)
*/

	int hashfun(s) 
	char            *s; /* stringa da eleborare */

		{
			int     l;
			char            w[82];
			unsigned short  temp = 0, *pw = (unsigned short *) w;

			strcpy(w, s);
			if (ODD(LENGTH(s))) strcat(w, " ");
			l = LENGTH(s);
			while ((char *) pw < w + l)
			{
				temp ^= *pw;
				pw++;
			}
			l = (short) (temp % (MaxFields - 3));
			if (l < 0)  l = -l;
			return(l);
		}

/*
@($) findfld  FILES

@(ID)
Ricerca all'interno di un record il campo di nome "s".
@(FD)

@(ISV)
i= variabile di lavoro.
startp = variabile di lavoro.
cmp = variabile di lavoro.
@(FSV)
*/

	int findfld(recd,s) 
	RecDes  *recd;  /* Descrittore record Tracciato Record  */
	char            *s;     /* stringa contenente il nome del campo */

		{
			int             i, cmp, startp;

			i = hashfun(s);
			startp = i;
			if (recd->SortFd[i] == INVFLD) return(-1);
			do
			{
				if (!(cmp = strcmp(recd->Fd[recd->SortFd[i]].Name, s)))
					return((int) (recd->SortFd[i]));
				else
					if (cmp > 0) return(-1);
					else
						if (++i >= MaxFields) i = 0;
				if (recd->SortFd[i] == INVFLD) return(-1);
			}
			while (i != startp) ;
			return(-1);
		}

/*
@(#) CFieldSize  FILES

@(ID)
Restituisce la lunghezza del campo.
@(FD)

@(ISV)
p = puntatore al campo.
@(FSV)
*/

  unsigned int  CFieldSize(fieldname,recd)
	char            *fieldname; /* nome del campo              */
	RecDes  *recd;      /* descrittore record            */

    {
			int     p;

			if ((p = findfld(recd, fieldname)) != -1) return(recd->Fd[p].Len);
		  else return(0);
    }

/*
@(#) CFieldDec  FILES

@(ID)
Restituisce il numero di decimali presenti nel campo.
@(FD)

@(ISV)
p = puntatore al campo.
@(FSV)
*/

  unsigned int  CFieldDec(fieldname,recd)
	char            *fieldname;  /* nome del campo */
	RecDes  *recd;       /* descrittore record */

    {
			int     p;

			if ((p = findfld(recd, fieldname)) != -1) return(recd->Fd[p].Dec);
		  else return(0);
    }

/*
@(#) CFieldType  FILES

@(ID)
Restituisce un intero rappresentante il tipo del campo.
@(FD)

@(ISV)
p = posizione all'interno del record del campo.
@(FSV)
*/

  int  CFieldType(fieldname,recd)
	char            *fieldname;  /* nome del campo */
	RecDes  *recd;       /* descrittore record */

    {
			int     p;

			if ((p = findfld(recd, fieldname)) != -1) return(recd->Fd[p].TypeF);
		  else return(NullF);
    }

/*
@($) getfrmt  FILES

@(ID)
Prepara il il formato per dsprintf per il campo "nf" del tracciato record "recd".
@(FD)

@(ISV)
len = lunghezza del campo.

dec = numero di decimali presenti nel campo.
@(FSV)
*/

	void getfrmt(recd,nf,frm) 
	RecDes  *recd;  /* descrittore record */
	int                     nf;     /* numero campo     */
	char            *frm;   /* stringa in formato per dsprintf */

		{
			int     len, dec;

			strcpy(frm, "");
			len = recd->Fd[nf].Len;
			dec = recd->Fd[nf].Dec;
			if (recd->Fd[nf].TypeF == IntF) sprintf(frm, "%%%dd", len);
			else
				if (recd->Fd[nf].TypeF == Int4F) sprintf(frm, "%%%dld", len);
				else
					if (recd->Fd[nf].TypeF == RealF) sprintf(frm, "%%%d.%dt",len, dec);
					/*cambiare */
					else
						if (recd->Fd[nf].TypeF == WordF)  sprintf(frm, "%%%du", len);
						else
							if (recd->Fd[nf].TypeF == ZeroF)  sprintf(frm, "%%0%dd", len);
							else
								if (recd->Fd[nf].TypeF == EZeroF)  sprintf(frm, "%%0%dld", len);
		}

/*
@(#) CGetField  FILES

@(ID)
Estrae il valore di un campo dal record e lo pone in "fout".

Restituisce un eventuale codice errore.
@(FD)

@(ISV)
r  = variabile che contiene l'eventuale codice errore.

p  = variabile per la chiamata di "findfld".

s  = puntatore alla zona di memoria allocata.

frm= stringa per contenere un formato per la dsprintf.
@(FSV)

@(IN)
Si osservi che "fout" deve essere un puntatore a una variabile di tipo coerente con il campo da leggere.
@(FN)
*/
              
#ifndef FOXPRO

/*
@(#) CPutField  FILES

@(ID)
Scrive il contenuto della variabile puntata da "fin" nel campo "fieldname" del record.

Restituisce un eventuale codice errore.
@(FD)

@(ISV)
r  = variabile che contiene l'eventuale codice errore.

p  = variabile per la chiamata di "findfld".

s  = puntatore alla zona di memoria allocata.

frm= stringa per contenere un formato per la dsprintf.
@(FSV)

@(IN)
Si osservi che "fin" deve essere un puntatore a una variabile di tipo coerente con il campo da leggere.
@(FN)
*/

	int CPutField(fieldname,recd,fin,recout)
	char            *fieldname; /* nome del campo                   */
	RecDes  *recd;      /* descrittore record                 */
	void            *fin;       /* puntatore al valore da scrivere  */
	RecType recout;     /* buffer contenetnte il record */

		{
		  int     p;
		  char    s[256], frm[30];

		  strcpy(s, "");
		  p = findfld(recd, fieldname);
		  getfrmt(recd, p, frm);
		  if (recd->Fd[p].TypeF == AlfaF) strcpy(s, (char *) fin);
		  else
		    if ((recd->Fd[p].TypeF == IntF) || (recd->Fd[p].TypeF == ZeroF))
		      sprintf(s, frm, *((int *) fin));
		     else
		       if ((recd->Fd[p].TypeF == Int4F) || (recd->Fd[p].TypeF == EZeroF))
		         sprintf(s, frm, *((long *) fin)) ;
		       else
		         if (recd->Fd[p].TypeF == RealF) dsprintf(s, frm, (DEC *) fin);
		         else                                 
    			     if (recd->Fd[p].TypeF == WordF)  sprintf(s, frm, *((unsigned *) fin)) ;
		    	     else
			           if (recd->Fd[p].TypeF == CharF)
			           {
			             s[0] = *((char *) fin);
				           s[1] = '\0';
			           }
			           else
				           if (recd->Fd[p].TypeF == BoolF)
				           {
			               s[0] = *((BOOLEAN*) fin) ? 'X' : ' ';
				             s[1] = '\0';
				           }
		  return CPutFieldBuff(fieldname, recd, s, recout);
		}

#endif /* FOXPRO */

/*
@(#) CGetFieldBuff  FILES

@(ID)
Estrae il valore di un campo dal record e lo pone nella stringa "s".

Restituisce un eventuale codice errore.
@(FD)

@(ISV)
p   = puntatore al campo.

i   = contatore.

Off = offest in byte all'interno del record per il campo in oggetto.

len = lunghezza campo.

s1  = stringa di lavoro.

d   = data in formato stringa.
@(FSV)

@(IN)
Utilizzato per il Data Entry.
@(FN)
*/

	int CGetFieldBuff(fieldname,recd,recin,s) 
	char            *fieldname; /* nome  del campo                       */
	RecDes  *recd;      /* descrittore record                      */
	RecType recin;      /* buffer contenente il record           */
	char            *s;         /* stringa per l'output           */

		{
			int p, i;
			char *s1;
			TrDate d;
			
			if ((p = findfld(recd, fieldname)) != -1)
			{
			  const int    tipo = recd->Fd[p].TypeF;
				unsigned int off  = recd->Fd[p].RecOff;
				byte         len  = recd->Fd[p].Len;
				
				if ((tipo != AlfaF) && (tipo != DateF) &&	(tipo != ZeroF) && (tipo != EZeroF))
				{
					while ((recin[off] == ' ') && (len))
					{
						off++;
						len--;
					}
					if ((tipo != RealF) && (tipo != CharF))
					{
						while ((recin[off] == '0') && (len))
						{
							off++;
							len--;
						}
					}
				}
				else
					if ((tipo == ZeroF) || (tipo == EZeroF))
					{
						char* c = &recin[off];                
						for (i = 0; i < len; i++, c++)
						{        
						  if (*c == ' ') 
						    *c = '0';
						  else  
						    if (*c != '0') 
						      break;
						}
						if (i == len) 
						{
							off += len;
							len = 0;
						}
					}
				if (len)
				{
					s1 = recin + off;
					for (i = 0; i < len; i++) s[i] = s1[i];
					s[len] = '\0';
					while ((len) && (s[len -  1] == ' ')) s[--len] = '\0';
				}
				else strcpy(s, "");
				
				if ((tipo == RealF)) 
					if ((s1 = strchr(s, ',')) != NULL) *s1 = '.';
				return(0);
			}
			else
			{
				strcpy(s, "");
				return(-1);
			}
		}

/*
@(#) CPutFieldBuff  FILES

@(ID)
Scrive il contenuto della stringa "s" nel campo "fieldname" del record.

Restituisce un eventuale codice errore.
@(FD)

@(ISV)
p   = puntatore al campo.

i   = contatore.

l   = variabile di lavoro.

off = offest in byte all'interno del record per il campo in oggetto.

len = lunghezza campo.

s1,s2  = stringa di lavoro.

d   = data in formato stringa.
@(FSV)

@(IN)
Utilizzato per il Data Entry 
@(FN)
*/

	int CPutFieldBuff(fieldname,recd,s,recout)
	char            *fieldname;  /* nome del campo */
	RecDes  *recd;       /* descrittore record */
	char            *s;          /* stringa contenente il valore da scrivere nel campo */
	RecType recout;      /* buffer contenente il record                   */

		{
			int                     p, off, len, l, i;
			TrDate  d;
			char            *s1;
/*
			char            *s2;
			s2 = malloc(256);
*/
      char s2[256];
			
			strcpy(s2, s);
			if ((p = findfld(recd, fieldname)) != -1)
			{
				off = recd->Fd[p].RecOff;
				len = recd->Fd[p].Len;
				if (recd->Fd[p].TypeF == RealF) setdec(s2, recd->Fd[p].Dec);
				l = LENGTH(s2);
				if (l > len) 
				{
/*					free(s2); */
					return(-1);
				}
				s1 = recout + off ;
				for (i = 0; i < l ; i++) s1[i] = s2[i] ;
				if ((recd->Fd[p].TypeF == IntF) ||
					 (recd->Fd[p].TypeF == Int4F) ||
					 (recd->Fd[p].TypeF == WordF) ||
					 (recd->Fd[p].TypeF == RealF) ||
					 (recd->Fd[p].TypeF == ZeroF) ||
					 (recd->Fd[p].TypeF == EZeroF))
				{
					char c;
					if ((recd->Fd[p].TypeF == ZeroF) ||
							(recd->Fd[p].TypeF == EZeroF))
						c = '0';
					else c = ' ';
					if (l == 0) s1[l++] = '0';
					while (l < len)
					{
						for (i = l; i > 0; i--) s1[i] = s1[i - 1];
						s1[0] = c;
						l++;
					}
				}
				else
					while (l < len) s1[l++] = ' ';
/*				free(s2); */
				return(0);
			}
			else
			{
				strcpy(s, "");
/*				free(s2);  */
				return(-1);
			}
		}


/*
@(#) CZeroField  FILES

@(ID)
Azzera un campo.
@(FD)

@(ISV)
p = puntatore al campo.

s = stringa messaggio.
@(FSV)
*/

	int CZeroField(fieldname,recd,recout)
	char            *fieldname; /* nonme del campo */
	RecDes  *recd; /* descrittore record */
	RecType recout; /* buffer contenente il record */

		{
			int             p;

			if ((p = findfld(recd, fieldname)) != -1)
			{
				if (recd->Fd[p].TypeF == DateF)
					memset(recout + recd->Fd[p].RecOff, '0', recd->Fd[p].Len);
				else
				{
					memset(recout + recd->Fd[p].RecOff, Blank, recd->Fd[p].Len);
					if ((recd->Fd[p].TypeF == IntF) ||
						 (recd->Fd[p].TypeF == Int4F) ||
						 (recd->Fd[p].TypeF == WordF))
					{
						*(recout + recd->Fd[p].RecOff + recd->Fd[p].Len - 1) = '0';
					}
					else
						if (recd->Fd[p].TypeF == RealF)
						{
							if (recd->Fd[p].Dec)
							{
								memset(recout + recd->Fd[p].RecOff + recd->Fd[p].Len - 
											 recd->Fd[p].Dec - 2, '0', recd->Fd[p].Dec + 2);
								*(recout + recd->Fd[p].RecOff + recd->Fd[p].Len -
									recd->Fd[p].Dec - 1) = '.';
							}
							else *(recout + recd->Fd[p].RecOff + recd->Fd[p].Len - 1) = '0';
						}
					return(NoErr);
				}
			}
			else return(-1);
			return(NoErr);
		}

/*
@(#) CZeroRec  FILES

@(ID)
Azzera tutto il record.
@(FD)

@(ISV)
i = contatore.

junk = variabile spazzatura per la chiamata di CZeroField.
@(FSV)
*/

	void CZeroRec(recd,recout)
	RecDes  *recd;  /* descrittore record */
	RecType recout; /* buffer contenente il record             */

		{
			int     i, junk;

			IRecallRec(recout) ;
			for (i = 0; i < recd->NFields; i++) junk = CZeroField(recd->Fd[i].Name,
																									recd, recout);
		}

	
/*
@($) prefname  FILES

@(ID)
Restituisce il nome del file che contiene il prefisso corrente.
@(FD)

@(ISV)
s,s1 = stringhe di lavoro.

Versione DOS e XENIX.
@(FSV)
*/   

#ifndef FOXPRO

  char *prefname()

		{
			static PathSt   s;
#ifdef DOS               
			char *s1 = getenv("PREFPATH");
			if (s1 == NULL) s1 = "prefix.txt";
			strcpy(s, s1);
#else
			sprintf(s, "prefix.%-d", getuid());
#endif
			return(s) ;
		}
		
#endif		

/*
@(#) CGetPref  FILES

@(ID)
Legge dal file prefisso il prefisso dati corrente.
@(FD)

@(ISV)
f = puntatore al file.
@(FSV)

@(IN)
NON UTILIZZARE !!.

Se si utilizza spiegarne dettagliatamente il motivo.
@(FN)
*/

  char *CGetPref()

		{                           
		  const char* p = prefname();
			FILE *f = fopen(p, "r");

			if (f == NULL) 
			{
			  strcpy(cprefix, "");
			}  
			else
			{
				if (fgets(cprefix, 42, f) != NULL)
				{
				  const int len = LENGTH(cprefix)-1;
					if (len >= 0 && cprefix[len] <= ' ') cprefix[len] = '\0';
				}	
				else
					*cprefix = '\0';
				fclose(f);
			}
			if (!pathpread)
			{   
			  const char* p = "pathpref.ini";
				FILE*	f = fopen(p, "r");
				pathpread = TRUE;
				if (f != NULL)
				{
					if (fgets(__ptprf, 42, f) != NULL)
					{
  				  const int len = LENGTH(__ptprf)-1;
	  				if (len >= 0 && __ptprf[len] <= ' ') 
	  				{
	  				  __ptprf[len] = '\0';
					    if (len > 0) strcat(__ptprf, "/");
					  } 
					}	
					else
						*__ptprf = '\0';
					fclose(f);
				}
			}
			if (*__ptprf)
			{
				char	ws[200];
				sprintf(ws, "%s%s", __ptprf, cprefix);
				strcpy(cprefix, ws);
			}
			return(cprefix);
		}

/*
@($) CPutPref  FILES

@(ID)
Aggiorna sul file prefisso il prefisso dati corrente.
@(FD)

@(ISV)
f = puntatore a file.
@(FSV)

@(IN)
NON UTILIZZARE !!.

Se si utilizza spiegarne dettagliatamente il motivo.
@(FN)
*/

  void CPutPref(pref)
  char    *pref; /* stringa contenente il nuovo prefisso */

  {
    FILE    *f;
    const int l = strlen(__ptprf);
    
    if (l && strncmp(pref, __ptprf, l) == 0) pref += l;
    if ((f = fopen(prefname(), "w")) == NULL)
      fatal_box("Put prefix. Error number : %d ", errno);
    fprintf(f, "%s\n", pref);
    fclose(f);
  }

/*
@($) CAddPref  FILES

@(ID)
Cerca il carattere "$" nel nome file e lo sostituisce con il prefisso corrente.
@(FD)

@(ISV)
s = stringa che contiene il nome.
@(FSV)

@(IN)
NON UTILIZZARE !!.

Se si utilizza spiegarne dettagliatamente il motivo.
@(FN)
*/

char *CAddPref(name)
char *name; /* nome file */

{
	static PathSt   s;

	if (*name == '$')
	{
		name++;
		return(CInsPref(name, NORDIR)) ;
	}
	else
  	if (*name == '%')
		{
			name++;
			return(CInsPref(name, COMDIR)) ;
		}
		else
		{
			sprintf(s, "%s%s", __ptprf, name);
			return(s);
		}
	}

/*
@($) CInsPref  FILES

@(ID)
Aggiunge (a sinistra) il prefisso corrente.
@(FD)

@(ISV)
s = stringa di lavoro.
@(FSV)

@(IN)
NON UTILIZZARE !!.

Se si utilizza spiegarne dettagliatamente il motivo.
@(FN)
*/

	char    *CInsPref(name,dirflg)
	char    *name; /* nome del file  cui aggiungere il prefisso */
	int     dirflg; /* flag per file comuni */

	{
		static PathSt   s;

		if (dirflg == NORDIR)
		{
			if (LENGTH(cprefix) == 0) sprintf(s,"%s", name);
			else sprintf(s,"%s%c%s",cprefix, DIRSEP, name);
		}
		else sprintf(s,"%scom%c%s", __ptprf, DIRSEP, name);
		return(s);
	}

/*
@(#) CGetIdxName  FILES

@(ID)
Dato un nome file costruisce il nome del file indice corrispondente.
@(FD)

@(ISV)
fdst,s1,s2 = stringhe di lavoro.
@(FSV)

@(IN)
NON UTILIZZARE !!.

Se si utilizza spiegarne dettagliatamente il motivo.

L' estensione dei file indice e' ndx; e' quindi vietato utilizzare un nome
di file che abbia tale estensione. L' estensione dei file dati e' dta.
@(FN)
*/

	char    *CGetIdxName(s)
	char    *s; /* stringa contenente il nome file */

		{
			static PathSt fdst;
			char    *s1, *s2;

			strcpy(fdst, s) ;
			s1 = strrchr(fdst,DIRSEP) ;
			if (s1 == NULL) s1 = fdst;
			s2 = strchr(s1,'.') ;
			if (s2 != NULL) s2[0] = '\0' ;
			s1 = strcat(fdst, ".ndx") ;
			return(fdst) ;
		}