Die Index-sequentielle Datei
Das Arbeiten mit einer relativen Datei ist gar nicht so komfortabel wie man es eigentlich möchte. Der Zugriff auf Datensätze nur über die Datensatznummer ist nicht besonders benutzerfreundlich und in der Regel auch praxisfremd. Unter Zuhilfenahme einer sequentiellen Datei wird dieser Nachteil jedoch aufgehoben.
In den letzten beiden Ausgaben des 64’er wurden Ihnen die Grundzüge der sequentiellen und der relativen Datei vorgestellt und erläutert. Ich deutete auch schon an, daß erst die Verbindung dieser beiden Dateiformen zu einer befriedigenden Lösung führt. Aber auch hier muß man Abstriche machen. Durch diese Vermischung werden leider nicht nur die Vorteile, sondern auch ein Teil der Nachteile mit übernommen. Ich möchte diese noch einmal kurz anreißen.
Das Wesen der sequentiellen Datei liegt in der aufeinanderfolgenden (eben sequentiellen) Anordnung der Daten. Um mit dieser Datei arbeiten zu können, muß sie vollkommen in den Speicher des Computers geladen werden. Bei großen Datenbeständen kann das eine ganze Zeit lang dauern. Andererseits wird die maximale Größe durch den zu Verfügung stehenden Speicherplatz im Computer selbst bestimmt. Sind jedoch alle Datensätze erst einmal geladen, ist ein Bearbeiten der Daten sehr einfach und auch schnell. Dann können alle Änderungen, Ergänzungen und sonstige Manipulationen im Computer selbst durchgeführt werden. Und für zeitkritische Funktionen wie Sortieren und Suchen kann man die Maschinensprache sehr wirkungsvoll einsetzen.
Die relative Datei hingegen benötigt außer dem eigentlichen Programm nur sehr wenig Speicherplatz, nämlich nur noch denjenigen für die internen Variablen und für einen Datensatz. Der Rest aller Daten befindet sich auf Diskette. Und dort stehen einem fast 170 KByte zur Verfügung. Allerdings ist das Arbeiten mit einer rein relativen Datei nur in speziellen Fällen sinnvoll und praktisch, da bei ihr ein Datensatz nur über die Datensatznummer angesprochen werden kann. Ein weiteres Merkmal ist, daß die Datensatzlänge vorher festgelegt werden muß und eine Floppy unbedingt notwendig ist.
Indizierung als Lösung
Durch die Verbindung einer relativen Datei mit einer sequentiellen wird ein Kompromiß geschlossen. Einerseits wird die Suche nach einem Datensatz, beispielsweise nach einer Adresse, jetzt direkt über den Namen möglich. Andererseits muß gleich nach dem Programmstart die sequentielle Datei geladen und am Ende wieder gespeichert werden. Allerdings fällt sie wesentlich kürzer aus. In ihr braucht lediglich ein Feld der Datensätze enthalten zu sein, nämlich das Indexfeld, im Beispiel die Nachnamen, und nicht, wie bei der puren sequentiellen Form, alle Felder.
Gehen wir einmal von folgender Voraussetzung aus: Auf der Diskette sind bereits eine Anzahl von Adressen gespeichert. Im RAM des Computers befindet sich das Programm und in einem eindimensionalen Feld (im Beispiel die Variable IN$) alle bisher eingegebenen Nachnamen. Indem wir diese Variable mittels einer FOR-NEXT-Schleife durchsuchen, können wir auch einen gespeicherten Namen finden. Allerdings kommen wir damit noch nicht an seine Adresse heran, da diese ja in diesem Moment nicht im Computer sondern auf Diskette gespeichert steht. Mit einem kleinen Kniff schaffen wir aber auch diese Hürde. Wir speichern bei der Eingabe einer neuen Adresse einfach die Datensatznummer vor dem Nachnamen in die Variable IN$. Und zwar reservieren wir vor jedem Nachnamen vier Stellen für die zugehörige Datensatznummer. Ab der 5. Stelle beginnt also der jeweilige Nachname. Wollen wir nun einen Namen suchen, so müssen wir mit der MID$-Funktion die Feldvariable IN$ ab dem fünften Buchstaben durchkämmen. Sobald der gesuchte Name gefunden wurde, trennen wir die ersten vier Zeichen ab und erhalten damit die zugehörige Datensatznummer. Mit dieser Nummer können wir jetzt direkt auf die relative Datei auf der Diskette zugreifen und holen uns die komplette Adresse.
… und so wird’s gemacht
Anhand eines Beispiels soll das noch einmal gezeigt werden:
Inhalt der ersten Elemente von IN$:
IN$(1) =»1… MEIER«
IN$(2) =»2… MUELLER«
IN$(3) =»3… ANDERMANN«
IN$(4) =»*«
Gesuchter Name = Mueller, er steht in der Variablen N$ (Zeile 3060)
3060 INPUT"NACHNAME";N$
3070 N = LEN(N$) Länge des eingegebenen Namens
Die folgenden Programmzeilen suchen den Namen.
3090 FOR I = 1 TO DATEIENDE
3100 IF IN$(I) = ”*” THEN 3120
3110 IF MID$(IN$(I),5,N)=N$ THEN gefunden
3120 NEXT I
Zur Zeile 3100 kommen wir später noch. Angenommen, wir haben nicht den ganzen Namen eingegeben, sondern lediglich die ersten drei Buchstaben MUE. Dann werden in der Variable IN$ nur die 5.,6. und 7. Zeichen, das entspricht den ersten drei Buchstaben eines jeden Namens, verglichen. Dafür sorgt die Zeile 3070 und in 3110 das »,N« als letzter Parameter der MID$-Funktion. Somit könnte mit dieser Eingabe auch der Name MUECKE gefunden werden. Im Extremfall, wenn nichts eingegeben, also RETURN gedrückt wird, findet diese Funktion jeden Namen. Das heißt, man kann mit der Suchfunktion sich nicht nur einzelne Adressen holen, sondern auch die gesamte Datei, oder zum Beispiel alle Adressen, die mit M anfangen. Damit würde der Menüpunkt »G = Anzeigen gesamte Datei« überflüssig. Ich habe ihn nicht entfernt, da hier unabhängig von der sequentiellen Datei alle Datensätze direkt von der Diskette aus der relativen Datei gelesen werden. Man könnte diese Funktion benutzen, um eine eventuell (zum Beispiel durch Stromausfall) teilweise zerstörte sequentielle Datei zu reorganisieren.
Die Zeile 3100 wird dann verständlich, wenn man sich den Programmteil »Neue Datei anlegen« ab 11000 anschaut. In den Zeilen 11320 bis 11350 wird jedes Element der Variablen IN$ mit einem »*« vorbesetzt. Der Stern kennzeichnet einen leeren Datensatz. Damit kommen wir auch gleich zum Programmteil »Löschen Datensatz« ab 4000. Auch dort wird ein zu löschender Datensatz in IN$ mit einem »*« gekennzeichnet und zusätzlich der entsprechende Datensatz auf der Diskette mit Hex FF (= Dezimal 255 = das Zeichen PI). Auch das wollen wir uns anhand eines kleinen Beispiels näher betrachten:
Wir wollen den Herrn Mueller aus unserer Datei entfernen. Nachdem wir seine Adresse mit der Suchfunktion gefunden haben, geben wir ein »L« für Löschen ein. Danach springt das Programm nach 4000, schreibt in die Variable IN$ das »*« , überschreibt den Datensatz auf der Diskette mit CHR$(255)(=PI), löscht die einzelnen Datensatzfelder (NN$, NV$, und so weiter) und springt zurück nach 3350. Die Variable IN$ sieht jetzt so aus:
IN$(1) =»1… MAIER«
IN$(2) =»*«
IN$(3) =»3… ANDERMANN«»
IN$(4) =»*«
Der zweite Datensatz ist nun mit »*« als gelöscht und leer gekennzeichnet. Das bedeutet auch, daß er wieder mit einer neuen Adresse belegt werden kann. Sehen wir uns dazu den Programmteil »Neueingabe Adresse« ab 1800 an.
Nachdem wir eine neue Adresse eingegeben haben (die einzelnen Programmteile, die in 1830 bis 1850 aufgerufen werden, kennen Sie ja bereits aus den letzten beiden 64'er Ausgaben), muß jetzt ein leerer Platz gefunden werden, auf dem wir die neue Adresse abspeichern können. Wichtig sind jetzt die Zeilen 1880 bis 1910. In diesem Abschnitt wird IN$ so lange durchsucht, bis ein mit »*« gekennzeichnetes Element gefunden wird (1910). In unserem Beispiel ist das bereits das zweite Element (IN$(I) = »*«, bei I = 2). Somit wird die neue Adresse als zweiter Datensatz auf Diskette gespeichert. In Zeile 1930 und 1940 wird die Variable IN$ auf den neuesten Stand gebracht. Zuerst wird die Datensatznummer (I) in einen String umgewandelt (1920). Dabei wird immer das (unsichtbare positive) Vorzeichen mit berücksichtigt. Da wir dieses nicht brauchen, wird es abgeschnitten (MID$(I$,2) und die Zahl mit Leerstellen auf insgesamt vier Zeichen Länge erweitert. Zeile 1940 verbindet dann die Datensatznummer mit dem Namen.
Vielleicht ein Wort noch zur MID$-Funktion. Normalerweise gehören zu dieser Funktion drei Parameter. So steht es auch kurz erläutert im Commodore-Handbuch. Der letzte Parameter gibt an, wieviele Zeichen ab einer definierten Stelle des Strings genommen werden sollen. Wird dieser Parameter weggelassen, werden ab der definierten Stelle alle restlichen Zeichen des Strings übernommen.
Probleme, die sich ergeben können
Es könnte sein, daß Ihnen die Dateistruktur nicht gefällt. Zum Beispiel möchten Sie die Länge der Datenfelder ändern. Das dürfen Sie nur machen, wenn die Datei neu eingerichtet werden soll. Bei einer bestehenden geht es nicht! Beim Verkürzen gibt es keine Probleme, auch keine beim Verlängern bis zu 88 Zeichen. Zu verändern sind dann die Zeile 30040 sowie die Längenangaben zwischen den Zeilen 5000 und 7100. Bedenken Sie dabei, daß die Variable BL$ mindestens so viele Leerstellen haben muß, wie das längste Datenfeld.
Schwieriger wird es, wenn Sie infolge einer Vergrößerung der Datensatzlänge über 88 Zeichen hinwegkommen. Das Problem hierbei ist der INPUT#-Befehl. Mit ihm kann man nämlich nur maximal 88 Zeichen aus einer Datei lesen. Es gibt zwei Methoden, diese Hürde zu überwinden. Erstens eine Maschinensprache-Routine, die den INPUT#-Befehl erweitert, so daß auch Datensätze mit bis zu 255 Zeichen gelesen werden können (schauen Sie doch einmal in das Floppy-Buch von Data Becker, dort finden Sie eine entsprechende Routine). Die zweite Möglichkeit ist die Verwendung des GET#-Befehls anstelle des INPUT#-Befehls. Dann ist die Zeile 9070 INPUT#1,RC$ durch folgende Zeilen zu ersetzen:
9068 RC$ = " "
9070 GET#1,W$
9072 RC$ = RC$+W$
9074 IF W$ = CHR$(255) THEN 9090
9076 IF W$ = CHR$(13) THEN 9070
Den GET#-Befehl kann man natürlich auch dann einsetzen, wenn die Satzlänge kleiner als 88 Zeichen ist. Dann werden die Zeichen jedoch um einiges langsamer eingelesen als mit dem INPUT#-Befehl. Aber es ist mit dem GET#-Befehl möglich, bis zu 255 Zeichen in eine Variable einzulesen.
Ein Problem ganz anderer Art kann auftauchen, wenn Sie eine Floppy besitzen, die vor Dezember 1983 gekauft beziehungsweise hergestellt wurde und gleichzeitig mit einem VC 1526 drucken. Es kann möglich sein, daß bei Benutzung einer relativen Datei Fehler auftauchen, sobald dieser Drucker eingeschaltet ist. Probieren Sie das vorher aus! Abhilfe schafft meines Wissens nur ein neues DOS für die alte VC 1541.
Anregungen für Programmierer
Dieses Programm ist — bis auf die Druckerroutine, die sich jeder für seinen eigenen Drucker selber schreiben sollte — komplett und funktionsfähig. Sicherlich lassen sich noch eine ganze Reihe von Schönheitsreparaturen machen. Auch eine Erweiterung des Programms ist durchaus sinnvoll. Zum Beispiel könnte man ein Unterprogramm schreiben, das, ähnlich einem professionellen Dateiprogramm, es ermöglicht, sich die Datenfelder selbst zu definieren. Auch die Suche nach mehr als einem Feld ist durchaus sinnvoll. Wenn erwünscht, kann auch eine Sortierroutine eingefügt werden. Der modulare Aufbau erlaubt dies ohne Schwierigkeiten. So kann sich jeder, der etwas Programmiererfahrung hat, eine Dateiverwaltung aufbauen, die sogar professionellen Programmen etwas voraus hat: Sie ist auf die persönlichen Bedürfnisse abgestimmt und läßt sich auch jederzeit ändern. Wer das Programm kompiliert, kann auch bei sehr großen Dateien noch mit guten Suchgeschwindigkeiten rechnen. Dieses Beispielprogramm enthält alle Voraussetzungen für eigene Erweiterungen. Ich selbst habe obengenannte Funktionen für meine eigene Dateiverwaltung bereits realisiert.
(gk)DL | = Datensatzlänge |
RN | = Record-Nummer |
RN$ | = Record-Nummer |
BL$ | = Leerstellen (Blanks) |
BL | = Anzahl Leerstellen |
FR$ | = Name der relativen Datei |
FI$ | = Name der Index-Datei |
A1 bis A4 | = Fehlermeldung der Floppy |
IN$(i) | = Inhalt der Index-Datei |
IN$(0) | = Größe der Datei |
MX/MX$ | = Größe der Datei |
AM | = Größe der Datei vor Erweiterung |
HB/LB | = High-Low-Byte |
ER | = Fehlermeldung der Floppy bezogen auf relative Datei |
RC$ | = ein gesamter Datensatz |
NN$ | = Nachname |
NV$ | = Vorname |
SR$ | = Straße |
OT$ | = Ort |
PL$ | = Postleitzahl |
TE$ | = Telefon |
ST | = Statusvariable (prüft auf Dateiende bei der Sequent. Datei) |
S1 | = stellt fest, ob die gesamte Datei durchsucht wurde |
F | = stellt fest, ob ein Datensatz belegt ist |
FS | = wenn 1, dann wird vor Beenden des Programms die sequentielle Datei erneut abgespeichert. |
100 rem ****************************** 110 rem * adressendatei 64'er/9 * 120 rem * index-sequentiell * 130 rem ****************************** 140 : 150 : 160 gosub30000:rem init 170 close1:open1,8,2,fr$+",l,"+chr$(dl) 180 close3:open3,8,3,fi$+",s,r" 190 gosub10000:rem:diskfehler 200 ifa1<>0thenrun 210 input#3,in$:mx$=left$(in$,15) 220 mx=val(mx$) 230 : 240 in$(0)=in$ 250 print"{clr}" 260 print:print:print 270 print" information" 280 print:print 290 print" bisherige dateigroesse: ";mx 300 print:print 310 print" bitte warten" 320 i=0 330 i=i+1 340 :input#3,in$(i):print""i;mx;in$(i) 350 ifst<>64then330 360 print:print 370 print" druecken sie eine taste" 380 poke198,0:wait198,1 390 rem --------------------------- 1000 rem - menue - 1010 rem --------------------------- 1020 : 1030 print"{clr}" 1040 print:print 1050 print" adressendatei" 1060 print" relativ und sequentiell" 1070 print:print 1080 print"{rvon} x = programmende" 1090 print 1100 print" g = anzeigen gesamte datei 1110 print 1120 print" s = suchen" 1130 print 1140 print" n = neue adressen eingeben" 1150 print 1160 print" ! = neue datei anlegen" 1170 print:print:print:print 1180 print"waehlen sie "; 1190 poke198,0 1200 getr$:ifr$=""then1200 1210 ifr$="x"thenclose1:gosub15000:close15:end 1220 ifr$="g"thengosub3500:rem anz. 1230 ifr$="s"thengosub2570:rem such 1240 ifr$="n"thengosub1800:rem neueing. 1250 ifr$="!"thengosub11000:rem neudatei 1260 goto390 1800 rem---------------------------- 1810 rem schreiben /eingabe seq/rel- 1820 rem---------------------------- 1825 nn$=".":nv$=".":ot$=".":te$=".":pl$=".":sr$="." 1830 gosub2000:rem ausgabe 1 datensatz 1840 gosub6000:rem eingabe 1850 gosub7000:rem verketten 1860 rem bestimmung satznummer 1870 lz$=" ":lz=4 1880 i=0 1890 i=i+1 1900 : 1910 ifin$(i)<>"*"then1890 1920 i$=str$(i) 1930 i$=mid$(i$,2)+left$(lz$,lz-len(i$)+1) 1940 in$(i)=i$+nn$ 1950 rn$=str$(i) 1960 gosub14000:rem satznr.aufteilen 1970 gosub8000:rem speichern 1980 ifi>=mxthenprint"{clr} datei voll":goto11500 1990 return 2000 rem ------------------------------ 2010 rem - ausgabe 1 datensatz 2020 rem ------------------------------ 2030 : 2040 print"{clr}{down} anzeige datensatz";rn+1 2050 print:print:print:print 2060 print" nachname "nn$ 2070 print" vorname "nv$ 2080 print" strasse "sr$ 2090 print" plz "pl$ 2100 print" ort "ot$ 2110 print" telefon "te$ 2120 print:print:print 2130 return 2140 : 2500 rem---------------------------- 2510 rem drucken 2520 rem---------------------------- 2530 : 2540 print"{up}{up} {rvon} noch nicht definiert ":print 2550 forj=1to500:next 2560 return 2570 rem-------------------------- 3000 rem suchen seq/rel 3010 rem-------------------------- 3020 n$="" 3030 print"{clr}":print:print 3040 print" suchen" 3050 print:print 3060 input" nachname";n$ 3070 n=len(n$) 3080 s1=1 3090 fori=s1tomx 3100 :ifin$(i)="*"then3120 3110 :ifmid$(in$(i),5,n)=n$then3180 3120 nexti 3130 ifs1>1thenprint"{up}{rvon} suche beendet{down}":goto3150 3140 print:printn$" nicht gefunden" 3150 print:print"druecke taste" 3160 getr$:ifr$=""then3160 3170 return 3180 rn$=left$(in$(i),4) 3190 gosub14000:rem satznr.aufteilen 3200 gosub9000:rem lesen 3210 gosub5000:rem aufteilen 3220 gosub2000:rem anzeigen 3230 print:print 3240 w$=" waehle " 3250 print"(w)eitersuchen (z)urueck" 3260 print"(a)endern (l)oeschen" 3270 print"(d)rucken " 3280 printw$ 3290 getr$:ifr$=""then3290 3300 w$=" warten " 3310 print"{up} "w$"{down}" 3320 ifr$="z"then3170 3330 ifr$="w"thens1=i+1:goto3090 3340 ifr$="a"thengosub12000:goto3240 3350 ifr$="l"thengosub4000:goto3220 3360 ifr$="d"thengosub2500 3370 print"{up}{up}{up}{up}{up}";:goto3240 3500 rem---------------------------- 3510 rem- lesen gesamte datei 3520 rem---------------------------- 3530 rn=0 3540 rn=rn+1 3550 :hb=int(rn/256) 3560 :lb=rn-hb*256 3570 :gosub9000:rem lesen 3580 :ifer=50thenprint"{clr} datei ende {down}{down}{down}":goto3620 3590 :iff=2thenprint"{home}{rvon} nicht belegt: datensatz-nr. ";rn;"{left} ":goto3540 3600 :gosub5000:rem aufteilen 3610 :gosub2000:rem anzeigen 3620 :print"druecke taste" 3630 :getr$:ifr$=""then3630 3640 :r$="" 3650 ifer<>50then3540 3660 return 4000 rem------------------------------ 4010 rem loeschen datensatz 4020 rem------------------------------ 4030 : 4040 in$(i)="*" 4050 rc$="~" 4060 gosub8000:rem speichern 4070 nn$=".":nv$=".":ot$=".":te$=".":pl$=".":sr$="." 4080 : 4100 return 5000 rem------------------------------ 5010 rem aufteilen datensatz in felder 5020 rem------------------------------ 5030 : 5050 nn$=mid$(rc$,1,15) 5060 nv$=mid$(rc$,16,15) 5070 sr$=mid$(rc$,31,20) 5080 pl$=mid$(rc$,51,4) 5090 ot$=mid$(rc$,55,15) 5100 te$=mid$(rc$,70,12) 5110 return 6000 rem------------------------------ 6010 rem- eingabe neue daten - 6020 rem------------------------------ 6030 : 6050 print"{home}" 6060 print" eingabe " 6070 print:print:print:print 6080 input" nachname ";nn$:nn$=left$(nn$,15) 6090 input" vorname ";nv$:nv$=left$(nv$,15) 6100 input" strasse ";sr$:sr$=left$(sr$,20) 6110 input" plz ";pl$:pl$=left$(pl$,4) 6120 input" ort ";ot$:ot$=left$(ot$,15) 6130 input" telefon ";te$:te$=left$(te$,12) 6140 print:print 6150 print" adresse ok (j/n) ?" 6160 getr$:ifr$=""then6160 6170 ifr$="n"then6050 6175 ifr$<>"j"then6160 6180 return 6190 : 7000 rem---------------------------- 7010 rem verketten der felder - 7020 rem---------------------------- 7030 : 7040 bl$=" " 7050 rc$=nn$+left$(bl$,15-len(nn$)) 7060 rc$=rc$+nv$+left$(bl$,15-len(nv$)) 7070 rc$=rc$+sr$+left$(bl$,20-len(sr$)) 7080 rc$=rc$+pl$+left$(bl$,4-len(pl$)) 7090 rc$=rc$+ot$+left$(bl$,15-len(ot$)) 7100 rc$=rc$+te$+left$(bl$,12-len(te$)) 7110 return 7120 : 8000 rem ---------------------------- 8010 rem - speichern daten auf disk - 8020 rem ---------------------------- 8030 : 8080 print#15,"p"+chr$(2)+chr$(lb)+chr$(hb)+chr$(1) 8100 print#1,rc$ 8110 fs=1:rem flag fuer speichern 8170 return 8180 : 9000 rem ---------------------------- 9010 rem - lesen datensatz von disk - 9020 rem ---------------------------- 9030 f=0 9040 print#15,"p"+chr$(2)+chr$(lb)+chr$(hb)+chr$(1) 9050 input#15,er 9060 ifer=50then9110 9070 input#1,rc$ 9080 ifrc$<>"~"thenf=1:goto9110 9090 f=2:rem freier datensatz 9100 : 9110 return 10000 rem ---------------------------- 10010 rem - diskettenfehler - 10020 rem ---------------------------- 10030 print"{clr}" 10040 input#15,a1,a2$,a3,a4 10050 ifa1=0then10180 10060 ifa1=62thengosub10200:goto10180 10070 print 10080 printa1,a2$;a3;a4 10090 print:print 10100 print" diskettenfehler" 10110 print:print 10120 print" beheben sie den fehler " 10130 print" und druecken sie" 10140 print 10150 print" >> f <<" 10160 getr$:ifr$=""then10160 10170 print"{clr}" 10180 return 10190 : 10200 print"{clr}" 10210 print:print:print:print 10220 print" die datei "fr$ 10230 print 10240 print" oder "fi$ 10250 print 10260 print" existieren nicht!" 10270 print:print 10280 print" l = datendisk einlegen" 10290 print 10300 print" n = datei neu anlegen" 10310 getr$:ifr$=""then10310 10320 ifr$="l"thenreturn 10330 ifr$="n"thengoto11000 10340 goto10310 11000 rem------------------------------ 11010 rem - neue datei anlegen 11020 rem --------------------------- 11030 : 11040 print"{clr}":print 11050 ifa1=0then11070 11060 print" " 11070 print" achtung, die gesamte diskette wird " 11080 print" geloescht ! " 11090 print:print 11100 print" n = neue datei x = ende" 11110 getr$:ifr$=""then11110 11120 ifr$="x"then close1:gosub15000:close15:end 11130 ifr$<>"n"then11110 11140 print:print" bitte warten" 11150 print#15,"n:relative datei" 11160 clr:gosub30000:rem init 11170 close1:open1,8,2,fr$+",l,"+chr$(dl) 11180 print"wieviele datensaetze soll die datei " 11190 print"verwalten? "; 11200 inputrn$:rn=abs(int(val(rn$))) 11210 ifrn<=mxthen11180 11220 hb=int(rn/256) 11230 lb=rn-hb*256 11240 print"bitte warten" 11250 print#15,"p"+chr$(2)+chr$(lb)+chr$(hb)+chr$(1) 11260 print#1,chr$(255) 11270 mx=rn 11280 mx$=str$(rn) 11290 close1 11300 : 11310 print"{home} " 11320 fori=am+1tomx 11330 :in$(i)="*" 11340 print"{home} "mx;i,in$(i) 11350 nexti 11360 fi$="@:"+fr$+"index" 11370 close3:open3,8,3,fi$+",s,w" 11380 in$(0)=mx$ 11390 fori=0tomx:print#3,in$(i):next 11400 close3 11420 run 11430 : 11500 rem---------------------------- 11510 rem datei erweitern 11520 rem---------------------------- 11530 am=mx 11540 mx=mx+50 11550 print:print" erweitern der datei" 11560 print:print" bisherige groesse= "am 11570 print:print" neue gr0esse = "mx 11580 rn=mx 11590 goto11220 12000 rem------------------------------ 12010 rem aendern datensatz 12020 rem------------------------------ 12030 gosub2000:rem anzeige datensatz 12040 gosub6000:rem eingabe neue daten 12050 lz$=" ":lz=4 12060 i$=str$(i) 12070 i$=mid$(i$,2)+left$(lz$,lz-len(i$)+1) 12080 in$(i)=i$+nn$ 12090 gosub7000:rem verketten 12100 gosub8000:rem speichern 12110 return 12120 : 14000 rem ---------------------------- 14010 rem - aufteilen datensatznummer 14020 rem ---------------------------- 14030 : 14080 rn=abs(int(val(rn$))) 14100 hb=int(rn/256) 14110 lb=rn-hb*256 14130 return 14140 return 14150 : 15000 rem----------------------- 15010 rem speichern seq datei - 15020 rem----------------------- 15030 iffs<>1then15120 15040 close3:open3,8,3,"@:"+fi$+",s,w" 15050 gosub10000:rem fehlerkanal 15060 ifa1<>0then15040 15070 fori=0tomx 15080 :print#3,in$(i) 15090 :print"{home}"i;mx;in$(i) 15100 nexti 15110 close3 15120 return 15130 : 15500 rem----------------------- 15510 rem lesen seq datei - 15520 rem----------------------- 15530 close3:open3,8,3,"@:"+fi$+",s,r" 15540 gosub10000:rem fehlerkanal 15550 ifa1<>0then15530 15560 fori=1tomx 15570 :print#3,in$(i) 15580 :print" "i;mx;in$(i) 15590 nexti 15600 close3 15610 return 15620 : 30000 rem---------------------------- 30010 rem initialisierung 30020 rem---------------------------- 30030 : 30040 dl=82:rem datensatzlaenge 30050 rn=1 30060 close15:open15,8,15 30070 bl$=" " 30080 bl=len(bl$) 30090 print"{cyn}":poke53281,0:poke53280,0 30100 fr$="adr.rel" 30110 fi$=fr$+"index" 30120 dimin$(2000) 30130 return 30140 stop