/* Attenzione!. Per costruire la DLL accertarsi che siano attivati i seguenti switch: 1) S4DLL_BUILD definito da command line del compilatore 2) Uno solo tra S4FOX S4CLIPPER S4NDX e S4MDX, definito in d4all.h Gli altri switch di configurazione generale sono a piacere (S4DEBUG, S4ERROR_HOOK, ecc.) Per costruire WINUNO.LIB Accertarsi che d4all.h non abbia definito S4DLL o S4UNIX, e tanto meno S4DLL_BUILD, altrimenti per costruire la library di UNIX e' necessario cambiare ogni volta. La definizione di tali simboli avviene qui dentro. Inoltre deve essere attivo uno solo degli switch di selezione formato database (S4FOX, S4MDX ecc.); nel caso si faccia uso della DLL non importa quale si e' definito. E' importante solo in caso di utilizzo di una static Library. Per costruire l'aga.fll e' necessario togliere le funzioni progind* e definire S4DLL. */ #if XVT_OS == XVT_OS_SCOUNIX #define S4UNIX #else #define S4DLL #endif #ifdef XVT /* This not recommended in Unix!*/ #undef S4UNIX #define S4DLL #endif #ifdef FOXPRO #undef S4UNIX #define S4DLL #endif #include #include #include #include #include #include #include #define MAXLEN 137 /* Lunghezza massima chiave */ extern char* CUpString(char *); static CODE4 code_base; static DATA4 *dbdata[CB4FILES]; static X4FILTER xdb[CB4FILES]; static char * find_slash_backslash(char * str) { int l=strlen(str); static char * xstr ; xstr = str + l; while (xstr-- && l--) if (*xstr == '\\' || *xstr == '/') break; if (l == 0) return NULL; else return xstr; } /*-------------------------------------------------------------------------- funzione di filtro usata su tutti i database --------------------------------------------------------------------------*/ int S4CALL notdelete(void *fd) { if(d4deleted(fd)) return r4ignore; else return r4keep; } /*-------------------------------------------------------------------------- inizializzazione di CodeBase e delle variabili necessarie questa funzione deve essere chiamata SOLO una volta all'interno di ciascun eseguibile --------------------------------------------------------------------------*/ void DB_init(void) { int i; for(i=0;i 0) x4top(&xdb[found]); return(found); } /*------------------------------------------------------------------------- chiusura del database inviduato da handle torna -1 se il database non puo essere chiuso --------------------------------------------------------------------------*/ int DB_close(int handle) { if(dbdata[handle]==0) return(-1); d4close(dbdata[handle]); dbdata[handle]=(DATA4 *) 0; code_base.error_code=0; return(0); } /*------------------------------------------------------------------------- torna il puntatore al buffer del record del database individuato da handle. In caso di errore torna (char *) 0 --------------------------------------------------------------------------*/ char *DB_getrecord(int handle) { if(dbdata[handle]==0) return((char *) 0); return(d4record(dbdata[handle])); } /*------------------------------------------------------------------------- torna la lunghezza del record --------------------------------------------------------------------------*/ int DB_reclen(int handle) { if(dbdata[handle]==0) return(-1); return((int) d4record_width(dbdata[handle])); } /*------------------------------------------------------------------------- torna la lunghezza della chiave corrente --------------------------------------------------------------------------*/ int DB_keylen(int handle) { TAG4 *t; if (dbdata[handle]==0) return(-1); if ((t=d4tag_default(dbdata[handle]))== NULL) return (-1); return(expr4key_len(t->expr)); } /*------------------------------------------------------------------------- torna il numero del record attuale --------------------------------------------------------------------------*/ long int DB_recno(int handle) { if(dbdata[handle]==0) return(-1L); return(d4recno(dbdata[handle])); } /*------------------------------------------------------------------------- torna il numero complessivo dei records presenti nell'archivio --------------------------------------------------------------------------*/ long int DB_reccount(int handle) { if(dbdata[handle]==0) return(-1L); return(d4reccount(dbdata[handle])); } /*------------------------------------------------------------------------- seleziona un indice sul database specificato torna -1 se errore, altrimenti 0 --------------------------------------------------------------------------*/ int DB_tagselect(int handle,int index_no) { TAG4 *tt; int i; if(dbdata[handle]==0) return(-1); /* si posiziona sul primo indice */ tt=d4tag_next(dbdata[handle],NULL); if(tt==NULL) return(-1); for(i=1;iexpr); k = t4key(tt); while (len > 0 && k[len-1] == ' ') len--; rc = strncmp(key, k, len); if (rc == 0) return 0; else if (rc < 0) return r4after; else return r4eof; } /*------------------------------------------------------------------------- torna 1 se eof, 0 altrimenti --------------------------------------------------------------------------*/ int DB_eof(int handle) { if(dbdata[handle]==0) return(-1); return(d4eof(dbdata[handle])); } /*------------------------------------------------------------------------- torna 1 se tof, 0 altrimenti --------------------------------------------------------------------------*/ int DB_bof(int handle) { if(dbdata[handle]==0) return(-1); return(d4bof(dbdata[handle])); } /*------------------------------------------------------------------------- legge un record per numero record --------------------------------------------------------------------------*/ int DB_go(int handle,long int recno) { if(dbdata[handle]==0) return(-1); return(x4go(&xdb[handle],recno)); } /*------------------------------------------------------------------------- cancella il record attuale. Non cancella le chiavi. --------------------------------------------------------------------------*/ int DB_delete(int handle) { if(dbdata[handle]==0) return(-1); d4delete(dbdata[handle]); return(0); } /*------------------------------------------------------------------------- ripristina il record attuale --------------------------------------------------------------------------*/ int DB_recall(int handle) { if(dbdata[handle]==0) return(-1); d4recall(dbdata[handle]); return(0); } /*------------------------------------------------------------------------- cancella dall'indice corrente la chiave specificata --------------------------------------------------------------------------*/ int DB_delkey(int handle, char* key, long recno) { INDEX4* i; TAG4* t; int rt=0; int is_locked = 0; /* Diverso da 0 se il file e' bloccato in modo esclusivo */ /* (dati o indice) da me stesso*/ char fn[64]; if(dbdata[handle]==0) return(-1); t=d4tag_default(dbdata[handle]); if (u4switch() & 2 || u4switch() & 8) /* Clipper & DBIII */ u4name_piece(fn,64,dbdata[handle]->file.name,0,0); else strcpy(fn,dbdata[handle]->file.name); if ((i=d4index(dbdata[handle],fn)) == NULL) return(e4index); is_locked = DB_file_locked(handle); if (is_locked == 0) /* Se non e' stato bloccato in modo esclusivo */ { while ((rt=i4lock(i)) == r4locked) #ifdef DBG yesnofatal_box("Sono in attesa nella DB_delkeys"); #else u4delay_sec(); #endif } if (rt == 0) rt=t4remove_calc(t,recno); if (is_locked == 0) /* Siccome ho fatto il lock dell'indice, devo anche sbloccarlo */ i4unlock(i); return(rt); } /*------------------------------------------------------------------------- cancella dall'indice corrente la chiave specificata --------------------------------------------------------------------------*/ int DB_flush(int handle) { int rt; while ((rt = d4flush(dbdata[handle])) == r4locked) #ifdef DBG yesnofatal_box("Sono in attesa nella DB_flush"); #else u4delay_sec(); #endif return rt; } /*------------------------------------------------------------------------- riscrive il record attuale --------------------------------------------------------------------------*/ int DB_rewrite(int handle) { int rt; if(dbdata[handle]==0) return(-1); while ((rt=d4write(dbdata[handle],d4recno(dbdata[handle]))) == r4locked) #ifdef DBG yesnofatal_box("Sono in attesa nella DB_rewrite"); #else u4delay_sec(); #endif if (rt == 0) { while ((rt = d4flush(dbdata[handle])) == r4locked) #ifdef DBG yesnofatal_box("Sono in attesa nella DB_rewrite (d4flush)"); #else u4delay_sec(); #endif } if (rt == e4unique) { DB_get_error(); fatal_box("Errore in DB_rewrite(): chiave duplicata nel record %ld, file %s", dbdata[handle]->rec_num + 1, dbdata[handle]->file.name); } rt=DB_unlock(handle); return (rt); } /*------------------------------------------------------------------------- appende il record attuale --------------------------------------------------------------------------*/ int DB_add(int handle) { int rt; int is_locked = 0; DATA4 * data = dbdata[handle]; if (data==0) return(-1); is_locked = DB_file_locked(handle); if (is_locked == 0) /* Se non e' stato gia' bloccato in modo esclusivo */ { while (file4lock(&data->file, L4LOCK_POS_OLD, 1L) == r4locked) #ifdef DBG yesnofatal_box("Sono in attesa nella DB_add"); #else u4delay_sec(); #endif } while ((rt = d4append_start(data,0)) == r4locked) #ifdef DBG yesnofatal_box("Sono in attesa nella DB_add (d4append_start)"); #else u4delay_sec(); #endif if (rt == 0) { d4recall(data); while ((rt = d4append(data)) == r4locked) #ifdef DBG yesnofatal_box("Sono in attesa nella DB_add (d4append)"); #else u4delay_sec(); #endif if (rt == e4unique) { DB_get_error(); if (data->rec_num > 0) fatal_box("Errore in DB_add(): chiave duplicata nell' indice %ld, file %s", data->rec_num + 1, data->file.name); else rt = _isreinsert; } else if (rt == 0) { while ((rt = d4flush(data)) == r4locked) #ifdef DBG yesnofatal_box("Sono in attesa nella DB_add (d4flush)"); #else u4delay_sec(); #endif } } DB_unlock(handle); if (is_locked == 0) { file4unlock(&data->file, L4LOCK_POS_OLD, 1L); } return(rt); } /*------------------------------------------------------------------------- Blocca in modo esclusivo il file dati ed indice --------------------------------------------------------------------------*/ int DB_lockfile(int handle) { int rt; if(dbdata[handle]==0) return(-1); rt = d4lock_file(dbdata[handle]); if (rt==0) rt=d4lock_index(dbdata[handle]); return(rt); } HIDDEN int is_inkey(RecDes *r, int numfield) { int found=0,i,j; for (i=0; ((i < MaxKeys) && (i < r->NKeys) && !found); i++) for (j=0; ((j < r->Ky[i].NkFields) && !found); j++) if (numfield == r->Ky[i].FieldSeq[j]) found=1; return(found); } HIDDEN void do_key(char *fname, RecDes *r, TAG4INFO *tag_info, int n_keys) { int i,j; char tiname[9]; /* Tag name, max 8 characters long! */ strcpy(tiname,fname); CUpString(tiname); for (i=0; ((i < MaxKeys) && (i < n_keys)); i++) { tag_info[i].name=(char *)u4alloc(9); tag_info[i].expression=(char *)u4alloc(256); tag_info[i].filter=(char*)u4alloc(20); tag_info[i].descending=0; if (r->Ky[i].DupKeys) tag_info[i].unique=0; else tag_info[i].unique= i == 0 ? e4unique : r4unique_continue; /* tag_info[i].unique=e4unique; */ strcpy(tag_info[i].filter,".NOT. DELETED()"); /* Not available for DBIII and CLIPPER */ strcpy(tag_info[i].name,tiname) ; if (strlen(tiname) < 8) strcat(tag_info[i].name," "); tag_info[i].name[strlen(tag_info[i].name)-1] = '0' + i + 1; for (j=0; j < r->Ky[i].NkFields; j++) { int nf= r->Ky[i].FieldSeq[j]; if (nf > MaxFields) /* When Upper field is specified */ { nf -= MaxFields; strcat(tag_info[i].expression,"UPPER("); } if (r->Ky[i].FromCh[j] != 255) /* When partial field is specified */ strcat(tag_info[i].expression,"SUBSTR("); switch (r->Fd[nf].TypeF) /* When numeric field in key is specified */ { case _intfld: case _longfld: case _realfld: case _wordfld: case _intzerofld: case _longzerofld: strcat(tag_info[i].expression,"STR("); break; case _datefld: strcat(tag_info[i].expression,"DTOS("); break; case _boolfld: strcat(tag_info[i].expression,"IIF("); /* Logical fields are in key too.. */ break; default: /* It's a non sense to keep _realfld in key... */ break; /* however it's possible to have it... */ } /* Le chiavi composte da campi data non necessitano di funzioni di traduzione. */ strcat(tag_info[i].expression,r->Fd[nf].Name); /* Append field name */ if (r->Ky[i].FromCh[j] != 255) /* If partial field was specified */ { /* add parameters to SUBSTR */ char ts[8]; strcat(tag_info[i].expression,","); sprintf(ts,"%d",r->Ky[i].FromCh[j]); strcat(tag_info[i].expression,ts); strcat(tag_info[i].expression,","); sprintf(ts,"%d",r->Ky[i].ToCh[j] - r->Ky[i].FromCh[j] + 1); strcat(tag_info[i].expression,ts); strcat(tag_info[i].expression,")"); } switch (r->Fd[nf].TypeF) /* If numeric field was specified */ { /* add parameters to STR */ case _intfld: case _longfld: case _realfld: /* Questo tipo di campo(real) non ha senso in un a chiave... */ case _wordfld: case _intzerofld: case _longzerofld: { char ts[8]; strcat(tag_info[i].expression,","); sprintf(ts,"%d",r->Fd[nf].Len); strcat(tag_info[i].expression,ts); strcat(tag_info[i].expression,",0)"); } break; case _boolfld: strcat(tag_info[i].expression,",\"T\",\"F\")"); break; default: break; } /* Close parentheses if UPPER or DTOS operators were used: */ if (r->Ky[i].FieldSeq[j] > MaxFields || (r->Fd[nf].TypeF == _datefld)) strcat(tag_info[i].expression,")"); /* If there's another field in key adds "+" operator: */ if ((j < (r->Ky[i].NkFields-1)) && (strlen(r->Fd[nf].Name) > 0)) strcat(tag_info[i].expression,"+"); } } tag_info[i].name=NULL; tag_info[i].expression=NULL; tag_info[i].filter=NULL; tag_info[i].unique=0; tag_info[i].descending=0; } /*------------------------------------------------------------------------- Compatta il file dati --------------------------------------------------------------------------*/ int DB_packfile(short vis, const char * filename, long eod) { int rt=0,handle; /* if(dbdata[handle]==0) return(-1); codebase.auto_open = 0 cosi' non apre gli indici */ code_base.auto_open = 0; handle=DB_open(filename,1); /* Exclusive mode open! */ if (handle > -1) { char s[81]; if (vis) { strcpy(s,"Compattamento dati file : "); strcat(s,(char*)filename); #ifndef FOXPRO progind_create(10L,s,1,1,1); #endif } if (eod < d4reccount(dbdata[handle])) { rt=d4zap(dbdata[handle],++eod,d4reccount(dbdata[handle])); } else rt=d4pack(dbdata[handle]); if (vis) { #ifndef FOXPRO progind_set_status((long)10); progind_destroy(); #endif } DB_close(handle); } else rt=code_base.error_code; code_base.auto_open = 1; return rt; } /*------------------------------------------------------------------------- Compatta il file dati --------------------------------------------------------------------------*/ int DB_packmemo(short vis, const char * filename) { int rt=0,handle; code_base.auto_open = 0; handle=DB_open(filename,1); /* Exclusive mode open! */ if (handle > -1) { char s[81]; if (vis) { strcpy(s,"Compattamento memo file : "); strcat(s,(char*)filename); #ifndef FOXPRO progind_create(10L,s,1,1,1); #endif } rt=d4memo_compress(dbdata[handle]); if (vis) { #ifndef FOXPRO progind_set_status((long)10); progind_destroy(); #endif } DB_close(handle); } else rt=code_base.error_code; code_base.auto_open = 1; return rt; } /*------------------------------------------------------------------------- Elimina i record duplicati --------------------------------------------------------------------------*/ int DB_clean_file(int handle, char * filename, char * ff, RecDes * r, short vis) { TAG4INFO tags[2]; TAG4 * t; char s[256], s0[256]; int l = 0, lt = 0, rt = 0; long cnt = 0; INDEX4 *w = NULL; long items = DB_reccount(handle); if (items == 0) return 0; s[0] = '\0'; do_key(ff, r, tags, 1); strcat(tags[0].expression, "+STR(RECNO(),9)"); w = i4create(dbdata[handle],(char*)filename,tags); u4free(tags[0].name); u4free(tags[0].expression); u4free(tags[0].filter); if (w == NULL) return code_base.error_code; t = d4tag_default(dbdata[handle]); lt = expr4key_len(t->expr); l = lt - 9; #ifndef FOXPRO if (vis) progind_create(items,"Ricerca record duplicati",1,1,1); #endif rt = t4bottom(t); while (code_base.error_code == 0) { strncpy(s0, t4key(t), lt); #ifndef FOXPRO if (vis) progind_set_status(++cnt); #endif if (!strncmp(s, s0, l)) { x4go(&xdb[handle],t4recno(t)); d4delete(dbdata[handle]); t4seek(t, s0, lt); } strncpy(s, s0, lt); if (t4skip(t, -1L) >= 0) break; } // while rt = code_base.error_code; #ifndef FOXPRO if (vis) progind_destroy(); #endif i4close(w); return rt; } /*------------------------------------------------------------------------- Compatta gli indici --------------------------------------------------------------------------*/ int DB_packindex(short vis, const char * filename, RecDes *r, long *peod, bool ask) { int rt=0,handle; TAG4INFO tags[MaxKeys+1]; char s[82]; INDEX4 * w = NULL; strcpy(s,"Ricostruzione indici file : "); strcat(s,filename); /* codebase.auto_open = 0 cosi' non apre gli indici */ code_base.auto_open=0 ; handle=DB_open(filename,1); /* Exclusive mode open */ if (handle > -1) { int i; char *ff = find_slash_backslash((char *)filename); #ifndef FOXPRO if (vis) progind_create((long)r->NKeys,s,1,1,1); #endif if ((ff == NULL) || *ff == '\0') ff = (char *)filename; else ff++; do_key(ff,r,tags, r->NKeys); w = i4create(dbdata[handle],NULL,tags); #ifndef FOXPRO if (vis) { progind_set_status((long)r->NKeys); progind_destroy(); } #endif if (w == NULL) rt = code_base.error_code; if (rt == e4unique || rt == r4unique) { rt = 0; if (!ask || yesno_box("Sono stati rilevati alcuni record duplicati devo eliminarli ?")) rt = DB_clean_file(handle, (char*) filename, ff, r, vis); else tags[0].unique = r4unique_continue; if (rt == 0) { #ifndef FOXPRO if (vis) progind_create((long)r->NKeys,s,1,1,1); #endif w = i4create(dbdata[handle],(char*)filename,tags); if (w == NULL) rt = code_base.error_code; #ifndef FOXPRO if (vis) { progind_set_status((long)r->NKeys); progind_destroy(); } #endif } } if (rt == 0) { if (u4switch() & 2 || u4switch() & 8) /* Clipper and DBIII */ { FILE *fp; char cgp[81]; strcpy(cgp,filename); strcat(cgp,".cgp"); if ((fp=fopen(cgp,"w"))!=NULL) { int j; for (j=0; jNKeys;j++) fprintf(fp,"%s\n",tags[j].name); fclose(fp); } } /* else if (u4switch() & 1 || u4switch() & 4) // FOXPRO and DBIV { } */ } for (i=0; ((i < MaxKeys) && (i < r->NKeys)); i++) { u4free(tags[i].name); u4free(tags[i].expression); u4free(tags[i].filter); } *peod=DB_reccount(handle); DB_close(handle); } code_base.auto_open = 1; return(rt); } /*------------------------------------------------------------------------- costruisce il file filename --------------------------------------------------------------------------*/ int DB_build(const char * filename, RecDes *r) { FIELD4INFO field_info[MaxFields+1]; /* Numero di campi in un record */ TAG4INFO tag_info[MaxKeys+1]; /* Numero di chiavi in un file */ DATA4 *dbuilded; int rt=0,i; char *ff = find_slash_backslash((char *)filename); for (i=0; ((iNFields) && (iFd[i].Name); field_info[i].len = r->Fd[i].Len; field_info[i].dec = r->Fd[i].Dec; switch (r->Fd[i].TypeF) { case _intfld: case _longfld: case _realfld: /* It's a non sense to keep this in key! */ case _wordfld: case _intzerofld: case _longzerofld: field_info[i].type=r4num; break; case _boolfld: field_info[i].type=r4log; break; case _datefld: field_info[i].type=r4date; break; case _memofld: field_info[i].type=r4memo; field_info[i].len = 10; field_info[i].dec = 0; break; case _charfld: default: field_info[i].type=r4str; break; } } field_info[i].name=NULL; field_info[i].type=0; field_info[i].len=0; field_info[i].dec=0; if (ff == NULL || *ff == '\0') ff = (char *) filename; else ff++; do_key(ff,r,tag_info, r->NKeys); if ((dbuilded=d4create(&code_base, (char *)filename, field_info, tag_info))==0) /* deve solo creare il file dati vuoto */ rt=code_base.error_code; else rt=d4close(dbuilded); if (u4switch() & 2 || u4switch() & 8) /* Rebuild filename.cgp for CLIPPER AND DBIII only */ { FILE* fp; char xx[81]; strcpy(xx,(char*)filename); strcat(xx,".cgp"); if ((fp=fopen(xx,"w"))!=NULL) { int j; for (j=0; tag_info[j].name ; j++) fprintf(fp,"%s\n",tag_info[j].name); fclose(fp); } } if (rt!=0) rt=code_base.error_code; for (i=0; ((i < MaxFields) && (i < r->NFields)); i++) u4free(field_info[i].name); for (i=0; ((i < MaxKeys) && (i < r->NKeys)); i++) { u4free(tag_info[i].name); u4free(tag_info[i].expression); u4free(tag_info[i].filter); } return(rt) ; } /*------------------------------------------------------------------------- ritorna l'ultimo errore --------------------------------------------------------------------------*/ int DB_get_error(void) { int rt = code_base.error_code; code_base.error_code=0; return (rt); } /*------------------------------------------------------------------------- Azzera la viarabile globale d'errore --------------------------------------------------------------------------*/ void DB_zero_error(void) { code_base.error_code=0; } /*------------------------------------------------------------------------- Si posiziona sull'indice attivo alla chiave indicata, restituisce la prima chiave che trova >= a from. (TCusrsor) --------------------------------------------------------------------------*/ int DB_index_seek(int handle, char* from) { TAG4 *t; if(dbdata[handle]==0) return(-1); if ((t=d4tag_default(dbdata[handle]))==NULL) return(-1); if (t4seek(t,from,strlen(from)) < 0) return(DB_get_error()); return(0); } /*------------------------------------------------------------------------- Ritorna il numero di record corrispondente alla chiave corrente --------------------------------------------------------------------------*/ long DB_index_recno(int handle) { TAG4 *t; if(dbdata[handle]==0) return(-1); if ((t=d4tag_default(dbdata[handle]))==NULL) return(-1); return(t4recno(t)); } /*------------------------------------------------------------------------- Si posiziona sulla chiave successiva dell'indice corrente --------------------------------------------------------------------------*/ long DB_index_next(int handle) { TAG4 *t; if(dbdata[handle]==0) return(-1); if ((t=d4tag_default(dbdata[handle]))==NULL) return(-1); return(t4skip(t,1L)); } /*------------------------------------------------------------------------- Restituisce la chiave corrente --------------------------------------------------------------------------*/ char* DB_index_getkey(int handle) { TAG4 *t; static char key[MAXLEN]; int klen; if(dbdata[handle]==0) return(NULL); if ((t=d4tag_default(dbdata[handle]))==NULL) return(NULL); klen=expr4key_len(t->expr); if (klen > (MAXLEN-1)) klen=MAXLEN-1; memcpy(key,t4key(t),klen); /* t4key non restituisce una null terminated string */ key[klen]='\0'; return(key); } /*------------------------------------------------------------------------- Restituisce vero se l'indice e' alla fine --------------------------------------------------------------------------*/ int DB_index_eof(int handle) { TAG4 *t; if(dbdata[handle]==0) return(-1); if ((t=d4tag_default(dbdata[handle]))==NULL) return(-1); return(t4eof(t)); } /*------------------------------------------------------------------------- Blocca il record indicato --------------------------------------------------------------------------*/ int DB_lock_rec(int handle,long nrec) { if(dbdata[handle]==0) return(-1); if(d4lock(dbdata[handle],nrec)==r4locked) return(-1); else return(0); } /*------------------------------------------------------------------------- Ritorna vero(non zero) se il file dati od indice sono stati bloccati in modo esclusivo dalla presente applicazione, non da altri programmi!!! --------------------------------------------------------------------------*/ int DB_file_locked(int handle) { if(dbdata[handle]==0) return(-1); return(d4lock_test_file(dbdata[handle]) + d4lock_test_index(dbdata[handle])); } /*------------------------------------------------------------------------- Ritorna vero se il record nrec e' bloccato dalla presente applicazione, non da altri programmi!!! --------------------------------------------------------------------------*/ int DB_rec_locked(int handle,long nrec) { if(dbdata[handle]==0) return(-1); return(d4lock_test(dbdata[handle],nrec)); } /*------------------------------------------------------------------------- restituisce la configurazione della libreria --------------------------------------------------------------------------*/ long DB_getconf() { return(u4switch()); } /*------------------------------------------------------------------------- Restituisce il numero di versione scritto sull'header dell'indice --------------------------------------------------------------------------*/ long DB_changed(int handle) { INDEX4 *i; char fn[64]; if(dbdata[handle]==0) return(-1); if (u4switch() & 2 || u4switch() & 8) /* Clipper & DBIII */ u4name_piece(fn,64,dbdata[handle]->file.name,0,0); else strcpy(fn,dbdata[handle]->file.name); i=d4index(dbdata[handle],fn); if (i == NULL) return(-1); return(i4changed(i)); } char* DB_memoptr( const int handle, const char * fieldname ) { FIELD4 * f; f = d4field( dbdata[ handle ], ( char *)fieldname ); return f4memo_ptr( f ); } int DB_memowrite( const int handle, const char * fieldname, const char * data ) { int ret; FIELD4 * f; f = d4field( dbdata[ handle ], fieldname ); ret = f4memo_assign( f, ( char * )data ); d4flush_data( dbdata[ handle ] ); return ret; }