Descriptions des modules de Medos-2
Le système d'exploitation Medos-2 était écrit en Modula-2, et les modules utilisés dans ce système faisaient partie intégrante du fonctionnement du système d'exploitation.
Module CardinalIO
Le module CardinalIO permet de lire les nombres octaux à partir du clavier et d'écrire les nombres octaux à l'écran. Le module est utilisé pour écrire des messages d'erreur et à des fins de débogage dans Medos-2 :
Voici les explications des procédures :
ReadOct(c)
La procédure ReadOct lit en octal un nombre cardinal c. Le caractère de fin (ESC, EOL et espace) n'est pas lu.
WriteOct(c)
La procédure WriteOct écrit en octal le nombre cardinal c. Le format du nombre écrit est un espace suivi de six chiffres octaux.
Module DefaultFont
Le module DefaultFont contient la police de caractères par défaut, la police de caractères utilisée par le module DisplayDriver pour écrire du texte à l'écran.
Remarque : ce module ne doit être utilisé que par le module DisplayDriver.
Voici les explications de ce module :
La variable defaultFont est l'adresse de la police par défaut divisée par quatre.
Module DiskSystem
Le module DiskSystem entrepose les fichiers sur des cartouches de 10 Mo pour le lecteur de disque Honeywell Bull D120/D140. Neuf fichiers sont préalloués.
Voici la définition du module DiskSystem :
- DEFINITION MODULE DiskSystem; (* Medos-2 Sv.E. Knudsen 25.09.80 *)
-
- FROM FileSystem IMPORT File,Response;
-
- EXPORT QUALIFIED
- InitVolume,OpenVolume,CloseVolume,FileDesc,FDKind,nofile,father,son,FileNumber,Position,Minute,Page,
- FreePages,ReadFileDesc,WriteFileDesc,Name,ExternalName,NameKind,free,fname,ReadName,WriteName;
-
- CONST
- nofile=0; father=1; son=2;
- maxfiller=27;
- modifyprot=100000B;
- sons=16;
- pagetablength=96;
-
- free=0; fname=1;
- enlength=24;
-
- TYPE
- FileNumber=CARDINAL;
- FDKind=CARDINAL; (* nofile, father, son *)
- Position=RECORD
- block:CARDINAL; (* des secteurs entiers *)
- byte:CARDINAL;
- END;
- Minute =RECORD
- day:CARDINAL; (* codé comme Time dans Monitor *)
- minute:CARDINAL;
- END;
- Page=CARDINAL;
-
- FileDesc=RECORD
- reserved:CARDINAL;
- filno:FileNumber;
- versno:CARDINAL;
- CASE fdt:FDKind OF
- nofile:
- filler:ARRAY[0..maxfiller] OF CARDINAL |
- father:
- length:Position;
- modification:CARDINAL;
- referenced:CARDINAL; (* référencé si différent de 0 *)
- protection:CARDINAL; (* protégé si différent de 0 *)
- ctime:Minute; (* temps de création *)
- mtime:Minute; (* dernière modification *)
- fres:ARRAY[0..3] OF CARDINAL;
- sontab:ARRAY[1..sons-1] OF FileNumber; |
- son:
- fatherfile:FileNumber;
- fathervers:CARDINAL;
- sonno:CARDINAL;
- END;
- pagetab:ARRAY [0..pagetablength-1] OF Page;
- END; (* FileDesc *)
-
- NameKind=CARDINAL; (* free, fname *)
- ExternalName=ARRAY[0..enlength-1] OF CHAR;
- Name=RECORD
- en:ExternalName;
- CASE nk: NameKind OF
- free: |
- fname:
- fno:CARDINAL; (* Numéro de fichier *)
- vno:CARDINAL; (* Numéro de version *)
- fres:CARDINAL;(* réservé (mis à zéro) *)
- END
- END;
-
- PROCEDURE InitVolume(VAR r:Response);
- PROCEDURE OpenVolume(VAR r:Response);
- PROCEDURE CloseVolume(VAR r:Response);
- PROCEDURE FreePages():CARDINAL;
- PROCEDURE ReadFileDesc(no:FileNumber;VAR fd:FileDesc;VAR r:Response);
- PROCEDURE WriteFileDesc(no:FileNumber;VAR fd:FileDesc;VAR r:Response);
- PROCEDURE ReadName(no:FileNumber;VAR n:Name;VAR r:Response);
- PROCEDURE WriteName(no:FileNumber;n:Name;VAR r:Response);
-
- END DiskSystem.
Voici l'explication des procédures :
InitVolume(res)
La procédure InitVolume initialise le disque monté, c'est-à-dire que les neuf fichiers système préalloués sont initialisés sur le disque. Attention : L'initialisation d'un disque détruit tous les fichiers y étant précédemment entreposés. Un disque ne peut être initialisé que s'il n'est pas ouvert pour des accès ordinaires aux fichiers.
res = done si le support est initialisé,
res = notdone si le module DiskSystem est ouvert pour les accès aux fichiers,
res = ... si une autre erreur s'est produite.
OpenVolume(res)
La procédure OpenVolume rend le module DiskSystem prêt pour les accès au disque monté.
res = done si le support est ouvert,
res = notdone si le module DiskSystem est ouvert pour les accès aux fichiers,
res = ... si une autre erreur s'est produite.
CloseVolume(res)
La procédure CloseVolume ferme le module DiskSystem pour les accès aux fichiers. CloseVolume ne peut être appelé qu'à partir du niveau de programme à partir duquel il a été ouvert précédemment. Le module DiskSystem ne peut pas être fermé si un fichier à côté des fichiers du répertoire est ouvert.
res = done si le support est fermé,
res = notdone si le module DiskSystem n'a pas pu être fermé
FreePages(): CARDINAL
La fonction FreePages renvoie le nombre de pages encore libres sur le disque monté.
ReadFileDesc(filenr, filedesc, res)
La procédure ReadFileDesc lit le descripteur de fichier du fichier filenr et le renvoie dans la variable filedesc. res indique le succès de l'opération.
res = done si le descripteur de fichier a été lu,
res = ... si une erreur s'est produite.
WriteFileDescdilenr, filedesc, res)
La procédure WriteFileDesc écrit filedesc comme descripteur de fichier du fichier filenr. res indique la réussite de l'opération.
res = done si le descripteur de fichier a été écrit,
res = ... si une erreur s'est produite.
ReadName(filenr, name, res)
La procédure ReadName lit le descripteur de nom du fichier filenr et le renvoie dans la variable nom, res indique le succès de l'opération.
res = done si le descripteur de nom a été lu,
res = ... si une erreur s'est produite.
WriteName(filenr, name, res);
La procédure WriteName écrit le descripteur de nom nom du fichier filenr. res indique le succès de l'opération.
res = done si le descripteur de nom a été écrit,
res = ... si une erreur s'est produite.
Principales caractéristiques et restrictions
Les modules DiskSystem et D140Disk implémentent des fichiers sur des cartouches pour les lecteurs de disque Honeywell Bull D120/D140. Les principales caractéristiques de l'implémentation actuelle sont répertoriées ci-dessous :
Description | Caractéristiques |
---|---|
Nombre maximal de fichiers | 768/cartouche |
Longueur maximale du fichier | 192 Ko |
Capacité de la cartouche | 9408 Ko |
Débits de transfert typiques | 3 à 30 Ko/s |
Débit de transfert minimal | < 10 octets/s |
Débit de transfert maximal | > 50 Ko/s |
Longueur du nom de fichier local | 1 à 24 caractères |
Nombre maximal de fichiers ouverts | 14 (16) |
Nom du support | "DK" |
Identification du support interne | ("DK", 65535) |
Chaque fichier réel ne peut être connecté qu'à une seule variable de fichier à la fois. Tant qu'un seul programme est exécuté sur la machine, cela devrait être acceptable, car il s'agit plus d'une aide que d'une restriction.
Les taux de transfert dépendent principalement du nombre de mouvements de la tête de disque nécessaires au transfert réel. Le positionnement d'un fichier pour chaque transfert d'un ou de quelques octets peut réduire le taux de transfert à quelques octets par seconde. D'autre part, les transferts séquentiels d'éléments plus volumineux (>= 16 octets/élément) sont effectués avec le taux de transfert maximal (50 à 60 koctets/s).
En fait, 16 fichiers peuvent être connectés en même temps. Le module DiskSystem utilise deux d'entre eux en interne pour accéder aux deux répertoires de la cartouche. Les 14 fichiers restants peuvent être utilisés librement par des programmes ordinaires.
La version actuelle du module DiskSystem ne fait pas de distinction entre les cartouches. Toutes les cartouches reçoivent simplement la même identification de support interne ("DK", 65535).
Fichiers système
L'espace sur une cartouche est alloué aux fichiers réels en pages de 2 Ko chacune (ou 8 secteurs). Les pages appartenant à un fichier ainsi que sa longueur et d'autres informations sont stockées dans un descripteur de fichier, lui-même entreposé dans un fichier sur la cartouche (répertoire de fichiers). Les noms de fichiers locaux de tous les fichiers d'une cartouche sont entreposés dans un autre fichier sur la cartouche (répertoire de noms). Lorsqu'une cartouche est initialisée, neuf fichiers (système) sont alloués sur la cartouche. Ces fichiers préalloués ne peuvent pas être tronqués ou supprimés. À l'exception des deux fichiers de répertoire et du fichier contenant les secteurs défectueux de la cartouche, tous les fichiers peuvent être lus et écrits (modifiés). Les fichiers préalloués sont :
Fichier | Description |
---|---|
FS.FileDirectory | Fichier avec répertoire de fichiers |
FS.FileDirectory.Back | Sauvegarde du répertoire de fichiers (non implémenté) |
FS.NameDirectory | Fichier avec nom répertoire |
FS.NameDirectory.Back | Sauvegarde du fichier avec le nom du répertoire (non implémenté) |
FS.BadPages | Fichier avec des secteurs inutilisables |
PC.BootFile | Fichier de démarrage normal |
PC.BootFile.Back | Fichier de démarrage alternatif |
PC.DumpFile | Fichier contenant un vidage de la mémoire principale (0..64k-1) |
PC.Dump1File | Fichier contenant un vidage de la mémoire principale (64k..128k-1) |
Gestion des erreurs
Normalement, toutes les erreurs détectées sont traitées en attribuant une réponse indiquant l'erreur au champ res dans la variable de fichier. Chaque fois qu'une erreur détectée ne peut pas être liée à un fichier ou si une erreur plus grave est détectée, un message d'erreur est écrit sur l'écran. Cela se fait selon le format suivant :
- DiskSystem. procedure name : error indicating text |
procedure name est le nom de la procédure dans le module où l'erreur a été détectée. Dans les explications des messages, les termes suivants sont utilisés pour les valeurs insérées :
Message | Valeur | Description |
---|---|---|
page number | nombre octal (0..137B) | Page dans un fichier affecté |
page | nombre octal (0..167340B) | Adresse du disque de la page DIV 8*13 |
file number | nombre octal (0.. 1377B) | Numéro du fichier concerné |
local file name | chaîne de caractères (1..24) | Nom du fichier local du fichier affecté |
response | chaîne de caractères | Texte décrivant la réponse |
statusbits | nombre octal (177400..177777B) | État de l'interface du disque |
disk address | nombre octal (0.. 111377B) | Adresse « logique » du secteur sur le disque |
Si certains des messages d'erreur suivants s'affichent, veuillez consulter la description du programme DiskCheck !
- DiskSystem.PutBuf: bad page: pageno = page number fno = file number |
La page indique une adresse de disque étant allouée à un «fichier système», mais le fichier n'est pas un «fichier système», ou la page indique une adresse de disque pour des fichiers normaux, mais le fichier est un «fichier système».
- DiskSystem.GetBuf: bad buffering while reading ahead |
L'adresse du disque d'un certain secteur alloué n'a pas été trouvée.
- DiskSystem.FileCommand: bad directory entry: fno = file number read |
Une incohérence dans le répertoire de fichiers a été détectée.
- DiskSystem.OpenVolume: bad page pointer: fno = file number pageno = page number page = page |
Une incohérence dans le répertoire de fichiers a été détectée lors de l'initialisation de Medos-2.
- DiskSystem.(ReadName, WriteName or SearchName): bad file number in file name = local file name found fno = file number, expected fno = file number |
Une incohérence dans le nom du répertoire a été détectée.
Avertissement : Il faut mentionner ici que l'une des meilleures façons d'obtenir certains de ces messages d'erreur à l'écran est celle-ci : éteignez le lecteur pendant qu'un programme «inoffensif» est en cours d'exécution, remplacez la cartouche dans le lecteur et rallumez le lecteur. Un échange de cartouche n'est tout simplement pas détecté par le module DiskSystem n'initialisant donc pas ses informations locales sur la cartouche montée à partir de la nouvelle cartouche.
Module DisplayDriver
Le module DisplayDriver est l'interface de plus bas niveau pour l'affichage de numérisation raster. Il fournit en fait une interface vers quatre sujets différents, à savoir :
- Le matériel d'affichage
- la police par défaut
- le bitmap par défaut et
- la procédure d'écriture standard.
Remarque : ce module ne doit être utilisé qu'avec Medos-2 et les modules de bibliothèque.
- DEFINITION MODULE DisplayDriver; (* Medos-2 V4 N. Wirth 10.6.82 *)
-
- EXPORT QUALIFIED
- BMDescriptor,ScreenWidth,ScreenHeight,Show,BuildBMD,DFF,CharWidth,LineHeight,
- BMD,BMF,MapHeight,ChangeBitmap,Write;
-
- TYPE
- BMDescriptor=RECORD
- f,w,h,z:CARDINAL
- END;
-
- PROCEDURE ScreenWidth(): CARDINAL;
- PROCEDURE ScreenHeight(): CARDINAL;
- PROCEDURE Show(VAR bmd:BMDescriptor; on:BOOLEAN);
- PROCEDURE BuildBMD(fp,width,height:CARDINAL;VAR bmd:BMDescriptor);
- PROCEDURE DFF():CARDINAL;
- PROCEDURE CharWidth():CARDINAL;
- PROCEDURE LineHeight():CARDINAL;
-
- VAR
- BM:BMDescriptor;
-
- PROCEDURE BMF():CARDINAL;
- PROCEDURE MapHeight():CARDINAL;
- PROCEDURE ChangeBitmap(height:CARDINAL;VAR done:BOOLEAN);
- PROCEDURE Write(ch: CHAR);
-
- END DisplayDriver.
Voici les explications des procédures :
ScreenWidth():CARDINAL
La fonction ScreenWidth renvoie la largeur de l'écran connecté en nombre de points.
ScreenHeight():CARDINAL
La fonction ScreenHeight renvoie la hauteur de l'écran connecté en nombre de lignes (pointées).
Show(bmd,on)
La procédure Show initialise l'interface d'affichage de telle sorte qu'elle affiche le bitmap décrit par le descripteur de bitmap bmd. Si la valeur booléenne on est TRUE, le bitmap est effectivement affiché sur l'écran.
BuildBMD(fp, width, height, bmd)
La procédure BuildBMD initialise le descripteur de bitmap bmd de telle sorte qu'il décrive une bitmap dans la trame fp avec des lignes de points de hauteur chacune avec des lignes de hauteur.
DFF():CARDINAL
La fonction DFF renvoie le pointeur de cadre pointant vers la police de caractères par défaut, c'est-à-dire son adresse divisée par quatre.
CharWidth():CARDINAL
La fonction CharWidth renvoie la largeur des points des caractères dans la police de caractères par défaut.
LineHeight():CARDINAL
La fonction LineHeight renvoie la hauteur du point d'une ligne de texte écrite avec la police de caractères par défaut.
BMD
La variable BMD est le descripteur bitmap du bitmap par défaut.
BMF():CARDINAL
La fonction BMF renvoie le pointeur de trame pointant vers le bitmap par défaut, c'est-à-dire son adresse divisée par quatre.
MapHeight():CARDINAL
La fonction MapHeight renvoie la hauteur du point du bitmap par défaut.
ChangeBitmap(height, done)
La procédure ChangeBitmap modifie la hauteur du bitmap par défaut en points de hauteur. Si la modification a été effectuée, done est défini sur TRUE.
Write(ch)
La procédure Write écrit le caractère ch sur le bitmap par défaut avec la valeur par défaut à la position d'écriture actuelle. La position d'écriture actuelle est modifiée par des appels à la procédure Write et ChangeBitmap. Les caractères de contrôle suivants sont interprétés :
Valeur | Nom | Description |
---|---|---|
10C | BS | Retour arrière d'un caractère |
12C | LF | Ligne suivante, même position x |
14C | FF | Efface la page |
15C | CR | Retour au début de la ligne |
30C | CAN | Efface la ligne |
36C | EOL | Ligne suivante |
177C | DEL | Revenir en arrière d'un caractère et l'effacer |
Restrictions d'implémentation
- Show ne prend en charge que deux bitmaps différents, à savoir le bitmap par défaut et un bitmap défini par l'utilisateur.
- BuildBMD : la hauteur ne peut pas être 0 ou 1 ; la largeur doit être divisible par 16.
- ChangeBitmap : la hauteur doit être paire.
Gestion des erreurs
HALT est appelé si BuildBMD est appelé avec une hauteur inférieure à 2. Aucun message n'est écrit.
Module D140Disk
Le module D140Disk est un pilote pour le lecteur de disquette Honeywell-Bull D120/D140. Le pilote est principalement destiné à être utilisé à partir du module DiskSystem, le module implémentant les fichiers sur ce type de support.
- DEFINITION MODULE D140Disk; (* Medos-2 V4 Sv.E. Knudsen 27.05.82 *)
-
- FROM SYSTEM IMPORT WORD;
- FROM FileSystem IMPORT Response;
-
- EXPORT QUALIFIED
- drives, tracks, sectors, sectorsize,
- DiskReset, DiskStatus, DiskRead, DiskWrite;
-
- CONST
- drives=2;
- tracks=784;
- sectors=48;
- sectorsize=128;
-
- PROCEDURE DiskReset;
- PROCEDURE DiskStatus():Response;
- PROCEDURE DiskRead(drive,diskadr:CARDINAL;VAR buffer:ARRAY OF WORD;VAR res:Response);
- PROCEDURE DiskWrite(drive,diskadr:CARDINAL;VAR buffer:ARRAY OF WORD;VAR res:Response);
-
- END D140Disk.
Voici les explications des procédures :
DiskReset
La procédure DiskReset réinitialise l'interface du disque et l'unité de disque connecté. Les têtes sont alors positionnées sur les pistes du cylindre zéro.
DiskStatus()
La fonction DiskStatus renvoie l'état actuel de l'unité de disque. Les résultats possibles (de type Response) sont répertoriés ci-dessous.
DiskRead(drive, diskaddr, buffer, res)
La procédure DiskRead lit le secteur diskaddr du disque dans l'unité de disque drive dans le tampon buffer. Le tampon doit avoir une longueur de 128 mots. Le paramètre de résultat res est effectué si l'opération a été exécutée normalement. D'autres valeurs possibles de res sont répertoriées ci-dessous.
DiskWrite(drive, diskadr, buffer, res)
La procédure DiskWrite écrit le tampon tampon dans le secteur diskaddr du disque dans l'unité de disque drive. Le tampon doit avoir une longueur de 128 mots. Le paramètre de résultat res est terminé si l'opération a été exécutée normalement. D'autres valeurs possibles de res sont répertoriées ci-dessous.
Valeurs possibles pour le paramètre drive :
- L'unité de disque D120 ignore le paramètre drive.
- L'unité de disque D140 possède un disque dur et un emplacement pour un disque amovible. L'unité de disque zéro est l'unité de disque pour le pack de disques amovibles, l'unité de disque est l'unité de disque avec le disque dur.
Valeurs possibles de la fonction DiskStatus et du paramètre res :
Valeur | Description |
---|---|
done | L'unité de disque est prêt |
notdone | L'unité de disque n'est pas prêt |
harderror | Accès à un secteur non valide |
hardprotected | Le pack consulté est protégé en écriture (écriture sur disque uniquement) |
hardparityerror | Une erreur CRC a été détectée (DiskRead uniquement) |
timeout | Le secteur adressé n'a pas été trouvé. |
harderror | Un autre type d'erreur détecté par l'unité de disque. |
softerror | Adresse du disque >= 37632 |
Notes de mise en oeuvre
L'adresse de disque d'un secteur [0..37631] est cartographiée sur une adresse de disque physique (cylindre, surface, secteur) par un algorithme similaire à celui-ci :
- cylinder:=diskadr DIV (2 * sectors); (* 2 surfaces *)
- surface:=diskadr DIV sectors MOD 2;
- sector:=diskadr MOD sectors;
- IF cylinder < 15 THEN
- sector:=3 * sector (* démarrage et vidage des cylindres *)
- ELSE
- sector:=12 * sector (* cylindres pour fichiers normales *)
- END;
- sector:=sector MOD sectors + sector DIV sectors
Gestion des erreurs
Normalement, toutes les erreurs détectées sont traitées en attribuant une réponse indiquant une erreur au paramètre res. Chaque fois qu'une erreur plus grave est détectée, l'un des messages d'erreur suivants est écrit.
- D140Disk: soft timeout in wait |
Une opération sur le disque a été interrompue par le logiciel. Cette erreur se produit principalement lorsque le disque est éteint pendant qu'une opération sur le disque est en cours.
- D140Disk.DiskRead: response diskadr = disk address, statusbits = statusbits |
Le pilote a détecté une erreur, n'ayant pas disparu après trois tentatives.
- D140Disk.DiskWrite: response - diskadr = disk address, statusbits = statusbit |
Le pilote de disque a détecté une erreur, n'ayant pas disparu après trois tentatives.
Dans les explications des messages, les termes suivants sont utilisés pour les valeurs insérées :
Message | Valeur | Description |
---|---|---|
response | Chaîne de caractères | Texte décrivant la réponse |
statusbits | Nombre octal (177400.. 177777B) | État de l'interface du disque |
disk address | Nombre octal (0.. 111377B) | Adresse du disque d'un secteur |
Les 8 bits d'état les moins significatifs ont les significations suivantes lorsqu'ils sont inclus :
Valeur | Description |
---|---|
001B | Secteur non valide rencontré. |
002B | Défaut de l'unité de disque. |
004B | L'unité de disque est prêt pour l'opération de recherche. |
010B | Opération d'écriture tentée, mais le pack est protégé en écriture. |
020B | Dépassement de délai |
040B | Erreur CRC |
100B | Transfert de données terminé |
200B | Unité de disque prêt pour une opération de recherche, de lecture ou d'écriture. |
Module FileMessage
Le module FileMessage permet d'écrire des messages d'erreur dans le système de fichiers.
Voici les explications des procédures :
WriteResponse(r)
La procédure WriteResponse écrit un texte correspondant à la réponse res sur le terminal.
Gestion des erreurs
Si le paramètre res de WriteResponse n'est pas une réponse valide, la valeur ordinale du paramètre est écrite au format octal.
Module FileSystem
Un fichier (Medos-2) est une séquence d'octets entreposée sur un certain support. Le module FileSystem est l'interface que le programmeur normal doit connaître pour utiliser les fichiers. Le système de fichiers prend en charge plusieurs implémentations de fichiers. Au moment de l'exécution, un programme peut déclarer qu'il implémente des fichiers sur un certain support nommé. Voici la définition du module FileSystem :
- DEFINITION MODULE FileSystem; (* Medos-2 Sv.E. Knudsen 1.6.81 *)
-
- FROM SYSTEM IMPORT ADDRESS, WORD;
-
- EXPORT QUALIFIED
- File, Response, Create,Close, Lookup, Rename, ReadWord, WriteWord, ReadChar, WriteChar, Reset, Again,
- SetPos, GetPos, Length, Command, MediumType, FileCommand, DirectoryCommand, Flag, FlagSet, SetRead,
- SetWrite, SetModify, SetOpen, Doio, FileProc, DirectoryProc, CreateMedium, RemoveMedium;
-
- TYPE
- MediumType=ARRAY [0..1] OF CHAR;
- MediumHint;
- Flag=(er, ef, rd, wr, ag, bytemode);
- FlagSet = SET OF Flag;
- Response=(done, notdone, notsupported, callerror, unknownmedium, unknownfile, paramerror,
- toomanyfiles, eom, deviceoff, softparityerror, softprotected, softerror, hardparityerror,
- hardprotected, timeout, harderror);
- Command = (create, open, close, lookup, rename, setread, setwrite, setmodify, setopen, doio,
- setpos, getpos, length, setprotect, getprotect, setpermanent, getpermanent, get internal);
-
- File=RECORD
- bufa:ADDRESS;
- ela:ADDRESS; elodd:BOOLEAN;
- ina:ADDRESS; inodd:BOOLEAN;
- topa:ADDRESS;
- flags:FlagSet;
- eof:BOOLEAN;
- res:Response;
- CASE com:Command OF
- create,open,getinternal:
- fileno,versionno:CARDINAL
- | lookup: new:BOOLEAN
- | setpos,getpos,length:
- highpos,lowpos:CARDINAL
- | setprotect,getprotect:wrprotect:BOOLEAN
- | setpermanent,getpermanent: on:BOOLEAN
- END;
- mt:MediumType;mediumno:CARDINAL;
- mh:MediumHint;
- submedium:ADDRESS;
- END;
-
- PROCEDURE Create(VAR f:File; mediumname:ARRAY OF CHAR);
- PROCEDURE Close(VAR f:File);
- PROCEDURE Lookup(VAR f:File; filename:ARRAY OF CHAR;new:BOOLEAN);
- PROCEDURE Rename(VAR f:File; filename:ARRAY OF CHAR);
- PROCEDURE ReadWord(VAR f:File; VAR w: WORD);
- PROCEDURE WriteWord(VAR f:File; w: WORD);
- PROCEDURE ReadChar(VAR f:File; VAR ch: CHAR);
- PROCEDURE WriteChar(VAR f:File; ch: CHAR);
- PROCEDURE Reset(VAR f:File);
- PROCEDURE Again(VAR f:File);
- PROCEDURE SetPos(VAR f:File; highpos, lowpos: CARDINAL);
- PROCEDURE GetPos(VAR f:File; VAR highpos, lowpos: CARDINAL);
- PROCEDURE Length(VAR f:File; VAR highpos, lowpos: CARDINAL);
- PROCEDURE FileCommand(VAR f:File);
- PROCEDURE DirectoryCommand(VAR f:File; filename:ARRAY OF CHAR);
- PROCEDURE SetRead(VAR f:File);
- PROCEDURE SetWrite(VAR f:File);
- PROCEDURE SetModify(VAR f:File);
- PROCEDURE SetOpen(VAR f:File);
- PROCEDURE Doio(VAR f:File);
-
- TYPE
- FileProc=PROCEDURE (VAR File);
- DirectoryProc=PROCEDURE(VAR File:ARRAY OF CHAR);
-
- PROCEDURE CreateMedium(mt:MediumType; mediumno:CARDINAL;fp:FileProc; dp:DirectoryProc;VAR done:BOOLEAN);
- PROCEDURE RemoveMedium(mt:MediumType; mediumno:CARDINAL;VAR done: BOOLEAN);
-
- END FileSystem.
Utilisation simple des fichiers :
Ouverture, fermeture et changement de nom des fichiers
Un fichier est soit permanent, soit temporaire. Un fichier permanent reste entreposé sur son support après sa fermeture et porte normalement un nom externe (ou symbolique). Un fichier temporaire est supprimé du support dès qu'il n'est plus référencé par un programme et il est normalement sans nom. Dans un programme, un fichier est référencé par une variable de type File. Du point de vue du programmeur, la variable de type File est simplement le fichier. Plusieurs routines connectent une variable de fichier à un fichier réel (par exemple sur un disque). Le fichier réel doit être créé sur un support nommé ou recherché par son nom de fichier. La syntaxe du nom de support et du nom de fichier est la suivante :
medium name = [ identifier ] . identifier = letter { letter | digit } . file name = medium name [ "." local name ] . local name = identifier { "." identifier } . |
Les majuscules et les minuscules sont traitées différemment. Le nom du support est le nom du support sur lequel un fichier est (censé être) entreposé. Le nom local est le nom du fichier sur un support spécifique. Le dernier (et peut-être le seul) identificateur dans un nom de fichier local est souvent appelé extension de nom de fichier ou simplement extension. Le système de fichiers ne traite cependant pas les extensions de nom de fichier d'une manière particulière. De nombreux programmes et utilisateurs utilisent les extensions pour classer les fichiers en fonction de leur contenu et traitent les extensions d'une manière spéciale (par exemple, en supposant des valeurs par défaut, en les modifiant automatiquement,...).
DK.SYS.directory.OBJ |
Nom du fichier SYS.directory.OBJ sur support DK. Son extension est OBJ.
Create(f,mediumname)
La procédure Create crée un nouveau fichier temporaire (et sans nom) sur le support donné. Après l'appel :
f.res = done si le fichier f est créé,
f.res = ... si une erreur s'est produite.
Close(f)
La procédure Close met fin à toute opération d'entrée ou de sortie réelle sur le fichier f et déconnecte la variable f du fichier réel. Si le fichier réel est temporaire, Close supprime également le fichier.
Lookup(f, filename, new)
La procédure Lookup recherche le fichier réel avec le nom de fichier donné. Si le fichier existe, il est connecté à f(opened). Si le fichier demandé n'est pas trouvé et que new est TRUE, un fichier permanent est créé avec le nom donné. Après l'appel f.res = done si le fichier f est connecté.
f.res = notdone si le fichier nommé n'existe pas,
f.res = ... si une erreur s'est produite.
Si le fichier f est connecté, le champ f.new indique :
f.new = FALSE Le fichier f existe déjà
f.new = TRUE Le fichier f a été créé par cet appel
Rename(f, filename)
La procédure Rename modifie le nom du fichier f en filename. Si filename est vide ou ne contient que le nom du support, f est modifié en un fichier temporaire et sans nom. Si filename contient un nom local, le fichier réel sera permanent après un appel réussi de Rename. Après l'appel :
f.res = done si le fichier f est renommé,
f.res = notdone si un fichier avec filename existe déjà,
f.res = ... si une erreur s'est produite.
Lecture et écriture de fichiers
A ce niveau de programmation, nous considérons qu'un fichier est soit une séquence de caractères (fichier texte) soit une séquence de mots (fichier binaire), bien que cela ne soit pas imposé par le système de fichiers. La première routine appelée provoquant une entrée ou une sortie sur un fichier (c'est-à-dire ReadChar, WriteChar, ReadWord, WriteWord) détermine si le fichier doit être considéré comme un fichier texte ou binaire.
Les caractères lus et écrits dans un fichier texte proviennent de l'ensemble ASCII. Les lignes sont terminées par le caractère 36C (= eol, RS).
Reset(f)
La procédure de réinitialisation met fin à toute entrée ou sortie réelle et définit la position actuelle du fichier f au début de f.
WriteChar(f, ch), WriteWord(f, w)
La procédure WriteChar(WriteWord) ajoute le caractère ch (mot w) au fichier f.
ReadChar(f, ch), ReadWord(f, w)
La procédure ReadChar(ReadWord) lit le caractère (mot) suivant du fichier f et l'affecte à ch (w). Si ReadChar a été appelé sans succès, OC est affecté à ch. f.eof implique ch = OC. L'inverse, cependant, n'est pas vrai : ch = OC n'implique pas f.eof. Après l'appel :
f.eof = FALSE ch (w) a été lu
f.eof = TRUE L'opération de lecture n'a pas réussi
Si f.eof est TRUE :
f.res = done La fin du fichier a été atteinte
f.res = ... Une erreur s'est produite
Again(f)
Un appel à la procédure Again empêche un appel suivant à la procédure ReadChar(ReadWord) de lire le caractère (mot) suivant sur le fichier f. Au lieu de cela, le caractère (mot) lu juste avant l'appel à Again sera relu.
Note d'implémentation
Les versions actuelles des routines ReadWord et WriteWord ne prennent pas en charge la lecture et l'écriture de mots à des positions impaires.
Positionnement des fichiers
Toutes les routines d'entrée et de sortie fonctionnent à la position actuelle d'un fichier. Après un appel à Lookup, Create ou Reset, la position actuelle d'un fichier est à son début. La plupart des routines opérant sur un fichier modifient la position actuelle du fichier dans le cadre normal de leur action. Les positions sont codées en cardinaux longs et un fichier est positionné à son début si sa position actuelle est égale à zéro. Chaque appel à une procédure, lisant ou écrivant un caractère (un mot) sur un fichier, incrémentant la position actuelle du fichier de 1 (2) pour chaque caractère (mot) transféré. Un caractère (mot) est entreposé dans 1 (2) octet sur un fichier et la position de l'élément est le numéro du (premier) octet contenant l'élément. À l'aide des procédures GetPos, Length et SetPos, il est possible d'obtenir la position actuelle d'un fichier, la position juste derrière le dernier élément du fichier et de modifier explicitement la position actuelle d'un fichier.
SetPos(f, highpos, lowpos)
Un appel à la procédure SetPos définit la position actuelle du fichier f à highpos * 2**16 + lowpos. La nouvelle position doit être inférieure ou égale à la longueur du fichier. Si la dernière opération avant l'appel de SetPos était une opération d'écriture (c'est-à-dire si le fichier f est en état d'écriture), le fichier est coupé à sa nouvelle position actuelle et les éléments de la position actuelle à la fin du fichier sont perdus.
GetPos(f, highpos, lowpos)
La procédure GetPos renvoie la position actuelle du fichier. Elle est égale à highpos * 2**16 + lowpos.
Length(f, highpos, lowpos)
La procédure Length récupère la position juste derrière le dernier élément du fichier (c'est-à-dire le nombre d'octets entreposés dans le fichier). La position est égale à highpos * 2**16 + lowpos.
Exemples d'écriture d'un fichier texte :
- VAR
- f:File;
- ch:CHAR;
- endoftext:BOOLEAN;
-
- (* .. *)
-
- Lookup(f, "DK.newfile", TRUE);
- IF(f.res <> done) OR NOT f.new THEN
- (* f n'a pas été créé par cet appel à « Lookup » *)
- IF f.res = done THEN Close(f) END
- ELSE
- LOOP
- (* trouver le prochain caractère à écrire -> fin du texte, ch *)
- IF endoftext THEN EXIT END;
- WriteChar(f, ch)
- END;
- Close(f)
- END
Pour lire un fichier texte :
Voici l'utilisation avancée des fichiers :
Les procédures FileCommand et DirectoryCommand
Dans les sections précédentes, la variable file servait, à quelques exceptions près, simplement de référence à un fichier. Les exceptions étaient les champs eof, res et new dans une variable file. En général, cependant, toutes les opérations sur un fichier sont implémentées soit en inspectant ou en modifiant directement les champs dans la variable file et/ou en codant l'opération (commande) nécessaire dans la variable file suivie d'un appel à la routine FileCommand ou DirectoryCommand. Les commandes nécessitant (une partie de) un nom de fichier comme paramètre sont exécutées par DirectoryCommand, toutes les autres par FileCommand. Une implémentation de SetPos et Lookup devrait illustrer cela :
Les commandes lookup et rename doivent être exécutées par DirectoryCommand, les autres commandes peuvent être exécutées soit par FileCommand, soit par DirectoryCommand. À moins que la commande ne soit lookup ou rename, un appel à DirectoryCommand sera converti par le système de fichiers en un appel à FileCommand. Cette fonction n'est utile que pour les commandes create et open.
Vous trouverez ci-dessous une liste de toutes les commandes où chacune est expliquée :
Commande | Description |
---|---|
create | Créer un nouveau fichier temporaire (et sans nom) |
open | Ouvrir un fichier existant par IFI |
close | Fermer un fichier |
lookup | Rechercher (ou créer) un fichier par nom de fichier |
rename | Renommer un fichier |
setread | Mettre un fichier en état de lecture |
setwrite | Définir un fichier dans l'état d'écriture |
setmodify | Mettre un fichier en état de modification |
setopen | Mettre un fichier dans l'état ouvert |
doio | Demande le prochain tampon |
setpos | Changer la position actuelle du fichier |
gefpos | Demande la position actuelle du fichier |
length | Demande la longueur du fichier |
setprotect | Modifier la protection du fichier |
getprotect | Demande la protection actuelle du fichier |
setpermanent | Modifier la permanence du fichier |
getpermanent | Demande la permanence du fichier |
getinternal | Demande le LFI du fichier |
Après l'exécution d'une commande, le champ res du fichier reflète le succès de l'opération. D'autres champs de la variable fichier peuvent cependant contenir des valeurs de retour supplémentaires, en fonction de la commande exécutée et de l'état du fichier. Ici, la manière normale de définir les champs avant un retour de la procédure FileCommand est donnée :
- WITH f DO
- (* définir d'autres champs *)
- res := "...";
- flags := flags - FlagSet(er, ef, rd, wr);
- IF "state = opened" THEN
- bufa := NIL; (* aucun tampon assigné *)
- ela := NIL; elodd := FALSE;
- ina := NIL; inodd := FALSE;
- topa := NIL;
- eof := TRUE;
- ELSE
- bufa := ADR("buffer"); (* tampon à la position actuelle du fichier *)
- ela := ADR("word in buffer at current position");
- elodd := ODD("current position");
- ina := ADR("first not (completely) read word in buffer");
- inodd := "word at ina contains one Byte";
- topa := ADR("first word after buffer");
- eof := "current position = length";
- IF "(state=reading)OR(state=modifying)" THEN INCL(flags, rd) END;
- IF "(state=writing)OR(state=modifying)" THEN INCL(flags, wr) END;
- IF elodd OR ODD("length") THEN INCL(flags, bytemode) END;
- END;
- IF res <> done THEN eof := TRUE; INCL(flags, er) END;
- IF eof THEN INCL(flags, ef) END
- END
Le champ flags permet un test simple (et donc efficace) de l'état du fichier, à chaque accès. Le "flag" ag est positionné par la routine Again et effacé par les routines de lecture.
Identification interne du fichier et nom de fichier externe
Tous les fichiers pris en charge par le système de fichiers ont une identification unique, appelée identification interne du fichier (IFI) et peuvent également avoir un nom de fichier externe (ou symbolique).
L'identification interne du fichier et le nom du fichier se composent de deux parties, à savoir une partie identificateur le support sur lequel un fichier est (censé être) entreposé et une partie identifiant le fichier sur le support sélectionné.
Les deux parties d'une identification interne du fichier sont appelées l'identification interne du support (IMI) et l'identification locale du fichier (LFI). Les deux parties d'un nom de fichier sont appelées le nom du support et le nom du fichier local.
L'IFI d'un fichier connecté (ouvert) peut être obtenu à tout moment : L'IMI est toujours stocké dans les champs mt et mediumno de la variable file. Le LFI est entreposé dans les champs fileno et versionno après l'exécution de la commande create ou getinternal.
Un fichier f peut être ouvert s'il existe et que son IFI est connu :
- f.mt := ...; f.mediumno := ...;
- f.fileno := ...; f.versionno := ...;
- f.com := open;
- FileCommand(f)
L'identification d'un fichier par un nom sélectionné ou calculé par l'utilisateur (une chaîne de caractères) est cependant à la fois communément acceptée et pratique. Les routines Create, Lookup, Rename et DirectoryCommand ont toutes un paramètre spécifiant le nom de fichier.
Si le nom du support est contenu dans le nom de fichier, il est «converti» en IMI et entreposé dans la variable de fichier, sauf lorsque la commande rename est utilisée. Dans ce cas, l'IMI «converti» est comparé à l'IMI entreposé dans la variable de fichier. Si le nom du support est manquant dans le paramètre de nom de fichier réel, on suppose que l'IMI correspondant est déjà entreposé dans la variable de fichier.
La partie du nom de fichier local du nom de fichier sera gérée par la routine implémentant DirectoryCommand pour le support donné par l'IMI.
Notes d'implémentation
La version actuelle du module FileSystem ne prend en charge que les noms de supports selon la syntaxe suivante :
medium name = letter [ letter ] { digit } . |
Lorsqu'un nom de support est «converti» en identification de support interne, la ou les lettres sont copiées dans la partie MediumType (champ mf) et les chiffres sont considérés comme un nombre décimal dont la valeur est attribuée à la partie numéro de support (champ mediumno). Si le nom de support ne contient aucun chiffre, le numéro de support 65 535 (= 177777B) est supposé.
"DK" => ( "DK", 65535) "DK0" => ( "DK", 0) "DK007" => ( "DK", 7) |
Permanence des fichiers
Un fichier est soit temporaire, soit permanent. La règle est que, lorsqu'un fichier est fermé (de manière explicite, implicite ou en cas de panne du système), un fichier temporaire est supprimé et un fichier permanent reste sur le support pour une utilisation ultérieure. Normalement, un fichier «sans nom» est temporaire et un fichier «nommé» est permanent. Il est cependant possible de contrôler explicitement la permanence d'un fichier. Cela est utile si, pour une raison quelconque, il est préférable de référencer un fichier par son IFI plutôt que par son nom de fichier (par exemple dans les systèmes de bases de données, d'autres systèmes de répertoires).
Définir le fichier comme permanent :
- f.on := TRUE; f.com := setpermanent;
- FileCommand(f)
Définir le fichier temporaire :
- f.on := FALSE; f.com := setpermanent;
- FileCommand(f)
Obtenir la permanence du fichier :
- f.com := getpermanent;
- FileCommand(f);
- (* f.on = TRUE si et seulement si f est permanent *)
Protection des fichiers
Un fichier peut être protégé uniquement contre les modifications (longueur, informations, nom,...). La seule exception à cette règle est bien sûr que la protection d'un fichier protégé peut être modifiée.
Protéger le fichier :
- f.wrprotect := TRUE; f.com := setprotect;
- F1leCommand(f)
Ôter la protection du fichier :
- f.wrprotect := FALSE; f.com := setprotect;
- F1leCommand(f)
Obtenir une protection de fichier :
- f.com := getprotect;
- FileCommand(f);
- (* f.wrprotect = TRUE si et seulement si f est protégé *)