#define XVT_INCL_NATIVE #include #include #define S4OFF_REPORT #if XVT_OS == XVT_OS_WIN32 #define S4DLL #define S4WIN32 #endif #include #include #include /*-------------------------------------------------------------------------- Utility --------------------------------------------------------------------------*/ HIDDEN void progind_create(long m, const char* t, bool b, bool c, int n) { statbar_set_title(TASK_WIN, t); } HIDDEN void progind_destroy() { statbar_set_title(TASK_WIN, NULL); // Restore default title } HIDDEN void progind_set_status(long l) { } /*-------------------------------------------------------------------------- numero massimo di database aperti contemporaneamente --------------------------------------------------------------------------*/ #define CB4FILES 64 #define MAXLEN 137 /* Lunghezza massima chiave */ static CODE4 code_base; static DATA4 *dbdata[CB4FILES]; bool handle_ok(int handle) { return handle >= 0 && handle < CB4FILES && dbdata[handle] != NULL; } static char* find_slash_backslash(const char* s) { const char* slash = NULL; for ( ; *s; s++) { if (*s == '\\' || *s == '/') slash = s; } return (char*)slash; } /*-------------------------------------------------------------------------- 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) d4top(dbdata[found]); return(found); } /*------------------------------------------------------------------------- chiusura del database inviduato da handle torna -1 se il database non puo essere chiuso --------------------------------------------------------------------------*/ int DB_close(int handle) { if(!handle_ok(handle)) return(-1); d4close(dbdata[handle]); dbdata[handle]=(DATA4 *) 0; code_base.errorCode=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(!handle_ok(handle)) return((char *) 0); return(d4record(dbdata[handle])); } /*------------------------------------------------------------------------- torna la lunghezza del record --------------------------------------------------------------------------*/ int DB_reclen(int handle) { if(!handle_ok(handle)) return(-1); return((int) d4recWidth(dbdata[handle])); } /*------------------------------------------------------------------------- torna la lunghezza della chiave corrente --------------------------------------------------------------------------*/ int DB_keylen(int handle) { return a4tagKeyLen(dbdata[handle]); } /*------------------------------------------------------------------------- torna il numero del record attuale --------------------------------------------------------------------------*/ long int DB_recno(int handle) { if(!handle_ok(handle)) return(-1L); return(d4recNo(dbdata[handle])); } /*------------------------------------------------------------------------- torna il numero complessivo dei records presenti nell'archivio --------------------------------------------------------------------------*/ long int DB_reccount(int handle) { if(!handle_ok(handle)) 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(!handle_ok(handle)) return(-1); /* si posiziona sul primo indice */ tt=d4tagNext(dbdata[handle],NULL); if(tt==NULL) return(-1); for(i=1;i 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(!handle_ok(handle)) return(-1); return(d4eof(dbdata[handle])); } /*------------------------------------------------------------------------- torna 1 se bof, 0 altrimenti --------------------------------------------------------------------------*/ int DB_bof(int handle) { if(!handle_ok(handle)) return(-1); return(d4bof(dbdata[handle])); } /*------------------------------------------------------------------------- legge un record per numero record --------------------------------------------------------------------------*/ int DB_go(int handle,long recno) { if(!handle_ok(handle)) return(-1); return(d4go(dbdata[handle],recno)); } /*------------------------------------------------------------------------- cancella il record attuale. Non cancella le chiavi. --------------------------------------------------------------------------*/ int DB_delete(int handle) { if(!handle_ok(handle)) return(-1); d4delete(dbdata[handle]); return(0); } /*------------------------------------------------------------------------- ripristina il record attuale --------------------------------------------------------------------------*/ int DB_recall(int handle) { if(!handle_ok(handle)) return(-1); d4recall(dbdata[handle]); return(0); } /*------------------------------------------------------------------------- --------------------------------------------------------------------------*/ int DB_flush(int handle) { int rt; while ((rt = d4flush(dbdata[handle])) == r4locked) u4delaySec(); return rt; } /*------------------------------------------------------------------------- riscrive il record attuale --------------------------------------------------------------------------*/ int DB_rewrite(int handle) { int rt; if(!handle_ok(handle)) return(-1); while ((rt=d4write(dbdata[handle],d4recNo(dbdata[handle]))) == r4locked) u4delaySec(); if (rt == 0) { while ((rt = d4flush(dbdata[handle])) == r4locked) u4delaySec(); } if (rt == e4unique) { char msg[256]; DB_get_error(); sprintf(msg, "Errore in DB_rewrite(): chiave duplicata nel record %ld, file %s", d4recNo(dbdata[handle]) + 1, d4fileName(dbdata[handle])); xvt_dm_post_fatal_exit(msg); } 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 (d4lockAll(data) == r4locked) u4delaySec(); } while ((rt = d4appendStart(data,0)) == r4locked) u4delaySec(); if (rt == 0) { d4recall(data); while ((rt = d4append(data)) == r4locked) u4delaySec(); if (rt == e4unique) { long rec_num = d4recNo(data); DB_get_error(); if (rec_num > 0) { char msg[256]; sprintf(msg, "Errore in DB_add(): chiave duplicata nell' indice %ld, file %s", rec_num + 1, d4fileName(data)); xvt_dm_post_fatal_exit(msg); } else rt = _isreinsert; } else if (rt == 0) { while ((rt = d4flush(data)) == r4locked) u4delaySec(); } } DB_unlock(handle); if (is_locked == 0) d4unlock(data); return(rt); } /*------------------------------------------------------------------------- Blocca in modo esclusivo il file dati ed indice --------------------------------------------------------------------------*/ int DB_lockfile(int handle) { int rt; if(!handle_ok(handle)) return(-1); rt = d4lockFile(dbdata[handle]); if (rt==0) rt=d4lockIndex(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! */ char* dot; strcpy(tiname,fname); dot = strchr(tiname, '.'); if (dot) *dot = '\0'; _strupr(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((char *)tag_info[i].filter,".NOT. DELETED()"); /* Not available for DBIII and CLIPPER */ strcpy((char *)tag_info[i].name,tiname) ; if (strlen(tiname) < 8) strcat((char *)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((char *) tag_info[i].expression,"UPPER("); } if (r->Ky[i].FromCh[j] != 255) /* When partial field is specified */ strcat((char *)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((char *)tag_info[i].expression,"STR("); break; case _datefld: strcat((char *)tag_info[i].expression,"DTOS("); break; case _boolfld: strcat((char *)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((char *)tag_info[i].expression,r->Fd[nf].Name); /* Append field name */ 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((char *)tag_info[i].expression,","); sprintf(ts,"%d",r->Fd[nf].Len); strcat((char *)tag_info[i].expression,ts); strcat((char *)tag_info[i].expression,",0)"); } break; case _boolfld: strcat((char *)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((char *)tag_info[i].expression,")"); if (r->Ky[i].FromCh[j] != 255) /* If partial field was specified */ { /* add parameters to SUBSTR */ char ts[8]; strcat((char *)tag_info[i].expression,","); sprintf(ts,"%d",r->Ky[i].FromCh[j] + 1); strcat((char *)tag_info[i].expression,ts); strcat((char *)tag_info[i].expression,","); sprintf(ts,"%d",r->Ky[i].ToCh[j] - r->Ky[i].FromCh[j] + 1); strcat((char *)tag_info[i].expression,ts); strcat((char *)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((char *)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; code_base.autoOpen = 0; handle=DB_open(filename,1,0); /* Exclusive mode open! */ if (handle > -1) { if (vis) { char s[_MAX_PATH]; strcpy(s,"Compattamento "); strcat(s, filename); progind_create(100L,s,0,0,60); } if (eod < d4recCount(dbdata[handle])) { rt=d4zap(dbdata[handle],++eod,d4recCount(dbdata[handle])); } else rt=d4pack(dbdata[handle]); if (vis) progind_destroy(); DB_close(handle); } else rt=code_base.errorCode; code_base.autoOpen = 1; return rt; } /*------------------------------------------------------------------------- Compatta il file dati --------------------------------------------------------------------------*/ int DB_packmemo(short vis, const char * filename) { int rt=0,handle; code_base.autoOpen = 0; handle=DB_open(filename,1,0); /* Exclusive mode open! */ if (handle > -1) { char s[81]; if (vis) { strcpy(s,"Compattamento memo file : "); strcat(s,(char*)filename); progind_create(100L,s,0,0,60); } rt=d4memoCompress(dbdata[handle]); if (vis) progind_destroy(); DB_close(handle); } else rt=code_base.errorCode; code_base.autoOpen = 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((char *) tags[0].expression, "+STR(RECNO(),9)"); w = i4create(dbdata[handle],(char*)filename,tags); u4free((char *) tags[0].name); u4free((char *) tags[0].expression); u4free((char *) tags[0].filter); if (w == NULL) return code_base.errorCode; t = d4tagDefault(dbdata[handle]); lt = expr4len(t->tagFile->expr); l = lt - 9; if (vis) progind_create(items,"Ricerca record duplicati",0,1,60); rt = tfile4bottom(t->tagFile); while (code_base.errorCode == 0) { strncpy(s0, a4tagKey(dbdata[handle]), lt); if (vis) progind_set_status(++cnt); if (!strncmp(s, s0, l)) { d4go(dbdata[handle],tfile4recNo(t->tagFile)); d4delete(dbdata[handle]); tfile4seek(t->tagFile, s0, lt); } strncpy(s, s0, lt); if (tfile4skip(t->tagFile, -1L) >= 0) break; } // while rt = code_base.errorCode; if (vis) progind_destroy(); i4close(w); return rt; } /*------------------------------------------------------------------------- Compatta gli indici --------------------------------------------------------------------------*/ int DB_yesnobox(const char* msg) { return xvt_dm_post_ask("Si", "No", NULL, msg) == RESP_DEFAULT; } int DB_packindex(short vis, const char * filename, RecDes *r, long *peod, bool ask) { int rt=0,handle; TAG4INFO tags[MaxKeys+1]; char s[256]; INDEX4 * w = NULL; strcpy(s,"Ricostruzione indici file : "); strcat(s,filename); code_base.autoOpen=0 ; handle=DB_open(filename,1,0); /* Exclusive mode open */ if (handle >= 0) { int i; char *ff = find_slash_backslash(filename); if (vis) progind_create((long)r->NKeys,s,0,1,60); if ((ff == NULL) || *ff == '\0') ff = (char *)filename; else ff++; do_key(ff,r,tags, r->NKeys); w = i4create(dbdata[handle],NULL,tags); if (vis) { progind_set_status((long)r->NKeys); progind_destroy(); } if (w == NULL) rt = code_base.errorCode; if (rt == e4unique || rt == r4unique) { rt = 0; if (!ask || DB_yesnobox("Sono stati rilevati alcuni records duplicati:\nsi desidera eliminarli?")) rt = DB_clean_file(handle, (char*) filename, ff, r, vis); else tags[0].unique = r4unique_continue; if (rt == 0) { if (vis) progind_create((long)r->NKeys,s,0,1,60); w = i4create(dbdata[handle],(char*)filename,tags); if (w == NULL) rt = code_base.errorCode; if (vis) { progind_set_status((long)r->NKeys); progind_destroy(); } } } 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); } } } for (i=0; ((i < MaxKeys) && (i < r->NKeys)); i++) { u4free((char *) tags[i].name); u4free((char *) tags[i].expression); u4free((char *) tags[i].filter); } *peod=DB_reccount(handle); DB_close(handle); } code_base.autoOpen = 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(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.errorCode; 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.errorCode; for (i=0; ((i < MaxFields) && (i < r->NFields)); i++) u4free(field_info[i].name); for (i=0; ((i < MaxKeys) && (i < r->NKeys)); i++) { u4free((char *) tag_info[i].name); u4free((char *) tag_info[i].expression); u4free((char *) tag_info[i].filter); } return(rt) ; } /*------------------------------------------------------------------------- reperisce il tracciato record e la stringa di definizione delle chiavi Stringa di definizione chiavi: expression1|unique1$expression2|unique2$expression3|unique3 --------------------------------------------------------------------------*/ int DB_recinfo(const char * filename, FileDes *d, RecDes *r, char* keys) { /* filename must not have extension since it's used to search index name too*/ FIELD4INFO *field_info; /* Definizione del tracciato record */ TAG4INFO *tag_info; /* Definizione delle chiavi */ INDEX4 *index_file; DATA4 *data_file; int rt=0,num_fields,i; data_file = d4open(&code_base, (char*)filename); if (data_file != NULL) { field_info = d4fieldInfo(data_file); index_file = d4index(data_file,"" /*(char*)filename */); if (index_file == NULL) { char msg[256]; sprintf(msg, "Il file %s e' senza indici.",filename); xvt_dm_post_fatal_exit(msg); } tag_info = i4tagInfo(index_file); d->EOD = d->EOX = d4recCount(data_file); d->LenR = (word)d4recWidth(data_file); d->Flags = 0L; strcpy(d->Des,"File esterno"); strcpy(d->FCalc,""); strcpy(d->GenPrompt,""); if (field_info != NULL && tag_info != NULL) { /* Compile field information */ num_fields = d4numFields(data_file); r->NFields = num_fields; for (i=0; ((iFd[i].Name,field_info[i].name); _strupr(r->Fd[i].Name); r->Fd[i].Len = (unsigned char)field_info[i].len; r->Fd[i].Dec = (unsigned char)field_info[i].dec; switch(field_info[i].type) { case r4str: if (r->Fd[i].Len > 1) r->Fd[i].TypeF = _alfafld; else r->Fd[i].TypeF = _charfld; break; case r4log: r->Fd[i].TypeF = _boolfld; break; case r4date: r->Fd[i].TypeF = _datefld; break; case r4memo: r->Fd[i].TypeF = _memofld; break; case r4num: if (r->Fd[i].Dec > 0) r->Fd[i].TypeF = _realfld; else r->Fd[i].TypeF = r->Fd[i].Len < 6 ? _intfld : _longfld; break; default: break; } } strcpy(keys,""); /* Compile key definition */ for (i=0; i < MaxKeys; i++) /* Browse all tags */ { if (tag_info[i].name == NULL) break; strcat(keys,tag_info[i].expression); /* Tell me if you're unique my Boy... */ strcat(keys,"|"); strcat(keys,tag_info[i].unique == 0 ? "X" : " "); strcat(keys,"$"); } r->NKeys = i; u4free(field_info); u4free(tag_info); } else rt = code_base.errorCode; d4close(data_file); } else rt = code_base.errorCode; return (rt); } /*------------------------------------------------------------------------- ritorna l'ultimo errore --------------------------------------------------------------------------*/ int DB_get_error(void) { int rt = code_base.errorCode; code_base.errorCode=0; return (rt); } /*------------------------------------------------------------------------- Azzera la viarabile globale d'errore --------------------------------------------------------------------------*/ void DB_zero_error(void) { code_base.errorCode=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(!handle_ok(handle)) return(-1); if ((t=d4tagDefault(dbdata[handle]))==NULL) return(-1); if (tfile4seek(t->tagFile,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(!handle_ok(handle)) return(-1); if ((t=d4tagDefault(dbdata[handle]))==NULL) return(-1); return(tfile4recNo(t->tagFile)); } /*------------------------------------------------------------------------- Si posiziona sulla chiave successiva dell'indice corrente --------------------------------------------------------------------------*/ long DB_index_next(int handle) { TAG4 *t; if(!handle_ok(handle)) return(-1); if ((t=d4tagDefault(dbdata[handle]))==NULL) return(-1); return(tfile4skip(t->tagFile,1L)); } /*------------------------------------------------------------------------- Restituisce la chiave corrente --------------------------------------------------------------------------*/ char* DB_index_getkey(int handle) { static char* key = NULL; TAG4 *t; int klen; if (key == NULL) key = malloc(MAXLEN); if(!handle_ok(handle)) return(NULL); if ((t=d4tagDefault(dbdata[handle]))==NULL) return(NULL); klen=a4tagKeyLen(dbdata[handle]); if (klen > (MAXLEN-1)) klen=MAXLEN-1; memcpy(key,a4tagKey(dbdata[handle]),klen); /* tfile4key non restituisce una null terminated string */ key[klen]='\0'; return key; } /*------------------------------------------------------------------------- Si posiziona sulla chiave ed il record indicati --------------------------------------------------------------------------*/ int DB_index_go(int handle, const char* key, long recno) { TAG4 *t; if(!handle_ok(handle)) return(-1); if ((t=d4tagDefault(dbdata[handle]))==NULL) return(-1); return(tfile4go(t->tagFile, key, recno, FALSE)); } /*------------------------------------------------------------------------- Restituisce vero se l'indice e' alla fine --------------------------------------------------------------------------*/ int DB_index_eof(int handle) { TAG4 *t; if(!handle_ok(handle)) return(-1); if ((t=d4tagDefault(dbdata[handle]))==NULL) return(-1); return(tfile4eof(t->tagFile)); } /*------------------------------------------------------------------------- Blocca il record indicato --------------------------------------------------------------------------*/ int DB_lock_rec(int handle,long nrec) { if(!handle_ok(handle)) 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(!handle_ok(handle)) return(-1); return a4lockTest(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(!handle_ok(handle)) return(-1); return(d4lockTest(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) { return(a4indexVersion(dbdata[handle])); } char* DB_memoptr( const int handle, const char * fieldname ) { FIELD4 * f; f = d4field( dbdata[ handle ], ( char *)fieldname ); return f4memoPtr( f ); } int DB_memowrite( const int handle, const char * fieldname, const char * data ) { int ret; FIELD4 * f; f = d4field(dbdata[handle], fieldname ); ret = f4memoAssign( f, ( char * )data ); d4flush(dbdata[handle]); d4unlock(dbdata[handle]); return ret; }