Apprenez par l’exemple!                            Allez! Et ne discutez pas!

 

C’est ce que j’ai toujours fait, et ce que je considère toujours être la meilleure façon d’apprendre un nouveau langage de programmation. Prenez un programme déjà existant et lisez-le. Vous y verrez tout ce qu’il y a à savoir sur la syntaxe, comment indiquer les commentaires, ainsi que plusieurs instructions.

Une fois ces connaissances acquises vous pouvez commencer à programmer vous-même, avec à vos côtés le "DCL Dictionary" ou alors la toujours pratique commande HELP.

Voici donc pour vous un petit exemple de programme. Il fait intentionellement usage de plusieurs "constructs", boucles, sous-routines et autres pour vous donner un aperçu de ce que vous pouvez faire avec DCL. Bien entendu, j'ai choisi d'utiliser des moyens plus compliqués que nécessaires à certains endroits, histoire d'introduire quelques instructions DCL. Je crois qu'il est quand même facile d'identifier où j'ai un peu trop forcé! L'usage des minuscules et majuscules dans le code est un choix personnel.

                             Boooooonsoir! Elle est partie!

 

 

$!------------------------------------------------------------------------------
$! SAMPLE.COM                                        Syltrem                  29-AVR-2001
$!------------------------------------------------------------------------------
$! Cette procédure donnera, pour le répertoire donné en paramètre, le nombre
$! de blocks occupés pour chaque groupe de fichiers d'un type donné.
$! Le type est identifié par l'extension (ex. PROGRAMME.EXE --> le type est EXE)
$! La liste est triée par ordre décroissant du nombre de blocks.
$!------------------------------------------------------------------------------
$ Init:
$    On Control_Y Then Goto Error_Trap
$    On Error Then Goto Error_Trap
$
$    P_Directory = P1
$
$    Say := Write SYS$OUTPUT             ! SYS$OUTPUT = sortie par défaut
$    Define TMP_File     SYS$SCRATCH:SAMPLE.TMP    ! Un fichier de travail
$
$    File_Types = ""    ! Contiendra une liste des types de fichiers rencontrés
$!-------------------------------------------------------------------------------
$ Begin:
$ File_Loop:
$    File = f$search(P1 + "*.*;*")
$    If    File .eqs. ""    -     ! Plus de fichiers; fin de la liste
    Then    Goto Arrange_Data
$
$    File_Type = f$parse(File,,,"type") ! Extraire le type (.EXE, .DAT etc)
$    ! Si le type de ce fichier n'est pas déjà dans notre liste, on l'ajoute
$    ! et on initialise une variable pour cumuler le nombre de blocks.
$    If    f$locate(File_Type, File_Types) .eq. f$length(File_Types) -
     Then    File_Types = File_Types + File_Type
