Suivez-nous sur X
|
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
ALL
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : Assembleur - création d'une bibliothèque - 2e partie
(Article écrit par Frédéric Delacroix et extrait d'Amiga News - février 1995)
|
|
J'espère que vous avez bien digéré la théorie du mois dernier car, comme promis,
je vous donne un exemple de bibliothèque, créée par la méthode décrite dans cet
article. Bien qu'assez court et finalement pas d'une grande utilité, cet exemple a
le mérite d'illustrer de façon concrète la marche à suivre.
La bibliothèque
Le rôle de cette bibliothèque, que j'ai baptisée "stringtools.library", est d'offrir
des fonctions de base pour le traitement des chaînes de caractères. Il s'agit, pour
la plupart, de clones de fonctions standard du C. Pour être honnête, je dois
signaler que je me suis inspiré d'un article de Max paru dans Commodore Revue en
décembre 1990.
J'ai également ajouté une routine de tri par bulles, tout ce qu'il y a de plus
classique dans son principe. Petite particularité toutefois : au lieu d'utiliser une
routine de comparaison fixe, cette routine, stBubbleSortHook(), fait appel à un hook
(voir le fichier "utility/hooks.i"), ce qui lui permet de changer l'ordre de
classement. On peut même faire du tri sur de tout autres objets que des chaînes de
caractères. Il suffit de dire à la routine comment les comparer grâce à ce hook. Je
vous renvoie au code source ci après pour plus de détails.
Le fichier "include" est également listé ici ; il est tout à fait standard, excepté
que je l'ai fusionné avec le fichier définissant les LVO. On y définit la structure
de base de la bibliothèque et d'autres choses utiles. La bibliothèque utilisant
l'utility.library, est, pour son usage, réservée aux possesseurs de la version 37
(Kickstart 2.04) et plus (c'est-à-dire tout le monde, normalement).
Programme d'exemple
Afin d'illustrer le fonctionnement de stringtools.library, j'ai également ajouté
un programme d'exemple. Son rôle est de trier les arguments qu'il reçoit sur sa
ligne de commande, ainsi :
TestST Amiga News Amiga Injector Helloween donnera, dans l'ordre : Amiga, Amiga News,
Helloween et Injector (attention, pour ce hook, les majuscules sont importantes).
Considérations de style
Première recommandation : ne faites pas de bibliothèque si ce n'est pas absolument
indispensable. Premièrement, parce que c'est du travail supplémentaire pour le
programmeur (vous !) qui doit faire attention à la réentrance (pas de variables
globales sans sémaphores !), et deuxièmement parce que cela encombre, souvent
inutilement, le tiroir Libs: de l'utilisateur (mon disque dur en comporte 129 !). Les
bibliothèques sont réservées aux routines relativement délicates, répétitives ou
encombrantes utilisées par plusieurs programmes. Les routines de la stringtools.library
seront avantageusement inclues dans votre programme.
Si votre (grosse) application utilise quelques bibliothèques très spécifiques,
placez celles-ci dans un répertoire spécial (les chemins complets sont des
paramètres valides à OpenLibrary()). De cette façon, l'utilisateur s'y perdra moins...
Maintenez toujours une compatibilité descendante totale. Si vous ajoutez des
fonctions à votre bibliothèque, vous devez incrémenter le numéro de version (pas
seulement de révision) de façon à ce qu'une application puisse être sûre que ces
nouvelles fonctions existent en fournissant le nouveau numéro de version à
l'ouverture.
Si vous diffusez une bibliothèque dans le domaine public, assurez-vous que vous
fournissez bien les fichiers includes C et assembleur, les autodocs (au format
standard, pour qu'ils puissent être convertis par AD2AG), le fichier FD, des scripts
d'installation, des exemples, des informations de révision. Comme référence, je ne
manquerai pas de vous citer la remarquable reqtools.library de Nico François...
A la prochaine !
Si vous souhaitez que j'aborde un sujet précis ou des éclaircissements, n'hésitez
pas à écrire à la rédaction, qui se fera un plaisir de transmettre vos requêtes...
Code source stringtools.i
; libraries/stringtools.i
; Fichier include pour stringtools.library
; ©F.Delacroix pour Amiga News
; version 1.0
IFND LIBRARIES_STRINGTOOLS_I
LIBRARIES_STRINGTOOLS_I SET 1
ST_VERNUM EQU 1
ST_REVNUM EQU 0
IFND EXEC_TYPES_I
include exec/types.i
ENDC
IFND EXEC_LIBRARIES_I
include exec/libraries.i
ENDC
STRUCTURE StringToolsBase,LIB_SIZE
ULONG stb_SegList
APTR stb_ExecBase
APTR stb_UtilityBase
LABEL stb_SIZEOF
STRINGTOOLSNAME MACRO
dc.b 'stringtools.library',0
ENDM
; decalages pour les fonctions
_LVOstStrLen EQU -30
_LVOstStrCmp EQU -36
_LVOstStrCpy EQU -42
_LVOstStrnCpy EQU -48
_LVOstStrCat EQU -54
_LVOstStrnCat EQU -60
_LVOstStrToUpper EQU -66
_LVOstStrToLower EQU -72
_LVOstBubbleSort EQU -78
_LVOstBubbleSortHook EQU -84
ENDC
|
Code source Library.s
opt AMIGA
OUTPUT LIBS:stringtools.library
include exec/initializers.i
include exec/resident.i
include exec/alerts.i
include exec/execbase.i
include exec/exec_lib.i
include utility/utility_lib.i
include stringtools.i
; au cas où un clown essaierait d'exécuter la bibliothèque
ST moveq #-1,d0
rts
RomTag
dc.w RTC_MATCHWORD ; voir le mois dernier
dc.l RomTag,EndLib
dc.b RTF_AUTOINIT,ST_VERNUM
dc.b NT_LIBRARY,0
dc.l StringTools.Name,Library.ID
dc.l Library.Init
Library.Init
dc.l stb_SIZEOF
dc.l Functions.Table
dc.l Data.Table
dc.l Lib.InitRoutine
Functions.Table
dc.l Lib.Open
dc.l Lib.Close
dc.l Lib.Expunge
dc.l NullFunc
dc.l stStrLen
dc.l stStrCmp
dc.l stStrCpy
dc.l stStrnCpy
dc.l stStrCat
dc.l stStrnCat
dc.l stStrToUpper
dc.l stStrToLower
dc.l stBubbleSort
dc.l stBubbleSortHook
dc.l -1
Data.Table
INITBYTE LN_TYPE,NT_LIBRARY
INITLONG LN_NAME,StringTools.Name
INITLONG LIB_IDSTRING,Library.ID
INITBYTE LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
INITWORD LIB_VERSION,ST_VERNUM
INITWORD LIB_REVISION,ST_REVNUM
dc.l 0
Lib.InitRoutine ; (D0)Success=Lib.InitRoutine(Base,SegList)(D0,A0)
movem.l d7/a5-a6,-(sp)
move.l d0,a5
move.l a6,stb_ExecBase(a5)
move.l a0,stb_SegList(a5)
lea Utility.Name(pc),a1
moveq #37,d0
jsr _LVOOpenLibrary(a6)
move.l d0,stb_UtilityBase(a5)
bne.s .UtilOpened
move.l #AG_OpenLib!AO_UtilityLib,d7
jsr _LVOAlert(a6)
bra.s .NoUtil
.UtilOpened
move.l a5,d0
.Back
movem.l (sp)+,d7/a5-a6
rts
.NoUtil
move.l a5,a1
moveq #0,d0
move.w LIB_NEGSIZE(a5),d0
sub.l d0,a1
add.w LIB_POSSIZE(a5),d0
jsr _LVOFreeMem(a6)
moveq #0,d0
bra.s .Back
Lib.Open
addq.w #1,LIB_OPENCNT(a6)
bclr #LIBB_DELEXP,LIB_FLAGS(a6)
move.l a6,d0
rts
Lib.Close
subq.w #1,LIB_OPENCNT(a6)
bne.s NullFunc
btst #LIBB_DELEXP,LIB_FLAGS(a6)
bne.s Lib.Expunge
NullFunc
moveq #0,d0
rts
Lib.Expunge
movem.l d2/a5-a6,-(sp)
move.l a6,a5
tst.w LIB_OPENCNT(a5)
beq.s .DoIt
bset #LIBB_DELEXP,LIB_FLAGS(a5)
moveq #0,d0
bra.s .Ret
.DoIt move.l stb_ExecBase(a5),a6
move.l a5,a1
jsr _LVORemove(a6)
move.l stb_UtilityBase(a5),a1
jsr _LVOCloseLibrary(a6)
move.l stb_SegList(a5),d2
moveq #0,d0
move.l a5,a1
move.w LIB_NEGSIZE(a5),d0
sub.l d0,a1
add.w LIB_POSSIZE(a5),d0
jsr _LVOFreeMem(a6)
move.l d2,d0
.Ret movem.l (sp)+,d2/a5-a6
rts
; (D0)Length=stStrLen(String)(A0)
; retourne la longueur de la chaîne
stStrLen
move.l a0,-(sp)
move.l a0,d0
.Loop tst.b (a0)+
bne.s .Loop
sub.l d0,a0
move.l a0,d0
subq.l #1,d0
move.l (sp)+,a0
rts
; (D0,Z,N)Result=stStrCmp(String1,String2)(A0,A1)
; Compare les deux chaînes :
; D0<0 => String1 < String2
; D0=0 => String1 = String2
; D0>0 => String2 > String2
stStrCmp
movem.l d1-d2/a0-a1,-(sp)
moveq #0,d0
.Loop move.b (a0)+,d1
beq.s .EOS1
move.b (a1)+,d2
beq.s .Sup
cmp.b d2,d1
beq.s .Loop
bcs.s .Inf
.Sup moveq #1,d0
bra.s .Ret
.EOS1 tst.b (a1)+
beq.s .Ret
.Inf moveq #-1,d0
.Ret movem.l (sp)+,d1-d2/a0-a1
rts
; stStrCpy(Buffer,String)(A0,A1)
; Copie la chaîne dans le tampon. Attention, le débordement
; du tampon n'est pas testé !
stStrCpy
movem.l a0-a1,-(sp)
.Loop move.b (a1)+,(a0)+
bne.s .Loop
movem.l (sp)+,a0-a1
rts
; stStrnCpy(Buffer,String,Max)(A0,A1,D0)
; Pareil, mais ne copie au maximum que Max caractères.
stStrnCpy
movem.l a0-a1/d0,-(sp)
subq.l #1,d0
.Loop move.b (a1)+,(a0)+
dbne d0,.Loop
.Ret movem.l (sp)+,a0-a1/d0
rts
; stStrCat(String1,String2)(A0,A1)
; String1 <- String1 + String2
; attention : pas de test de débordement de tampon !
stStrCat
movem.l a0-a1,-(sp)
.LLoop tst.b (a0)+
bne.s .LLoop
subq.l #1,a0
.CLoop move.b (a1)+,(a0)+
bne.s .CLoop
movem.l (sp)+,a0-a1
rts
; stStrnCat(String1,String2,Max)(A0,A1,D0)
; pareil, mais au plus Max caractères de String2 seront ajoutés
; à String1.
stStrnCat
movem.l a0-a1/d0,-(sp)
.LLoop tst.b (a0)+
bne.s .LLoop
subq.l #1,a0
subq.l #1,d0
.CLoop move.b (a1)+,(a0)+
dbne d0,.CLoop
movem.l (sp)+,a0-a1/d0
rts
; stToUpper(String)(A0)
; convertit la chaîne en majuscules
stStrToUpper
movem.l d0-d1/a0-a2/a6,-(sp)
move.l a0,a2
move.l stb_UtilityBase(a6),a6
.Loop move.b (a2)+,d0
beq.s .End
jsr _LVOToUpper(a6)
move.b d0,-1(a2)
bra.s .Loop
.End movem.l (sp)+,d0-d1/a0-a2/a6
rts
; stToLower(String)(A0)
; convertit la chaîne en minuscules
stStrToLower
movem.l d0-d1/a0-a2/a6,-(sp)
move.l a0,a2
move.l stb_UtilityBase(a6),a6
.Loop move.b (a2)+,d0
beq.s .End
jsr _LVOToLower(a6)
move.b d0,-1(a2)
bra.s .Loop
.End movem.l (sp)+,d0-d1/a0-a2/a6
rts
; stBubbleSort(Array)(A0)
; Cas particulier de stBubbleSortHook() avec un hook
; consistant en un appel à stStrCmp() (tri alphabétique
; normal, en différenciant majuscules et minuscules) :
stBubbleSort
lea StrCmp.Hook(pc),a1
; stBubbleSortHook(Array,CompHook)(A0,A1)
; La fonction la plus délicate : trier un tableau de pointeurs sur des
; chaînes de caractères. Pour la comparaison, on utilise un hook
; fourni par l'utilisateur, ce qui permet différents types de tri.
; Le hook est appelé avec en A1 et A2 les deux chaînes à comparer.
stBubbleSortHook
movem.l d0-d3/a0-a6,-(sp)
moveq #0,d2
move.l a0,a5
move.l a1,d3
move.l stb_UtilityBase(a6),a6
.Loop1 tst.l d2
bne.s .End
moveq #-1,d2 ; fini
move.l a5,a3
tst.l (a3) ; a3= 1ere chaine **
beq.s .Loop1
.Loop2 lea 4(a3),a4 ; a4= 2nde chaine **
tst.l (a4)
beq.s .Loop1
move.l (a3),a1
move.l (a4),a2
move.l d3,a0
jsr _LVOCallHookPkt(a6)
tst.l d0
ble.s .NoSwap
move.l (a3),d0
move.l (a4),(a3)
move.l d0,(a4)
moveq #0,d2
bra.s .Loop2
.NoSwap move.l a4,a3
bra.s .Loop2
.End movem.l (sp)+,d0-d3/a0-a6
rts
stStrCmp.HookFunc
move.l a1,a0
move.l a2,a1
bra stStrCmp
StrCmp.Hook dc.l 0,0,stStrCmp.HookFunc,0,0
StringTools.Name dc.b 'stringtools.library',0
Library.ID dc.b 'stringtools.library 1.0 (25.12.94)',0
Utility.Name dc.b 'utility.library',0
EndLib
|
Code source "TestST.s"
opt AMIGA
include exec/exec_lib.i
include exec/exec.i
include dos/dos_lib.i
include stringtools.i
move.l 4.w,a6
lea StringTools.Name(pc),a1
moveq #1,d0
jsr _LVOOpenLibrary(a6)
move.l d0,StringTools.Base
beq.s Exit
lea DOS.Name(pc),a1
moveq #37,d0
jsr _LVOOpenLibrary(a6)
move.l d0,DOS.Base
beq.s CloseST
move.l #Args.Template,d1
move.l #Args.Array,d2
moveq #0,d3
move.l DOS.Base(pc),a6
jsr _LVOReadArgs(a6)
move.l d0,Args.RDArgs
beq.s CloseDOS
move.l Args.Array(pc),a0
move.l StringTools.Base(pc),a6
jsr _LVOstBubbleSort(a6)
move.l Args.Array(pc),a2
move.l DOS.Base(pc),a6
PrintLoop
move.l (a2)+,d1
beq.s EndPrint
jsr _LVOPutStr(a6)
move.l #LineFeed,d1
jsr _LVOPutStr(a6)
bra.s PrintLoop
EndPrint
move.l Args.RDArgs(pc),d1
jsr _LVOFreeArgs(a6)
CloseDOS
move.l DOS.Base(pc),a1
move.l 4.w,a6
jsr _LVOCloseLibrary(a6)
CloseST move.l StringTools.Base(pc),a1
jsr _LVOCloseLibrary(a6)
Exit moveq #0,d0
rts
StringTools.Base dc.l 0
DOS.Base dc.l 0
Args.Array dc.l 0
Args.RDArgs dc.l 0
StringTools.Name STRINGTOOLSNAME
DOS.Name DOSNAME
Args.Template dc.b 'WORDS/M/A',0
LineFeed dc.b 10,0
|
|