Dans tout programme C, les champs des PAGES doivent pouvoir être consultés ou assignés. Le compilateur scr4_e génère à cet effet une série de variables et de #define qui permettent d'accéder aux champs façon très simple et très rapide, tant du point de vue de l'écriture que de celui de la vitesse d'exécution.
Référence aux objets PAGE
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
PAGE pg_print {
BOX 2 CENTER BACK REVERSE
FIELD Prompt "Nom du Fichier à imprimer : " DIR NC 30 NAME FILE
FIELD Prompt "Nombre de copies : " NATURAL NC 3 NAME NB
FIELD Prompt "Printer name : " NAME printer MENU {
Auto
OPTION "lpt1"
OPTION "lpt2"
}
}
on trouvera dans le fichier .c une entrée du type
PAGE *pg_print;
et dans le fichier .h, la déclaration
extern PAGE *pg_print;
De cette façon, on utilisera dans les sources C le même nom que celui de l'objet SCR/AL1. Par exemple :
PG_edit_window(pg_print);
pour éditer la PAGE pg_print.
Références aux champs des PAGES
Pour utiliser les champs des PAGES, 3 méthodes sont possibles :
A chaque champ d'une PAGE est associé un #define dans le fichier .h généré par scr4_e. Ce #define est du type :
#define pg_print_NB (*(double *)(pg_print->pg_rec + 31))
De sorte que pour rechercher le nombre de copies défini dans la PAGE pg_print, il suffit de faire :
nb = pg_print_NB;
De même, pour assigner une valeur à un champ, il suffit d'entrer :
pg_print_NB = 1;
L'assignation a lieu au niveau des champs. La PAGE devra encore être affichée (ou du moins le champ NB), après d'éventuelles autres modifications, par la fonction PG_display() ou PG_display_flds(), pour que les modifications deviennent visibles.
Dans le cas des champs de type caractère (STRING, DIR), 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(pg_print_FILE, "MAKEFILE ", 30);
L'assignation suivante est également valable :
strcpy(pg_print_FILE, "MAKEFILE");
Un caractère NULL se trouvera dans le champ, mais lors de l'affichage, tous les caractères à partir de caractère NULL sont affichés comme blancs.
A l'inverse des ISAM, tous les champs de type caractère sont toujours terminés par un 0 dans la PAGE. Donc l'instruction suivante est tout-à-fait valable et sans risque de dépassement de buffer.
strcpy(buffer, pg_print_FILE);
Les champs peuvent donc être utilisés par des fonctions de gestion de strings terminés par 0 comme strcpy(), printf(), etc.
printf("Fichier : %s. Nombre de copies : %ld\n",
pg_print_FILE, pg_print_NB);
Remarquez que les champs entiers et naturels sont repris comme des LONG dans le record de la PAGE (même s'ils sont hérités d'un champ SHORT d'un ISAM).
Les champs de type MENU sont représentés comme des SHORT dans le record de la PAGE. Ce nombre correspond à l'option sélectionnée dans le MENU.
Ainsi, pour assigner et fixer la valeur d'un champ MENU, il suffit de faire :
pg_print_PRINTER = 1;
print_nb = pg_print_PRINTER;
Les références des tableaux de champs
Lorsque plusieurs champs consécutifs d'une PAGE 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
PAGE pg_cmds {
...
FIELD Prompt "Commande 1 : " STRING NC 40 name cmd1
FIELD Prompt "Commande 2 : " STRING NC 40 name cmd2
FIELD Prompt "Commande 3 : " STRING NC 40 name cmd3
FIELD Prompt "Commande 4 : " STRING NC 40 name cmd4
FIELD Prompt "Commande 5 : " STRING NC 40 name cmd5
...
}
Jusqu'à la version 3.49, les #defines suivants sont générés (les premiers comme décrit plus haut, sauf le tout premier) :
typedef char _T_P1_[31]; /* Seulement pour les champs string */
#define pg_cmds_CMD1 ((_T_P1 *)(pg_ccmds->pg_rec + 0))
#define pg_cmds_CMD2 (pg_ccmds->pg_rec + 31)
#define pg_cmds_CMD3 (pg_ccmds->pg_rec + 62)
#define pg_cmds_CMD4 (pg_ccmds->pg_rec + 93)
#define pg_cmds_CMD5 (pg_ccmds->pg_rec + 124)
L'exécution des commandes de la page pg_cmds peut se faire par conséquent de la façon suivante :
ExecCmds()
{
int i;
for(i = 0 ; i < 5 ; i++)
system(pg_cmds_CMD1[i]);
}
Cette définition est donc différente de ce qui est généré dans le cas des ISAM. Pour cette raison, et pour assurer la cohérence des définitions, les DEFINITIONS SONT MODIFIEES A PARTIR DE LA VERSION 3.50.
A partir de la version 3.50, une version compatible avec les définitions des ISAM est générée par défaut. Pour garder la compatibilité avec les applications existantes, le paramètre -olddef peut être ajouté à scr3_e ou scr4_e.
Attention, dans l'ancienne version, le soit un char *, soit un typedef (char **). Dans la nouvelle, toute ambiguité est levée, mais les anciennes applications doivent être vérifiées, notamment en étant attentif aux warnings générés par le compilateur C.
Dans la nouvelle version, les champs de tous les types peuvent être définis via typedef.
L'exemple précédent se traduit dans la nouvelle version par :
typedef char _T_P1_[31]; /* Seulement pour les champs string */
#define pg_cmds_CMD1 (pg_ccmds->pg_rec + 0)
#define pg_cmds_vCMD1 ((_T_P1 *)(pg_ccmds->pg_rec + 0))
#define pg_cmds_CMD2 (pg_ccmds->pg_rec + 31)
#define pg_cmds_vCMD2 ((_T_P1 *)(pg_ccmds->pg_rec + 31))
#define pg_cmds_CMD3 (pg_ccmds->pg_rec + 62)
#define pg_cmds_vCMD3 ((_T_P1 *)(pg_ccmds->pg_rec + 62))
#define pg_cmds_CMD4 (pg_ccmds->pg_rec + 93)
#define pg_cmds_vCMD4 ((_T_P1 *)(pg_ccmds->pg_rec + 93))
#define pg_cmds_CMD5 (pg_ccmds->pg_rec + 124)
ExecCmds()
{
int i;
for(i = 0 ; i < 5 ; i++)
system(pg_cmds_vCMD1[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 (voir ISAM). 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 :
pg_print_file
Les instructions et fonctions présentées plus haut peuvent être réécrites 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_double() en lieu et place de SCR_get_long() donnera un résultat incorrect non détecté par le compilateur !
La modification d'une valeur est un cas intéressant :
pg_print_NB ++;
est remplacé par
SCR_set_long(pg_print_nb,
SCR_get_long(pg_print_nb) + 1);
ExecCmds()
{
int i;
char buffer[81];
for(i = 0 ; i < 5 ; i++) {
SCR_get_vtext(pg_cmds_cmd1, i, buffer);
system(buffer);
}
}
L'accès du plus bas niveau aux champs des PAGES se fait par les fonctions SCR_set_field_*() et SCR_get_field_*(). Il ne sera utilisé que lorsque les autres méthodes sont inopérantes.
Ces fonctions, décrites dans la librairie scr4a, demandent de connaître le numéro du champ. Elles nécessitent la connaissance du type de champ. Elles offrent l'avantage dans le cas des champs de caractères d'éviter les dépassements de buffers et de compléter les champs par des blancs si le texte input est trop court.
Exemple
long nb = 0;
char buffer[81];
SCR_set_field_long(pg_print, 1, nb);
SCR_get_field_text(pg_cmds, 0, buffer);
...
Copyright © 1998-2015 Jean-Marc Paul and Bernard PAUL - Envoyez vos remarques ou commentaires à bernard@xon.be