Cat routine basic * (c) Tom et Jerry 1997
-----------------------------------------
Quelques explications sommaires...
----------------------------------
La routine permet d'obtenir dans un tableau Basic la liste des fichiers
presents sur une disquette, ainsi que le nombre de ces fichiers. En cas
d'erreur (pas de disquette), le nombre de fichier est 255.
Pour ce faire, il faut charger en memoire le code assembleur, reserver la
zone ram superieure a &97ff (stockage du catalogue), et initialiser les
variables Basic qui vont contenir le resultat du cataloguage :
* Le nombre de fichier est un entier
* Le type d'extension a chercher est une chaine de trois caracteres.
La routine reconnait le caractere '?' comme un joker. Le caractere
'*' n'est pas reconnu.
* Le tableau 'nom des fichiers' est un tableau de 64 cases, chaque case
contenant une chaine de 12 caracteres.
!! Ces variables doivent OBLIGATOIREMENT etre initialisees avant d'appeler la
routine assembleur, sous peine de plantage sauvage.
Le tableau doit etre initialise d'une maniere bien precise, de facon a ce
que chacune de ses cases ait a disposition 12 octets (taille d'un nom de
fichier). L'initialisation doit se faire avec une case deja definie, ou par
les commandes STRING$ ou SPACE$.
L'init via une chaine en 'dur' (ex : "TOTO .TXT") n'est pas bonne, car le
cpc n'attribue de la place que pour le premier element du tableau. Pour les
autres, il gere juste un pointeur sur l'adresse ou se trouve en memoire la
chaine "TOTO .TXT") !
Hum, pas simple ! Le mieux est de faire un essai et de geler la memoire.
Resultat garanti !
Un CALL &A000,[1ere case du tableau$],[extension$],à[nombre de fichiers %]
permet d'indiquer a la routine assembleur ou se trouvent les zones de stockage
des variables a utiliser.
Le caractere 'à' est OBLIGATOIRE avant le nom de la variable entiere, car cela
indique au cpc qu'il faut transmettre a la routine assembleur l'adresse dont
se sert la variable pour stocker sa valeur, et non l'adresse du pointeur sur
cette adresse !
Ces informations sont stockees dans une liste. Cette liste commence a l'adres-
se pointee par le registre IX. Une chose assez rigolote, cette liste est
inversee par rapport aux parametres que l'on passe. Un petit exemple sera plus
parlant :
CALL &A000,A$(0),exten$,àfiles%
adresse contenant la variable A$(0) = &2C0 (valeur au hasard !)
adresse contenant la variable exten$ = &2A2 (idem)
adresse contenant la variable files% = &2A0 (idem 2 !)
suite au CALL, le registre IX pointe sur la valeur &BCF0. Si on
regarde ce qu'il y a en &BCF0, on trouve :
A0 02 A2 02 C0 02
Ce qui nous fait donc &2A0 suivi de &2A2 puis &2C0 !
Parlons maintenant un peu de la routine assembleur. Elle aurait pu etre plus
courte mais j'ai rajoute quelques babioles qui la rendent plus presentable.
La routine se decompose comme suit :
1) Detournement des eventuels messages d'erreur de l'Amsdos (pas de
disquette, etc.. ) pour ne pas avoir de message Retry, Ignore or
Cancel s'il y a un probleme lors de la lecture du catalogue.
Le detournement se fait via l'appel de la RSX cachee &1 de l'Amsdos.
L'adresse de ce vecteur est determinee grace a une recherche de la
RSX. Cela evite ainsi d'avoir des problemes de compatibilite avec
les differents types de cpc (cpc plus surtout). Un test est meme
fait pour verifier que la rsx existe bien (pas evident si la rom
Amsdos a ete remplacee par une autre ?).
2) Detournement de l'affichage des caracteres a l'ecran, pour qu'on ne
puisse par 'voir' le catalogue.
3) Appel de la routine systeme de cataloguage. Le resultat est stocke
a partir de &9800 sous la forme suivante pour chaque fichier :
FF 20 20 20 20 20 20 20 20 20 20 20 00 00
> Nom du fichier sans separateur <
Le &FF est un bete separateur entre les donnees, et ne correspond
pas a une information pertinente.
L'octet suivant le nom indique la taille du fichier en blocs.
Le dernier octet, pas trouve !
A noter que la routine 5) annule le bit 7 du premier octet de l'ex-
tension. Ce bit permet de savoir si le fichier est protege contre
l'ecriture (R/W).
Pour savoir si on est a la fin de la liste, facile. A la place
d'un &FF, on a un beau &00.
4) Annulation du detournement de l'affichage
5) Lecture des noms de fichiers en ram et copie de ces noms dans les
cases reservees du tableau Basic. On en profite pour les compter !
Seule petite chose un peu tordue, la facon dont notre ami le cpc
stocke ses chaines Basic. Pour chaque element, le cpc gere dans la
RAM Basic trois octets :
1er octet : longueur de la chaine
2eme & 3eme octets : adresse de la chaine
Ces informations sont stockees dans une liste sequentielle. Le
debut de cette liste nous est donne par la liste pointee par le
fameux registre IX (voir plus haut).
La routine en appelle une autre, permettant de verifier que l'ex-
tension du fichier traite correspond a l'extension de selection
transmises par l'utilisateur lors du CALL &A000
6) Annulation du detournement des messages de l'Amsdos
7) hop, retour au Basic.
Limites de la routine :
---------------------
* On ne catalogue qu'un User a la fois (comme un CAT Amsdos)
* La routine ne traite pas correctement les catalogues speciaux, affichant a
l'ecran du texte (ex : les catalogues des loaders Applebye)
NOTICE TEXTE n° 2 (7.07 Ko)
; Cat routine * Tom et Jerry (c) 1997
; Version 1.1a avec filtrage au niveau de l'extension des fichiers...
; Maj du 22/01/98, plus de bug avec le lecteur B:
ORG &A000
WRITE "CAT.BIN"
NOLIST
buffer_cat equ &9800 ; longueur = 2ko ou &800
cat_vect equ &BC9B ; vecteur Amsdos de la commande CAT
no_print_vect equ &BB57 ; interdit l'affichage de caracteres
print_ok_vect equ &BB54 ; autorise l'affichage de caracteres
find_rsx_vect equ &BCD4 ; recherche une Rsx
dsk_etat equ &BE4C ; case ou est stocke le resultat des operations disk
; par le systeme
generic_char equ "?" ; joker pour la comparaison des extensions avec
; l'extension de selecton
extension_char equ "." ; le point separant le nom et l'extension d'un fichier
JP main ; saut a la routine principale. Ainsi, l'addy de base
; de la routine ne change jamais.
; Appel d'un vecteur Amsdos pour inhiber le message Retry, Ignore, Cancel
ric_off LD HL,no_mes_dsk_name ; nom en ASCII du vecteur
CALL find_rsx_vect ; on recherche des infos sur le vecteur
; (adresse dans HL et rom dans C)
RET NC ; RSX introuvable ! Normalement impossible avec
; un cpc equipe d'Amsdos
PUSH HL ; on sauvegarde les infos trouvees dans une
POP DE ; table de 3 octets, utilisee pour appeler la
LD HL,no_mes_dsk_vect ; routine !
LD (HL),E
INC HL
LD (HL),D
INC HL
LD (HL),C
LD A,&FF ; on appelle le vecteur avec un parametre dans
ric_of2 RST &18 ; le registre A
ric_of1 DEFW no_mes_dsk_vect
SCF
RET
no_mes_dsk_vect db 0,0,0
no_mes_dsk_name db &81
ric_on LD A,&0
JR ric_of2
; Appel du catalogue
cat CALL no_print_vect
LD DE,buffer_cat
CALL cat_vect
CALL print_ok_vect
LD A,(dsk_etat) ; Merci Monsieur Amsdos de ne pas mettre le flag
CP &40 ; C si le catalogage est ok, contrairement a toutes
JR Z,cat_2 ; les autres routines disks. Il faut se debrouiller
CP &41 ; avec les resultats du FDC... Test drives A et B
RET NZ
cat_2 SCF
cat_1 RET
; Copie dans le tableau Basic du nom des fichiers
gen_bas LD C,&0 ; nombre de fichiers trouves, au debut 0
LD L,(IX + 2) ; on recupere le pointeur sur la variable contenant
LD H,(IX + 3) ; l'extension a trier eventuellement
INC HL ; 1ere valeur, inutile
LD E,(HL) ; on recupere l'adresse de l'extension
INC HL
LD D,(HL)
EX DE,HL ; recopie de l'addresse pour plus tard...
LD (extension +1 ),HL
EX DE,HL
LD L,(IX + 4) ; On recupere le pointeur sur le premier element
LD H,(IX + 5) ; du tableau servant a stocker les noms
PUSH HL
POP IX ; IX devient le pointeur sur ces pointeurs !
INC IX ; 1er caractere = longueur de la chaine, on s'en
; fout, donc on pointe sur le suivant
LD HL,buffer_cat ; zone ou se trouve les noms des fichiers
INC HL ; 1er caractere sans interet, on passe...
gen_ba1 LD A,(HL) ; dernier fichier ?
AND A
RET Z
PUSH BC ; on recopie le nom du fichier dans le tableau Basic
LD E,(IX + &0) ; en rajoutant le point entre le nom et l'extension
LD D,(IX + &1)
CALL exten ; fichier ok par rapport a extension chosie ?
AND A
JR NZ,gen_ba3
LD BC,&8
LDIR
LD A,extension_char
LD (DE),A
INC DE
LD A,(HL) ; on fait disparaitre le bit R/W
AND &7F
LD (DE),A
INC HL
INC DE
LD BC,&2 ; copie de la fin de l'extension
LDIR
LD BC,&3 ; on pointe sur le nom de fichier suivant
ADD HL,BC
INC IX ; on pointe sur l'entree suivante du tableau Basic
INC IX
INC IX
POP BC
INC C ; nombre de fichiers + 1 !
JR gen_ba1
gen_ba3 LD BC,&E ; on pointe sur le fichier suivant sans incrementer
ADD HL,BC ; le nombre de fichiers trouves
POP BC
JR gen_ba1
; Sauvegarde du nombre de fichiers
; Si valeur = &FF, erreur disque quelconque...
sav_fil LD HL,&0000 ; on sauvegarde le nombre de fichers dans la variable
LD (HL),C ; Basic appropriee. Cette variable etant un INTEGER,
INC HL ; elle est stockee sur deux octets, d'ou le zero poke
LD (HL),&0 ; apres le contenu de C
RET
; Verification de l'extension
exten PUSH HL ; HL pointe sur le nom du fichier
PUSH DE
PUSH BC
LD BC,&8
ADD HL,BC ; on pointe sur l'extension du fichier
EX DE,HL
extension LD HL,&0000 ; code auto-modifie !
LD B,&3
exten_3 LD A,(HL)
CP generic_char ; generic, rien a verifier pour ce caractere...
JR Z,exten_1
LD A,(DE)
AND &7F
CP (HL)
JR NZ,exten_2 ; si le caractere de l'extension n'est pas bon,
exten_1 INC HL ; on arrete tout avec registre A=&FF
INC DE
DJNZ exten_3
XOR A
exten_4 POP BC
POP DE
POP HL
RET
exten_2 LD A,&ff
JR exten_4
; Appel de toutes les routines...
main LD L,(IX + 0) ; on sauvegarde le pointeur sur le contenu de la
LD H,(IX + 1) ; variable Basic "nombre de fichiers en sortie"
LD (sav_fil +1),HL ; pour l'utiliser plus tard... code auto-modifie
PUSH IX ; on sauvegarde le pointeur sur la liste des variables
; transmises par le Basic, soit normalement :
; adresse de la variable de stockage du nb de fichiers
; donnee sur deux octets
; adresse du pointeur contenant l'extension a recher-
; cher dans la liste des fichiers
; adresse du pointeur contenant les informations du
; premier element du tableau qui va contenir les noms
; des fichiers
; donnee sur deux octets
CALL ric_off
JR NC,main_2 ; si rsx non trouvee, pas de flag C
CALL cat
JR NC,main_2 ; si erreur de lecture, pas de flag C
CALL ric_on
POP IX
CALL gen_bas
main_1 JP sav_fil ; un JP au lieu d'un CALL permet de gagner 1 octet !
; RET
main_2 POP IX
LD C,&FF
JR main_1