$    File_Type = File_Type - "."            ! Enlever le point (.)
$    If    f$type(Num_Blocks_'File_Type) .eqs. "" -! Symbole n'existe pas
    Then    Num_Blocks_'File_Type = 0         ! initialiser cumulatif
$    Num_Blocks_'File_Type = Num_Blocks_'File_Type         -
            + f$file_attributes(File,"ALQ") ! ALlocation Quantity
$    Goto     File_Loop    ! Passer au fichier suivant
$
$!-------------------------------------------------------------------------------
$ Arrange_Data:
$    Cpt = 1
$    Open/Write TMP TMP_File     ! Ouvrir un fichier de travail
$ Arrange_Data_Loop:
$    File_Type = f$element(Cpt, ".", File_Types)
$    If    File_Type .eqs. "."             - ! Fin de la liste
    Then    Goto Arrange_Data_End
$
$    ! Écrire dans le fichier le nombre de blocks en format 9(8) avec zéros
$    ! non significatifs, suivi du type (Ex.: "00012345DAT")
$    Write TMP f$fao("!8ZL", Num_Blocks_'File_Type), File_Type
$    Cpt = Cpt + 1
$    Goto    Arrange_Data_Loop
$ Arrange_Data_End:
$    Close    TMP
$
$    Call     Sort_TMP_File 1 8 Zoned Descending
$
$!-------------------------------------------------------------------------------
$ Display_Results:
$    Open/Read TMP TMP_File
$
$    Total_Blocks = 0
$
$    Say "Type de fichier Nombre de blocks"
$    Say "--------------- ----------------"
$ Display_Results_Loop:
$    Read/End_of_File=Display_Results_End    TMP TMP_Rec
$    Num_Blocks = f$integer(f$extract(0, 8, TMP_Rec))
$    File_Type = f$extract(8, f$length(TMP_Rec) - 8, TMP_Rec)
$
$    Say f$fao("!15AS !15UL", File_Type, Num_Blocks)
$    Total_Blocks = Total_Blocks + Num_Blocks
$
$    Goto    Display_Results_Loop
$
$ Display_Results_End:
$    Close TMP
$    Say " ----------------"
$    Say f$fao("!15AS !15UL", "Total", Total_Blocks)
$    Goto End_Proc
$
$!-------------------------------------------------------------------------------
$ Sort_TMP_File: SubRoutine
$    Exit_Status = 1                         ! Succès
$    On Error Then Goto Sort_TMP_File_Err
$
$    P_Pos = P1
$    P_Size = P2
$    P_DataType = P3
$    P_Order = P4
$
$    ! On trie notre fichier de travail selon le nombre de blocks descendant.
$    Sort/NoStat     TMP_File TMP_File                 -
        /Key=(Position='P_Pos, Size='P_Size, 'P_DataType, 'P_Order)
$
$    Goto    Sort_TMP_File_End
$
$ Sort_TMP_File_Err:
$    Exit_Status = $STATUS
$    Say "%SAMPLE-E-SORTERR, error in sorting the temp file"
$
$ Sort_TMP_File_End:
$    Exit 'Exit_Status
$    EndSubroutine
$
$!-------------------------------------------------------------------------------
$ Control_Y:
$    Exit_Status = $STATUS
$    Say "%SAMPLE-F-CTRLY, user cancelled execution"
$    Goto End_Proc
$
$ Error_Trap:
$    Exit_Status = $STATUS
$
$ End_Proc:
$    Set NoOn
$    If        f$trn("TMP") .nes. ""                     -
      Then   Close TMP
$    If         f$search("TMP_File:") .nes. ""                 -
      Then   Delete/NoConf/NoLog TMP_File:;*
$    Exit 'Exit_Status

                                                                                                                      On peut m'aider un peu???
Voyons cela plus en détail...

$STATUS Ce symbole est mis à jour à l'exécution de chaque commande. Vous pouvez l'utiliser pour vérifier le résultat (succès ou erreur) et pour signifier ce résultat à une procédure appelante. Voyez la fonction lexicale F$MESSAGE().
Sauvegardez sa valeur si vous comptez l'utiliser dans le futur car elle sera changée à la prochaine instruction que vous ferez exécuter.
Dans la même optique, le système tient aussi à jour le symbole $SEVERITY.
ON CONTROL_Y Que faire si l'utilisateur décide de stopper l'exécution de la procédure. On pourrait aussi empêcher un arrêt par l'utilisateur en employant SET NOCONTROL = Y.
P1..P8 Les paramètres P1 à P8 peuvent êtres données à une procédures.
ON ERROR Que faire en cas d'erreur (on peut déterminer la sévérité des erreurs à contrôler avec ON WARNING, ON SEVERE).
SYS$OUTPUT C'est la sortie par défaut (écran, ou fichier .LOG pour une exécution en lot (batch). C'est là qu'on peut écrire les messages à l'intention de l'utilisateur.
Symbole de commande Un symbole de commande est un genre de raccourci pour une commande fréquemment utilisée.
DEFINE Assignation de nom logique
Étiquette: Communément appelé label. Pour faire des branchements, mais j'ai l'habitude d'en mettre un peu partout pour délimiter les actions et clarifier le code.
F$SEARCH() Fonction lexicale qui retourne les noms des fichiers demandés, un par un. La fin de la liste est indiquée par une chaîne vide.
F$PARSE Fonction lexicale permettant d'extraire les composantes (disque, répertoire, etc) d'une spécification de fichier.
F$LOCATE Fonction lexicale permettant de trouver la position d'une chaîne de caractères dans une autre. Si la valeur retournée égale la longueur de la chaîne de caractères examinée c'est qu'on n'a pas trouvé. Le premier caractère est à la position zéro.
Concaténation et soustraction On peut concaténer des chaînes de caractères en employant le + (addition). De même, on peut retirer des caractères d'une chaîne en employant le - (soustraction).
F$TYPE Fonction lexicale permettant de déterminer si un symbole est défini et de quel type (caractère ou numérique) il est. Les symboles ne sont pas déclarés explicitement, mais dynamiquement la première fois qu'on leur assigne une valeur.
GOTO Il n'y a pas de commande d'itérations. L'utilisation judicieuse de GOTO ne nuit pas à la clarté du code mais est réellement nécessaire.
OPEN On peut lire ou créer des fichiers avec DCL. Même des fichiers indexés.
F$ELEMENT Fonction lexicale permettant d'extraire des éléments d'une liste d'items séparés par un caractère quelconque.
F$FAO Fonction lexicale utilisée pour formatter des données. Ici, une valeur numérique d'une longueur de 8 caractères avec zéros non-significatifs.
CALL Appel d'une sous-routine. Obtenez plus d'informations ici.
SUBROUTINE Utilisation tout à fait superflue ici pour lieu de démonstration. Une sous-routine se comporte exactement comme une autre procédure appelée avec @ et est régie par les mêmes règles (symboles locaux/globaux, etc). En passant, rien n'empêche de mettre une instruction sur la même ligne qu'une étiquette comme je l'ai fait ici.
F$EXTRACT Fonction lexicale utilisée pour extraire des caractères d'une chaîne. Employée ici pour séparer les 2 informations provenant du fichier TMP_File et lues dans le symbole TMP_Rec.
F$INTEGER Fonction lexicale qui converti des caractères (de 0 à 9) en valeur numérique.
SORT On trie notre fichier de travail.
EndSubroutine Marque la fin de la sous-routine. Pas une instruction exécutable en tant que telle mais délimite le code. Tiendra lieu implicitement de la commande EXIT en son absence.
DELETE On fait notre petit ménage. J'utilise toujoure /NOCONFIRM/NOLOG dans les procédures pour m'assurer que peut importe l'environnement de l'utilisateur aucun message ne sera affiché ( Ex. Si DEL*ETE:==DELETE/CONFIRM/LOG dans le
LOGIN.COM de l'utilisateur).
Apostrophe On peut substituer dans une commande la valeur d'un symbole. Apprenez tout à ce sujet ici.
F$FILE_ATTRIBUTES Fonction lexicale utilisée pour obtenir de l'information sur un fichier. Ici, le nombre de blocks qu'il occupe.
EXIT Annonce la fin de la procédure. Optionnellement, on peut terminer avec succès ou en erreur en donnant la valeur de retour appropriée.

                                                                                                Je m'en vais écrire ma 1ère procédure...