Dans tout programme C, les databases doivent pouvoir être consultées de la façon la plus simple. Le compilateur scr4_e génère à cet effet une série de variables et de #define qui permettent d'accéder aux enregistrements et aux champs qui les composent de la manière la plus rapide, tant du point de vue de l'écriture que de celui de la vitesse d'exécution.
La connaissance des fonctions de base de la librairie scr4i est évidemment nécessaire pour permettre la compréhension complète des exemples proposés dans le texte.
Référence aux objets ISAM
Le compilateur scr4_e génère un fichier .h et un ou des fichiers .c. Ces fichiers contiennent pour chaque objet rencontré dans la lecture des sources une variable (un pointeur) dont la valeur correspond à l'objet du même nom. Ainsi, si dans les sources on a
ISAM is_client {
"client"
FIELD string 6 Name Code Title "Code client" UPPER
FIELD zstring 31 Name nom Title "Nom client"
FIELD zstring 41 Name adresse Title "Adresse"
FIELD string 8 Name post Title "Code postal"
FIELD double Name chaff Title "Chiffre d'affaire"
INDEX {code} NODUP ASC NAME code
INDEX {nom:20 sqz} DUP ASC NAME nom
}
on trouvera dans le fichier .c une entrée du type
ISAM *is_client;
et dans le fichier .h, la déclaration
extern ISAM *is_client;
De cette façon, on utilisera dans les sources C le même nom que celui de l'objet SCR/AL1. Par exemple :
IS_open_files(is_client, 0L);
pour ouvrir la base de données is_client.
Références aux champs des ISAMS
Lorsqu'un record est lu, ou lorsqu'il doit être créé par un programme C, il faut lire ou introduire les valeurs des différents champs dans ce record.
Pour utiliser les champs des ISAMS, 3 méthodes sont possibles :
Références aux index
Pour chaque index nommé (où l'on trouve NAME dans sa définition), une variable de type OBJ est construite. Cette variable identifie l'ISAM et le numéro de l'index. Elle porte le nom de l'ISAM, suivi du nom de l'index, suivi de "_i". Cette extension permet de différencier les champs et les index d'un ISAM qui pourraient porter le même nom.
Par exemple :
is_client_nom_i
est un objet qui détermine le second index (numéro 1) de l'ISAM is_client. Cet OBJ pourra être utilisé dans les recherches via la fonction OBJ_search().
Exemple
if(OBJ_search(is_client_nom_i, SCR_GE)) {
PG_display_error("Pas de client trouvé");
return(-1);
}
A chaque champ d'un ISAM est associé un #define dans le fichier .h généré par scr4_e. Ce #define est du type :
#define is_client_CHAFF (*(double *)(is_client->is_rec + 84))
De sorte que pour additionner les valeurs des chiffres d'affaires du fichier is_client, il suffit de faire :
double TotChaff()
{
double total = 0.0;
if(IS_open_files(is_client, 0L)) return(total);
if(IS_search(is_client, 0, SCR_GE)) goto fin;
while(1) {
total += is_client_CHAFF;
if(IS_next(is_client)) break;
}
fin:
IS_close_files(is_client, 0L);
return(total);
}
De même, pour assigner une valeur à un champ, il suffit d'entrer :
is_client_CHAFF = montant;
L'assignation a lieu au niveau du record courant. Le record devra encore être sauvé dans le fichier, après d'éventuelles autres modifications par la fonction IS_rewrite() ou IS_write().
Dans le cas des champs STRING ou ZSTRING, la même assignation est possible. Comme il s'agit de string, il faudra prendre garde à ne pas dépasser le nombre de bytes réservés au champ, en utilisant par exemple la fonction strncpy() au lieu de strcpy().
strncpy(is_client_CODE, "BAMBY ", 6);
strncpy(buffer, is_client_CODE, 6);
Dans le cas des champs ZSTRING cependant, le dernier byte est toujours nul et les fonctions de gestion de strings terminés par 0 comme strcpy(), printf(), etc, peuvent s'appliquer.
printf("Client : %s\n", is_client_NOM);
Les références des tableaux de champs
Lorsque plusieurs champs consécutifs d'un ISAM sont de même type et de même longueur, des #define supplémentaires sont générés par scr4_e pour ces champs. Ces #defines permettent d'utiliser les champs successifs comme des éléments de tableaux.
Exemple
ISAM is_art {
...
FIELD short NAME stsize1 TITLE "Stock Taille 1"
FIELD short NAME stsize2 TITLE "Stock Taille 2"
FIELD short NAME stsize3 TITLE "Stock Taille 3"
FIELD short NAME stsize4 TITLE "Stock Taille 4"
FIELD short NAME stsize5 TITLE "Stock Taille 5"
FIELD short NAME stsize6 TITLE "Stock Taille 6"
...
}
Les #defines suivants sont générés (les premiers comme décrit plus haut) :
#define is_art_STSIZE1 (*(short *)(is_art->is_rec + 0))
#define is_art_STSIZE2 (*(short *)(is_art->is_rec + 2))
#define is_art_STSIZE3 (*(short *)(is_art->is_rec + 4))
#define is_art_STSIZE4 (*(short *)(is_art->is_rec + 6))
#define is_art_STSIZE5 (*(short *)(is_art->is_rec + 8))
#define is_art_STSIZE6 (*(short *)(is_art->is_rec + 10))
#define is_art_vSTSIZE1 ((short *)(is_art->is_rec + 0))
De sorte que le calcul du stock pour un article se ramène à :
Stock1Art()
{
int i, tot = 0;
for(i = 0 ; i < 6 ; i++)
tot += is_art_vSTSIZE1[i];
return(tot);
}
Cette fonction est généralisée aux champs de type STRING : des typedef sont automatiquement générés dans le fichier .h qui permettent d'employer les suites de champs string comme un tableau :
Exemple
ISAM is_art {
...
FIELD short NAME stsize1 TITLE "Stock Taille 1"
FIELD short NAME stsize2 TITLE "Stock Taille 2"
FIELD short NAME stsize3 TITLE "Stock Taille 3"
FIELD short NAME stsize4 TITLE "Stock Taille 4"
FIELD short NAME stsize5 TITLE "Stock Taille 5"
FIELD short NAME stsize6 TITLE "Stock Taille 6"
FIELD zstring 4 NAME taille1 Title "Nom taille1"
FIELD zstring 4 NAME taille2 Title "Nom taille2"
FIELD zstring 4 NAME taille3 Title "Nom taille3"
FIELD zstring 4 NAME taille4 Title "Nom taille4"
FIELD zstring 4 NAME taille5 Title "Nom taille5"
FIELD zstring 4 NAME taille6 Title "Nom taille6"
...
}
En C :
PrintStock1Art()
{
int i;
for(i = 0 ; i < 6 ; i++)
printf("\tTaille : %s - Stock : %d\n",
is_art_vTAILLE1[i],
is_art_vSTSIZE1[i]);
}
Suppression des #define
Il est possible de supprimer la génération de ces #define en utilisant le flag -nodef dans la commande de compilation scr4_e.
Le compilateur scr4_e crée dans le fichier .c et dans le fichier .h des variables de type OBJ. Ces variables sont utilisées dans les fonctions de haut niveau SCR_get_*() et SCR_set_*().
Les structures OBJ sont détaillées dans le chapitre OBJ ci-dessous. Elles reprennent l'information permettant d'identifier complètement un champ dans un objet.
Les OBJ ont pour nom celui de l'objet, suivi de celui du champ, le tout en minuscules. Par exemple :
is_client_nom
Les programmes présentés plus haut peuvent être réécrits en utilisant les fonctions de librairies comme suit. Il est à noter que le code généré sera plus lourd et plus lent. De plus la taille de l'exécutable sera augmentée en raison des appels de fonctions qui en C sont relativement consommateurs d'instructions.
Autre désavantage de cette méthode : les types des champs doivent être connus : SCR_get_short() en lieu et place de SCR_get_long() donnera un résultat incorrect non détecté par le compilateur !
double TotChaff()
{
double total = 0.0;
if(IS_open_files(is_client, 0L)) return(total);
if(IS_search(is_client, 0, SCR_GE)) goto fin;
while(1) {
total += SCR_get_double(is_client_chaff);
if(IS_next(is_client)) break;
}
fin:
IS_close_files(is_client, 0L);
return(total);
}
La modification d'une valeur est un cas intéressant :
is_client_CHAFF += montant;
est remplacé par
SCR_set_double(is_client_chaff,
SCR_get_double(is_client_chaff + montant));
Stock1Art()
{
int i, tot = 0;
for(i = 0 ; i < 6 ; i++)
tot += SCR_get_vshort(is_art_stsize1, i);
return(tot);
}
PrintStock1Art()
{
int i;
char buf[10];
for(i = 0 ; i < 6 ; i++) {
SCR_get_vtext(is_art_taille1, i, buf);
printf("\tTaille : %s - Stock : %d\n",
buf,
SCR_get_vshort(is_art_stsize1, i);
}
}
Le seul cas où ces fonctions sont plus intéressantes sont ceux où des champs STRING ou ZSTRING sont lus ou modifiés. En effet, l'appel à fonction est toujours présent (strncpy() par exemple), mais les fonctions SCR_get_*() et surtout SCR_set_*() assurent de ne pas dépasser la taille du champ.
L'accès du plus bas niveau aux champs des ISAMS se fait par les fonctions IS_set_field() et IS_get_field(). Il ne sera utilisé que lorsque les autres méthodes sont inopérantes.
Ces fonctions, décrites dans la librairie scr4i, demandent de connaître le numéro du champ. Elles prennent un buffer en input ou en output et lisent ou écrivent le nombre exact du champ dans ce buffer.
Exemple
double chaff = 0.0;
IS_set_field(is_client, 4, &chaff);
IS_set_field(is_client, 0, "CODE ");
IS_get_field(is_client, 4, &chaff);
...
Les structures OBJ sont générés par le compilateur scr4_e et placées dans les fichiers .c et .h. Elles sont utilisées par les fonctions SCR_get_*(), SCR_set_*(), OBJ_search(), etc.
Pour chaque champ des PAGES et des ISAMS, ainsi que pour chaque INDEX des ISAMS, une variable de ce type est créée. Pour éviter de surcharger les programmes, il est possible de supprimer ces définitions pour certains objets en plaçant dans le code des PAGES ou des ISAMS le mot-clé NO_OBJ.
La définition d'un structure OBJ est la suivante (voir scr4_str.h) :
typedef struct _obj {
char *obj_ptr; /* Pointer to objet (ISAM or PAGE) */
short obj_fld; /* Field or Index number */
short obj_type; /* Objet type (ISAM, PAGE) */
} OBJ;
Remarquez qu'un OBJ utilise moins de 8 bytes et peut donc être passé par VALEUR aux fonctions. Les appels à SCR_get_text() par exemple demandent un argument de type OBJ et pas (OBJ *).
Il est parfois utile de construire un objet :
OBJ my_obj;
my_obj.obj_ptr = is_client;
my_obj.obj_fld = 2;
my_obj.obj_type = SCR_TYPE_ISAM;
Cet objet pourra être utilisé dans toutes les fonctions employant des OBJ.
Copyright © 1998-2015 Jean-Marc Paul and Bernard PAUL - Envoyez vos remarques ou commentaires à bernard@xon.be