allegro-C

Schnell mal eben ...

Trick 17 - 77

(aus der E-Mail-Liste ab 31.10.2006)
17 -  Suche in einer Textdatei  (schnell eine Angabe in einer TXT-Datei finden)
18 -  Datum ausrechnen
(verschiedene Möglichkeiten)

19 -  Das Ende der Such-Verzweiflung
(Doku- und E-Mail-Texte finden)

20 -  Eieruhr
(Signal nach einer bestimmten Zeit)
21 -  Schau'mer mal (Dateiverzeichnisse besichtigen)
22 -  Zwischenablage (bequeme Kopie aus dem Anzeigefeld)
23 -  Nostalgietrip
(schnell mal eben ein DOS-Fenster)
24 -  Per FLEX neue Erg.Menge aus Satznummern anlegen
25 -  Kalenderdatum auswählen lassen
(für beliebige Zwecke)
26 -  Kann man in alcarta F5 abschalten? (d.h. Internanzeige verhindern)
27 -  IMPORT.EXE soll mehrere Dateien auf einmal verarbeiten
28 -  Aktuellen Satz als Ergebnismenge nehmen (also nur 1 Satz)
29 -  Kalender als Startbild
30 -  Private LOG-Datei (automatisch eigene Aufzeichnungen machen)
31 -  FLEX-Verschachtelung (FLEX aus FLEX aufrufen und rückspringen)
32 -  LOG-Datei besichtigen (was steht momentan drin?)
33 -  Volltextsuche in eigenen FLEX einbauen (Erg.Menge per RegEx bilden)
34 -  Grunddatei mit RegEx durchsuchen (ALG-Datei verarbeiten)
35 -  Gleichlautende Flips (... und es geht doch!)
36 -  Umcodierung testen (Index-, Anzeige-, Exportparameter, p/q-Befehle)
37 -  Das Feld ohne Eigenschaften (Anzeigefeld, onprop.flx)
38 -  Opulente Hierarchien (Mehrere Formulare für hierarch. Untersätze)
39 -  Dopplung mit Doppeltrick (Erg.Menge bzw. Gesamtbank verdoppeln)
40 -  Alles entladen (Gesamte Datenbank exportieren)
41 -  Auf die Schnelle ne Tabelle (mit FLEX spaltenrichtige Listen)
42 -  Persistente Ergebnismenge (Erg.Menge dauerhaft aufbewahren)
43 -  Zwischendurch und nebenbei: Objekt 2 (Zweiten Datensatz laden/benutzen)
44 -  Textdateien umcodieren (z.B. ASCII -> ANSI oder umgekehrt)
45 -  Versionskontrolle (Hat der Anwender eine zu alte/neue Version?)
46 -  Alle Felder #nn durcharbeiten (Ohne zu wissen, wieviele und welche es gibt)
47 -  Längsten/kürzesten Satz finden (in der gesamten Datenbank)
48 -  Präzisions-Ersetzungen (In Zeichenfolgen an bestimmten Positionen etwas austauschen)
49 -  Mehr Mobilität (Fliegender Wechsel des Arbeitsverzeichnisses)
50 -  Datensatz umtopfen (in eine andere .ALD-Datei derselben Datenbank)
51 -  Gesetzt den Fall... (Werte vorbesetzen, insbes. Flags, zur Verwendung in FLEXen)
52 -  Dateien abklappern (Liste von Dateien nacheinander durchsehen und etwas damit tun)
53 -  Qual der Verzeichniswahl (Ordner auswählen. ExtraTrick: 2 oder mehr Dateitypen gleichzeitig zur Wahl)
54 -  Von Rechts wegen... (Beim Start prüfen, ob Nutzer Schreibrecht hat)
55 -  Schnelle Rechenhilfe (Lange Listen von Zahlen abarbeiten mit minimaler manueller Eingabe)
56 -  Ordnung im Feld (Mehrfacheinträge innerhalb eines Feldes alphabetisch ordnen)
57 -  Sauberes Filtern
(Dateien verarbeiten ohne unfreiwillige Umcodierung)
58 -  Strategie der kleinsten Schritte
(Datei Byte für Byte lesen und verarbeiten)
59 -  Superschnelles Einspeisen (großer Mengen neuer Datensätze)
60 -  Wiederholungstaten
(Alles über Schleifen in FLEX)
61 -  Druckregler (Wechsel der Druckparameter während der Sitzung)
63 -  Das Wichtigste zuerst (Beim Start sofort den Index erscheinen lassen)
64 -  FLEXiermaschine
(1. FLEX ohne Datenbank? / 2. Jedem User seinen _start.flx)
65 -  Umrechenwerk (Hex, Dez, Oct, Bin, Vig... Zahlensysteme umrechnen)
66 -  Daten aus dem Off (Offline-Speicher genauer inspizieren)
67 -  Schnellzählung (Wieviele Einträge sind im Index unter xyz?)
68 -  Gibt's ein Verzeichnis für das Ereignis? (Prüfen, ob Pfad c:\abc\xyz existiert)
69 -  Schiebereien mit Maus (Feldinhalt manuell ordnen per Verschiebung mit Maus)
70 -  FLEXoFlip oder FlippoFLEX (Flips per FLEX erzeugen)
71 -  Cambio (Fremdwährungen in Euro umrechnen)
72 -  Bedenke wohl die letzte Zeile ... (Was steht am Ende einer Textdatei?)
73 -  Datumsverdruß (Unbrauchbare Datumsangaben standardisieren)
74 -  Globale Dollarkrise (Den $ überall ersetzen)
75 -  Index ändern on-the-fly (Bestimmte Einträge ändern ohne "Index erneuern")
76 -  Erweiterter Aktionsradius (Erg.Menge samt verknüpften Sätzen durcharbeiten)
77 -  RAK = Register-Abschnitts-Kopie (Reg.Abschnitt in eine andere Indexdatei kopieren)




Trick 17: Suche in einer Textdatei

Aufgabe: Schnell mal eben aus irgendeiner Textdatei (Parameter,
CFG oder was immer) eine bestimmte Angabe rausfischen, per FLEX.

Jemand warf z.B. die Frage auf, ob man irgendeine Einstellung, die in
der INI-Datei steht, im Programm abfragen könne.
Manche der Werte sind ja als Sondervariablen zugänglich, andere
aber nicht, so z.B. die Angabe NewMode oder PageSize.
Was tun?
Dazu genügt ein FLEX-Einzeiler, und der sieht so aus:

x var Fa99.ini\var (b"~newmode=" e"^M" e" ")

???

Mit  Var Fa99.ini  holt man die gesamte Datei a99.ini in die iV.
Mit  var (b"~newmode="  wird die iV auf das beschränkt, was hinter
der Zeichenkette NewMode= steht, das ~ bewirkt, daß Groß/klein dabei
nicht relevant ist.
Und e"^M" schneidet am Zeilenende und am nächsten Leerzeichen ab, denn
man will ja nur die Angabe hinter dem = haben, nicht den ganzen Rest
der Datei. (die Zeichen ^ und M gibt man einzeln ein, nicht Strg+M)

Wer noch weiß, daß FLEX von "flexibel" kommt, den wundert sowas
nicht... Und auf INI begrenzt ist es klarerweise auch nicht,
denn hinter dem F darf irgendein Dateiname stehen. Nur nicht
größer als 256 K darf sie sein.
ZusatzTip: Mit sho IV kann man das Ergebnis im Anzeigefeld sehen.

----------------------------------------------------------------------

Trick 18: Datum ausrechnen

Wie rechnet man schnell mal eben ein Datum aus?
Z.B. bei folgenden Fragen:

1. Welches Datum haben wir heute in 100 Tagen? (Die Frage kommt immer
    bei einem Regierungsantritt hoch!)

2. Welches Datum ist 53 Tage vor Weihnachten?

3. Auf welches Datum fiel Ostern 1900?

4. Wieviele Tage sind verstrichen seit dem 11.9.2001?


Das geht so:

1.
X Day +100\mes

2.
x Day 20061225-53\mes

3.
X gauss   oder   X kalender

4.
x day 20061102-20010911\mes


----------------------------------------------------------------------

Trick 19 : Das Ende der Such-Verzweiflung

1. Aufgabe: Man will schnell mal eben was finden, was mal irgendwann
   irgendwo in irgendeinem allegro-Papier gestanden hat oder in
   einer E-Mail aus der Liste - aber wo?

Lösung:  In das Schreibfeld eingeben:
         www.allegro-c.de/az.htm

Oben links ist ein neues Eingabefeld, mit dem dann nichts anderes als
eine Google-Suche in der allegro-Domäne incl. E-Mail-Liste ausgelöst
wird. Klar, man konnte ja schon längst in Google nach allegro-Listen-
Inhalten suchen! Die gingen dann aber mitunter unter.


2. Aufgabe: Eben mal schnell bei der Library of Congress was
            nachschauen

Lösung:  http://catalog.loc.gov           Katalogdaten
             http://authorities.loc.gov     Normdaten


Pfiffige LeserInnen schließen messerscharf, und es stimmt sogar:
Ins Schreibfeld kann man auch jede andere gültige URL
eingeben. Ungültige kann man auch eingeben, aber auf
eigene Gefahr ...
Wenn die URL mit www. anfängt, kann man auf http:// verzichten.

Was da in Wahrheit passiert, ist dies: a99 merkt, daß die Eingabe
kein gültiges Datenfeld ist. Dann reicht es die Eingabe weiter
an den FLEX  onerror.flx. Der stellt fest: Oho, eine URL! Und reicht
sie weiter an JanaS.
Nun gibt's da aber diejenigen, die an der Stelle nicht JanaS wollen,
sondern ihren StandardBrowser. Dann ist  onerror.flx  so zu ändern:

:www
var "start http://" #uxE
Dos
var ""
end

:http
var "start " #uxE
Dos
var ""
end

--------------------------------------------------------

Trick 20 : Eieruhr

Aufgabe: Man will in 5 Minuten ein dezentes Signal, weil dann
irgendwas wichtiges nicht verpaßt werden darf. Wie kann man
sowas schnell mal eben arrangieren, wenn keine Eieruhr zur Hand ist?

Lösung: Im Schreibfeld folgendes eingeben

x slice 300000=1x mes ACHTUNG!

???
5 Minuten sind 300000 Tausendstelsekunden (5 * 60 * 1000).
Die 1 bedeutet, daß das Signal nur 1mal kommen soll und
nicht etwa alle 5 Minuten - was passieren würde, wenn
man i (für "immer") hinschreibt statt 1.
Da Signal besteht in einer MessageBox mit dem Inhalt ACHTUNG, die
dann pünktlich aufgeht. Mit "Mes" statt "mes" kommt eine weniger
aufdringliche Box in der linken oberen Ecke, die dann nach 10 Sek.
von selber wieder verschwindet.
Hinter dem x kann aber auch irgendein anderer FLEX stehen.
Während der 5 Minuten kann man ansonsten unbekümmert weiterarbeiten.

Mehr dazu:  h xsleep

Kompliziertere Anwendung:  h memo
(mit V26 verbessert und auch in die N-Datenbank eingebaut)

Empfehlung: Die memo-Anwendung an der DemoBank ausprobieren und
bei Bedarf auch mit dieser zusammen einsetzen, um die eigene DB
damit nicht zu befrachten)

--------------------------------------------------------

Trick 21 : Schau'mer mal

Aufgabe: schnell mal eben schauen, was auf dem Arbeitsverzeichnis
so alles herumliegt. Oder auf einem anderen. Ohne Explorer.

Lösung:
         d a     eingeben - die Liste der Dateien erscheint
                   aber es gibt noch mehr:
         d d     Datenverzeichnis       
         d p     Programmverzeichnis
         d f     FLEX-Verzeichnis
         d html  HTML-Verzeichnis

         d t     Temporäres Verzeichnis   

Leichter zu merken ist: nur  d eingeben und dann wählen.

Aber Sie wollen NOCH mehr, z.B.
Welche CFG-Dateien auf dem Arb.Verz. rumliegen?

dir *.cfg   eingeben - wie im DOS-Fenster

Aber man bekommt dann nicht nur diejenigen auf dem Arb.Verz., sondern
auch auf dessen Unterverzeichnissen vorgelegt, sauber geordnet.
Wählt man eine aus, kann man sie gleich anzeigen lassen, editieren,
löschen, umbenennen, kopieren. Für solche Zwecke muß man also
nicht mehr zwingend in den Explorer oder in das DOS-Fenster gehen...

Aber wenn es nicht das Arb.Verz. sein soll, sondern c:\daten?

Dann:  dir c:\daten   oder z.B.  dir c:\daten\*.cfg

und man sieht alle Dateien auf c:\daten bzw. alle dort liegenden
CFG-Dateien, plus diejenigen auf allen Unterverzeichnissen, die
an c:\daten dranhängen. Tja.
(Beachte: hier keine Verdopplung des \ !)

Für Neugierige:
Dahinter steckt dirs.flx, aufgerufen von onerror.flx.

--------------------------------------------------------

Trick 22 : Zwischenablage

Aufgabe: Schnell mal eben alles, was im Anzeigefeld steht, in die
Zwischenablage kopieren, damit man es gleich danach in ein Word-
Dokument einkopieren kann.

Lösung 1:  Ins Anzeigefeld klicken und Strg+a Strg+c

Lösung 2:  Wenn man das sehr oft machen will, dann dies eingeben:

           #uX9 x ccopy d

           Dann braucht man nur jeweils  Alt+9  zu drücken, um dasselbe
           zu erreichen. Und dazu braucht man nicht erst in das
           Anzeigefeld zu klicken.

Dann wie gewohnt in Word o.a. den Cursor an die richtige Stelle und
Strg+v - voilà!


--------------------------------------------------------


Trick 23 : Nostalgietrip

Aufgabe: Schnell mal eben ein DOS-Fenster aufmachen
         (korrekter: eine "Eingabeaufforderung" öffnen)
         Denn der Weg über "Start / Programme / Zubehör" ist zu lang.

Lösung:  Dos cmd   eingeben (im Schreibfeld von a99)
         Man ist dann schon automatisch in seinem Arbeitsverzeichnis
         und kann dort tun und lassen, was man will...
         Im DOS-Fenster  exit  eingeben, dann geht's wieder zu.
         (Bleiben Sie locker, dabei geht nichts kaputt!)

Wenn man im DOS-Fenster nicht (mehr) recht weiß, was für Befehle man
da geben kann: Im Füllhorn gibt es den Punkt "Befehlsliste" neben
"MS-DOS". Da steht alles drin.

Wer im Dos-Fenster nur ein bestimmtes Programm starten will, kann
auch dessen Namen, mit "Dos " davor, ins Schreibfeld eingeben!
Versuchen Sie mal den vollkommen ungefährlichen Befehl "Dos cp".
(Tip: mit Alt+x kommen Sie da wieder raus, falls Sie das Ding noch
 nie gesehen haben...)

--------------------------------------------------------


Trick 24: Per FLEX neue Erg.Menge aus Satznummern anlegen


Aufgabe: 1. Mehrere einzelne Satznummern zu einer Erg.Menge vereinigen
             2. Einen ganzen Bereich von Satznummern zusammenfassen

1. Mehrere einzelne Nummern
Der Befehl find #a,b,c geht nur bei avanti, um aus den Satznummern
a,b,c eine Ergebnismenge zu machen. Das kommt, weil a99 das '#'
als Aufforderung deutet, sich NUR um die dahinter stehenden Satznummer
zu kümmern und sonst gar nichts, wobei eine bestehende Erg.Menge
unangetastet bleibt.

Und so kann man a99 austricksen:

find per xyz or #a,b,c

xyz ist ein nicht existenter Name, d.h. der erste Teil
des Befehls liefert die leere Menge. Das "or" wird dennoch
ausgeführt, wie man ja auch erwartet, und an der Stelle
klappt dann die Angabe #a,b,c!
Es ist sogar möglich, statt "per" irgendeinen nicht
existenten Registernamen zu verwenden. Es funktioniert
z.B. auch
find ... ... or #a,b,c

Was hinter "find" steht, kann auch vorher per var "..."
aufbereitet werden, dann in der nächsten Zeile nur "find"

2. Ganze Nummernbereiche
Wenn man die Sätze 1000 bis 2000 als Erg.Menge haben will, ist
Methode 1 ungeeignet. Im DOS-Programm PRESTO war es ganz einfach:

  Anzeigebildschirm mit ganz beliebigem Satz
  x #1000 eingeben: Satz 1000 erscheint
  (   tippen - Nummer 100 wird gemerkt
  x #2000 eingeben: Satz 2000 erscheint
  )  tippen - fertig ist die Ergebnismenge!

Anders, aber nicht schwieriger ist es mit a99 - man macht es jetzt so:
(ab V28.4)

X ergnum
Eine Eingabezeile erscheint, "Satznummern? (z.B. 1000-2000)"
1000-2000   eingeben
fertig, die Erg.Menge erscheint.

Der Trick steckt also im neuen FLEX ergnum.flx. Der ist gar nicht mal
so lang, hier haben wir den wichtigen Teil, samt Kommentar:

  -----------------------------------------------------
  ERGNUM.FLX : Ergebnismenge aus Nummernbereich bilden
  2008-05-21
  ...
ask Satznummern? (z.B. 1000-2000)
if "" end
ins #unE
if not %-% mes BINDESTRICH FEHLT;end

  Zaehler auf den Anfangswert setzen
Z=#unE

  Datei f. externe Erg.Menge oeffnen
open x x.set
  Ueberschrift
wri "Saetze " #unE n

  Schleife zur Abarbeitung von #unE bis #unL
:loop
  Satznummer schreiben, neue Zeile
wri Z n
  erhoehen
Z+1
if Z<#unL jump loop
  #unL ist erreicht, dann Datei zumachen
close x

  und einlesen als ext. Erg.Menge
read set x.set
  zeigen
show list
end
  --------------------------------------------------------

Es wird also, und das ist der Trick, eine Datei x.set angelegt, in der
dann nichts anderes steht als eine Überschriftszeile und dann die
Liste der Nummern von 1000 bis 2000. So eine Datei entsteht auch, wenn
man über das Menü "Datei / DOS-Programm" PRESTO aufruft und damit dann
eine Ergebnismenge per F4 ausgibt. Mit  read set x.set  kann man
die sog. "externe Erg.Menge" einlesen - ob sie nun von PRESTO angelegt
wurde oder sonstwie.

--------------------------------------------------------


Trick 25: Kalenderdatum auswählen lassen

Aufgabe: Der Nutzer soll ein Datum eingeben. Damit dabei kein
                Fehler passiert, soll die Kalenderfunktion zum Einsatz kommen.

Lösung: Im Datenverzeichnis einen FLEX  term.flx  bereitstellen, dann
        mit  exec kalender  die Kalenderfunktion aufrufen.
        Wenn der Nutzer ein Datum anklickt, wird term.flx gestartet,
        und zwar mit der Tageszahl in der iV und dem Monat in der Form
       
JJJJMM  in der Variablen #uU1

Natürlich kann es sein, daß man im DbDir schon eine andere term.flx
zu liegen hat. Wie man dies dann löst, kann man am Beispiel
nel.flx
studieren. Alles ausführlich kommentiert.
Die DemoBank hat einen FLEX namens  term.flx, wo man die Nutzung
exemplarisch sehen kann.


--------------------------------------------------------

Trick 26: Kann man in alcarta F5 abschalten?

Das nicht, aber man kann in den Anzeigeparametern den Abschnitt
#-(
so ändern, daß dann etwas erscheint, was der Nutzer sehen darf
oder soll.
Im einfachsten Fall:

#-(
#uzp +C c"alc" e0
  Rest unverändert belassen
...

Dann braucht man keine eigenen Anzeigeparemeter für alcarta,
denn #uzp ist nur in alcarta mit "alc" belegt, und dann passiert
bei F5 eben scheinbar nichts, weil #-C der Startpunkt für die
Normalanzeige ist.

---------------------------------------------------------

Trick 27 : IMPORT.EXE soll mehrere Dateien auf einmal verarbeiten

Beim Indexieren geht es mit Option  -d*xyz
und dann werden alle Dateien, deren Namen mit xyz beginnen,
genommen und indexiert.

Beim Importieren geht das nicht. Warum? Weil der * dabei auch
als erstes Dateinamenzeichen eingesetzt werden kann, um alle
Dateien zu zeigen, deren Namen mit irgendeinem Zeichen beginnen.
(So etwas hat man beim Indexieren nie gebraucht.)

Dennoch ist es möglich. Das Problem wurde vor sehr langer Zeit
bereits gelöst und die Lösung war daher in Vergessenheit
geraten. Einsichtnahme in die alten Quellen legte den
altmodischen Trick wieder frei:

Man nimmt + statt *  -- Dann geht's.

Also z.B.

  import -f5 -d+xyz*.?lg ...

Damit erwischt man alle Dateien, deren Namen mit xyz beginnen
und deren Typ ?lg ist (.alg, .blg, ...)

Korrektur der online-Doku wird erfolgen.

-------------------------------------------------------------

Trick 28 : Aktuellen Satz als Ergebnismenge nehmen

Aufgabe: Eine bequeme Funktion, um den aktuellen Satz zur Ergebnismenge
                zu machen (die dann also nur aus diesem einen Satz besteht)

Lösung:  In  onf8.flx  gibt es bereits die beiden Funktionen
            + : Aktuellen Satz zur Erg.Menge hinzunehmen
            - : Aktuellen Satz aus Erg.Menge herausnehmen

          Um diese noch zu erweitern, ergänzt man zunächst eine neue
          Zeile VOR diesen beiden. In onf8.flx sieht das dann so aus:

var + n "Aktuellen Satz als Erg.Menge nehmen (nur diesen einen!)"
var + n "+ : Aktuellen Satz zur Erg.Menge hinzunehmen"
var + n "- : Aktuellen Satz aus Erg.Menge herausnehmen"

Sodann, einige Zeilen tiefer, ist ein Sprungbefehl zu ergänzen:
(die mittlere dieser drei Zeilen)

if "h" Fam;end
if "Aktu" jump akterg
if "A" help alfa;end

Und ganz am Ende fügt man diese Zeilen an:

:akterg
var "or #" i
find
end

Fertig! Mit F8 a Enter bildet man nun nach Belieben eine Erg.Menge aus
dem aktuellen Satze, mit F8 + Enter  bzw.  F8 - Enter  ergänzt man einen
weiteren Satz zur Erg.Menge bzw. nimmt ihn wieder heraus - das war ja
bisher schon drin und bleibt unverändert.

SuperTip: Um diese Änderungen vorzunehmen, können Sie onf8.flx im
           Anzeigefeld bearbeiten:
--  h onf8.flx   eingeben
--  Änderungen vornehmen (copy&paste aus dieser Mail heraus)
--  Alt+s  (Speichern) und Button [Speichern]

Nachtrag
Die Geschichte mit der Bildung einer Ergebnismenge aus nur einem
einzigen Satz und dem Hinzufügen weiterer Sätze ist nicht
vollständig ohne folgende Hinweise:

Manuell gibt es zwei Methoden, eine Erg.Menge aus nur einem
Satz zu bilden:

1. Im Register kann man jede Zeile mit nur einem Eintrag zu
    einer Erg.Menge mit nur diesem einen Satz machen, wenn
    man den Button [Erg] drückt, oder Alt+e
    Weitere Sätze oder auch die zu einer Mehrfachzeile gehörigen
    Einträge fügt man mit / hinzu = Button [Oder]

2. Wenn man die "Lesezeichen" ansonsten nicht braucht, kann man
    diese Funktion ersatzweise heranziehen, sie ist dann bequemer
    als die (gestern geschilderte) mit F8:
    -- Zuerst mit Besen die Lesezeichen wegfegen
    -- den gewünschten Satz mit Button [Lesezeichen] behandeln
    -- weitere Sätze desgleichen.
    -- Mit dem Button rechts neben Lesezeichen aktiviert man die
       Sonder-Erg.Menge namens "Lesezeichen", d.h. sie wird gezeigt
    per FLEX:  find s1  macht die Lesezeichen zur aktuellen Erg.Menge
    Mit [Oder] im Index kann man die Lesezeichen, wenn sie gerade
    die aktuelle Erg.Menge sind, erweitern - dann entsteht aber eine
    normale Erg.Menge, und die eigentlichen Lesezeichen bleiben
    unverändert.

Zur Erinnnerung:
Jede Erg.Menge, auch die Lesezeichen, kann mit der [Entf.]-Taste
(gleichwertig: [Entf]-Button) um ausgewählte Sätze verkleinert
werden. Erst bei Schließen des Kurzlistenfensters werden diese dann,
nicht ohne Nachfrage, tatsächlich herausgenommen. Vorher erscheint
vor den betr. Zeilen nur "DEL".



-------------------------------------------------------------

Trick 29 : Kalender als Startbild

Aufgabe: Beim Start der Datenbank soll als erstes der Kalender
          erscheinen.

Lösung: in der Datei  _start.flx  als letzten Befehl diese Zeile einbauen:
         exec kalender

Wer die DemoBank gerne nebenbei als Werkzeug oder Testfahrzeug nutzt,
kann dies in vier schnellen Schritten ausführen, auch wenn man noch
nie eine Zeile in eine Datei eingebaut hat:

1.  h _start.flx  eingeben, die Datei erscheint in der Anzeige
2.  Strg+f  h cat   : Die Zeile  h cat  erscheint
3.  Diese Zeile überschreiben durch  exec kalender
4.  Alt+s Enter Enter: Datei wieder speichern

Zusatztip: Wer nur schnell mal eben den Kalender vom Mai 1995 sehen
will, gibt ein:
     X kalender 199505
Wohlgemerkt: kein Zeichen zwischen Jahreszahl und Monat!

-------------------------------------------------------------


Trick 30 : Private LOG-Datei

Aufgabe: Jeden Satz, den man abgespeichert hat, gleich nach dem
          Speichern schnell noch eben in eine eigene Datei kopieren.
          Das könnte sinnvoll sein, wenn man bestimmte Auswertungen
          machen will.

Lösung:  Eingriff in den FLEX  onput.flx
          Dieser wird beim manuellen Speichern (nicht beim Speichern
          mit  put  in irgendeinem FLEX oder bei "Global"-Aktionen!)
          ausgeführt.
          Darin steht ein Befehl  put
          Gleich daran anschließend kann man z.B. einbauen:

          open x +privat.log
          wri ...
          close x

          Und statt  wri ...  dann alles, was in der LOG-Datei stehen
          soll - es muß nicht der komplette Satz sein, denn der wird
          ja eh in der normalen LOG-Datei gesichert.
          Das + beim open-Befehl stellt sicher, daß die Datei verlängert
          wird und nicht jedesmal überschrieben.
ZusatzTip:
          Mit  h privat.log kann man sich jederzeit die private Datei
          anschauen.
SonderTip:
          Im Anschluß an den put-Befehl kann natürlich auch irgendwas
          ganz anderes ausgeführt werden...

Hinweis: Im Offline-Speicher (Alt+q) sammeln sich ALLE im Verlauf
          der Sitzung bearbeiteten Datensätze, auch die bei globalen
          Befehlen behandelten, die in einem FLEX mit put gespeicherten
          und die noch nicht gespeicherten, aber schon veränderten.
          Mit "download off" kann man jederzeit diese Datei selber
          in ihrem momentanen Zustand in eine ExportDatei speichern
          lassen.

-------------------------------------------------------------




Trick 31 : FLEX-Verschachtelung

Immer mal wieder wird gewünscht, aus einem FLEX heraus einen
zweiten aufrufen zu können, aber so, daß es nach dessen Ende
im selben FLEX weitergeht.
Mit dem Befehl

exec zweit
:weiter

wird zwar  zweit.flx  gestartet, aber wenn der endet, geht
es nicht mit der Zeile  :weiter  weiter, sondern gar nicht,
weil zweit.flx eben nicht automatisch zurückkehrt. (Der FLEX-
Aufruf ist, programmiertechnisch gesagt, nicht rekursiv.)

Es gibt zwei Tricks, um diesem scheinbaren Mangel abzuhelfen:

1. include
Man bindet den aufzurufenden FLEX einfach mit ein, und zwar so:

include zweit.flx
:weiter

Dann verhält es sich so, als stünde der gesamte Text des
FLEXes zweit.flx an der Stelle, wo "include..." steht.
Wenn zweit.flx so gestaltet ist, daß er bis zu seinem Ende
läuft und dort kein Befehl "end" steht, geht es dann zwanglos
mit der Zeile  :weiter  weiter.
Nachteile:
1. Gefahr, daß in zweit.flx Sprungmarken vorkommen, die es auch
in erst.flx gibt - dann passieren Fehler.
2. höchstens bei sehr großen FLEXen eine Einbuße an
Leistung. Der interne Speicher für die auszuführende FLEX-Datei
ist 64K groß, dabei zählen Kommentare nicht mit. Das ist eine
Menge. Der längste mitgelieferte FLEX ist files.flx mit 18K,
aber inclusive Kommentare!


2. Rückaufruf des ersten FLEXes
Nichts spricht dagegen, in einem aufgerufenen FLEX einen weiteren
exec-Aufruf unterzubringen, um den ersten wieder fortzusetzen.
Das könnte etwa so aussehen:
Wenn der aufrufende FLEX etwa  erst.flx  heißt, schreiben wir
oben an den Anfang

  zuerst die Variable #urC löschen!
#urC
ins #urC     // iV-Inhalt in #urC speichern
var #urC     // pruefen, ob das mit "jump" anfaengt
if "jump" var #urC(b"jump ");jump
...   // beliebiger Inhalt
exec zweit.flx first;weiter
:weiter

Und in den aufgerufenen  zweit.flx  schreiben wir rein:

#urC
ins #urC
if #urC jump start
:anfang
  Normaler Anfang
...
:start
  hier anfangen, wenn mit  exec xyz  aufgerufen
...
:rueck
var #urC(e";") " jump " #urC(b";")
exec


Wenn die Zeile  :rueck  erreicht wird, erfolgt der Rücksprung zu
erst.flx, wo die zurückgegebene Sprungmarke verwertet wird, um dann
dorthin zu springen. Der Aufruf lautet dann in Wirklichkeit
   exec jump weiter
FLEXologen erkennen leicht, wie sie dies Schema weiter aufbohren
können, um die Sache weiter zu FLEXibilisieren.
Die Variable #urC sollte selbstredend nicht zugleich irgendwo für
andere Zwecke verwendet werden.

Die Übergabe von Werten ist natürlich immer auch mit Variablen
möglich,  die hier gezeigte Methode ist nur eine von vielen
denkbaren Varianten.
Nachteile:
1. Etwas umständlicher
2. Die Variable #urC könnte zufällig doch einmal für
andere Zwecke irgendwo benutzt werden, d.h. es könnte eine Neben-
wirkung geben.


-----------------------------------------------------------

Trick 32: LOG-Datei besichtigen

Aufgabe: Schnell mal eben schauen, was in der LOG-Datei steht.

Warum sollte man das tun? Besonders dann, wenn man aus Versehen einen
Satz gelöscht hat.

Lösung:
Auf der Quick-Liste findet man gleich zwei Möglichkeiten, aber nur die
zweite ist die echte:

1. LOG-Datei: Zuletzt bearbeitete Sätze zeigen
----------------------------------------------
Dann kommt zuerst die Supervisor-Seite (h super). Auf der gibt es
als 4. Menüpunkt  "LOG-Datei besichtigen"
mit zwei Unterpunkten:
 1a:  Zuletzt bearbeitete Sätze
      Damit werden die letzten 20000 Byte der Logdatei genommen und NUR
      die darin steckenden bearbeiteten Sätze aufbereitet und als
      Erg.Menge gezeigt. Damit hat man die Daten NICHT so vor sich, wie
      sie wirklich in der LOG stehen, sondern in der Datenbank. Das be-
      deutet: ein mehrfach bearbeiteter Satz ist hier nur in seinem
      letzten Zustand zu sehen. Zudem: die neuen und die gelöschten
      Sätze sind dabei nicht berücksichtigt.
      Der Punkt müßte heißen: Zuletzt neu erfaßte Sätze.

 1b:  Neue Daten von heute
      Dabei wird nur die Erg.Menge der am betr. Datum angefallenen
      NEU-Sätze gebildet! Bearbeitete und gelöschte fehlen.
      (Klappt nur, wenn das Erf.Datum im Reg, 9 unter D steht)

Beides ist somit KEIN Einblick in die LOG-Datei.
Diesen gewährt NUR der zweite Punkt der Quick-Liste, und genauso,
wenn Sie im Supervisor-Menü direkt auf LOG klicken:

2. LOG-Datei besichtigen (als externe Erg.Menge)
------------------------------------------------
   Die echte LOG-Datei wird dann in eine Offline-Datei umgewandelt
   und diese dann gezeigt (wie beim Menüpunkt "Weitere Offline-Datei
   laden".
   ACHTUNG: Kann länger dauern, abhängig von der Größe der Datei!

   Die Sätze haben dann alle ganz vorn ein Feld #u1, in dem ein
   Buchstabe steht:

   N : Neuer Satz
   K : Korrigierter Satz
   D : Gelöschter Satz (deleted)

   Und das alles genau in der Reihenfolge, wie die Bearbeitung
   tatsächlich gelaufen ist. Von einem mehrfach bearbeiteten Satz
   findet man also alle Fassungen.
   Jeden dieser Sätze können Sie von der #u1 befreien, ändern und
   als Neusatz speichern. Das ist besonders praktisch, wenn man einen
   Satz aus Versehen gelöscht hat und ihn anders nicht mehr findet.

Vorsicht:
---------
Wenn man die Funktion 2. benutzt, sollte man

vorher den Offline-Speicher löschen, d.h. bearbeitete Sätze zuerst
       alle speichern und dann den Befehl   x erase off   geben

hinterher ebenfalls den Offline-Speicher mit  x erase off  löschen,
weil sonst, wenn man nicht am Ende der Sitzung aufpaßt, der Inhalt des
Offline-Speichers insgesamt als Neusätze gespeichert würde.

-----------------------------------------------------------------------

Trick 33: Volltextsuche in eigenen FLEX einbauen

Warum? FLEX ersetzt zunehmend die alten Batchdateien! Und eine der
wichtigsten Komponenten in der allegro-Umgebung ist das Volltext-
Suchprogramm SRCH. Mit einem ganz einfachen Aufruf:

srch -f4 -s<suchbegriff> -e<expar>/<outfile> ...

konnte und kann man eine Datenbank volltextdurchsuchen und zugleich
die Treffer in jedem gewünschten Format exportieren lassen.
Diese hochwirksame Methodik wird auch in FLEX gebraucht! Und es gibt
sie jetzt:

Lösung: Man baut diese Zeilen ein:

#u!!<suchbegriff>
perf ftr
sho list
...
end

include ftr.inc


Die neue Datei "ftr.inc" enthält die komplette Prozedur für die
Volltextsuche in der gesamten Datenbank. Bei Rückkehr stehen die
Ergebnisse in der aktuellen Ergebnismenge, die man sofort anzeigen
lassen kann (show list) oder sonstwie verarbeiten, vor allem
natürlich exportieren (dow set).
Bei Mißerfolg wirft  ftr.inc  die Meldung "nichts gefunden" aus.
Wer will, kann sie herausnehmen.
Selber testen kann man den Mißerfolg so

var Z
if Z<1 jump misserfolg
...

denn Z ist der Trefferzähler.

Und wie steht's mit der Geschwindigkeit? Auf Systemen mit schnellen
Platten ist ftr deutlich schneller als SRCH, generell aber nicht
langsamer.

In  ftr.inc  findet man die nötigen Kommentare. Die darin
verwendeten Sprungmarken beginnen alle mit :ftr: und sind deshalb
nicht in Gefahr, mit anderen im eigenen FLEX zu kollidieren!


Aber was bedeutet "ftr"? Es kommt von Full Text RegEx.

----------------------------------------------------


Trick 34: Grunddatei mit RegEx durchsuchen

Warum?
Schon bisher konnte man eine Grunddatei zuerst einlesen (mit "Datei /
Weitere Offlien-Datei laden") und dann mit einer Eingabe von
+xyz  im Suchbefehlsfeld durchsuchen lassen! Dies jedoch ohne
die RegEx-Syntax, sondern nur automatisch mit Index-Umcodierung.

Für diese Standardaufgabe des alten SRCH gibt es jetzt auch einen
Ersatz mit der neuen RegEx-Methode.
Mitgeliefert wurde dafür eine Datei  algsrch.inc, die das
nötige Unterprogramm enthält.
Dem Unterprogramm muß man zwei Werte übergeben: den Namen der Datei
und den Suchbegriff. Das geschieht mit den Variablen #u!f und #u!!.

Lösung:
Sagen wir, die Datei  stuff.alg  soll nach dem Begriff  xyz  durchsucht
werden. Dann braucht man im eigenen FLEX nur zu schreiben:

#u!! xyz
#u!f stuff.alg
perform algsrch
if Z>0 jump treffer
mes Leider nichts gefunden
end
:treffer
...

include algsrch.inc


Was man mit den Treffern macht, ist natürlich völlig frei.
Mit Alt+q kann man sie durchsehen, denn sie stehen dann im
Offline-Speicher. Einzelne oder alle kann man in die Datenbank
speichern. Oder mit  dow off  alle exportieren. Damit hat man den
vollen Ersatz für das DOS-SRCH-Programm, das ja in vielen
Batchdateien dazu genutzt wird, Grunddateien in anderem
Format zu exportieren.

SonderTip: Mit  #u!! 0  kriegt man den gesamten Inhalt der
           Grunddatei.
           (Genauso war es mit SRCH -f4 ... -s0 )

----------------------------------------------------------------------


Trick 35: Gleichlautende Flips


Aufgabe: Mehrere gleichlautende Flips präsentieren, die aber
unterschiedliche Dinge tun.

Was ist das Problem? Flips funktionieren so, daß die sichtbare
(meistens blau unterstrichene) Zeichenfolge beim Anklicken
verglichen wird mit den in den Variablen #uY? hinterlegten
Zeichenfolgen. Die erste Übereinstimmung wird genommen,
sagen wir #uYk. (Mit Alt+r kann man sie alle sehen und diese
Dinge kontrollieren!) Dann wird #uZk hergenommen, als FLEX
interpretiert und ausgeführt. Daher sind, einfach weil
immer die ERSTE Ubereinstimmung genommen wird, gleichlautende
Flips nicht möglich - ausgeführt wird immer nur der erste.

Der Trick besteht darin, daß der FLEX zuerst die TextZEILE
auswertet, in der geklickt wurde. Und in der Textzeile muß
ein Kriterium stehen, das dann eindeutig ist und das eindeutige
Funktionieren ermöglicht.
Die Textzeile auswerten? Das geht mit

var zc

schon hat man sie in der iV und kann machen damit, was immer
man will.

Dieser Trick wird ausgenutzt in dem neuen FLEX 
xgrep.flx,
der mit V27.1 kommt. Er dient dazu ausgewählte Textdateien
zu durchsuchen mittels RegEx-Methodik, z.B. Importparameter,
CFG-Dateien oder Verlautbarungen. Wenn man letztere wählt
und als Suchbegriff eingibt:  isbn + 13
dann kommt heraus:

DATEI: c:\allegro\help\vb184
  show  -- c:\allegro\help\vb184@309 - Ab 2007 wird eine 13stellige,...

DATEI: c:\allegro\help\vb193
  show  -- c:\allegro\help\vb193@84 - Man gibt die ISBN so ein, wie sie...

DATEI: c:\allegro\help\v258\vb184
  show  -- c:\allegro\help\v258\vb184@309 - Ab 2007 wird eine 13stellige, ...

***** 3 Vorkommnisse von isbn + 13 gefunden


Und in jeder Zeile ist "show" ein Flip - 3mal dasselbe! Es können aber
auch 100 sein oder mehr!
Die Zeile enthält aber jeweils den Dateinamen und die Zeilennummer
(hinter @) innerhalb der Datei! Das ist eindeutig. Aus dem Inhalt
von  zc  kann man also präzise isolieren, welche Datei es ist und
welche Zeile, und der Klick auf "show" liefert genau diese Datei
in der Anzeige, positioniert auf genau die Zeile.

Pfiffige werfen jetzt ein: Aber zwei gleichlautende Flips dürfen dann
nicht in derselben Zeile stehen! Doch, wenn diese genügend geschickt
gestaltet ist. Denn  var zc  liefert die Textzeile, aber an der
exakten Stelle, wo geklickt wurde, ist __ eingefügt, daher kann
der FLEX dann genau herausfinden, welcher von mehreren Flips angeklickt
wurde. Wie gesagt, die Zeilengestaltung muß dafür gut durchdacht
sein, damit man mit Manipulationsbefehlen das Kriterium herausfischen
kann, um das es geht.

Wir denken, das neue  xgrep  wird sehr populär werden, auch bei
jenen, die sich mit FLEX weiter nicht befassen.
Die bisherige Verlautbarungssuche wird auch hinsichtlich
Schnelligkeit übertroffen.

----------------------------------------------------------------------


Trick 36: Umcodierungen testen


Aufgabe: Schnell mal eben prüfen, ob eine Umcodierung korrekt
         funktioniert.

Warum?  Im Index sieht man "mueller" statt "Müller". Das liegt daran,
        daß die Sonderzeichen über eine Tabelle umgewandelt werden.
        Auch in den Anzeige- und Exportparametern gibt es solche
        Tabellen. Darin können Fehler stecken oder unerwünschte
        Umwandlungen, die man ändern möchte. Jede Parameterdatei
        kann aber zwei Tabellen haben, die mit den p- bzw. q-
        Befehlen definiert werden. (Handbuch 10.2.4.1)

Methode 1 (schon lange existent): F7
---------
   In irgendeinem Datensatz ein Feld eingeben, in dem die fraglichen
   Sonderzeichen vorkommen. Dann F7. (Vorher speichern, wie bei DOS,
   ist nicht nötig!) Man sieht, was dabei rauskommt.
   In der Anzeige sieht man zudem, wie die Zeichen in den Display-
   parametern umgewandelt werden.
   Nachteil: An dieser Stelle muß man wissen, über welche der beiden
   Tabellen (p oder q) das betr. Feld für Index bzw. Anzeige
   umcodiert wird.
  

Methode 2 (NEU in V27): Der FLEX-Befehl  xcode
----------------------
   Einen Befehl in dieser Form eingeben:

      x var "zeichenfolge"\xcode ab\mes

   Dabei gilt:
       zeichenfolge: diejenigen Zeichen, deren Umcodierung man
                     prüfen will
       a: einer dieser Werte:
          d : Display-Parameter
          x : Export-Parameter
          i : Index-Parameter

       b: einer dieser beiden Werte
          p : p-Tabelle (incl. der P-Befehle)
          q : q-Tabelle (incl. der Q-Befehle)

   Damit kann man nun jede Tabelle ganz gezielt und genau testen.

   UND: In eigenen FLEXen kann man die Tabellenumwandlung mit ihren
        vielen Möglichkeiten einsetzen, um Zeichenfolgen in jeder
        denkbaren Weise umzuwandeln. Bisher mußte man umständlich eine
        Parameterdatei mit einem Abschnitt machen, in dem dann die
        Umcodierung ausgeführt wurde. Dazu wurde der Befehl  dow wX
        gebraucht. Jetzt ist sowas viel leichter.

   Zum Ausprobieren geben Sie mal:

   x var "äöüßÄÖÜ"\xcode iq\mes
   und dann dasselbe mit ip .


----------------------------------------------------------------------


Trick 37: Das Feld ohne Eigenschaften


Frage: Wieso passiert eigentlich nichts, wenn man im Kontextmenue
           (rechte Maustaste) des Anzeigefelds von a99 den Punkt
           "Eigenschaften" wählt?

Antwort: Einerseits: Was sollte denn auch Großartiges passieren?
           Gäbe es hier einen Bedarf, er wäre doch längst artikuliert
           worden!
         Andererseits: Sie haben es selber in der Hand, an der
           Stelle genau das passieren zu lassen, was Ihnen da
           vorschwebt: Sie schreiben erstens einen FLEX, der das
           nämliche tut. Zweitens, und das ist nun der Trick,
           nennen Sie diesen FLEX  onprop.flx.

Das ganze Geheimnis ist also, daß dieser Menuepunkt einer von
jenen ist, die einen "On-FLEX" auslösen, und zwar in diesem Falle
den des Namens onprop.flx.
Da wir keinen solchen mitliefern - passiert bisher nichts.
Wenn ein On-FLEX nicht existiert, werden FLEXperten jetzt einwerfen
(denn so steht's in flex.rtf), dann gibt es eine Standard-Aktion.
Richtig, bei den anderen ist das so, z.B. onprint.flx und
onput.flx. Ist dieser eine Fall eine Ausnahme? Je nachdem - wenn
man die leere Aktion (das Nichtstun) auch als Aktion gelten läßt,
dann nicht.
Jetzt überlegen Sie fieberhaft: Was könnte man da Schönes
passieren lassen? Sehen Sie - uns ist auch noch nichts eingefallen,
sonst hätten wir einen onprop.flx ja längst gemacht. Wir setzen
als Preis 10 Punkte für die Anwartschaft auf das Silberne Doppel-
kreuz aus für denjenigen, der den originellsten onprop.flx
erfindet!

----------------------------------------------------------------------


Trick 38: Opulente Hierarchien

Aufgabe: Für den hierarchischen Untersatz mehr als ein Formular
ermöglichen.

Warum? Es gibt Anwendungen, wo hierarchische Untersätze einen
enormen Reichtum an Datenelementen umfassen können.
Ein lumpiges Formular mit 14 Feldern reicht nicht aus,
man will zwei oder drei Formulare.

Lösung
Zuerst einmal die zusätzlichen Abschnitte in der FRM-Datei einrichten.
Dann: im input.flx gibt es für die hierarchischen Untersätze den
Abschnitt :H. Den bauen Sie wie folgt aus:

:H
#01 ---
sub #01 ---
form Hier
form teil2
form teil3

Statt "teil2" und "teil3" aber die Namen der neuen, zusätzlichen
Formulare einsetzen.

Während der Eingabe dann das erste Formular nicht mit einem Formular-
wechsel zum zweiten beenden, sondern das Formularfenster mit [Ende]
verlassen! Die o.a. Erweiterung im input.flx sorgt dann dafür, daß
das zweite und dritte Formular vorgelegt werden.

Das Problem ist, daß beim Formularwechsel innerhalb des Formularfensters
wieder zum Hauptsatz zurückgegangen wird, so daß nachfolgende Eingaben
dann in diesem landen statt im Untersatz. Beim Beenden des Formulars
dagegen wird nicht zum Hauptsatz positioniert, sondern der Auswahlbalken
steht dann im Untersatz, der nächste Formularaufruf ändert daran
nichts - die nachfolgenden Eingaben gehen also auch in den Untersatz.
Daraus ergibt sich auch das Folgende:
Achtung beim nachträglichen Bearbeiten von Untersätzen!
Balken auf den Untersatz, Alt+#, erstes Untersatz-Formular wählen.
Dieses mit [Ende] verlassen, wieder Alt+# und nächstes Formular wählen.

----------------------------------------------------------------------


Trick 39:  Dopplung mit Doppeltrick
              Erg.Menge bzw. Gesamtbank verdoppeln

Aufgabe: Die Sätze der aktuellen Erg.Menge schnell mal eben duplizieren
Erweiterte Aufgabe: Alle Sätze duplizieren.

Warum? Vielleicht braucht man ja gelegentlich mal Kopien von
       bestimmten Sätzen und will sie nicht alle einzeln von
       Hand verdoppeln.
       Auch wenn das nicht der Fall ist, kann man doch aus diesem
       Problem was lernen, und wenn's nur ist, daß nichts wirklich
       GANZ einfach ist... (OK, das wußten Sie schon)

Lösung:
Das Kopieren eines Satzes wird nicht mit  copy  gemacht, denn
dabei entsteht ein irritierendes Flackern, weil jeder kopierte
Satz erst einmal angezeigt wird - das brauchen wir in diesem
Fall ja nicht, und es kostet mehr Zeit. Es wird vielmehr Gebrauch
gemacht von der neuen (ab V27.1) Spezialvariablen kn. Das ist der
eigentliche Trick.
Noch ein Trick: Den Befehl "put" weglassen, dann hat man die Duplikate
erst mal nur im OfflineSpeicher. Mit "erase off" wird man sie
dann wieder folgenlos los...
Hier der komplette FLEX. Kopieren Sie ihn in eine Datei
ergdopp.flx, bei Bedarf zu starten mit  X ergdopp

----------------------------------------------------------------------
  ERGDOPP.FLX : Verdopplung der Erg.Menge
  20070209

if empty mes Keine Erg.Menge;end

set e0   // EditorFehlermeldungen verhindern
first

:loop
  Satz als Ganzes in iV kopieren
var kn
  leeren Neusatz anlegen
new 0
  iV einspeisen - d.h. Satz kopieren
insert
  Falls hierarchischer Satz: auf Hauptsatz schalten
first sub
  Feld #00 geeignet belegen (klappt nicht ohne "first sub"!)
#00 dopp?5
  Datumsfelder beseitigen
#99e
#99n
  Duplikat speichern (wenn man das 'put' wegläßt, werden die
    Sätze erst mal nur im OfflineSpeicher gestapelt)
put

next
if yes jump loop

:exit
set e1
------------------------------------------------------------------------

Und nun zur erweiterten Aufgabe. Im ersten Moment ist man versucht,
den obigen FLEX herzunehmen und einfach "first #" bzw. "next #" zu
schreiben. Damit hätte man ein anderes Problem gelöst: Die Datenbank so
aufblähen, daß sie die gesamte Platte füllt? Stimmt nicht, denn mit
next # kommt der nächste Satz, ausgehend von der momentanen Satznummer,
und die ist nach dem "put" die Nummer des gerade gespeicherten Satzes.
Aus demselben Grund geht es auch nicht mit last # / prev #! "Er" würde
pausenlos den letzten Satz kopieren.
Der Trick ist deshalb eine Schleife mit einem Zähler, ausgehend vom
letzten Satz bis runter zur Nummer 1. Dabei muß man nur achten auf die
gelöschten Sätze und die nicht besetzten Satznummern (wg. Entlüftung).
ABER: Wenn es am Anfang unbesetzte Nummern gibt, werden sie besetzt, und
beim Rückwärtszählen kommt dann eine dieser Nummern dran und ist
plötzlich besetzt, mit einer Kopie! Die würde nochmals kopiert, das muß
man verhindern. Der Trick ist, beim Speichern der Kopien eine IdNummer
zu verpassen, an der man erkennen kann, daß es ein kopierter Satz ist.

Andererseits könnte man auch hier das "put" erstmal weglassen! Mit
diesem Trick würde man die beschriebenen Probleme vermeiden. Am Ende
dann: "Datei / Offline-Speicher -> Datenbank".
In diesem Fall führt also mehr als ein Trick zum Ziel...

Der ausgetüftelte FLEX sähe insgesamt so aus:

  DBDOPP:FLX : Verdopplung der Datenbank
  20070209
yes Im Ernst?
if not yes end
set e0
last #
var i
z=
:loop
var "#" z
f1nd
  geloescht?
if del jump nxt
  unbesetzte Nummer?
if no jump nxt
var #00
  ist es ein verdoppelter Satz?
if "dopp" jump nxt
var kn
new 0
ins
first sub
  IdNr vorgeben setzen
#00 dopp?5
#99e
#99n
put
:nxt
z -1
  Zaehler zeigen
var z
sho iv
  Abbruch ermoeglichen
keychk
if yes end
if z>0 jump loop
:exit
set e1

----------------------------------------------------------------------


Trick 40: Alles entladen   (zum Aschermittwoch 2007)
Aufgabe: Schnell mal eben die gesamte Datenbank entladen, d.h. alle
         Daten in brauchbarer Form rausschreiben in eine Datei.

Warum?
Entladen heißt nicht, daß anschließend nichts mehr drin ist! Das
würde "Löschen" heißen, und das wird keiner wollen, sondern nur
kopieren. Aber eben so, daß jemand anders was anfangen kann damit.
Denn mit allegro-Datenbankdateien kann nicht jeder unmittelbar was
anfangen. D.h. eine direkte Kopie der Dateien nützt dann nichts.
("Laden" und "Entladen" sind keine allegro-Begriffe, bei anderen
Systemen aber zumindest als Metaphern nicht unbekannt. Mit dem
Aschermittwoch und dem Entledigen von allem Zweifelhaften oder
Entsagen von allem potentiell Unheilvollen, aber sogar mit dem
Entlasten von obsoletem oder unnützen Kram hat es
selbstverständlich
weniger als nichts zu tun! Nur, damit das klar ist.)

Lösung:
Der Möglichkeiten gibt es viele, und einige davon erfordern
keine Kenntnisse. Man muß nur das Menü finden. Hier ist es:

   h dbxport

Zu erreichen auch über Menü "Export / Komfort-Methoden / Gesamte
Datenbank exportieren".
Klicken Sie da auf "mehreren Möglichkeiten", dann kommt eine Auswahl-
Liste der ohne eigene Parametrierung sofort ausführbaren Exporte.
Nur der Dateiname ist dann noch anzugeben, wo die Daten hineinsollen.
(Wenn die Datei schon existiert, wird gefragt, ob sie überschrieben
werden soll. Also keine Gefahr, daß man was kaputtmacht.)

Sind die angebotenen Möglichkeiten alle nicht ganz passend, hilft oft
die Methode "Tabellen erstellen" weiter. Dort gibt es einen seit
V27.1 neuen Menüpunkt "Schnellmethode". Dabei braucht man nur noch die
gewünschten Feldnummern einzugeben und bekommt eine Tabellendatei,
in der jeder Datensatz als einzelne Zeile dasteht, Felder mit TAB-
Zeichen abgegrenzt. Damit kann nun wirklich jeder Datenbanker
etwas anfangen! Man wird sehen, ob es das ist, was er sich gedacht
hat. Oder ob er sich überhaupt was Sinnvolles gedacht hat... Garantiert
wird er sagen, "also diese und diese Datensätze brauche ich natürlich
nicht!" Kein Problem, dann macht man zuerst eine Ergebnismenge, evtl.
mit Volltextsuche, und wendet den Export auf diese an statt auf die
Gesamtbank.


----------------------------------------------------------------------


Trick 41: Auf die Schnelle ne Tabelle

Aufgabe: Schnell mal eben ein paar Angaben als kleine Tabelle
         in Textform aufbereiten.

Warum kann das ein Problem sein?
Zwar gibt es die Tabellenmethodik, sogar ab V27.1 mit einem
Schnellverfahren (siehe  h table), aber manchmal kommt man damit nicht
klar, weil die Inhalte nicht fertig und schön in vorhandenen Daten-
feldern stehen, sondern erst aufbereitet werden müssen mittels
var-Befehlen, wobei dann evtl. auch noch Zahlenwerte vorher
ausgerechnet werden sollen. Manchmal will man auch das Ergebnis nicht
in Word verarbeiten, sondern nur ganz schlicht als TXT-Datei, die
aber wenigstens "ordentlich" aussehen soll, also mit Text und Zahlen
schön spaltenrichtig untereinander.

Lösung:
Hierfür sollte man zwei Kniffe kennen:

1. Textinhalt auf bestimmte Länge rechts- oder linksbündig
   zurechtrücken. (Falls zu lang, dann abschneiden)

  a) Rechtsbündig
     Sagen wir, es steht etwas in #uxy und man will es auf eine
     Länge von 20 Zeichen links mit Leerzeichen auffüllen (d.h.
     in ein 20stelliges Feld rechtsbündig einstellen)
     var/wri ... #uxy(0,r20)

  b) Linksbündig
     var/wri ... #uxy(0,20)

2. Zahl mit 2 Dezimalstellen (gerundet) in ein Feld von 12 Stellen
   rechtsbündig einstellen. Die Zahl steht in #uij
     var #uij
     Z=
     var Z2
     ins #uik
     ...
     var/wri ... #uik(0,r12)

Zuerst wird man also dafür sorgen, daß man alle Textteile in
Variablen oder Datenfeldern vorliegen hat, dann wird man mit
einem einzigen wri-Befehl diese Elemente alle hintereinander mit
den gewünschten Zahlenwerten (0,...) versehen ausgeben:

wri #uab(0,10) "/" #uac(0,20) ":" #uad(0,r15) n

Das n für "neue Zeile" am Ende nicht vergessen, denn sonst kommt
alles in eine riesenlange Zeile...

Selbstverständlich kann so ein Befehl dann in einer Schleife
vorkommen, mit der man eine Erg.Menge oder die Gesamtbank abarbeitet.
Hat man auf diese Weise eine Textdatei abc.txt fabriziert, kann man
sie mit  help abc.txt  ins Anzeigefeld holen oder sonstwas damit
anstellen.
[Erg.Menge abarbeiten: Schema z.B. in Fb-Lektion  13.3 oder ganz
 kurz in  xnext.rtf ]


Word-Tabelle:
Wenn man zwischen den Elementen statt "/" und ":" jeweils den
Code 9 einsetzt, hat man eine TXT-Datei, die man in Word einfügen
und dort in eine Word-Tabelle wandeln kann - das ist das das
Wirkprinzip der Tabellenmethodik.

Hinweis:
Die oben gezeigten Formatierungstricks sind enthalten in der
Beschreibung  xcstring.rtf
Da stehen auch noch mehr Tricks, wie man seine Feldinhalte zurecht-
frisiseren kann!

----------------------------------------------------------------------


Trick 42: Persistente Ergebnismenge


Aufgabe: Eine mühsam erstellte Ergebnismenge schnell mal eben
         permanent absichern

Warum: Es kann passieren, daß man eine Erg.Menge ganz exakt für
       nachfolgende Sitzungen aufbewahren will. Denn durch die
       laufenden Veränderungen aller Art kann es ja sein, daß man
       genau diese Erg.Menge später u.U. nicht mehr bilden kann.
       Auch die Option "Ergeb. aufbewahren" garantiert keine
       sichere Aufbewahrung für unbegrenzte Zeit!

Lösung:
   1. Das Abspeichern in einer Datei:
     
     
x open x ABC\wri U n in\close x
     
      mit beliebigem Dateinamen ABC . 
      (Dateityp: Empfehlung .LST, jedoch nicht verpflichtend)

   2. Das Laden zu einem beliebigen späteren Zeitpunkt:
     
x read set ABC

Der Trick ist die Sondervariable  
in  im write-Befehl.
Sie liefert die internen Satznummern, jede auf eigener Zeile, und zwar
sauschnell.
Die interne Variable U ist der Titel der Ergebnismenge und wird als erste Zeile in
die externe Datei ABC geschrieben.

Und wie hätte man das selber rauskriegen können?
In FLEX.VW  (v flex eingeben)  findet man die nötigen Hinweise,
wenn man nach "satznummer" sucht, und zwar in folgenden Zeilen:

  Satznummern der aktuellen E-Menge ausg.    wri ixk-j
  Satznummernliste als Erg.Menge einlesen    read set <name>

Den Rest muß man sich dann zusammenreimen...

----------------------------------------------------------------------


Trick 43: Zweiten Datensatz laden oder anlegen und nutzen


Aufgabe: In einem FLEX wird irgendein Satz bearbeitet, und man
         will schnell mal nebenbei einen anderen Satz heranziehen, um
         daraus irgendwas zu entnehmen oder irgendwas damit zu tun,
         dann aber zum ersteren zurück, mit dem man noch nicht fertig
         gewesen war.

Warum: Sowas kommt halt immer öfter mal vor! Z.B. ein Stammsatz, ein
       Lesersatz, ein Auftraggeber-, Kontingent-, Medientypsatz und
       was dergleichen mehr so alles auftritt beim Erwerbungs- und
       Ausleihgeschäft.

Lösung: Zu Fuß macht man es so, und dieses Rezept findet sich auch
in so manchem mitgelieferten FLEX immer noch:

   REZEPT 1
var i          // Nummer des aktuellen Satzes
ins #uaI       //   in der Variablen #uaI sichern
f1nd ...       // einen anderen Satz laden
 ...           // damit irgendwas tun
var "#" #uaI   // den vorherigen Satz zurückholen
find
 ...           // und damit weitermachen

Problem: Wenn es sich um einen neuen, noch nicht gespeicherten Satz
handelt! Dann ist die Variable i nämlich 0 ...

Zum Glück geht es aber auch anders und sicherer: (siehe in  h xset )

   REZEPT 2
switch obj 2   // umschalten auf Satzobjekt 2
f1nd           // anderen Satz holen
 ...           // damit irgendwas tun
switch obj 1   // Satzobj. 1 wieder einschalten

Auf diese Weise bleibt der erste Satz ("Objekt 1") unberührt liegen,
während das, was zwischendurch gemacht wird, an einem getrennten
"Objekt 2" stattfindet.
Bei avanti war das übrigens schon lange so.
M.a.W.: Wenn man "switch obj" nie benutzt, arbeitet man automatisch
immer mit "Objekt 1", und "Objekt 2" liegt ungenutzt herum.

Im Abschnitt "damit irgendwas tun" können durchaus mehrere find-
oder f1nd-Befehle vorkommen, nicht aber weitere "set obj ...", denn
es gibt nur die Objekte 1 und 2, und Nummer 1 ist die ganze Zeit
derjenige Satz, zu dem man letztlich dann zurückgehen will.

Die ältere Methode dagegen würde es gestatten, daß man einfach mehrere
Variablen #u... mit mehreren Satznummern belegt und diese Sätze dann
nach Bedarf wieder aktiviert. Falls man nicht die Übersicht verliert...

Die Umschaltung gilt bis zum nächsten switch, wenn keiner kommt also
bis zum Sitzungsende, d.h. über den konkreten FLEX hinaus. Man arbeitet
also, wurde "switch obj 1" vergessen, anschließend die ganze Zeit mit
dem Objekt 2. Was jedoch keinen Schaden stiftet.

Gewiefte Programmierer bohren sofort nach:
Warum gibt dann nicht gleich ein ganzes Array von Sätzen, zwischen
denen man nach Belieben umschalten kann? Nun, das Array gibt es! Das
ist der Reservespeicher. Was fehlt, ist nur eine FLEX-Methodik,
zwischen diesen nach Belieben herumzuspringen, wie man es ja
manuell schon kann! Es wird ins Auge gefaßt, dies zu realisieren.
(SEHR groß kann der Bedarf wohl nicht sein, er hätte sich dann
längst artikuliert...)

Anwendungsbeispiel
Situation: Man hat eine Ergebnismenge von Bestelldatensätzen und
will dazu schnell mal eben eine Titelliste, in der man die wichtigsten
Titel- aber auch Bestellangaben sieht. Das kann man nun machen,
ohne irgendwelche Parameter zu schreiben!
Das könnte so aussehen (und wird Bestandteil von ORDER werden):
Mit **** ist markiert, wo man variieren und erweitern könnte. Es ist
auch mehrfaches Umschalten zwischen Bestell- und Titelsatz möglich,
aber zu beenden ist der Vorgang mit  set obj 1!

  O-TLISTE.FLX : Titelliste der Bestellungen
  20070529       ausgehend v. einer Bestellungs-Erg.Menge

  Erster Satz d. Bestellmenge
first
if not #9DA jump sorry

open x liste.txt
  Titel der Erg.Menge
wri n U n n

:loop
  TitelID aus Bestellsatz entnehmen
var "|9 " #9DA$T
set obj 2
  Titelsatz dazu laden
f1nd
  V14-Verkn. aufloesen
if v14 export Ref
  **** Titeldaten ausgeben
wri #20(e" : ") " / " #40 ". - " #76 n
  zurueck zum Bestellsatz
set obj 1
  **** Bestelldaten
wri "   A:" #9DB$A " L:" #9DB$j " D:" #9DB$d " : " #9DB$c " " #9DB$p n n
  naechster Bestellsatz
next
if yes jump loop
close x
  Datei schliessen und anzeigen
h liste.txt
end

:sorry
var "Sorry, die aktuelle Ergebnismenge besteht nicht aus Bestelldaten"
mes
end


----------------------------------------------------------------------


Trick 44: Textdatei umcodieren

Aufgabe: Schnell mal eben eine Textdatei von ASCII nach ANSI umcodieren.
         Oder allgemeiner: vom Codesystem X ins Codesystem Y.

Warum: Der alte DOS-Zeichencode ASCII gerät zunehmend auf den abstei-
       genden Ast. Aber auch ANSI ist nicht von hohem Ewigkeitswert,
       denn Unicode dringt immer weiter vor.

Früher schrieb man dafür eine Exportparameterdatei mit den
entsprechenden p-Befehlen, mußte aber zuerst einen Import machen, um
die Textdatei zeilenweise in Datensätze zu verwandeln, die dann z.B.
nur die Kategorie #20 oder #u1 enthielten, um diese dann sofort mit
den Exportparametern wieder ausgeben zu können. Wer hat denn schon
heute noch solchen Durchblick? Oder man griff murrend zu einem
Fremdwerkzeug oder einer Skriptsprache. Nicht jedem stehen aber solche
Wege offen...

Eine "Textdatei" - damit sind Dateien gemeint, die in Zeilen angeordnet
sind, mit Codes 13 10 (oder nur einem von beiden) als Trennung.

Lösung:
Das Einzige, was man jetzt noch braucht, ist eine Liste von p-Befehlen.
Davon sind mehrere schon als Tabellen vorhanden:
(Wenn man hineinschaut, sieht man gleich, wie solche Tabellen aussehen
müssen und wie man sie erstellen und modifizieren kann. Bearbeiten kann
man sie mit Notepad o.a.)

asciansi.apt   ASCII -> ANSI
ansiasci.apt   ANSI -> ASCII
d.apt          ASCII -> RTF
d.npt          ANSI -> RTF
d-utf8.apt     ASCII -> UTF-8
d-utf8.npt     ANSI -> UTF-8  [auch f. HTML]

p-htm.apt      ASCII -> HTML

durtf.apt      UTF-8 -> ASCII
durtf.npt      UTF-8 -> ANSI

Wenn man nun mit B.CFG arbeitet, intern ASCII hat und nach ANSI
umcodieren will?  Dann Kopie machen:  asciansi.apt -> asciansi.bpt

Wenn die richtige Tabelle erst feststeht, geht es ganz leicht,
sofern man das "final release" von V27.2 hat:

1. Füllhorn / Alles von A-Z / Umcodierung einer Textdatei
   (Aufgerufen wird dann  filecode.flx)

2. Man wird informiert:
  "Sie wählen jetzt zuerst eine Datei aus. Diese wird zeilenweise
   gelesen und geschrieben"
   Dateiauswahlbox erscheint, Datei wählen (evtl. zuerst Verzeichnis
   wechseln)

3. Frage beantworten, die danach kommt:
   "Neuer Name für die Datei?"
   Dateiname und -pfad ist beliebig

4. Und es kommt noch eine Dateiauswahlbox:
    "Wählen Sie eine Codetabelle"  
    Aus der Liste die korrekte Tabelle (siehe oben) wählen

Verarbeitung wird ausgeführt, Endemeldung:

... verarbeitet, Neue Datei: ...
... Zeilen, ... Bytes

FERTIG!

  ------------------------------------------------------------------

FLEXperten wollen mehr wissen: Was ist der Trick dabei?

Der FLEX  filecode.flx  ist abgeleitet von der allgemeineren
Vorlage  file.flx  (ASCII-Datei zeilenweise lesen+schreiben),
die es schon seit 2004 gibt. Neu ist in V27.2 die Möglichkeit,
Umcodierbefehle zu nutzen: Befehl  xcode ...  (h xxcode)
Hier die entscheidenden Zeilen:

export p i-1
  i-1.apr laden. Diese wird aber nicht als solche gebraucht,
  das ist der Trick, sondern nur, weil man eine Tabelle dazuladen
  will, in der die Umcodierbefehle stehen:

var "Wählen Sie eine Codetabelle|*." K1 "pt"
fnam
  Diese Tabelle zu den Exp.Parametern laden
export t

  Danach kann man in der Schleife :loop, die jeweils eine Zeile mit get
  aus der Datei liest, dies sagen:

xcode xp
wri
wri n

und es werden die p-Befehle der Exportparameter zum Umcodieren benutzt,
die umcodierte Zeile ausgegeben und ein Zeilenvorschub hinterdrein.


Trick 45: Versionskontrolle

Aufgabe: Schnell mal eben checken, ob a99 oder alcarta in einer
         geeigneten Version vorliegt.

Warum? Wenn man einen fortschrittlichen FLEX schreibt, in dem z.B. der
       Befehl  xcode  vorkommt, dann klappt dieser nicht mit einer
       V25.3, sondern erst ab V27.2
       Um sicherzugehen, daß der Nutzer des FLEXes damit auch was
       anfangen kann, ist dann eine Prüfung sinnvoll, ob er eine V27
       hat oder nicht.
       Natürlich sollte ein mündiger Anwender immer die aktuelle
       Version im Einsatz haben, aber wer FLEXe für größere Anwender-
       kreise schreibt, kann davon nicht einfach so ausgehen...

Lösung:
Man macht sich die interne Sondervariable m zunutze. Sie enthält immer
die Versionsnummer in der Form  "a99 vnn.n"  oder  "alc vnn.n"
(avanti:  "av-x vnn.n"), also z.B.  a99 v26.5
Damit kann man folgende kleine Sequenz schreiben:

var m
var (b"v")
if <27.2 jump gehtnich
  ... Befehle, die erst ab V27.2 gehen ...
end
:gehtnich
var "Sie haben die Version " m ". Die gewünschte Funktion geht aber"
var +" erst ab V27.2 - sorry!"
mes
end

ABER: Der Befehl  var (b"v")  geht erst ab V24.42 (Vb.179), also die
Anwendung eines Manipulationsbefehls direkt auf die interne Variable.
Wenn es daher sein kann, daß anwenderseitig etwas noch älteres in
Betrieb ist, dann empfiehlt sich das folgende Konstrukt:

var m
ins #uvv
var #uvv(b" ")
if <"v27.2" jump gehtnich

Das ging schon vor V20, aber "var m" gibt es erst ab V22.0 (Vb.155).
Ohne diesen Befehl kann man nichts machen? Doch, und zwar noch diese
Zeile ergänzen:
if ="m" jump gehtnich
denn vor V22.0 kam dabei nur der Buchstabe m heraus.
Fazit: Die Prüfung gelingt nur, wenn mindestens eine V20 vorhanden ist.

  -----------------------------------------------------------------

Schon länger bekannt ist dies: Wenn etwas nur unter a99 laufen soll, dann

var m
if "alc" mes "Sorry, nicht in alcarta";end
...

------------------------------------------------------------------------------------------------


Trick 46: Alle #nn-Felder durcharbeiten
                Ohne zu wissen, wiviele und welche es gibt

Aufgabe: Alle Felder, deren Nummer mit #nn anfängt, durcharbeiten.

Warum? Manchmal weiß man z.B. nicht, in welchem von evtl. mehreren
Mehrfachfeldern eine bestimmte Angabe steht. Oder man will die Inhalte
aller dieser Felder in eine Datei schreiben.

Lösung 1
========

Man nimmt sich hintereinander alle Felder vor und prüft dann nur
diejenigen, deren Nummer mit nn anfängt.
Dazu dienlich sind die internen Sondervariablen k_1 und k_2:
k_1 = Erstes Datenfeld des aktuellen Satzes, incl. der Feldnummer
k_2 = nächstes Feld, "" wenn es keins mehr gibt

Damit sieht die Lösung so aus:
  Gewünschte Nummer in #uxx vorgeben
#uxx 30
perf abarbeitung
jump rest
  Hierher wird aus dem UP gesprungen:
:aktion
  Feldinhalt jetzt in iV, incl. Feldnummer!
  ... irgendwelche Aktionen mit dem Inhalt
  zurück in das UP!
jump weiter
:rest
  ...
end

  Unterprog., um das man sich nicht kuemmern muss.
  Es funktioniert mit jeder Konfiguration.
:abarbeitung
var 34 #uxx 'zz' 34
ins #uxy
var 34 #uxx 34
ins #uxx
var k_1
:loop
if >#uxx if <#uxy jump aktion
:weiter
var k_2
if not "" jump loop
return


Im Abschnitt :aktion  hat man den gesamten Feldinhalt incl. der
Nummer in der iV. Daher kann man z.B. schreiben

ins #uxz
  .. irgendwelche Aenderungen an #uxz
var "#" #uxz
ins
jump weiter

Dadurch kann man also gezielt die einzelnen Feldinhalte auch
modifizieren.

Und noch ein Vorteil:
Statt  #uxx 30  kann man auch schreiben  #uxx 3
Dann werden alle Felder bearbeitet, die mit #3 beginnen!!!

  ===========================================================

Lösung 2  (H. Allers)
========
Man bastelt alle in Frage kommenden Feldnummern nacheinander
in der iV zusammen und läßt sich mit erneutem "var" den Inhalt
geben (wenn es denn einen gibt). Das ist besonders trick- und
damit lehrreich, aber ansonsten hat es keine Vorteile gegenüber
Lösung 1, auch schneller ist es wohl kaum:


#uxx "#30"
Z=31
:anfang
  Es beginnt mit 32 = Spatium
Z+1
var Z
  problematische Folgezeichen uebergehen: $ : ( .
if =36 jump anfang
if =58 jump anfang
if =40 jump anfang
if =46 jump anfang
if >122 end
var #uxx ' ' Z
  in iV steht jetzt z.B.  #30 65
var
  und jetzt: #30A
ins #ux2
var   // #ux2 ist Kategoriebezeichnung
  und jetzt der Inhalt von #30A - das ist der Haupttrick
if not "" perf aktion
jump anfang

  Was will man machen mit dem Inhalt?
:aktion
ins #ux1   // #ux1 ist aktueller Kategorieninhalt
var "Mit >>" #ux2 #ux1 "<< machen, was man will"
mes
return

---------------------------------------------------------------------------------------------------


Trick 47: Längsten/kürzesten Satz finden


Aufgabe: Schnell mal eben in einer Datenbank den längsten Satz finden!

Warum: allegro-Datenbanken haben keine festgelegte Satzlänge, jeder
Satz nimmt nur soviel Platz ein, wie er eben braucht. Grenzenlos lang
können Sätze jedoch nicht sein und auch nicht grenzenlos zahlreich die
Indexeinträge. Es ist nur nicht leicht zu sagen, wo denn die Grenzen
wirklich verlaufen.  --> Grenzen Schranken, Barrieren
   http://www.allegro-c.de/grenzen.htm

Für Testzwecke kann es also interessant sein, mal den längsten
Datensatz herauszufinden.

Das leistet der folgende FLEX:


#ulg 0
#uks 0

first #
:loop
keycheck
  Wurde [Esc] gedrückt?
  Wenn ja und Nachfrage mit ja beantwortet, dann -> :exit
if yes jump exit
var jb
if >#ulg ins #ulg;var i;ins #uil
if <#uks ins #uks;var i;ins #uik
next #
if yes jump loop
:exit
  Ende, jetzt den Satz noch zeigen
var "#" #uil
find
sho rec
disp
  und Meldung:
var  "Laengster Satz  :  " #uil ", Laenge " #ulg
var +"Kuerzester Satz :  " #uik ", Laenge " #uks
message


Er findet in der gesamten Datenbank den längsten u. kürzesten Satz und
zeigt den längsten am Ende an.
Wenn man  first #  und  next #  ersetzt durch  first  bzw.  next,
wird nur die aktuelle Egebnismenge durchgeforstet.
Der Ablauf kann mit Esc unterbrochen werden (Befehl keycheck), dann
erhält man den längsten bis dahin gefundenen Satz.

Der Trick ist nur die interne Sondervariable jb, mit der man die Länge
des jeweils aktuellen Satzes erhält. Die Zeile

if >#ulg ins #ulg;var i;ins #uil

vergleicht die so erhaltene Länge mit dem Wert in der Variablen
#ulg. Ist #ulg kleiner, wird der iV-Wert, also der nun größere,
in #ulg kopiert und die interne Satznummer (denn die wird ja am
Ende gebraucht) wird in #uil aufbewahrt. Am Ende hat man die
gewünschten Werte in diesen beiden Variablen.
Mitgeliefert wird ab V27.4 ein FLEX namens lk.flx, der die drei längsten
und kürzesten Sätze als Erg.Menge liefert.

Wo ist die Liste der internen Sondervariablen?
Hier:
http://www.allegro-c.de/flex/seite09_3.html#_Kap09_03
oder auch in  xcstring.rtf

---------------------------------------------------------------------------------------------------


Trick 48: Präzisions-Ersetzungen

Aufgabe: Schnell mal eben in eine Zeichenfolge an einer bestimmten
         Position 1 oder mehr Zeichen einfügen, und zwar 
         mit oder ohne Ersetzung von 1 oder mehr dort stehenden Zeichen

Warum? Man hat zuweilen Zeichenfolgen, in denen an bestimmten (festen)
       Positionen bestimmte Angaben stehen, die man durch etwas anderes
       ersetzen will.

Hinweis: Zum Ersetzen von exakten Zeichenfolgen an beliebiger Stelle
         durch andere gibt es den Befehl  insert %abc%xyz%
         Zum Ersetzen einzelner Zeichen oder Doppelzeichen durch andere
         im gesamten Text (das nennt man "Umcodierung") gibt es das
         Instrumentarium des Befehls  xcode

Lösung:
Man schreibt sich eine Datei  stri.inc  (siehe unten) und bindet sie
mit "include stri.inc" ein.
So wird die Funktion dann benutzt:

Wenn in das Feld  #789  an der Position 11 die Zeichen "abc" eingesetzt
werden sollen, dort genau 2 Zeichen ersetzend, die vorher da stehen,
dann macht man folgendes:

var #789
  Startstring
ins #usT
  Befehlsstring (kann beliebig konstruiert werden, auch aus Variablen!)
var "10,abc,2"
  (Statt , als Trenner ist auch / möglich)
  Aufruf
perf stri
  Ergebnis in iV nach #789 sichern
ins #789

var "Resultat: " #789
mes
  ... weitere Aktionen
  Am Ende das UP einbinden:
include stri.inc



            Und dies ist das Unterprogramm  stri.inc
 ***********************************************************
  STRI.INC : Zeichen an fester Position in eine Zeichenfolge einfuegen
  2007-07-17   u.U. mit Ersetzung vorhandener Zeichen

  Aufruf :  Man besetzt zuerst folgende Variable:
          #usT  : die Ausgangs-Zeichenfolge

          iV    : zahl1,zeichenfolge,zahl2  oder  / statt ,
                  die beiden Zahlen muessen positive ganze sein oder 0
                  zahl2 mit dem vorangehenden Komma darf fehlen
         
          Bedeutung:  zahl1 Zeichen vom Anfang von #usT belassen
                      dann die  zeichenfolge  anhaengen
                      vom Rest von #usT  zahl2  Zeichen wegnehmen,
                      und was noch von #usT uebrig ist, anhaengen
          Beispiele:
                 Das vierte Zeichen durch x ersetzen
          var "3,x,1"
                 In #upo steht Position, in #uez die einzufueg. Zeichen
                      in #uaz ANz. der zu ersetzenden Zeichen
          var #upo "," #uez "," #uaz
                 Hinter dem 10. Zeichen  Inhalt von #uab  zwischenfügen
          var "10," #uab ",0"   oder   var "10," #uab
                 Vorn 2 Zeichen durch abcdeg  ersetzen, Rest belassen
          var "0,abcdeg,2"
                   (einfacher mit  var "abc" #usT(2,0) )
                 Hinter dem 2. Zeichen  abcdeg  einsetzen, Rest weg
          var "2,abcdeg,1000"
                   (einfacher mit  var #usT(0,2) "abcdeg" !)

       Dann der Aufruf:

          perf stri

       Ergebnis steht danach in der iV

  UPro beginnt hier
end
  Setze
         #uS1 = zahl1 , #uS2=zahl2 , #uSB = Zeichenfolge bei Beginn
:stri
  Kontrolle beim Testen
 mes
ins #uSB
var #uSB(f"0123456789")
if "/" jump stri:s
if not "," return
  Komma ist Trennung:
var #uSB(e",")
ins #uS1
var #uSB(b"," b",")
ins #uS2
  Trennsymbol ,
#uST,
jump stri:w

  / ist Trennung:
:stri:s
var #uSB(e"/")
ins #uS1
var #uSB(b"/" b"/")
ins #uS2
  Trennsymbol /
#uST/

:stri:w
eval #uS1 + #uS2
  Position, wo der Rest beginnt
ins #uS3
  Manipulations-Ausdruck in die iV schreiben:
       (beachte den Nebentrick mit dem Trennsymbol #uST)
var #uS1
if not "0" var "#usT(0," #uS1 " F' ') #uSB(b'#uST' e'#uST') #usT(" #uS3 ",0)"
if "0" var "#uSB(b'#uST' e'#uST') #usT(" #uS3 ",0)"

  zur Kontrolle beim Testen den Ausdruck zeigen:
 mes
  Ausdruck auswerten   (das ist der eigentliche Trick!)
var
  Nun steht das Erg. in der iV
  Hilfsvar. loeschen
#uST
#uSB
#uS1
#uS2
#uS3
return

  **********************************************************
 
---------------------------------------------------------------------------------------------------


Trick 49: Mehr Mobilität : Fliegender Wechsel des Arbeitsorts

Aufgabe: Mal eben auf ein anderes Verzeichnis umschalten, um dort
         irgendwelche Aktionen durchzuführen, dann zurück.

Warum: Ambitionierte Anwender wollen von a99 aus alles mögliche mit
       Dateien anstellen, die irgendwo liegen. Dafür gibt es ja auch
       so einige Befehle, bis hin zu mkdir und dem mächtigen fnam.
       Es kann nützlich sein, wenn man für Dateiaktionen ein anderes
       Basis-Verzeichnis einstellen kann als das vorgegebene.
      
Hintergrund:
Wenn man eine Datei öffnet oder sonstwie anspricht, und dabei keinen
Pfad angibt, sondern nur den Namen, wird die Datei auf dem Arbeits-
verzeichnis gesucht, auch "Startverzeichnis" genannt. Es handelt sich
dabei um denjenigen Ordner, aus dem heraus a99 bzw. alcarta gestartet
wird. Sein Name steht in den "Eigenschaften" des Desktop-Icon in dem
Feld "Ausführen in". Startet man das Programm von Hand im DOS-Fenster,
ist es das dort gerade (mit cd ...) eingestellte Verzeichnis.

Erst ab V27 ist die Möglichkeit gegeben, das Arbeitsverzeichnis
per FLEX zu wechseln, und zwar mit

set W verzeichnisname

Und so kann eine Sequenz aussehen, um auf ein anderes Verzeichnis zu
wechseln, dort schnell mal etwas zu tun, und dann zurückzuschalten.

var W
ins $temp
set W verzeichn
 ... sonstwas tun
var $temp
set W

Ganz nett außerdem:
>> Das Verzeichnis muß nicht auf demselben Laufwerk liegen!
>> In einem Pfadnamen kann man / statt \\ als Trenner verwenden.

KEINE SORGE:
Das Umschalten bewirkt NICHT, daß die temporären Dateien verlagert
würden oder plötzlich nicht mehr da wären, die das Programm braucht.
Und zwar für die Erg.Mengen und die bearbeiteten Sätze, d.h. Dateien
der Typen .$$$, .RSS, .TAB und ._nn
Diese Dateien bleiben wo sie sind: auf dem beim Programmstart
eingestellten Arbeitsverzeichnis. Man hätte sonst womöglich
merkwürdige Probleme!


Zusatzfrage: Wie stellt man fest, wo momentan das Arbeitsverzeichnis
ist?
     1. Lösung:  Eingabe von  x var W\mes

     2. Lösung:  Eingabe von  d a  (siehe Trick 21 "Schau'mer mal")


---------------------------------------------------------------------------------------------------


Trick 50: Datensatz umtopfen

Aufgabe: Einen Datensatz in eine andere Datei überführen.
         (Gemeint ist: in eine andere Datendatei innerhalb derselben
         Datenbank, nicht in eine andere Datenbank!)

Warum: Im Prinzip (für das Funktionieren der Software) hat es keine
       Bedeutung, in welcher Datei sich ein Satz befindet! Man muß
       sich also deswegen eigentlich keinen Kopf machen. Es gibt
       aber Systemverwalter, die gerne hübsch ordentlich ihre Daten-
       sätze auf eine Anzahl von Dateien aufteilen. Dann müssen
       Vorkehrungen getroffen werden, damit ein Satz bei seiner
       Erfassung gleich in die richtige Datei gespeichert wird.
       Versehentlich entwischt dann schon mal einer in die falsche
       Datei, und man ärgert sich - obwohl's, wie gesagt, egal ist.

       Es kann aber ein Vorteil sein, wenn Sätze bestimmter Typen in
       separaten Dateien sind, z.B. kann eine Volltextsuche dann
       schneller sein, wenn sie auf nur eine, die richtige, Datei
       begrenzt wird. Oder man kann besondere Sätze, die nur
       temporär gebraucht werden, leicht wieder alle loswerden.

Wo sieht man, in welcher Datei ein Satz steckt? Im zweiten Statusfeld
unten rechts stehen 3 Zahlen. Liest man da z.B. 938/1 L225, so
bedeutet das: Satz 938 ist gerade zu sehen, er steckt in Datei 1 und
ist 225 Byte lang.
Tip: Im FLEX kann man dieselben Angaben als Sondervariablen abrufen:
     i    interne Nummer des Satzes
     j    Dateinummer
     jb   Länge des Satzes in Byte


Lösung:
-------
Direkt (physisch) in eine ander Datei verschieben kann man den Satz
nicht. Er muß kopiert und als neuer Satz gespeichert werden, den alten
dagegen muß man löschen.
(Die Dateinummer kann eine Zahl von 1 bis 255 sein.)
Sagen wir, ein Satz ist in der Datei mit der Nummer 17 gespeichert,
also in  cat_17.ald  beim Standardmodell. Er soll aber in die Datei 50.

Das geht so: (man staunt doch, wieviele Schritte nötig sind, wenn alles
stimmen soll... Wenn man nicht mit A.CFG arbeitet, sind einige Feld-
nummern sinngemäß zu ändern.)


  Momentane Nummer f. NEUE Sätze ist die Sondervar. N
var N
ins $unn
  Statt dessen Nummer 50 einstellen (mit ".."!)
var "50"
input
var #00
ins $u00
var #99n
ins $u99n
  den aktuellen Satz löschen
erase
  ihn kopieren
copy
  und als neuen Satz speichern - kommt in Datei 50
  aber zuerst die alte #00 wieder einsetzen
var $u00
ins #00
put
  Jetzt die alte #99n auch wieder einsetzen, nochmal speichern
var $u99n
ins #99n
put
  Nummer für neue Sätze wieder zurückstellen
var $unn
input
  kopierten Satz anzeigen
sho rec
disp


Hinweise:
Man braucht im FLEX nur die Nummer der Zieldatei (die 50 also).
Die Sache mit #99n (Datum der Erfassung des Satzes) wird nur
gemacht, weil sonst die #99n auf das aktuelle Datum gesetzt wird, denn
der Satz gilt für das System als neuer Satz und kriegt automatisch
in der #99n das aktuelle Datum. Deshalb wird der Satz nach dem
Speichern nochmal um die alte #99n bereichert und erneut gespeichert,
dann bleibt sie nämlich erhalten, es gibt aber eine neue #99e. Das
kann man NICHT verhindern, d.h. die alte ist dann weg.

Die #00 wird gleichfalls beim Kopieren gelöscht und dann beim
Speichern erneuert. Wenn man sie aber vor dem Speichern neu belegt,
wird keine neue Nummer vergeben.

Seine INTERNE Nummer kann der Satz nicht behalten, er bekommt eine
neue - die alte bleibt beim gelöschten Satz. Dies macht aber nichts
aus, denn die interne Nummer hat nur interne Bedeutung, der Anwender
kann nichts damit anfangen. Die interne Nummer steht nicht in einer
Kategorie! Die #00 ist etwas anderes, sie bleibt beim Kopieren
zwar nicht automatisch erhalten, wenn man sie aber wieder in die
#00 einsetzt (wie oben zu sehen), dann wird keine neue vergeben.

Die ganze Prozedur kann man auch in die normale Schleife zum
Abarbeiten einer Ergebnismenge einbauen, um gleich in einem Zuge
eine größere Zahl von Sätzen umzutopfen.

---------------------------------------------------------------------------------------------------


Trick 51: Gesetzt den Fall ...

Aufgabe: Für eine Sitzung bestimmte Werte voreinstellen, die jederzeit
         in jedem FLEX bereitstehen, um Unterscheidungen aller Art
         treffen zu können.

Warum: Bei den immer umfangreicheren Funktionssystemen, die man sich
       mit FLEX basteln kann, ist es oft erwünscht, je nach Situation
       unterschiedlich reagieren zu können.

Lösungen:
1. kann man schon im  _start.flx  jede beliebige Variable besetzen und
   diese dann jederzeit heranziehen,

2. Auch kann man in einem eigenen Initialisierungs-FLEX beliebig
   viele Einstellungen für Spezialanwendungen vornehmen.
   Beispiele sind o-init.flx und a-init.flx für Erwerbung / Ausleihe.


Welche Variablen eignen sich dazu?
Grundsätzlich zwar auch die #u-Variablen mit kleinen Buchstaben,
aber besser sind die relativ neuen $-Variablen (mit großem Anfangs-
buchstaben!), denn diese können längere Namen haben, bei denen dann
weniger leicht eine Kollision mit einer schon vorhandenen Variablen
passieren kann. Warum große Anfangsbuchstaben? Weil nur diese
Variablen während der ganzen Sitzung erhalten bleiben, die kleinen
aber nur während der Laufzeit des FLEXes.

$-Variablen können, genau wie die #u-Variablen, leicht belegt und
für Prüfungen genutzt werden.
Das Belegen geht so:

$Abc 1

belegt die Variable $Abc mit dem Wert 1.


Das Prüfen geht so:
Möglich ist, bisher undokumentiert, der Befehl

   if $xyz <befehl>

Der <befehl> wird nur ausgeführt, wenn $xyz belegt ist. Also genauso
wie es mit #u-Variablen geht und mit Datenfeldern!

Wenn dagegen nicht die Existenz, sondern der Inhalt zu prüfen ist,
verfährt man so:

var $Xyz
if "1" jump label1
if "pqr" jump label2


Hinweis
Trick 17 zeigt, wie man Setzungen aus der INI-Datei entnehmen kann. Das
klappt zwar einwandfrei, ist aber unnötig betulich, wenn man die
hier dargestellten Möglichkeiten ausnutzt.



---------------------------------------------------------------------------------------------------


Trick 52: Dateien abklappern

Aufgabe: Schnell mal eben eine Anzahl Dateien durchsehen oder sonstwas
         mit jeder einzelnen davon machen.

Warum: Gelegentlich will man nicht nur eine einzelne Datei,
       sondern gleich ein ganzes Bündel irgendwie behandeln. 

Lösung
Man braucht drei Funktionen:

1. :dirlist
   Die Zusammenstellung der Namensliste der Dateien
   Dabei kann es sein, daß diese nicht alle auf nur einem Verzeichnis
   liegen, sondern auch welche auf einem oder mehreren Unterverzeich-
   nissen. Die Funktion soll ein bequemes Zusammenstellen einer solchen
   Liste ermöglichen.

2. :firstname
   Aufruf der ersten Datei (d.h. ihres Namens)

3. :nextname
   Aufruf der nächsten Datei. Mit Feststellung, ob es keine mehr gibt.

Diese Funktionen wurden in eine Datei  dirlist.inc  verpackt.
Richtig einfach sind diese Funktionen nicht, weil allerhand Rand-
bedingungen zu berücksichtigen sind.
Die Nutzung ist jedoch ganz leicht. Hier ganz knapp das Strickmuster,
das man auch für eigene Zwecke noch modifizieren kann:
(Stellen mit ... sind darin frei gestaltbar)

  -----------------------------------------------------
  Flag #udS setzen: Unterverzeichnisse mitverarbeiten
  (wenn nicht gewünscht, dann die 1 weglassen)
#udS 1
  Flag #udE setzen: Liste vor Verarbeitung noch editieren
  (in einem aresqa-Fenster) Sonst die 1 weglassen
#udE 1

  Namensmuster in iV vorbereiten, z.B. c:/allegro/*.apr
var ...
  Und nun kommen die Funktionen:
  1. Dateiliste dazu erstellen
perf dirlist
if not $DL mes Keine Datei gefunden;end

  2. Ersten Namen in iV kopieren
perf firstname
if "" mes Abbruch oder keine Datei gefunden;end

  Schleife. Dateiname steht in iV
:lp
  Hier einfuegen, was mit der Datei passieren soll
...

  3. Naechsten Namen in iV kopieren
perf nextname
if "" jump ende
jump lp

:ende
  Ende-Aktion nach Verarbeitung der letzten Datei
...
end
  Unterprogramm einbinden
include dirlist.inc
  ------------------------------------------------------

Tips:
Die Liste der Dateien ist nach Ablauf immer noch in der
Variablen  $DL, wo man sie sich anschauen oder für andere
Zwecke weiterverwenden kann. $DL wird erstellt in der
Unterfunktion :dirlist, d.h. man braucht nur diese auszuführen,
wenn man nichts anderes als diese Variable braucht.

Die Liste kann, weil $DL erhalten bleibt, auch mehrfach mit
"perf firstname / perf nextname ..." abgearbeitet werden.

Anwendungsbeispiel:
Ein FLEX namens  DIRLIST.FLX  zeigt: Man kann sich Listen
bestimmter Dateitypen zusammenstellen und dazu dann eine
alphab. Liste der Dateien mit Datum, Größe und den ersten
drei Zeilen erstellen lassen.

---------------------------------------------------------------------------------------------------


Trick 53: Qual der Verzeichniswahl
ExtraTrick: Mehrere Dateitypen gleichzeitig zur Wahl

Aufgabe: Der Nutzer soll ein Verzeichnis auswählen dürfen

Warum: Es kann immer mal vorkommen, daß bestimmte Dinge
       wohlsortiert in bestimmten, parallelen Ordnern liegen. Wenn es
       dann an die Nutzung der Dinge geht, ist mitunter erst einmal
       der richtige Ordner auszuwählen.

Lösung:
       Mit fnam ... geht das nicht direkt, aber indirekt!
       In xfnam.rtf steht es auch, aber ...

Sagen wir, es hängen mehrere Unterordner an  c:\allegro, und der
Nutzer soll einen davon wählen. Das geht so:

fnam |.c:/allegro/*
ins #uvz
var "Wahl=" #uvz
  zur Wahl anbieten
select
if cancel end
  gewaehlten Namen in #uvZ
ins #uvZ
var "Ihre Wahl: " #uvZ
mes

In #uvZ steht dann nur der Name des Unterordners, den man also
mit c:\allegro\ zusammensetzen muß zum vollständigen Pfadnamen,
z.B. mit   var "c:\\allegro\\" #uvZ

Der Trick steckt in der ersten Zeile, also in dieser Syntax:

fnam |.<verzeichnisname>/*

Hier kann man somit statt  c:/allegro  jeden beliebigen Ordnernamen
einsetzen, mit / oder \\ als Trennzeichen zwischen den Stufen.
Statt nur * könnte da z.B. a* stehen, dann würden nur die mit
a beginnenden Ordnernamen angeboten.

Der Befehl  fnam |.  schreibt die Namen der Unterordner in die iV,
bietet sie also nicht selber zur Wahl an! Das tut erst der Befehl
select, der sich mit der korrekten Syntax anschließt.

Statt als select-Liste kann man auch die Namen als ViewListe anbieten.
Beide Rezepte sind als Beispiele 3 und 4 in der Dokumentation zum
Befehl  fnam  genau angegeben! Trick 53 ist also streng genommen
überflüssig - aber hatten Sie's schon gewußt?

Damit sich's aber trotzdem lohnt, hier noch ein


ExtraTrick:
Dem Nutzer sollen alle Dateien vom Typ .flx und .inc gemeinsam
zur Wahl angeboten werden! Das geht so:

fnam FLEXdateien|*.flx;*.inc

Ergo: Hinter dem | kann nicht nur einer, sondern mehrere Dateitypen
stehen, getrennt durch ;. Das ist nicht neu, das war schon lange so,
es stand bloß noch nirgends.
Wenn es ein bestimmtes Verzeichnis sein soll, z.B. c:\allegro\flex,
dann muß es so aussehen:

fnam FLEXdateien|c:\\allegro\\flex\\*.flx;*.inc

Hier allerdings geht / statt \\ nicht, sorry. Es liegt einfach daran,
daß nicht alle internen Windows-Funktionen in dem Punkt einheitlich
arbeiten.


---------------------------------------------------------------------------------------------------


Trick 54: Von Rechts wegen ...
Prüfen, ob Schreibrecht besteht

Aufgabe: Beim Start automatisch prüfen, ob die Rechte ausreichen.

Warum: Es kommt vor, daß z.B. der Administrator einem Nutzer von a99
       zu geringe Rechte zugeteilt hat. Der wundert sich dann, daß er
       keine Daten korrigieren kann oder die TBL nicht freigeben etc,
       Derlei Irritation sollte sich verhüten lassen.

Lösung: Dafür kann man sich folgende Sequenz in den _start.flx
        einbauen. An die ausgelieferte kann man dies einfach
        unten anhängen.

  ------------------------------------------------------------
  1./2. Schreibrecht auf Temp- und Start-Verz. prüfen

var M "testdatei"
open x
if no perform nom
close x

var W "\\testdatei"
open x
if no jump now
close x

  3. Prüfen, ob access-Zahl und tatsächliche Berechtigung gleich sind
  Tatsächl. Berechtigung:
var A
ins #uzB
  Trick 17, um die INI-Einstellung  access=...  zu ermitteln:
var "F" V
var
var (b"~access=" e"^M" e" " f" ")
  Beides vergleichen:
if not =#uzB mes Berechtigung auf Datenverz. reicht nicht zum Schreiben!
end

:nom
var "Kein Schreibrecht auf dem temp. Verzeichnis " M
mes
return
:now
var "Kein Schreibrecht auf dem Arbeitsverzeichnis " W
mes
end
  ------------------------------------------------------------

Der Trick ist nur, daß die tatsächliche Berechtigung A beim Start
automatisch auf 0 geht, wenn auf dem Datenverzeichnis kein Schreibrecht
besteht. Die INI-Einstellung "access=..." wird mit Trick 17 ermittelt.
Sie gilt dann aber womöglich nicht, weil der Admin das Schreibrecht auf
dem DbDir nicht eingeräumt hat.

---------------------------------------------------------------------------------------------------


Trick 55: Schnelle Rechenhilfe


Aufgabe: Schnell mal eben eine FLEX-Prozedur machen, die immer dieselbe
         Rechnung ausführt, nur mit einem jeweils anderen Eingabewert

Warum: Zuweilen muß man routinemäßig eine Reihe von Zahlen abarbeiten,
       z.B. jede Zahl mit einem bestimmten Faktor multiplizieren.
       Man wünscht sich dann, daß man nur die Zahlen eingeben muß und
       sonst nichts, damit es schnellstmöglich geht.

Lösung: Mit den Rechenfunktionen gibt es eine Vielzahl von Lösungen.
        Hier wird nur ein Grundkonzept gezeigt, das sich bei Bedarf
        leicht ganz beliebig ausbauen läßt.
        Es folgt das kleinstmögliche Skript, um vom eingebebenen Betrag
        jeweils die Mehrwertsteuer zu errechnen, also 19%.

:begin
Z=0,19
ask Betrag
if "" end
Z*
var Z
show iv
jump begin

Der Trick ist der Befehl  show iv, der das Ergebnis (in dem Moment
in der iV befindlich) im Schreibfeld anzeigt. Dadurch kann der
Nutzer, ohne erst noch ein OK zu bestätigen oder dergl., sofort die
nächste Eingabe tätigen. Leereingabe beendet die Schleife.
Etwas genauer:
Der Befehl  Z*  nimmt den gerade eingegebenen Betrag, der sich in
dem Moment in der iV befindet, und multipliziert ihn mit dem Wert
von Z, der vorher auf 0,19 gesetzt wurde. Das Ergebnis landet wieder
in der iV und kann mit  show iV angezeigt werden.

1. Verbesserung
---------------
Wenn man es ausprobiert, kommt ganz sicher die Situation: Autsch,
hatte ich den Betrag richtig eingegeben? Oder: Hatte ich diesen
Betrag nicht vorhin schon berechnet? Dann wär's gut, man könnte
nochmal sehen, was gerade oder vorher eingegeben und schon berechnet
worden war.
Das Basis-Skript für diesen Zweck sieht so aus:

var ""
sho IV
:begin
Z=0,19
ask Betrag
if "" end
ins #ubt
Z*
var #ubt(0,10) Z n
sho iv
sho +IV
jump begin

Hier ist der Trick das Anhängen (mit show +IV) der jeweiligen Zeile mit
Eingabe und Ergebnis an den Text im Anzeigefeld, der zu Anfang
leergemacht wird.
NebenbeiTrick: Die Angabe  #ubt(0,10)  bewirkt ein Auffüllen des
eingegebenen Betrags mit Leerzeichen auf 10 Stellen, wodurch das
Ergebnis immer schön auf derselben Spalte anfängt.


2. Verbesserung für Fortgeschrittene
------------------------------------
Wenn es eine kompliziertere Berechnung statt einer simplen Grundrechen-
aufgabe ist, nutzt man seit V27 komfortabel die Funktion "eval"
(siehe  h xeval)
Man modifiziert dann so:

ask Betrag
ins #ubt
 ... eval-Funktion mit Verwendung von #ubt
 ... Rest wie gehabt.

SonderTip
Der FLEX  evt.flx  zeigt, wie man eval-Funktionen sogar so einbinden
kann, daß der Nutzer statt einer einzelnen Zahl eine richtige
Rechenaufgabe mit Zahlen, Operatoren und Variablen eingeben kann.

---------------------------------------------------------------------------------------------------


Trick 56: Odnung im Feld schaffen

Aufgabe: Schnell mal eben die in #31 stehenden Schlagwörter
            alphabetisch ordnen.

Warum: Manche Felder werden mit mehreren gleichartigen Inhalten
       gefüllt, mitunter werden es recht viele. Wenn sich z.B.
       50 Schlagwörter in #31 angesammelt haben, ist ein Sortieren
       sinnvoll, um etwa Doppeleinträge leichter zu entdecken. Bei
       der Anzeige des Titelsatzes macht es sich auch besser, wenn
       die Schlagwörter nicht total ungeordnet erscheinen.

Lösung: Bis V27.5 war das eine echt schwierige Aufgabe und wurde
        kaum jemals angepackt. Ab V27.6 ist es leicht, weil es den
        neuen FLEX-Befehl "sort" gibt. Ganz ohne Trick kommt man aber
        auch hier nicht aus...

So sieht der Kern eines FLEXes aus, der die Aufgabe löst:

var #31 " ; ||"
ins _; _^M^J_
sort
ins _^M^J_; _
var (e"; ||")
ins #31

Und der Kenner erkennt: Im lokalen Ersetzungsbefehl ins _.._.._
können jetzt Steuerzeichen vorkommen! ^A für Code 1, ^M für 13,
^J für 10 usw. usf. Der Befehl "sort" braucht die Steuerzeichen
13 10 (= Zeilenvorschub) als Trenner zwischen den zu ordnenden
Elementen, denn beim Ordnen von Textdateien sind das Zeilen.
Deshalb wird der Trenner "; " zuerst durch 13 10 ersetzt, nach
dem "sort" dann wieder retour.

Aber wozu das  "; ||"?  Das ist der wahre ExpertenTrick.
Ohne es würde hinterher dem letzten Schlagwort, wenn es dann
plötzlich in der Mitte auftaucht, die Trennung "; " zum nächsten
fehlen! Wenn am Ende "; ||" steht, dann wirkt 
||  wie ein
weiteres Schlagwort, aber es bleibt beim Ordnen am Ende, weil
|| auf jeden Fall hinter allem kommt, was mit z beginnt.

Wie man's macht, wenn es nicht #31 ist und/oder wenn die
Trennung nicht "; " ist, das wird jeder leicht erkennen.
Auch der Einbau in die gewöhnliche Schleife zum Abarbeiten
einer Erg.Menge oder gar der Gesamtbank ist Routine.
Aber wäre nicht ein Unterprogramm das Beste, das einem die
Arbeit abnimmt, d.h. dem man nur die Kategorienummer übergibt und
dann macht es den Rest alleine? Gute Idee. So könnte das aussehen:

  Das ist der Aufruf: (statt #31s die gewünschte Nummer)
var "#31s"
perf fsort
...
end

  Und das ist das Unterprogramm:
  (in der iV steht die übergebene Kategorienummer)
:fsort
ins $katnr
var
var +"; ||"
ins _; _^M^J_
sort
ins _^M^J_; _
var (e"; ||")
ins $inhalt
var $katnr " " $inhalt
ins
return

Tip: Wer das schrittweise analysieren und verstehen will, setzt sich
mes-Befehle dazwischen und sieht dann, was in dem Moment in der iV
steht. Der entscheidende Trick ist das  ins  in der zweitletzten
Zeile. In der iV steht in dem Moment die übergebene Feldnummer (hier
die #31s) und in  $inhalt  steht der neue (geordnete) Feldinhalt, zusammen
ergibt das also ein komplettes Datenfeld. Das  ins  ordnet es nur noch in den
Datensatz ein.

---------------------------------------------------------------------------------------------------


Trick 57: Sauberes Filtern   (Ohne unfreiwillige Umcodierung)

Aufgabe: Schnell mal eben eine Textdatei einlesen und wieder

            rausschreiben, garantiert ohne daß ein Zeichen verändert
            wird, außer bestimmten Zeichen(folgen) oder Zeilen.

Warum: Mitunter liegt eine Textdatei vor (ASCII oder ANSI oder noch was
       anderes) und man muß einzelne Zeilen hinauswerfen, herausfischen
       oder in ganz bestimmter Weise verändern, alles andere soll aber
       exakt so bleiben, wie es ist. Solche Vorgänge werden gern als
       "Filtern" bezeichnet.
       Perlentaucher und Pythonbändiger werden hier abwinken: Mach'
       ich mit einem Zweizeiler, wenn nicht gar mit "grep"! Sicher,
       aber es geht darum, solche Vorgänge auch bei Bedarf innerhalb
       eines FLEXes nebenbei miterledigen zu können, als Teil einer
       größeren Aufgabe. Zwar kann ein FLEX auch Python- oder Perl-
       skripte anstoßen und deren Ergebnisse verwerten, aber das
       Vorhandensein der betr. Skriptsprache kann man leider nicht
       generell voraussetzen.
       OK, es gibt schon den FLEX file.flx, der Textdateien zeilenweise
       liest und wieder schreibt. Aber dabei verschwinden Leerzeichen
       am Zeilenende. Und: Sonderzeichen außerhalb des definierten
       Bereichs von OstWest-Zeichen, vor allem in der Gegend von
       186-218, werden u.U. verfälscht. Das soll nicht sein!

Lösung: Die Zeilen werden eingelesen wie sonst auch, sie werden aber
        NICHT in einer #u-Variablen zwischengespeichert, sondern, und
        das ist der Trick, ganz ohne solche Umschweife gleich wieder
        rausgeschrieben.
        Der Hinweis soll nicht fehlen:
        WENN Zwischenspeicherung, dann in einer $-Variablen! Diese
        unterliegen beim Einlesen und Speichern keiner Umcodierung
        oder Leerzeichenbeseitigung (siehe Fußnote ganz unten).

Sagen wir, unsere Ausgangsdatei ist "input.txt", die Ergebnisdatei soll
"output.txt" heißen.

Wir zeigen hier einen FLEX-Abschnitt, der das Problem löst, auf die
kürzestmögliche Weise. Diesen Abschnitt kann man sich herauskopieren
und in beliebige FLEXe modifiziert einbauen, wo man derartige Aktionen
braucht. Es sind mehr als zwei Zeilen, zugegeben, es sind sieben (ohne
Öffnen und Schließen), aber kurz und unkryptisch.

  ------- BEGINN DES MUSTERS --------------------------------------
...
  Die Dateien öffnen (zum Lesen bzw. Schreiben)
open input.txt
open x output.txt
  ^^^^^^^^^^^^^^^^^ Beginn der Schleife
:GLOOP
  naechste Zeile lesen
get iV
  war keine Zeile mehr da? Dann Ende
if cancel jump GLEND

  eine gelesene Zeile steht jetzt in der iV
  ***************************************************
  Hier ist der Platz zum Manipulieren der Zeile!
  Ein paar Beispiele:
     Hinauswerfen: wenn "xyz" drinsteht, die Zeile weglassen
  if %xyz% jump GLOOP
     Herausfischen: wenn "xyz" drinsteht, die Zeile übernehmen
  if not %xyz% jump GLOOP
     Verändern: Z.B. Text-Ersetzung 'abc' durch 'xyz':
  ins _abc_xyz_
  ***************************************************
  In iV steht jetzt ein u.U. veränderter Inhalt
  Raus damit in die Datei, dann Zeilenvorschub dahinter:
write
write n
jump GLOOP

:GLEND
  ^^^^^^^^^^ Ende der Schleife
  Dateien schliessen
close
close x
...

  ------- ENDE DES MUSTERS -------------------------------------
 
Hinweis:
Man KANN auch auf Trick 44 zurückgreifen, der das Umcodieren einer
Datei vorführt! Man nimmt schlicht die Zeilen heraus, die sich mit
der Umcodierung befassen, bes. die Zeile  xcode xp. Fertig eingebaut
ist das in den mitgelieferten FLEX  filecode.flx.
Ferner kann man kombinieren mit Trick 52 ("Dateien abklappern"), um
mehrere Dateien in gleicher Weise zu filtern.

ABER ACHTUNG:
Hier ist von TEXTdateien die Rede, die aus ZEILEN bestehen! Die
Zeilen sind durch die Codes 13 10 getrennt, der Befehl "get"
liest genau die Zeichen zwischen zwei solchen Kombinationen,
die Steuerzeichen selbst gehören nicht zur Zeile. Sie werden deshalb
im write-Befehl mit dem  n  (für 'newline') wieder angefügt.
Dateien ohne solche Struktur sind ein anderes Thema (Trick 58).

Fußnote zur Umcodierung
=======================
Wenn man im FLEX schreibt:
var "xyz"\ins #nnn
was passiert dann?
Dann wird der Text, der in der iV steht, so behandelt, als hätte man
ihn gerade im Schreibfeld eingegeben. Und was ist das Problem?
Was man im Schreibfeld eingibt, das ist intern immer ANSI-Code.
Im FLEX kann es aber sein, wenn er z.B. mit X-Editor erstellt
wurde oder wenn man ASCII-Daten bearbeitet, daß der iV-Inhalt nicht
ANSI ist, sondern ASCII. Was per Schreibfeld eingegeben wurde,
das wird per o-Tabelle der Indexparameter in den internen Daten-
bankcode gewandelt, normalerweise also von ANSI nach ASCII.
Deshalb wird im Normalfall unser ASCII-"xyz" VOR der Übergabe an
die Verarbeitung noch per o-Tabelle nach ANSI gewandelt - um dann
sofort wieder zurückverwandelt zu werden. Na schön, dann ist es
wieder mit "xyz" identisch, alles in Butter!? Normalerweise ja, aber
beim Vararbeiten einer Textdatei kann diese auch Zeichen enthalten,
die es im OstWest-ASCII nicht gibt, z.B. 202 oder 217. Diese werden
per o.apt - aus lauter Verlegenheit - alle auf 127 abgebildet. Für
die Abbildung ANSI->ASCII bedeutet das aber, daß sie alle auf 217
landen, welches zufällig der letzte Wert in o.apt ist, der die 127
zugewiesen bekommt. [Könnte man das nicht wirklich nochmal ändern?
Gute Frage, wird notiert. Könnte nicht mit "set c2" die gesamte
Umschalterei abgeschaltet werden? Guter Vorschlag, steht schon
auf dem Zettel für V28.]

Wenn der FLEX nun aber mit einem ANSI-Editor (z.B. NotePad) erstellt
wurde? Dann muß man
set c1
geben, bevor ein "insert" kommt. Die erste der beiden Umwandlungen
(die des FLEX-Textes in ANSI) unterbleibt dann, aber die zweite muß
natürlich sein.

Aber wenn man intern ANSI hat und nicht ASCII? Dann braucht man eine
andere o.xpt! Wie z.B. beim N-Format: Die o.npt ist fast leer,
nur wenige Werte müssen aus internen Gründen umgewandelt werden.

Klingt verzwickt? Klar, müßte alles nicht sein, wenn man nur ein
einziges Codesystem hätte, z.B. UTF-8. So bequem ist die reale Welt
aber nun mal nicht beschaffen.

---------------------------------------------------------------------------------------------------


Trick 58: Strategie der kleinsten Schritte   (Datei Byte für Byte lesen und verarbeiten)

Aufgabe: Schnell mal eben eine Binärdatei durchsehen und schauen, ob
            eine bestimmte Codefolge darin vorkommt und wie oft.
            Schön wäre, die Vorkommnisse auch angezeigt zu bekommen,
            aber mit 30 Zeichen oder so links und rechts davon. Und
            auch die Position innerhalb der Datei (sog. "Offset")!

Warum: Es gibt Dateien ohne Zeilenstruktur, und zwar nicht wenige.
       Oft steht kein lesbarer Text drin, sondern codierte Daten.
       Man nennt sie oft "Binärdateien", obwohl JEDE Datei aus Bytes
       und jedes Byte aus Bits (= binary digits) besteht und somit
       ALLES binär gespeichert ist.
       Neben den Programmdateien (.EXE u.a.), von denen man besser
       die Finger läßt, gibt es Bild- und Videodateien (.JPG. .AVI
       u.a.), mit denen aus Sicht von allegro-Anwendungen wohl auch
       nichts gemacht werden muß, aber es ist z.B. auch möglich,
       daß eine XML- oder HTML-Datei keine Zeilentrenner enthält!
       Das trifft auch auf MARC-Originaldateien zu. Und schließlich
       sind die allegro-Dateien der Typen .ALD/.ALG nicht zeilenweise
       strukturiert und enthalten neben Text- auch Steuerzeichen. Das
       bequeme Einlesen einer Zeile mit "get iV" geht jedenfalls dann
       nicht, weil die Zeilen-Steuerzeichen 13 10 fehlen.

Anm.:  Das Durchsuchen und Verarbeiten von .ALD und .ALG-Dateien geht
       natürlich am allerbequemsten mit der Volltextsuche, wenn man
       Zeichenfolgen sucht, die in den Datenfeldern vorkommen.

Will man sich nicht auf Dateien unterhalb einer bestimmten Länge
beschränken, sondern prinzipiell in der Lage sein, beliebig lange
Dateien durchzusehen, dann hilft nur die Verarbeitung Byte für
Byte. Ist das nicht furchtbar langsam? Es geht.
Zwar ist auch das Einlesen von Blöcken fester Länge
möglich (z.B. fetch 1000), aber wenn die zu suchende Zeichenfolge
genau auf einer Blockgrenze liegt (z.B. auf Position 999 beginnt),
gibt es ein Problem...


Lösung:
       Ein einzelnes Byte einlesen, das kann man auf zwei Arten machen:

fetch 1  
          holt ein Byte in die iV, wobei Steuercodes unterhalb

          32 ersetzt werden durch ^ und einen nachfolgenden Buchstaben,
          und zwar A für 1 usw., @ für 0, ^Z für 26
          Mit  if "1" ...   prüft man, ob das Byte die Ziffer 1 ist
          Mit  if "^A" ...  dagegen, ob es der Bytecode 01 ist.

fetch b  
          holt das nächste Byte als Dezimalzahl; statt A also 65

          und statt a die Zahl 97, statt Ziffer 1 die 49.
          Mit  if 49 ...  prüft man, ob das Byte die Ziffer 1 ist
          Mit  if 1 ...   dagegen, ob es der Bytecode 01 ist.

Beide Befehle eignen sich für den hier in Rede stehenden Zweck.
(Umcodiert wird hierbei übrigens nie!)
Nur der erste eignet sich, wenn man das gelesene Byte hernach mit
"write ^" wieder korrekt in eine andere Datei hinausschreiben will.

Der erste Trick besteht nun darin, Zeichen für Zeichen mit einem der
beiden Befehle zu lesen und jeweils mit dem ersten Zeichen der
gesuchten Folge zu vergleichen. Nur bei Gleichheit geht es dann
weiter mit dem Lesen des nächsten Zeichens und Vergleich mit dem
zweiten Zeichen der Folge usw., sonst braucht das zweite Zeichen
ja nicht mehr verglichen zu werden.

Der zweite Trick ist, bei einer Übereinstimmung des ersten Zeichens
dessen Position in der Datei mit  fetch p  zu bestimmen und zu sichern.
Bei Nichtübereinstimmung des zweiten, dritten ... Zeichens wird dann
zu der gesicherten Position zurückgekehrt (mit fetch m) und das
nächste Zeichen geholt. Nur so kann man, wenn z.B. nach der Folge
'121' gesucht wird, zwei Treffer ermitteln, wenn in der Datei die
Folge  '12121' auftritt, d.h. die gesuchte Folge innerhalb ihrer
selbst neu beginnt.

Beispiel
========
Es soll festgestellt werden, ob und wie oft in der Datei abc.xyz
die Zeichenfolge '121' auftritt. (Leider muß man an mehreren Stellen
eingreifen, wenn es eine andere Folge sein soll, siehe ACHTUNG...
Enorm elegant ist diese Lösung also nicht, zugegeben.)

  ------------------------ MUSTER ------------------------
  Die Datei öffnen
open abc.xyz
  Protokolldatei öffnen
open x ergebnis.txt

  Zähler für die Vorkommnisse
z=0
  ^^^^^^^^^^^^^^^^^ Beginn der Schleife
:GLOOP
  naechstes Zeichen lesen, als dezimale Bytezahl
fet b
  war denn noch eins da? Sonst Ende
if can jump GLEND
  ein gelesenes Zeichen steht in der iV als Zahl
  ***************************************************
  Hier ist der Platz zum Manipulieren!
  Erstes Zeichen vergleichen: (Ziffer 1 = Byte 49)
if =49 jump MATCH   // <- ACHTUNG: anpassen
  ***************************************************
  Das erste Zeichen wurde noch nicht gefunden
jump GLOOP

  erstes Zeichen gefunden, die weiteren einzeln vergleichen
:MATCH
  Offset-Position hinter dem ersten Zeichen in $pos vermerken
fet p
ins $pos
  jetzt einzeln lesen und vergleichen, bei Ungleichheit -> :NEXTP
fet b
       ACHTUNG: hier ebenfalls anpassen für die weiteren Bytes
if not =50 jump NEXTP   // Ziffer 2
fet b
if not =49 jump NEXTP   // Ziffer 1
  ... hier evtl. noch weitere Bytes in dieser Weise behandeln
  Treffer! Zähler erhöhen
z+1
  Meldung in die Ergebnisdatei
wri "Pos. " $pos ": "

  Umgebung 30 Zeichen links und rechts abgreifen
eval $pos -30
if <0 var "0"
  Pos. 30 Byte nach links setzen
fet m
  50 Zeichen holen
fet 60
ins $umg
  und mit ausgeben
write "..." $umg "..." n

:NEXTP
  Zur gemerkten Position zurück
var $pos
fet m
  und dort weitermachen
jump GLOOP

:GLEND

  ^^^^^^^^^^ Ende der Schleife
  Datei schliessen
close
  Zähler ausgeben (ACHTUNG: Wert "121" anpassen)
wri n "121  wurde " z "mal gefunden"
close x
  Ergebnisdatei zeigen
help ergebnis.txt

  --------------------- MUSTER ENDE ------------------------

Teil 2:
Binäre Dateien Byte für Byte verarbeiten, z.B. auch XML

Brauchen kann man das immer dann, wenn eine Datei u.U. keine
Zeilentrenner hat, wie z.B. bei XML. Dann ist vor allem "get" zum
Einlesen der nächsten Zeile nicht anwendbar.

Im Kern gibt es dabei zwei Tricks:

1. Die Sequenz 

   fetch 1
   write ^

   (Sonderfall: Zeichen ^ wird intern zu ^~)
   liest zuerst ein Byte als Zeichen, wobei Steuercodes wie z.B. 13 10
   in der Form  ^M^J  in die iV gesetzt werden (^ und M getrennt!).
   Der zweite Befehl schreibt den Inhalt der iV in entsprechender
   Weise in die Ausgabedatei, d.h. aus  ^M  wird wieder der Code 13.

   Zwischen diesen beiden Zeilen kann man mit dem eingelesenen Zeichen
   natürlich anstellen, was immer man will. Statt des zweiten Befehls
   kann man auch ganz andere Dinge machen, schließlich muß nicht für
   jedes Zeichen wieder genau ein Zeichen ausgegeben werden.

2. Mit dem Befehl

   fetch c

   schaut man nach, was das nächste Zeichen ist, ohne daß schon der
   Dateizeiger weitergerückt würde. Das braucht man, um nach dem
   Einlesen eines '<' schon mal zu spicken, ob als nächstes
   ein '/' kommt.

Als Beispiel nehmen wir die Aufgabe, schnell mal eben eine XML-Datei
ein ganz klein wenig leichter lesbar darzustellen:
1. Jedes Tag soll auf neuer Zeile beginnen, schließende Tags aber nicht
2. Die echten Daten, also was zwischen den Tags steht, sollen fett
   angezeigt werden.
[Man braucht das nicht wirklich, es gibt ja mächtige XML-Werkzeuge,
angefangen bei notepad++. Es geht nur um das Schema der VerFLEXung
dieser Aufgabe. Anwendbar auch auf HTML.]

So sieht der fertige FLEX aus:

  ----------------------------------------------------------------
  XMLSHOW.FLX : XML-Datei anzeigen, Feldinhalte fett
  2008-12-09  : Es wird zunaechst eine RTF-Datei draus gemacht

  Aufruf:   X xmlshow dateiname

  Dateiname steht in iV, oeffnen
open
if no mes Die Datei gibt's nicht;end

  Datei zum Schreiben oeffnen
open x xmlshow.rtf
  Dateikopf, damit rtf-Anzeige dann klappt
wri Flisthead.rtf

  Schleife verarbeitet die Datei zeichenweise
:LOOP
  naechstes Zeichen holen
fetch 1
  Dateiende? -> :dende
if cancel jump dende
  Ist es < oder > ? Dann Sonderbehandlung
if "<" perf k;jump LOOP
if ">" perf g;jump LOOP
  normal: Zeichen einfach wieder rausschreiben
wri ^
jump LOOP

:dende
close
  Abschluss der rtf-Datei
wri "}}}"
close x
  und anzeigen
help xmlshow
end

:k   // UPro fuer Zeichen <
  welches Zeichen kommt hinter < ?
fetch c
  Falls nicht </, dann auch neue Zeile
if not ="47" wri "\\b0 \\par " n "<";return
  sonst nur Fett abschalten
wri "\\b0 <"
return


:g   // UPro fuer Zeichen >
  Fett einschalten, es kommt (vielleicht) ein Inhalt
wri ">\\b "
return

---------------------------------------------------------------------------------------------------


Trick 59: Superschnelles Einspeisen   (großer Mengen neuer Daten)

Aufgabe: Schnellstmöglich 20.000 oder mehr Datensätze einbringen.
           
Warum: Es kommt vor, daß man ohne spürbare Beeinträchtigung des
       laufenden Betriebs ganz schnell eine größere Menge neuer Daten
       verfügbar machen will.

Lösung:
Falls es genügt, die neuen Daten zunächst über einen oder zwei ganz
wichtige Schlüssel finden zu können, dann läßt sich etwas machen.
Eine Index-Erneuerung irgendwann später muß dann aber den Index
vervollständigen.
Vorliegen müssen die Daten zuerst einmal als Grunddatei (Typ .ALG)
oder Externdatei (Typ .ADT).
Dann kommen zwei Tricks zur Anwendung:

1. Es wird eine abgemagerte Indexparameterdatei automatisch erstellt,
   die nur die ersten zwei ak-Befehle enthält. Diese wird dann statt
   der normalen geladen, so daß dann neu zu speichernde Daten viel
   schneller indexiert werden können - die Anzahl der Schlüssel ist
   nämlich der Haupt-Zeitfaktor beim Abspeichern.

2. Das Einlesen geschieht zunächst ohne Speichern mit dem z-Wert 0
   beim update-Befehl, dann gelangen die Sätze nur in den Offline-
   speicher. Danach wird mit "save off" gespeichert. Das geht schneller
   als update mit z-Wert 1, denn dabei wartet das Programm jeweils
   0.5 Sekunden zwischen zwei Sätzen.

Als Vorbereitung kann man in den Indexparametern die ersten zwei
ak-Befehle so präparieren, daß damit die entscheidenden Schlüssel
erzeugt werden. In cat.api könnte man etwa direkt unter die Zeile
ak=zz+@
diese neue Zeile einsetzen:
ak=20+G
dann würde der Titelanfang als zweiter der beiden Schlüssel produziert,
der erste wäre der Primärschlüssel (IdNummer in #00).
An drei Stellen, mit *** markiert, muß man eingreifen, bevor man den
FLEX einsetzt:
***1 Sollen es drei oder mehr Schlüssel sein? Bei  z>2  Zahl einsetzen!
         Vielleicht sogar nur 1, vielleicht auch 5.
***2 Den korrekten Dateinamen statt <xyz> einsetzen.
***3 Die Nummer der Datei einsetzen, in welche die neuen Daten sollen

So sieht der FLEX aus, der beide Tricks realisiert:

  ----------------------------------------------------------------
  Vorbereitung: Prüfen, ob neue oder bearb. Saetze im Offline-Speicher
find new
if g0 mes Es gibt noch ungespeicherte neue Saetze, zuerst speichern!;end
find edit
if g0 mes Es gibt noch ungespeicherte bearbeitete Daten, zuerst speichern!;end
  Wenn nicht, dann Offline-Speicher leeren
erase off

  1. Indexparameter abspecken: nur die ersten 2 ak-Zeilen
     alles andere bleibt drin.
var D B "." K1 "pi"
open
if no mes Kann die Indexparameter nicht finden!;end
  Abgespeckte Datei soll mager.api heissen und auf DbDir liegen
var D "mager." K1 "pi"
open x

z=0
:loop
get
if cancel jump lend
  Kommentare und leere Zeilen weglassen
if " " jump loop
if "" jump loop
  ak-Zeile gefunden: zaehlen, bei 3 abbrechen  ***1
if "ak=" z+1;if z>2 jump loop
write
write n
jump loop

:lend
close
close x
  Magere Index-Param.datei ist fertig
  Diese jetzt laden
var "mager"
index p

  2. Update
     Einstellung: alle Saetze nehmen, aber nicht sofort speichern
set u010
  Dateinummer für die neuen Daten (Nummer von 1 bis 255)  ***3
input 129
  Datei <xyz> einspeisen. Statt <xyz> den echten Namen einsetzen! ***2
update <xyz>
  Daten jetzt im Offline-Speicher
  Fragen ob Speichern gewuenscht
yesno Speichern?
if yes save offline
if no var "Speicherung dann auf Wunsch mit 'x save off'" n "Oder Abbruch mit 'x erase off'";mes
sho off
  Jetzt sind die Sätze gespeichert und "mager" indexiert
  Die normalen, fetten Indexparameter wieder laden
var B
index p
  Dateinummer zurücksetzen  ***3
input 1

---------------------------------------------------------------------------------------------------


Trick 60: Wiederholungstaten   
                Alles Wichtige über Schleifen in FLEX

Aufgabe: Einfachstmöglich eine Befehlsfolge immer wieder abarbeiten,
         bis ein bestimmter Wert oder eine Bedingung auftritt.

Warum: Das zyklische Durchlaufen von Befehlsfolgen gehört zu den
       häufigsten Übungen beim Programmieren. Dafür muß es einfache
       Rezepte geben, die man routinemäßig anwenden kann.
       So etwas nennt man auch "Schleife", weil dabei wieder und
       wieder zum Anfangspunkt einer Befehlsfolge zurückgekehrt wird.

Lösung:
Zuerst etwas Theorie
Richtige Programmiersprachen (so eine ist FLEX nicht) haben drei
oder vier Lösungen. Schematisch sehen sie folgendermaßen aus:

1. Die for-Schleife      for(anfangswert; bedingung; schrittbefehl)
   ----------------         <befehle>

   Das ist wohl die beliebteste Form.
   Der "for"-Befehl setzt einen Anfangswert, eine Bedingung
   und einen Schrittbefehl. Die dann folgenden <befehle> werden so oft
   ausgeführt, und jeweils danach der Schrittbefehl, wie die bedingung
   noch gilt.
   Falls die bedingung gleich schon zu Anfang nicht gilt, werden
   die  <befehle>  gar nicht ausgeführt.

2. Die while-Schleife    while(bedingung)
   ------------------       <befehle>

   <befehle> werden so lange immer wieder ausgeführt, wie bedingung
   gilt. Gilt die bedingung schon am Anfang nicht, passiert nichts.

3. Die do-Schleife       do
   ---------------          <befehle>
                               while(bedingung)

   <befehle> werden ausgeführt, dann bedingung geprüft, und wenn
   erfüllt, abermals <befehle>, bis bedingung nicht mehr gilt.
   Die Befehle werden also mindestens einmal ausgeführt, im
   Gegensatz zu 2. 

4. Die goto-Schleife     wenn nicht bedingung dann goto weiter
   -----------------     :marke
                                <befehle>
                                wenn bedingung dann goto marke
                                :weiter

   Die erste Zeile läßt man weg, wenn die <befehle> mindestens einmal
   ausgeführt werden sollen.
   Diese Form wird von Informatikern gering geschätzt, weil sie
   wenig übersichtlich ist und deshalb auch fehlerträchtig, vor allem
   ist sie kaum prüfbar, z.B. von einem Compiler oder Interpreter.
   Es gab Bestrebungen, sie in Acht und Bann zu tun, dazu ist es aber
   nicht gekommen.

Wichtig zu wissen: Alle 4 Formen sind logisch gleichwertig. Was man
mit einer davon machen kann, kann man auch mit jeder der anderen drei
Formen machen, allenfalls mit einer zusätzlichen Bedingungsprüfung.
Programmierer können sich folglich entscheiden, auf eine oder
mehr als eine davon ganz zu verzichten. Ob eine Konstruktion
übersichtlich und verständlich ist, hängt aber nicht nur von
ihrem Typ ab, sondern auch von der Art, wie sie umgesetzt ist,
wozu auch Kommentare gehören. So *kann* selbst der Typ 4 durchaus
übersichtlich und verständlich realisiert werden, der Typ 1 dagegen
erzwingt geradezu ein hohes Maß an Übersichtlich- und Durchschau-
barkeit, aber die Formulierung der Bedingung kann manchmal recht
abstrakt und schwer durchschaubar sein - Gewohnheitssache.
Form 1 ist scheinbar suboptimal in Fällen, wo die Anzahl der
Schleifendurchläufe nicht von einem Zähler abhängt. Mit geschickter
Wahl der Bedingung kann man das aber leicht umgehen und dann den
Schrittbefehl und sogar den Anfangswert weglassen - damit hat man
dasselbe wie Form 2.
Alle vier Formen stehen in der Gefahr, daß bei ungenügend durch-
dachten Bedingungen Endlosschleifen entstehen können. Es ist sogar
grundsätzlich unmöglich, dies softwaretechnisch auszuschließen.

FLEX kennt leider nur den Typ 4, wobei es scheinheiligerweise nicht
goto heißt, sondern jump. Man muß also überlegen, wie man damit
geschickt und sicherheitsbewußt umgeht, aber schwer ist das nicht.
Wir zeigen es an zwei Beispielen, die man als Schemata leicht
übernehmen und verinnerlichen kann.

A. Schleife mit Zähler
======================
Für die Zahlen von 1 bis 100 sollen bestimmte Dinge ausgeführt
werden, die hier symbolisch durch <befehle> dargestellt sind:

   z=1
   :loop
   <befehle>
   z+1
   if z<101 jump loop

Innerhalb der <befehle> kann z auch noch vorkommen, muß aber nicht.
Aufzupassen ist, z nicht innerhalb der <befehle> zu *verändern*, es
sei denn, aus genau überlegten Gründen. Beim if-Befehl wird der
momentane Wert von z genommen, egal wie er zustandekam.

Hinweis: Als Name für eine Schleifenvariable nehmen Programmierer
gewohnheitsmäßig oft das i. In FLEX gibt es das nicht, da ist z
die einzige ganzzahlige Variable und Z die einzige Gleitkommavariable.
Mit den sonstigen Variablen kann man jedoch auch gut rechnen, nur
nicht ganz so direkt wie mit z und Z.
Ersatzweise kann man z.B. so arbeiten - mit $i statt i:

   $i=1
   :loop
   <befehle>
   eval $i+1
   ins $i
   if <101 jump loop
     --- Ende :loop ---

Hier steht vor dem <101 kein $i! Es wird vielmehr der Inhalt der
internen Variablen genommen, und das ist in dem Moment eben noch
der Wert von $i. Verbal kann man die letzten drei Zeilen so ausdrücken:
Addiere 1 auf den Wert von $i, setze das Ergebnis in die Variable $i,
vergleiche diesen Wert mit der Zahl 101, und wenn er kleiner ist,
springe zur Marke :loop.
Variante: Die Endzahl kann auch in einer #u-Variablen stehen oder in
einem Datenfeld. Dann sieht die Endprüfung so aus:

if <#nnn ...
   also z.B.  if <#uxy jump loop   oder   if <#123 jump loop


Empfehlung: Eine Sprungmarke, die als Schleifenbeginn dient, benennt
man entweder :loop  oder mit einem Namen, in dem :loop vorkommt.
So wird visuell immer sofort klar, was da vorliegt. Einen Anfangswert,
wenn einer gebraucht wird, immer in der direkt vorangehenden Zeile
setzen. Zur visuellen Verdeutlichung *kann* man einen Kommentar, wie
hier  --- Ende :loop ---  unter das Schleifenende setzen.
Hinweis: Wenn zwei gleiche Sprungmarken in einem FLEX vorkommen, dann
         gilt nur die erste.

B. Schleife mit beliebiger logischer Bedingung
==============================================
   In FLEX sehr viel häufiger als Zählschleifen! Aber genaugenommen
   ist A. sowieso nur ein Spezialfall von B.
   Beispiel: Ergebnismenge abarbeiten
   Die Sätze einer Ergebnismenge sollen abgearbeitet werden, d.h. für
   jeden Satz sind bestimmte Befehle auszuführen. Dabei wird kein
   Zähler gebraucht. Hier das Muster:

first
:eloop
<befehle>
next
if yes jump eloop

   Im Hilfetext zu "next" (h xnext  eingeben) findet man auch das
   Muster, mit dem man die gesamte Datenbank abarbeiten kann.

Und wo ist jetzt der Trick? Ob man wirklich hier von Tricks sprechen
will, sei dahingestellt. Es sind zwei Dinge zu nennen, die dem
Einsteiger wie auch dem in anderen Sprachen bewanderten Programmierer
als Aha-Erlebnis erscheinen können:
1.
Eine FLEX-Schleife kann mehr als einen Rücksprung zum Schleifenanfang
haben. Das ist nicht nur praktisch, es ist hinsichtlich der Durchschau-
barkeit und Fehlerträchtigkeit auch mit Vorsicht zu genießen!
2.
Der Rücksprung zum Schleifenanfang kann nicht nur durch einen Zahlen-
vergleich ausgelöst werden, sondern durch jeden der zahlreichen if-
Befehle, die FLEX bereithält.

Zusatz-Trick: Ausbruch aus Endlosschleifen
Mit dem Einbau dieser zwei Zeilen in das Innere einer Schleife:

keycheck
if yes jump weiter

kann man erreichen, daß man sie mit Druck auf Esc abbrechen kann.
Wenn dann mal stundenlang einfach nichts zu geschehen scheint, entnervt
Esc drücken - und dann die Schleifenlogik nochmal durchdenken!

---------------------------------------------------------------------------------------------------

Trick 61: Druckregler   
                Druckparameter während der Sitzung wechseln

Aufgabe: Schnell mal eben die Druckparameter wechseln, ohne
         a99 mit anderer INI neu starten zu müssen.

Warum: Die Druckparameter werden in der INI-Datei mit dem Befehl
       PrintParameter=...
       eingestellt und gelten dann fuer die ganze Sitzung.
       So scheint es. Aber bei den Anzeigeparametern ist es anders,
       und auch die Exportparameter lassen sich per Menü ändern!
       Auch für das Drucken sollte es eine Schraube geben, an der
       man drehen kann!

Lösung:
Man braucht nicht auf die Entwicklungsabteilung zu warten! Geben Sie
mal ein:    h xprint
Da sehen Sie, daß es einen FLEX-Befehl dafür gibt.
Wer den kennt und weiß, daß er nun zur Abwechslung die Parameter
namens xyz.apr nutzen will, der gibt einfach ein

   x print p xyz

Wer das nicht weiß und auch nicht einsieht, es wissen zu sollen,
oder wer eine zu geringe Berechtigung hat (dann geht das mit dem x
nämlich nicht), dem kann auch geholfen werden.
Zum Beispiel so (siehe Trick 37):

Man macht sich eine Datei namens  onprop.flx, in der steht:

yesno Druckparameter wechseln?
if no end
var "Druckparameter|" D "*." K1 "pr"
fnam
if "" end
print p
mes Parameter sind gewechselt

Danach geht das Wechseln so: Rechter Mausklick ins Anzeigefeld,
"Eigenschaften" wählen, und schon kann man sich die Parameter
aus der erscheinenden Dateiauswahlbox aussuchen.
Statt des fnam-Befehls könnte auch eine select-Liste oder eine
View- oder Aresqa-Liste zum Einsatz kommen, die nur bestimmte,
ausgewählte Dateien anbietet! Ganz nach Geschmack.

---------------------------------------------------------------------------------------------------

Trick 62: Neues Erlebnis mit dem Ergebnis   
                Aus der aktuellen Erg.Menge eine andere machen

Aufgabe: Schnell mal eben aus einer Ergebnismenge eine andere machen,
         aus Sätzen, die mit denen der Erg.Menge zusammenhängen

Warum: Z.B. hat man eine Ergebnismenge, die aus lauter Bestell-
       datensätzen besteht, oder aus Exemplarsätzen. Was man aber
       gerne hätte in der Situation, das wären die dazugehörigen
       Titeldatensätze!

Lösung:

Man braucht folgende Dinge:
1. Einen Suchbefehl, mit dem man zu jedem Satz der Erg.Menge den
   gewünschten anderen Satz erhält.
   Der Trick dazu ist, den geeigneten Suchbefehl zu basteln und
   dann den Satz mit dem Befehl  f1nd herbeizuholen - denn dabei
   wird die momentane Erg.Menge nicht verändert! Das ist nötig,
   sonst könnte man sie nicht Satz für Satz durcharbeiten.

2. Ein Verfahren, wie man die so gefundenen Datensätze zu einer
   Ergebnismenge machen kann.
   Der Trick dazu ist, daß man zuerst die Satznummern der mit f1nd
   geholten Sätze in eine Datei schreibt und dann diese mit dem
   Befehl  read set ...  in eine Erg.Menge umwandelt!

Eine Komplikation besteht darin, daß es z.B. mehrere Bestellsätze
oder Exemplarsätze zu einem Titelsatz geben kann! In der angestrebten
Erg.Menge der Titelsätze soll es aber keine doppelten Sätze geben.
Der Trick dazu ist, die Erg.Menge der Titelsätze zuerst nach
Satznummern zu sortieren, dann die Nummern in eine Datei auszugeben
und dann diese Datei nochmals mit  read set ...  als Erg.Menge
einzulesen.
Puh! Hört sich schwierig an - viel einfacher geht es aber nicht.
Am besten nimmt man wohl ein ganz konkretes Beispiel und ändert
es an den wenigen Stellen ab, wo es sein muß. Hier ist das Beispiel:
o-titel.flx: (Kommentar ist erweitert, die zu modifizierenden Stellen
sind mit *** markiert)

  --------------------------------------------------------------------
  O-TITEL.FLX : Erg.Menge besteht aus Bestellsaetzen, finde dazu die
  2005-08-23    Titelsaetze und praesentiere als Erg.Menge
                Es kann zu einem Titel mehrere Bestellungen geben,
                das wird abgefangen, jeder Titelsatz kommt nur einmal!

if empty mes Keine Erg.Menge;end
first
  *** Spezifische Pruefung ***
  Sind das ueberhaupt Bestellsaetze?
if not #9DA jump sorry
  *** Ende spezifische Pruefung ***
 
  Hilfsdatei mit den internen Nummern der Titelsaetze zusammenstellen
open x titel.num
  Es muss zuerst eine Ueberschrift rein
wri "bestell" n

  Schleife zur Abarb. d. Bestellsaetze
:bloop
  *** Spezifischer Teil, nur hier muss man eingreifen! ***
  **** hier wird der zugehoerige Satz gesucht. ***
  Bestellsatz enthaelt TitelIdNr in #9DA$T
  Findbefehl fuer den Titelsatz zu der betr. Bestellung anlegen
var "|9 " #9DA$T
  *** Ende des spezifischen Teils ***

  Befehl ausfuehren, d.h. zugeh. Datensatz laden
  (f1nd laedt den Satz, bildet aber keine neue Erg.Menge)
f1nd

  interne Nummer dieses Titelsatzes in die Datei schreiben
write i n
  naechsten Bestellsatz aus der Erg.Menge holen
next
if yes jump bloop
  es gab keinen mehr
close x

  Jetzt Hilfsdatei (Nummernliste!) titel.num als Erg.Menge laden
    Da sind evtl. noch doppelte drin!
read set titel.num
  deshalb erst nach internen Nummern ordnen
order n
  Neue Hilfsdatei aufmachen
open x titel.set
  Ueberschrift rein
wri "Bestellungen" n
  und die Titeldaten-Erg.Menge wieder als Nummernliste speichern.
wri in
close x
  Liste neu einlesen, dabei fliegen Doppelte raus, weil sie direkt
    hintereinander stehen wegen der Ordnung mit "ord n"
read set titel.set
var "Die Erg.Menge besteht jetzt aus den Titeldaten" n "und wird gleich gezeigt!"
mes
  Erg.Menge im Kurzlistenfenster zeigen
show list
  Hilfsdateien loeschen
delete titel.num
delete titel.set
end

:sorry
var "Sorry, die aktuelle Ergebnismenge besteht nicht aus Bestelldaten"
mes
end

---------------------------------------------------------------------------------------------------


Trick 63: Das Wichtigste zuerst   
                Beim Start sofort den Index erscheinen lassen
Warum: Es kann in einer Anwendung sehr sinnvoll sein, wenn der Nutzer
       sofort beim Start eine ganz bestimmte Stelle in einem der
       Register aufgeblättert bekommt.
       Ein Anwender kann auch der Meinung sein, daß der Index das
       zentrale Konzept der Datenbank ist, und deshalb zu Beginn
       erst einmal ein Register präsentieren wollen.

Lösung:
Sagen wir, um konkret zu sein, es soll Register 3 an der Stelle
"goethe" erscheinen.
Was NICHT geht (sonst wäre dieser Trick nicht nötig), das ist, in den
_start.flx  einfach reinzuschreiben

index |3 goethe

Warum geht das eigentlich nicht? Nun, das hat mit den internen
Bedingungen zu tun, die im Moment der Abarbeitung des _start.flx
vorliegen - man erspare uns die Einzelheiten, es führt zu weit
und ist ab jetzt uninteressant.

Der Trick ist, sich das Hilfsprogramm "flex" dienstbar zu machen!
Dieses ermöglicht, einen FLEX von außen an ein laufendes a99 zu senden,
um ihn ausführen zu lassen. Das kann manuell, aber auch aus einem
Batch heraus geschehen. Wir lassen einfach a99 selber einen Befehl an
das System geben, indem wir in den  _start.flx  an das Ende schreiben
(und statt  |3 goethe  natürlich was immer Sie wollen):

open x dothis.flx
wri "index |3 goethe" n
close x
var P "flex dothis"
dos

Das ist schon alles! Die letzten 2 Zeilen lassen schlicht den Befehl
  flex dothis
ausführen. Damit wird  flex.exe  als externes Programm gestartet
und sendet von außen den vorher präparierten FLEX  dothis.flx
an a99 - und da steht genau der index-Befehl drin.
Wenn  flex.exe  dann seine Arbeit tut, sind in a99 die "internen
Bedingungen" inzwischen erfüllt, die das problemlose Aufklappen des
Registers ermöglichen.

Wichtig: In der INI-Datei darf nicht  exflex=0  stehen.
Die Berechtigung (also der Wert  access=...) spielt keine Rolle!

Jetzt können Sie natürlich drangehen und in  dothis.flx  reinschreiben,
was immer Sie wollen und am Anfang ausgeführt werden soll. Aber alles
andere außer "index" kann _start.flx ja sowieso ausführen, dafür ist
der Trick unnötig.
Mehr zum Hilfsprogramm  flex.exe:  h exflex.txt
(Darauf beruhte übrigens auch das alte RuckZuck-Konzept!)

Die allerersten Versionen von a99 waren, ironischerweise, so
gestrickt, daß zuerst ein Register erschien - aber das konnte man
nicht abschalten. Vehemente Wünsche bewogen uns, die Sache zu ändern,
aber die Möglichkeit, ein Register als erstes erscheinen zu lassen,
ging aus den genannten internen Gründen dann leider verloren und wurde
bis heute nicht wiedergefunden...

---------------------------------------------------------------------------------------------------


Trick 64: FLEXiermaschine   
                1. FLEX ohne Datenbank?
                    2. Jedem User seinen _start.flx

Aufgabe: Ein FLEX, der mit einer Datenbank gar nichts zu tun hat,
         soll erledigt werden - geht das ohne a99? (Z.B., ein
         Kalenderblatt erstellen als RTF-Datei, oder eine Zins-
         berechnung für einen Kredit...)

Warum: Mit FLEX kann man z.B. dank der Dateifunktionen viel Nützliches
       programmieren, was mit der Datenbank gar nichts zu tun hat!
       Das müßte sich doch ausnutzen lassen, um sonstwas machen zu
       können!? Es sei denn, man hat z.B. Perl gelernt, versteht sich.
       Wer das kann, braucht Ziffer 1. nicht.
       Ziffer 2. kann dagegen überall virulent werden, wo es diffizile
       Unterschiede zwischen Anwendern gibt.

Lösung:
Gleich vorweg: Ohne Datenbank geht es nicht, a99 kann nicht als
FLEXiermaschine völlig losgelöst von jeder Datenbank arbeiten.
Das macht aber nichts - jeder HAT ja eine Datenbank: warum nicht die
DemoBank für diesen Zweck als "Strohmann" benutzen?! Sie muß nur
da sein, ihr Inhalt ist egal und wird nicht verändert.

Es zeigt sich überraschenderweise, daß man mit der Lösung zugleich
das ganz andere Problem erschlägt: Wie kann man jedem Nutzer
seinen eigenen  _Start.flx  geben?

Der Trick ist drei- bzw. zweiteilig:

1. Am Ende des _start.flx diese 3 Zeilen anhängen:

var "myjob.flx"
fsize
if >0 exec myjob

2. Den FLEX, der eigentlich zu erledigen ist, auf dem Startverzeichnis
   ablegen und  myjob.flx  nennen

3. Ans Ende des  myjob.flx  den Befehl  STOP  setzen.


Wenn es  myjob.flx  nicht gibt, startet die Datenbank normal und es
kommt wegen der Prüfung mit  fsize  auch keine Fehlermeldung.

Wer auf einem anderen Verzeichnis startet und dort keinen  myjob.flx
zu liegen hat, merkt nichts. D.h. die drei Zeilen im _start.flx  haben
keine unerwünschte Nebenwirkung.

Zweittrick: (und nur dieser ist auch für Perlianer interessant)
Wenn Punkt 3. entfällt, ist der  myflex.flx  praktisch eine
individuelle Erweiterung des  _start.flx !!! Denn die Datenbank
arbeitet dann normal.

Hinweis zu Ziffer 1.:
Wer eine avanti-Installation auf seinem PC hat, kann auch avanti-cl
zum Abarbeiten von datenbankfremden FLEXen entzweckfremden:
Der FLEX muß nur eine entsprechende Endzeile mit @ haben, z.B.
@ DB=avdemo ID=opac/OPAC
und dann gibt man nur den Befehl   avanti-cl <myflex.flx
Wobei die Unterschiede zwischen a99 und avanti zu beachten sind!
Der Vorteil ist: avanti-cl braucht weniger Zeit.

Hinweis zu Ziffer 2.:
Wenn man will, daß jeder Nutzer einen ganz individuellen  _start.flx 
hat, dann ginge das auch so, daß man keinen solchen auf
DbDir, ProgDir und ProgDir\FLEX hat, sondern jeweils den ganz
individuellen auf dem Arbeitsverzeichnis des Nutzers.
Besser wäre gewiß, der Name "_start.flx" wäre nur default und
man könnte in der INI-Datei einen Namen vorgeben.
Kommt auf den Zettel, mit H-Faktor 2.


---------------------------------------------------------------------------------------------------


Trick 65: Umrechenwerk  
                Umrechnen zwischen Zahlensystemen (Hex, Dez, Bin, ...)

Aufgabe: Schnell mal eben eine hexadezimale Zahl in ihr dezimales,
         oktales, binbäres ... Äquivalent umrechnen. Oder umgekehrt.

Warum: Das Umrechnen von einem Zahlensystem in ein anderes gehört
       zu den Grundaufgaben der Programmierung, und zu den einfachsten
       überhaupt. FALLS so etwas also nebenbei mal auftritt, sollte
       man dafür eine fertige Prozedur bei der Hand haben, wenn es
       schon keinen direkten Befehl dafür gibt. FLEX, das ja keine
       richtige Programmiersprache ist, hat leider keinen.
       Also her mit einem Unterprogramm, das man unbesehen einbinden
       kann! Man muß ja wirklich nicht mehr selber rechnen können ("Ist
       Mathematik noch zeitgemäß?" fragte jüngst eine führende
       Zeitung), sondern nur noch wissen, welchem Programm man eine
       Aufgabe in welcher Weise zu stellen hat.

Lösung:
Nicht jeder wird das Unterprogramm sehen und verstehen wollen, daher
wird es hier nicht abgedruckt, obwohl's nicht groß ist, sondern zum
Download bereitgestellt:
              http://ftp.allegro-c.de/aktuelle-version/numcon.inc
Es geht nur um positive ganze Zahlen! Andere braucht man wohl nie
auf eine andere Basis umzurechnen - oder doch?

Nebenbemerkung:
Jeder hat andererseits mit dem Zubehör-"Rechner" von Microsoft ein
geeignetes Werkzeug zur Verfügung, das auch die Umrechnung zwischen den
genannten Zahlsystemen beherrscht. Erstens aber kann man es nicht in
FLEX einbinden, und zweitens kann man mit FLEX, wenn schon, denn schon
auch noch etwas weiter gehen als Onkel Bill! Die Rechenmethodik, die
man braucht, funktioniert nicht nur für 2,8,10 und 16, sondern auch
für andere Basiszahlen. In  numcon.inc  befindet sich in der Tat eine
Funktion, mit der man jedes Zahlsystem von 2 bis 20 in jedes andere
umrechnen kann.

Hintergrund:
Warum gerade bis 20? Kelten und Mayas hatten ein auf 20 basierendes
Zahlensystem. Ganz spurlos verschwunden ist das nicht! Das französische
Wort für 80, "quatre-vingt" (vier-zwanzig) kommt daher, es wird aber
schon ab 60 im Zwanzigerschritt gezählt: 70 ist soixante-dix, nicht
"septante" - außer in Belgien und teilweise Schweiz. Das englische
"score" hatte früher auch die Bedeutung zwanzig, und ein Pfund hatte
20 Schillinge. Das Deutsche kannte mal die Bezeichnung "altes Schock"
für 20 Groschen, ein "Schock" waren 60, also 3x20. Und es gibt das aus
der Reihe tanzende russische Wort "sorok" für 40 - das soll aus dem
Persischen stammen. Aber genug solcher Quisquilien, der Leser wird
schnellstens wissen wollen, wie's denn nun geht.

Rezept:
Hier knapp das Rezept, wie man den "Number Converter" anwendet:
Sagen wir, in #uzz steht eine Hex-Zahl, und sie soll ins Achtersystem
verwandelt werden, das Ergebnis soll in #uyy. So geht das:

var #uzz " 16 8"
perform numcon
ins #uyy
...
end
  Einbindung des UP:
include numcon.inc

Man übergibt also dem Unterprogramm drei Zahlen, getrennt durch
Leerzeichen! Allgemein:  var "nnn B Z"
Die erste Zahl, nnn, ist die umzurechnende, die zweite (B) ist
deren Basiszahl (die kann das Programm nicht selber erraten!), die
dritte, Z, ist die Zielbasis. Läßt man die Zielbasis weg, wird dafür 10
genommen, läßt man die Basis auch weg, wird dafür 16 genommen.
Default ist also die Umrechnung Hex->Dez, aber B und Z können beide
von 2 bis 20 reichen.

Und was ist der Trick?  Das Unterprogramm ist so verdächtig kurz...
Verbal gesagt, arbeitet es im Kern so:

1. Die gegebene Zahl in eine dezimale wandeln.
2. Die ermittelte Dezimalzahl ins angegebene Zielsystem konvertieren.

So kommt man daran vorbei, sich um jeden der rund 800 denkbaren Fälle
einzeln kümmern zu müssen, denn 1. und 2. arbeiten immer in derselben
Weise, nur mit jeweils anderem Faktor.
SonderTip:  Mit  X numcon.inc  auch direkt aufrufbar.
            Einfach mal probieren.

Vorschau V28.1:
Eingebaut wird die Sache noch in den  umrech.flx.
Den haben Sie schon!   Geben Sie mal ein:   X umrech

Und noch was:
Auch in den EXPORTparametern kann man Zahlen umrechnen!
Dafür haben wir ein entsprechendes Unterprogramm, das wir bei
Interesse oder Bedarf zugänglich machen. Es wurde gebraucht für
die Unicode-Datenbank.


---------------------------------------------------------------------------------------------------


Trick 66: Daten aus dem Off  
                Offline-Liste genauer inspizieren

Aufgabe: Schnell mal schauen, was in der Offline-Datei WIRKLICH alles
         steht.

Warum: Zu sehen bekommt man in der Offline-Datei mit Alt+q und dann
       Alt+w immer nur den jeweils aktuellen und den davor zuletzt
       überschriebenen Stand der Bearbeitung eines Satzes, nicht
       die evtl. erfolgten mehrfachen, jeweils gespeicherten Korrekturen
       während einer Sitzung.
       JEDE der GESPEICHERTEN Fassungen ist jedoch in der Offline-Datei
       festgehalten! Sollte man darauf nicht zurückgreifen können?

Tip: Was ist die Offline-Datei?  h off  eingeben.

Hintergrund:
Es wird tatsächlich jedesmal beim Speichern eines Satzes seine dabei
überschriebene Vorversion aus der Datenbank heraus in die Offline-
Datei kopiert. Mit Alt+w ("Wechseln") bekommt man diese Vorversion
wieder zu sehen - aber leider nur diese, nicht die vorvorige usw.,
obwohl diejenigen aus derselben Sitzung alle noch in der Offline-
Datei stehen.
 
Wenn man einen Datensatz bearbeitet, aber NICHT sofort speichert,
sondern sich erst mal einen anderen vornimmt, was passiert dann?
Dann wird der bearbeitete Satz nur schnell noch in die Offline-Datei
geschrieben und erscheint beim Aufblättern gelb. Erst wenn man ihn
später wirklich speichert, wird die Vorversion aus der Datenbank
herauskopiert in die Offline-Datei. Mit Alt+w kriegt man danach diese
alte Fassung wieder zu sehen, dann aber diese in gelb. Nach mehrfachem
Speichern sieht man stets nur die letzte Vorversion und die aktuelle,
nicht mehr die älteste oder irgendwelche Zwischenversionen.
Typischerweise steht, wie sich hieraus ergibt, die ältere Version
unterhalb ihrer Nachfolgerin in der realen Offline-Datei!


Es gibt zwei Tricks, mit denen man die Aufgabe lösen kann:
Der erste besteht darin, daß man die Offline-Datei in eine Externdatei
verwandelt (extern,dat) und diese dann laden läßt. Darin sieht man dann
alle Fassungen von Datensätzen, so wie sie eingelagert wurden (s.o.).
Die Offline-Datei hat den Dateityp .$$$, ist aber in Wahrheit in
ihrer Struktur nichts anderes als eine Grunddatei - man braucht sie
also nur umzubenennen oder zu kopieren! Sie liegt auf dem Temp-
Verzeichnis (bzw. dem mit DbAux=... in der INI angegebenen Pfad).


Lösung 1: (kurz, aber mit Vorsicht zu genießen)
---------
Hier ein ganz kleiner FLEX, mit dem man es bewerkstelligen kann:

var M B ".$$$ extern.dat"
fcopy
erase off
read extern
delete extern.dat


Danach erst Esc, um die erscheinende Liste zu schließen, dann mit
Alt+q wieder öffnen, um die Sätze dann als Ganzes zu sehen,

Aber Vorsicht! Irgendwelche noch nicht gespeicherten Datensätze im
Offline-Speicher sind dann nicht mehr mit ihrem Originalsatz verbunden
und per Alt+w umschaltbar! Speichert man sie nun, entstehen neue
Datensätze.
Man KANN den Befehl "erase off" weglassen, dann sind die noch nicht
gespeicherten Sätze noch korrekt vorhanden und darunter die Liste der
eingelesenen Datei extern.dat, in der sie nochmals als unabhängige
Sätze auftreten. Aufpassen, um dann nicht durcheinander zu kommen ...


Lösung 2: (jederzeit schnell mal eben zwischendurch möglich, denn es
---------  geht ganz enorm rasch)
Die genannten Probleme vermeidet ein anderer Trick: Die Offline-
Datei als solche unberührt lassen, aber als Datei lesen und in eine
Textdatei verwandeln, die man mit dem help-Befehl anzeigen läßt:
(am besten in eine Datei offlist.flx speichern und dann X offlist, ab
V28.2 ist offlist.flx im Gesamtpaket dabei.)


var M B ".$$$"
open
open x offlist
  erstes Byte überspringen, dann satzweise einlesen
fetch b
:loop
fetch b
if ="-1" jump ende
fetch rec
if cancel jump ende
  Satz rausschreiben
write
write 13 10 "................" 13 10
jump loop
  Das war's, Daten anzeigen
:ende
close x
h offlist


Aus der Anzeige dieser Textdatei kann man natürlich beliebig mit
Copy&Paste wieder Sachen entnehmen und in aktuelle Sätze einfügen.
Möglicher Nachteil: Bei sehr großer Zahl von Sätzen, z.B. nach
umfangreichen globalen Ersetzungen, ist die Datei  offlist  evtl.
zu lang. Man kann sie dann aber außerhalb des Programms mit jedem
Texteditor oder -betrachter lesen, darin suchen, vergleichen usw.


ZusatzHinweis
Die Offline-Datei ist nicht zentral für alle Bearbeiter, sondern
individuell nur für den einzelnen Bearbeiter, und zwar je nach
Einstellung nur die aktuelle Sitzung (SaveResults=2 in der INI-Datei)
oder übergreifend für zwei oder mehr Sitzungen (SaveResults=0 oder 1).

Wer also sehen will, was INSGESAMT in der Datenbank passiert ist,
muß die LOG-Datei auswerten, denn dort stehen chronologisch alle
gespeicherten Datensätze, und zwar stets komplett, auch wenn nur
winzige Änderungen gemacht wurden. Die Werkzeuge dafür sind vorhanden
und bekannt (s. Quick-Liste).


---------------------------------------------------------------------------------------------------


Trick 67: Schnellzählung  
                Wieviele Einträge sind im Index unter xyz?
Aufgabe: Hurtig mal prüfen, wieviele Einträge es z.B. im Register 3
         unter xyz gibt. Anspruchsvolle wollen noch mehr:
         Wieviele Einträge gibt es, die mit xyz beginnen?

Warum: Man will vielleicht in einem FLEX prüfen, ob es im Index unter
       irgendeinem Kriterium überhaupt schon etwas gibt, und wenn ja,
       wieviele Zeilen. Das kann z.B. die Anzahl der Ausleihen eines
       Lesers sein, oder die Anzahl von Heften zu einer Zeitschrift.
       Oder: Hat dieser Satz verknüpfte Untersätze und wieviele?
             (Die erste Frage ist auch mit  if main  beantwortbar!)
       Solche Einträge haben immer eine bestimmte Struktur, sind also
       in Index an einer Stelle versammelt. Mit bloßem Auge sieht ja
       jeder sofort, wieviele Treffer es da gibt - kann FLEX das auch?

Lösung:
Das geht mit dem Befehl "qrix". Den gibt es schon lange, aber man
findet nicht so leicht raus, daß der solche Sachen kann. Wie soll man
auch wo nach dieser Funktion suchen? (Sagen Sie uns, wie und wo Sie
gesucht und es nicht gefunden haben! Wir richten das dann.)

Geben Sie mal bei der DemoBank ein:

x qrix 1 per shak\mes

Es erscheint die Mitteilung   "74  shakespeare, william"
Und jetzt:

x qrix 1 per shak?\mes

Dann kommt die Meldung   "274  shak"

Dasselbe sehen Sie mit bloßem Auge im Personenregister, wenn Sie
zu der Stelle  shak  gehen bzw. dann mal  shak?  eintippen.

Das Rezept ist also ganz klar:

qrix 1 abc xyz

liefert in der internen Variablen genau die Registerzeile, die man
haben will. abc ist der symbolische Name des Registers, xyz ist die
Stelle bzw. der Anfang davon, wenn man mit ? trunkiert.
Die 1 hinter dem "qrix" ist die Anzahl Zeilen, die man haben will!
Mit einer Zahl >1 kriegt man entsprechend viele Zeilen in die iV,
getrennt durch den Code 20. Das braucht man weniger oft.
Läßt man aber die Zahl ganz weg, gibt's gleich 20 Zeilen!

Nun aber die Frage: Wenn xyz im Register gar nicht auftritt?
Dann kriegt man die Zeile, die genau an der Stelle steht, wo xyz
stehen müßte und nicht steht.
Und wie kann man diesen Sachverhalt im FLEX prüfen, d.h. daß es
die gesuchten Einträge nicht gibt?
Sagen wir, Zeilen mit "shakesp" werden gesucht, und man will prüfen,
ob welche vorkommen, bevor man weitermacht im FLEX.
Hier ist das Strickmuster:

qrix 1 per shakesp
var (f" " b" " f" ")
if not ="shakesp" jump nix
  ....
:nix
mes es gibt keine Zeilen an der Stelle!

Die komische Zeile  var (f" " b" " f" ") beseitigt am Anfang der
Zeichenfolge, die sich in der iV befindet, die Leerzeichen, dann die
Zahl, dann die evtl. noch folgenden Leerzeichen vor dem Text. Übrig
bleibt der Text! Und der läßt sich dann mit  ="shakesp"  vergleichen,
also mit dem, was man haben wollte...
-----------------------------------------------------------------------
Und nun noch die Frage: Wieviele verkn. Untersätze?
var p
if "" mes Kein Prim.Schl.!;end
var "1 |9 " p "+?"
qrix
eval
ins #uvk
var "Es gibt " #uvk " verkn. Untersätze"
mes

Hier werden also die Angaben für qrix per var-Befehl zusammengestellt,
die Zahl aus der dann in iV befindlichen Indexzeile per eval ermittelt.
-----------------------------------------------------------------------
Übrigens: Statt des symbolischen Namens geht auch die übliche
Bezeichnung |1 für Register 1 usw., also z.B.

x qrix 1 |3 shak?\mes

um im Register 3 die Stelle "shak" abzuprüfen.

---------------------------------------------------------------------------------------------------


Trick 68: Gibt's ein Verzeichnis für das Ereignis?  
                Existiert der Pfad c:\abc\xyz?

Aufgabe: Geschwind mal nachschauen, ob ein bestimmtes Verzeichnis
         eigentlich auf dem System schon existiert.

Warum: Man will dann und wann eine Datei mit  "open x ..." anlegen und
       der Dateiname enthält einen Pfad. Dann klappt das ja nur, wenn
       der Pfad schon da ist. Im Fall seines Fehlens erfährt man aber
       mit "if no ..." nur, daß es nicht geklappt hat. Der Grund kann
       dafür auch ein anderer sein: z.B. mangelndes Schreibrecht auf
       dem Verzeichnis, oder Datei existiert schon und ist schreib-
       geschützt. Um sicher zu gehen, würde man gerne vorab die
       Existenz des Verzeichnisses schnell mal eben abchecken können.
       Weitere Gründe für einen solchen Wunsch sind denkbar.

Lösung:   [siehe dazu  h xfnam ]
       Es geht erfreulich schnell. Sagen wir, man will die Existenz des
       Verzeichnisses  c:\allegro\altdaten\kopie  prüfen. So geht's:

       fnam |.c:/allegro/altdaten/kopie
       if "" jump fehler

Was stünde in der iV als Ergebnis, wenn das Verzeichnis existiert?
Da stünde dann einfach nur "kopie" drin. Dasselbe passiert, wenn
man schreibt:
      fnam |.c:/allegro/altdaten/kop*

Hier sind also die bequemeren normalen Schrägstriche möglich, aber
der Backslash - verdoppelt - tut es auch. Dabei Vorsicht: Wenn der
Name des Verzeichnisses in einem Datenfeld vorkommt, dürfen die
Backslashe darin nicht verdoppelt sein. Sagen wir, es ist:

#uvz c:\allegro\altdaten\kopie

dann ist das OK, und man hätte zu schreiben:

var "|." #uvz
fnam
if "" jump fehler

Wäre es nicht unpraktisch, in solchen Fällen, wo man den Verzeichnis-
namen womöglich aus anderer Quelle hat, sich erst noch um die Striche
kümmern zu müssen? Muß man also nicht.

Vorsicht:
Am Ende des Namens darf kein Strich sein!
Was macht man, wenn man das nicht weiß? So kriegt man sie weg:

var "|." #uvz(F"/\\")

Und geht das auch mit $-Variablen? Ja, das geht:

var "|." $Verz (F"/\\")

Wichtig: Das Spatium zwischen dem Variablennamen und der Klammer! Denn
die Namen der $-Variablen sind ja variabel lang, da muß das Programm
erkennen können, wo der Name zu Ende ist: am Spatium eben.

ExtraTip:
Gibt es das Laufwerk K:?  Das prüft man so:
fnam |.k:\\*.*
if "" jump fehler

SonderTip:
Dürfen eigentlich bei den Befehlen "open" und "open x" die Striche
auch normal sein? Ja. Auch gemischt? Ja.


Hinweis: Trick 53 befaßte sich nur mit der Frage, welche Verzeichnisse
an einer bestimmten Stelle im System anzutreffen sind, nicht gezielt
mit der Frage, ob es ein bestimmtes gibt.

---------------------------------------------------------------------------------------------------


Trick 69: Schiebereien mit der Maus  
                Feldinhalt manuell sinnvoll sortieren durch Verschieben mit Maus

Aufgabe: Im Feld #31 stehen 25 Schlagwörter, mit ; getrennt.
         Sieht ja chaotisch aus, Schnell mal eben sinnvoll umordnen!

Warum: Alphabetische Ordnung in einem Feld (s. Trick 56) ist leicht
       herzustellen, seit es den FLEX-Befehl  sort  gibt.
       Aber "sinnvolle Ordnung"?
       Mit Cut&Paste kann man das eine oder andere Schlagwort an
       eine andere Stelle verschieben, auf die Dauer ist das aber
       zeitraubend. Kann man sowas nicht heutzutage auch mit der Maus
       machen - wie in jedem vernünftigen Programm einfach rauf und
       runter verschieben oder so?

Lösung:
Genau das kann man machen, Und zwar mit aresqa! Vermutlich ist es
wenig bekannt: wenn man eine aresqa-Liste vor sich hat, kann man
jede Zeile mit der Maus ergreifen und beliebig verschieben. Sie wird
dann VOR diejenige Zeile geschoben, auf die man zeigt, im Moment des
Loslassens der linken Maustaste.

Prima, aber wie kriegt man den Feldinhalt von #31 (oder was immer es
sei) in eine aresqa-Liste? Und von da wieder zurück?
Man muß dafür sorgen, daß die zu ordnenden Elemente durch Zeilenwechsel
(Codes 13 10) getrennt sind. Das ist mit einer lokalen Ersetzung zu
lösen, aber es gibt subtile Klippen zu umschiffen dabei.
Damit es unter allen Umständen klappt, haben wir ein Unterprogramm
gemacht, das man leicht aufrufen kann. Als Vorbereitung muß man
den zu ordnenden Inhalt in  $fu  so bereitstellen, daß zwischen den
Elementen die Zeichenfolge %%% steht. Das Ergebnis kriegt man in $fs
zurück und kann die %%% wieder entsprechend zurückumwandeln.
(Warum %%%? Jede andere eindeutige (sonst nicht vorkommende) Zeichen-
folge würde es auch tun, also warum nicht diese?)
SonderBonus: In der aresqa-Liste kann man sogar jede Zeile bearbeiten:
einfach Balken drauf, Enter, Zeile bearbeiten, Enter.

Damit geht es dann folgendermaßen (statt #31 das Feld, um das es
bei Ihnen geht):

var #31
ins _; _;_
ins _;_%%%_
ins $fu
  Unterprog. f. manuelles Ordnen aufrufen:
perf feld-mord
var $fs
ins _%%%_; _
ins #31
...

include fsort.inc

---------------------------------------------------------------------

Damit sich's aber lohnt, ist in  fsort.inc  auch gleich noch ein
Unterprogramm für das alphabetische Sortieren mit drin. Man ruft es
auf mit  perf feld-asort.

Und wie sieht es aus, das Unterprogramm  :feld-mord  für das
manuelle Ordnen? Gar nicht lang:

:feld-mord
mes Zeilen mit Maus verschieben, dann Liste mit OK speichern
var $fu
ins _%%%_^M^J_
  Liste zeigen, Nutzer kann sie bearbeiten
aresqa
  Wurde Esc gegeben? Dann $fu in $fs kopieren
if "" var $fu;ins $fs;return
  Bearbeitete Liste steht in aresqa.lst
var Faresqa.lst
ins _^M^J_%%%_
var (F"% ")
ins $fs
del aresqa.lst
return

---------------------------------------------------------------------------------------------------


Trick 70: FLEXoFlip oder FlippoFLEX?  
                Flip per FLEX erzeugen

Aufgabe: Im Anzeigefeld mit FLEX einen zusätzlichen, anklickbaren Flip
         erscheinen lassen, wie von Geisterhand.
           
Warum: Es ist nicht jedermanns Sache, in die Anzeigeparameter einzu-
       greifen, um einen neuen Flip einzubauen. Warum kann man nicht
       eigene Flips auch mit FLEX erzeugen und unter der Anzeige
       als Sonderservice bei Bedarf auftauchen lassen?

Lösung: Ein Trick reicht nicht, drei sind nötig.

1.
Der zentrale Trick ist der Befehl  show +IV
Damit kann man den Inhalt der internen Variablen unter der Anzeige
aufscheinen lassen. Und wenn in der iV in dem Moment ein korrekt
aufbereiteter Fliptext steht, dann sieht er genauso aus wie ein
echter. Der Text muß dazu nur die richtigen RTF-Formatierungs-
anweisungen enthalten. Geben Sie mal ein:

x var "\\ul HALLO\\ul0"\sho +IV

... denn \ul schaltet die Unterstreichung ein, \ul0 wieder aus.

2.
Das allein reicht noch nicht. Man muß in zwei Variablen, #uYi und #uZi,
erstens den Fliptext und zweitens die Aktion bereitstellen.

Sagen wir, "Info zur Datenbank" soll als Flip erscheinen, blau und
unterstrichen, und soll die bekannte Funktion "Info zur Datenbank"
auslösen. D.h., es müßte der FLEX dbinfo.flx aufgerufen werden. Dazu
braucht's ein paar #u-Variable, die man auch per FLEX herstellen kann.

So geht's:
(Zum Testen schreiben Sie mal den folgenden Text in eine Datei ff.flx
und geben dann ein:  X ff )

  -----------------------------------------------------
  Text
$uy Info zur Datenbank
  Aufruf
$uz X dbinfo
  Flip erzeugen
perf flexoflip
end

  Unterprogramm
:flexoflip
  Text $uy aufbereiten (Code 160 = Flip-Begrenzungszeichen)
var n 160 "\\ul\\cf2 " $uy "\\ul0\\cf1 " 160
  und anzeigen unter dem schon vorhandenen Text
sho +IV
  $uy in die nächste freie #uYi kopieren (dafür sorgt ~)
var $uy
asci
ins #uY~
  $uz in die nächste freie #uZi kopieren
var $uz
ins #uZ~
return
  -------------------------------------------------------

3.
Das reicht aber auch noch nicht, wenn der Flip in jedem Fall sofort
bei der Anzeige eines Datensatzes aufblitzen soll! Er zeigt sich erst,
wenn der FLEX aktiviert wird - was aber eben nicht von allein passiert
und nicht aus den Exportparametern heraus veranlaßt werden kann.

Hier hilft das Konzept "autoflex" weiter (siehe h flex=autoflex).
Das einfache Rezept für diesen Fall ist folgendes: Schreiben Sie in
die Anzeigeparameter, am besten VOR die erste Zeile, die mit #
anfängt, diese Zeile

#nr "X ff!" e"!" =X:

... wenn ff.flx der FLEX ist, um den es geht. Dann wird ff.flx immer
sofort im Anschluß an das Erzeugen der Anzeige ausgeführt.
Wenn dasselbe auch bei F5 (Umschaltung auf Kategorieanzeige) passieren
soll, dann muß diese Zeile auch in den Abschnitt der Parameterdatei,
der mit  #-(  beginnt. Sie können in Ihren Autoflex ansonsten noch
ganz andere Dinge einbauen, das ist klar - er ist ein FLEX wie jeder
andere.
Anzeigeparameter - welche Datei das in Ihrem Fall ist? Mit  X dbinfo 
sehen Sie es.

Aber mit "display" kommt der Flip nicht!?
Das ist richtig. Der FLEX-Befehl  disp  läßt zwar die Anzeigeparameter
abarbeiten, aber den Autoflex nicht, denn das geht dann nicht.
Wenn man aber "disp" gibt, ist man ja sowieso in einem FLEX und
kann die nötigen Befehle gleich dort mit einbauen. Oder als nächste
Zeile nach dem "disp" den Befehl "exec ff", falls der FLEX nach dem
"disp" sowieso endet. Oder im Anschluß, wenn der eigene FLEX fertig
ist, zweimal F5 drücken.


Vorsicht Umlaute:
Hier ist angenommen, daß der FLEX in ANSI geschrieben ist, z.B.
mit Notepad. Wichtig ist das nur, wenn Umlaute vorkommen.
Wenn man in ASCII schreibt, dann muß das Unterprogramm so beginnen:

var $uy
ansi
ins $ux
var n 160 "\\ul\\cf2 " $ux "\\ul0\\cf1 " 160
sho +IV
  $uy in #uYx kopieren
var $uy
ins #uY~
...

Hinweis:
Daß mit \cf2 auf blau umgestellt wird, ist nicht selbstverständlich.
Es beruht auf den Farbeinstellungen in disphead.rtf. Hat man diese
verändert, sind die Farbnummern evtl. andere.

Fortgeschrittene wollen mehr:
Der Flip soll OBERhalb des Anzeigetexts erscheinen!
Dann muß das Unterprogramm so aussehen:

:flexoflip
  Anzeige speichern in body.rtf
file body.rtf
  Mini-RTF-Datei mit dem Flip erzeugen:
open x head.rtf
wri "{ " 160 "\\ul\\cf2 " $uy "\\ul0\\cf1 " 160 "\\par }"
close x
  und anzeigen ueber dem vorhandenen Text
help head
help +body
  $uy in die nächste freie #uYi kopieren (dafür sorgt ~)
var $uy
asci
ins #uY~
  $uz in die nächste freie #uZi kopieren
var $uz
ins #uZ~
return

Trick Nummer 70.4 ist das Laden von zwei Hilfetexten untereinander,
wobei hier der erste schnell mal eben erstellt wird, der zweite
ebenfalls, aber als Kopie der momentanen Anzeige mit "file body.rtf".

---------------------------------------------------------------------------------------------------


Trick 71: Cambio  
                Fremdwährungen in Euro umrechnen

Aufgabe: Schnell mal eben einen Fremdwährungsbetrag in Euro umrechnen

Warum: Das wird gebraucht, wenn man bei einer Bestellung Preise in
       Fremdwährungen vorliegen hat oder Rechnungen zu erfassen sind,
       die in Nicht-Euro-Währungen vorliegen.

Im Prinzip ist kein Trick nötig, wenn es nur um EINE Währung geht,
z.B. nur um US-Dollar. Man besorgt sich den aktuellen Umtauschkurs,
etwa von  
http://de.finance.yahoo.com/waehrungsrechner
Da findet man vielleicht, daß  1 EUR zu  1,5719 USD gehandelt wird.
Man muß folglich einen Dollarbetrag durch  1,5719  teilen, um den
EUR-Gegenwert zu erhalten.
Sagen wir, in  $bt steht der Dollarbetrag, dann:

eval $bt / 1,5719
ins $eu

und schon hat man in $eu den Gegenwert davon in EUR.
Soll das Ergebnis gerundet sein auf zwei Stellen, dann geht es
auch etwas anders (aber es muß das große Z sein!):

Z=$bt / 1,5719
var Z2
ins $eu

Nun schwankt der Kurs aber von Tag zu Tag. Daher muß statt 1,5719 eine
Variable her, die anderswo gesetzt wird. Sagen wir, $wk enthält
den aktuellen Dollarkurs. Dann gelten dieselben Formeln, nur mit
$wk statt 1,5719.

Das waren noch keine besonderen Tricks. Aber man will ja noch mehr:
Nicht nur Dollars, sondern alle Währungen, die in unseren Bestellungen
und Rechnungen auftreten, will man sofort in EUR umrechnen können.
Dafür gibt es in der DemoBank eine Währungstabelle. Sie steckt in einem
Systemsatz, der unter SYSWWHRG im Reg. 11 zu finden ist. Darin stehen
in $W beliebig viele Kurse, codiert in dieser Form:

... USD:1.5719:US-Dollar%AUD:1.60:Austral.$%CAD:1.47:Canad.$ ...

So können wir das ausnutzen:

1. Kurse aktualisieren und evtl. die Liste erweitern:
   X o-kurse
   In der Regel kann man die Kurse dem Wirtschaftsteil der Tageszeitung
   entnehmen - geht schneller, falls eine zur Hand ist.
   Beim Bearbeiten auf die Doppelpunkte aufpassen! Die Zahl in der
   Mitte ist immer der Wert eines EUR in der Fremdwährung.

2. Kurse zum Rechnen verwenden
   Schön wäre ein kompaktes Unterprogramm ":wumrech".
   Der Aufruf soll so aussehen: Zuerst Betrag und Währungsbezeichnung
   in der iV bereitstellen, z.B.  100 USD oder auch CAD 250, oder
   SWF320 - alles das sollte gehen. Man will z.B. schreiben können:
     var "nnnXYZ"
     perform wumrech
     ins $eu
   um nnn Einheiten der Währung XYZ in Euro umzurechnen,
   d.h. das Ergebnis soll dann in der iV stehen. Negativ, wenn
     es den Währungscode XYZ gar nicht gibt.

Hier ein vollständiger FLEX zum Ausprobieren, samt Unterprogramm:

  ---------------------------------------------------------------
:start
ask Bitte Eingabe: Betrag Währung
if "" end
perf wumrech
if "-" mes Keine gültige Währung;jump start
ins $eu
var $betrag " = " $eu " EUR
mes
jump start

  ****** Unterprogramm ***********
:wumrech   // Waehrung nach Kurswert umrechnen
ins $betrag
if $Wtab jump wu2
set obj 2   // Tabelle laden, falls noch nicht da
var "|; SYSWWHRG"
f1nd
var #9A$W
ins $Wtab
set obj 1
:wu2         // Zahlenwert mit eval aus $betrag entnehmen
eval $betrag
ins $bt
  // Trick1 : Waehrungscode entnehmen -> #uwk
var $betrag (f"0123456789,. " F"0123456789,. ")
ins #uwk
  // TRICK2 : Umrechnungswert aus $Wtab entnehmen
var $Wtab (b"#uwk" f":" e":")
if "" var "-1"
ins $wk
  // jetzt rechnen und Ergebnis zurueckgeben
Z=$bt / $wk
var Z2
return
  ---------------------------------------------------------------

Der Trick liegt darin, wie man den zur gewählten Währung gehörigen
Umrechnungskurs aus der Liste herauszieht. Das macht die Zeile
var $Wtab (b"#uwk" f":" e":")
Damit ergibt sich, wenn USD in #uwk steht, genau "1.5719".

Ein weiterer Trick entnimmt vorher den Währungscode aus der Eingabe,
indem vorn und hinten Ziffern sowie Komma, Punkt und Spatium
weggenommen werden.

Ab V28.3 wird es so sein, daß man auch schreiben kann
var $Wtab (b"~#uwk" f":" e":")
und dann ist es egal, ob in #uwk  USD steht oder usd oder Usd.

Anmerk.:  b"$wk" geht leider auch in V28.3 nicht! In solchen Fällen
          gehen nur die #u-Variablen.

Hinweis:  Auch in der Exportsprache kann man mit Hilfe der Währungs-
          tabelle umrechnen. Das geschieht in kont.apr, womit das
          Durchrechnen der Kontingente bewerkstelligt wird.

---------------------------------------------------------------------------------------------------


Trick 72: Bedenke wohl die letzte Zeile ...  
                Was steht am Ende einer Datei?

Aufgabe: Schnell mal eben die letzte Zeile / die letzten 100 Bytes
             einer Datei besorgen

Warum: Hat man eine Datei produziert oder von woanders bezogen, kann
           es nützlich sein, sich mal das Ende anzuschauen.
 
Die Probleme damit sind weit größer als mit der ersten Zeile, aber mit
diesen Hinweisen geht es auch bei extrem großen Dateien sehr schnell.
Eine Datei mit 250MB kriegt man kaum in einen Editor...
Trickreich ist es vor allem wegen der Steuerzeichen! Hier finden Sie
ein paar erprobte Rezepte zum Abkupfern. Ganz unten ein fertiger FLEX,
mit dem man sofort die letzte Zeile jeder Datei sehen kann.

Ist die Datei xyz.txt sehr klein, sagen wir mal unter 10000 Zeichen,
lautet das schnellste, einfachste Rezept so:

var Fxyz.txt
var (0,r10000)
var (9900,0)

und schon hat man die letzten 100 Bytes. Der Trick  ist:
Der Dateitext wird nach dem Einlesen in der iV nach rechts geschoben,
so daß eine Zeichenfolge von 10000 Byte entsteht, der eigentliche
Text ganz am Ende. So kann man den Abschnitt ab Position 9900 nehmen,
das sind dann genau die letzten 100 Zeichen. (Es gibt leider keinen
Manipulationsbefehl, der direkt die letzen 100 Byte herausgriffe.)
Hierbei erhält man alle Zeichen, auch die Leer- und Steuerzeichen,
also vor allem 13 und 10, die sich am Ende befinden.

Wenn man aber genau die letzte Zeile will, und nicht weiß, wie lang
diese ist, kann man es so machen:

var Fxyz.txt
var (T"^J" e"^M")


Der Manipulationsbefehl (T"^J" nimmt das hinter dem letzten Code 10
stehende Stück, und das ist die letzte Zeile. Mit ^J ist nicht der
Code 10 gemeint, sondern man gibt die Zeichen ^ und J getrennt an.
Das Programm interpretiert das so, daß der Code 10 gesucht werden soll.

Moment, sagen Schlauköpfe jetzt, die letzte Zeile kann leer sein,
oder es gibt am Ende sogar mehrere Leerzeilen mit oder ohne Blanks.
aber man will natürlich die letzte echte Textzeile haben! Was dann?
Da hilft dieser Trick:

ins _^M^J_{{{_
var (F" {" T"{{{")

Damit werden erst einmal alle Kombinationen 13 10 durch {{{ ersetzt,
dann am Ende die Zeichen { und Blank weggenommen - egal wie viele es
sind,  und dann im verbleibenden Text nach der letzten Sequenz {{{
gesucht und der dahinter stehende Text genommen. Das ist die letzte
Zeile, in der was steht.

Nur bei Dateien oberhalb 10000 Byte Länge empfiehlt sich das weniger.
Es gibt eine viel schnellere Methode. Sagen wir, die Datei ist
wieder xyz.txt. Dann ist dies das geeignete UP, um die letzte Zeile
anzeigen zu lassen:


  ---------------------------------------------------------------------
  LASTLINE.FLX
  Aufruf:  X dateiname  (d.h. dateiname steht dann in der iV)

perf lastline
mes
end

  Unterprogramm "Letzte Zeile nach iV holen"
  Funktioniert bei allen Konfigurationen.
:lastline
  Name steht in iV
ins #upA
fsize
if no var "DATEI " #upA " NICHT GEFUNDEN";return
ins #upL
var #upA
open
  Dateilaenge minus -1000
eval #upL -1000
  positionieren
fetch m
   1000 Bytes holen (d.h. gesamten Rest der Datei)
      laenger wird die letzte Zeile ja wohl nicht sein?
fetch 1000
  13 10 durch {{{ ersetzen (fetch macht ^ und M aus Code 13)
  Wenn man aber das Zeichen ^ suchen und ersetzen will,
  dann muss man  ^~  angeben
ins _^~M^~J_{{{_
var (F" {" T"{{{")
close
return
  ---------------------------------------------------------------------

Nochmal langsam zum Mitschreiben, warum hier ^~M  statt ^M usw.?
Weil der Befehl "fetch m" die Steuerzeichen in Codierungen der Form ^X
verwandelt, also jeweils zwei Zeichen draus macht, d.h. aus 13 wird ein
^ und ein M. Bei  var Fxyz.txt  ist das nicht so, da bleiben 13 und 10
als solche erhalten, als einzelne Codes also. Das "Suchen und Ersetzen
mit dem Befehl  ins _..._..._  erfordert bei dem Spezialfall des
Zeichens ^, daß man dafür ^~ angibt. Solche Sonderfälle sind immer
ärgerlich, aber das UP kann man immerhin ohne dieses Wissen verwenden.

Anm.:
Ab V28.4 wird man auch sagen können:
var (F"^~ MJ")
um hinten direkt die Zeichen  ^  und  M  und  J  alle wegzunehmen.
(Bis jetzt geht ^~ bei F"..." und f"..." nicht.)
 
---------------------------------------------------------------------------------------------------


Trick 73: Datumsverdruß  
                Unbrauchbare Datumsangaben standardisieren
Immer mal wieder kommt Mißmut auf über unstandardgemäße Datumsangaben!
Da steht in einem Feld sowas wie  3.10.98 oder 10-03-01, man braucht
aber 19981003 bzw. 20010310.

Die schlechte Nachricht: Man kann kein Programm schreiben, das _jede_
Form von Datum standardisieren könnte. Denn es ist ja auch möglich,
daß  10-03-01  in Wahrheit 20100301 bedeutet! Oder daß  04/09/2009
amerikanisch gemeint ist und  20090409  heißen soll.

Wenn es aber so ist, daß die Datumsangaben alle von derselben Struktur
sind, also etwa  TT.MM.JJJJ, dann läßt sich was machen. Es gibt ein
allgemeines Rezept, das man für andere Fälle leicht modifizieren kann:

Sagen wir mal, die konkrete Aufgabe lautet so:
In #999 steht immer etwas von der Struktur  TT.MM.JJJJ, und
es soll daraus eine #99n werden mit JJJJMMTT. Und als Besonderheit
kann TT bzw. MM auch einstellig sein, also z.B. 1.2.1999.
Hinter dem Datum könnte auch noch etwas stehen, was dann verschwinden
soll.
Die #999 soll dann weg. Die Umwandlung soll auf die gesamte Datenbank
angewendet werden.

Hier der komplette FLEX:

first #
:loop
  Die Zahlen umordnen, 1stellige nach rechts ruecken
var #999(b"." b"." e" " 0,r4) #999(b"." e"." 0,r2) #999(e"." 0,r2)
  Leerzeichen durch 0 ersetzen, Ergebnis nach #99n
ins _ _0_
ins #99n
  und weg mit der #999, Satz speichern
#999
put
:weiter
next #
if cancel jump ende
  geloeschte Saetze nicht behandeln!
if del jump weiter
if yes jump loop
:ende
mes Uff, erledigt!


Die Zeile mit "var" ist diejenige, die aus dem vorgegebenen Datum die
richtige Struktur macht. Diese muß man bei einer anderen Vorgabe dann
entsprechend ändern, u.U. wird's schwieriger als in diesem Fall!

Der Trick liegt hier in dem Manipulationsbefehl 0,r2, der bei den
Zahlen für Monat und Tag angewendet wird. Damit rückt man eine
einstellige Zahl nach rechts, so daß sich zwei Stellen ergeben.
Leider ist die erste dann ein Leerzeichen. Man erhält also aus
1.2.1998 dann   1998 2 1.  Hm, was nun?
Der zweite Trick ist der Befehl  ins _ _0_, der die Leerzeichen im
iV-Text durch Nullen ersetzt. Und das war's dann.
Der Rest ist die normale Vorgehensweise, wenn man die Gesamtbank
durcharbeiten will. (S. Beisp. 3 in der Doku zu next: h xnext)

Tip: Das "put" weglassen, wenn man nach dem Durchlauf erst nochmal
schauen will, ob's denn gut geklappt hat. Danach dann in dem Memü
"Datei" die Funktion "Alle bearb. Daten speichern" aktivieren.

Ist statt der Gesamtbank nur eine Erg.Menge abzuarbeiten, läßt man
das Zeichen # bei first und next weg.

Hinweis:
Ab V29.6 gibt es den Manipulationsbefehl  rN,x
Dieser rückt den iV-Inhalt auf N Stellen nach rechts zurecht und füllt
links den Leerraum mit dem Zeichen x auf. Damit könnte man den
var-Befehl des FLEXes so schreiben:

var #999(b"." b"." e" " r4,0) #999(b"." e"." r2,0) #999(e"." r2,0)
 
Dies entspricht dem r-Befehl der Export-Manipulationssprache.

(20090611)

  ---------------------------------------------------------------------------------------------------


Trick 74: Globale Dollarkrise  
                Das Zeichen $ überall ersetzen

Aufgabe: Man hat in seiner Datenbank den $ als Unterfeldzeichen,
             nun soll er durch das Dreieck (Code 31) ersetzt werden.

Aber Achtung: wenn der $ irgendwo als solcher vorkommt, dann wird
er ebenfalls ersetzt, denn das Programm kann dies nicht unterscheiden.

Das Durcharbeiten der gesamten Datenbank ist kein großer Trick, es
wird im Text  xnext.rtf  unter Beispiel 3 beschrieben.

Der erste Trick ist, daß man die lokale Ersetzung mit insert _abc_XYZ_
verwenden muß, denn bei der globalen hat der $ leider die Wirkung
eines Abzwack-Operators: es verschwindet der ganze Rest des Felds.
(s. Handbuch S. 118)

Der zweite Trick ist, mit var k_1 und var k_2 die Felder einzeln

zu bearbeiten, wobei die Feldnummer mitgenommen wird (mit k1/k2
hat man die Feldtexte ohne Nummer), so daß mit
var k_2
...
ins
das Feld wieder korrekt in den Satz zurückgegeben wird.

Der dritte Trick ist, mit  if _$_  zu prüfen, ob im Satz wirklich
ein $ vorkommt, denn wenn nicht, braucht ja nichts getan zu werden
und insbes. der Satz nicht wieder gespeichert.

Der vierte Trick ist, daß man mit ^_ (zwei Zeichen) das Dreieck
angeben kann (Strg+_ ist Code 31). Dies gehört zu den Eigenheiten
der lokalen Ersetzung (h xinsert)

Hier die Lösung:

  DOLL.FLX : Dollarzeichen ueberall durch das Dreieck ersetzen
  2009-11-26

first #
  falls der erste Satz gelöscht ist: nächster Satz
if del jump weiter
  Jeder Satz wird in dieser Schleife verarbeitet:
:schleife

  Kommt $ im Satz vor? Wenn nicht, -> :weiter
if not _$_ jump weiter

  *************
var k_1

:loop
  Kombination ^ und _ steht fuer das Dreieck:
ins ,$,^_,
ins
var k_2
if not "" jump loop
  **************

put   speichern

  Nächsten Satz holen (interne Nummernfolge)
:weiter
next #

  kein Satz mehr, Ende erreicht
if cancel jump exit
  der Satz ist gelöscht
if del jump weiter

  es gab noch einen Satz? dann -> :schleife
if yes jump schleife

:exit
end

Statt des Abschnitts zwischen ***** geht auch, kürzer:

var kn
ins ,$,^_,
ins
put

Das wäre der fünfte Trick: mit  var kn  wird der gesamte Satz in die iV kopiert
die Ersetzung darin durchgeführt und das Ganze wieder in den Arbeitsspeicher
zurückkopiert.

(2009-11-26)

 
---------------------------------------------------------------------------------------------------


Trick 75: Index ändern on-the-fly  
                Bestimmte Einträge im laufenden Betrieb ändern

Aufgabe: Schnell mal eben für eine Anzahl von Sätzen einen bestimmten
              Registereintrag ändern.
 
Warum das?
Wer kennt es nicht: Man macht an den Indexparametern eine ganz kleine
Änderung, aber a99 ist zu dumm, dann schnell mal eben die nicht mehr
korrekten Schlüssel automatisch rauszusuchen und -zuwerfen und die
nunmehr korrekten einzusortieren.
Warum das so ist? Nun, a99 kriegt einfach gar nicht mit, daß man was
geändert hat - es prüft nicht ständig, ob die Datei noch so ist wie
vorher - und falls nicht, dann genau das Richtige zu tun. Das wäre
leider zuviel verlangt, man muß also selber dran denken, daß man den
Index dann erneuert.
Ha! Index erneuern, das ist bei Kleinbanken kein Problem, aber bei
sehr großen braucht's massig Zeit und ist im Netz auch nur dann
möglich, wenn gerade keiner an der Datenbank arbeitet, und das kann
schon ein arges Ärgernis sein; in einem 24/7-Betrieb geht das gar
nicht!

Aber FLEX birgt das Potential für einen pfiffigen Trick, und der geht so:

Zuerst die Ergebnismenge aller Sätze bilden, bei denen die

Änderung sich auswirken würde.
Dann einen FLEX schreiben, der
a) aus einem Satz den nicht mehr gültigen Schlüssel bildet und
   diesen löscht (mit  ixdel ...)
b) aus demselben Satz den nunmehr gültigen Schlüssel bildet und
   diesen einfügt (mit  ixadd ...)

Es folgt das Kochrezept, an das man sich in jedem Fall halten kann.
(Doku zu den zwei Befehlen: h xixadd. Darin auch Hinweis auf einen
aufwendigeren FLEX umindex.flx, der sich empfiehlt, wenn besonders
viele Schlüssel zu ändern sind; darauf wurde auch in der Vb.202
schon kurz aufmerksam gemacht. Er löscht zunächst *alle* Schlüssel
eines Satzes nach Maßgabe der alten Parameter und speist dann alle
nach Vorschrift der neuen neu ein. Je nach Menge dauert das viel
länger. umindex.flx ist im Gesamtpaket mit drin.)


// Ergebnismenge der relevanten Sätze vorher bilden

first
:loop
// den alten, nicht mehr korrekten Schl. bilden
// und zwar mit Index-Präfix, z.B  |7, ohne Spatium dahinter
var "|..." ...
ins #uzA
var i " " #uzA
ixdel

// den neuen, jetzt korrekten Schl. bilden
var "|..." ...
ins #uzN
var i " " #uzN
ixadd

:nxt
next
if yes jump loop
mes ERLEDIGT!


Statt  var "..." ...  ist natürlich jeweils ein geeigneter Algorithmus
für den betr. Schlüssel einzusetzen. Dazu sind evtl. mehrere Befehle
nötig. Insbes. kann man mit  xcode ip  oder  xcode iq  die Umcodierung
der Indexparameter mit heranziehen.

Auch umgekehrt, zuerst neu dann alt, ist es möglich. Oder wahlweise nur
den alten, nicht mehr benötigten Schlüssel löschen oder nur den neuen,
den es bisher noch nicht gab, erzeugen.

Ferner ist es natürlich auch möglich, statt nur eines Schlüssels gleich
mehrere zu löschen und/oder neu einzuspeisen; dann erweitert man eben
die Sache um entsprechende Abschnitte. Ratsam ist natürlich immer, es
erst mit einer kleinen Erg.Menge zu testen...

Aber was, wenn man auf keine Weise die Ergebnismenge aller betroffenen
Sätze bilden kann? Dann erweitert man die Schleife mit  first #  und
next #  eben auf die Gesamtbank und startet es vor der Mittagspause.
Aber Achtung: Statt einfach nur  next #  muß es dann so lauten:

:nxt
next #
if deleted jump nxt
if not cancel jump loop

denn es könnte sich bei dem mit  next #  geladen Satz um einen
gelöschten handeln ("deleted"), so einer ist zu überspringen.

(2010-05-04)

  ---------------------------------------------------------------------------------------------------


Trick 76: Erweiterter Aktionsradius  
                Ergebnismenge einschl. verknüpfter Sätze durcharbeiten

Aufgabe: Schnell mal eben eine Ergebnismenge durcharbeiten, wobei aber
zu jedem Satz auch die mit ihm in bestimmter Weise verknüpften Sätze
mit verarbeitet werden sollen, aber nicht unbedingt in derselben Weise
wie der Hauptsatz.

 
Warum das?
Beispiele sind nicht nur die verknüpften Bandsätze, sondern auch Exemplar- oder Bestellsätze
oder die Ausleihen von
Nutzern etc., d.h. alles kommt in Betracht, was durch die Indexierung
miteinander zusammenhängt.
Ferner: Es soll ein reines FLEX-Verfahren sein, also ohne Exportparameter, bis auf Umcodierung.
Und: Das Verfahren soll mit a99 und mit acon funktionieren.

Option: Vielleicht will man auch gelegentlich schnell mal eben die
Gesamtbank entsprechend abarbeiten ...

Beisp.1: Erg.Menge exportieren, aber unter jedem Satz die Exemplardaten
         auflisten.

Beisp.2: In jedem Satz der Erg.Menge bestimmte Änderungen vornehmen,
         zusätzlich aber auch in den verknüpften Untersätzen.

Gesucht ist eine allgemeine Lösung, die in allen vergleichbaren
Fällen zum Einsatz kommen kann! Ein FLEX-Unterprogramm also, aber mit
Variationsmöglichkeiten.

Man konnte solche Produktionen seit langem mittels der "Nachladung"
in den Exportparametern bewerkstelligen. Nun aber soll eine Methode
gefunden werden, die allein mit FLEX arbeitet, denn die Export-
Parametrierung ist eine wegen ihrer Abstraktheit und Kryptik doch recht
schwierig anzuwendende Sache.

Der Lösungsweg

Folgende Kurzbezeichnungen sind sinnvoll:
   HM = Hauptergebnismenge
   ZM = Zusatz-Erg.Menge, jeweils zu einem Satz der HM zu bilden
        (Manchmal ist sie leer!)

Zwei Probleme stellen sich in den Weg:

Problem 1:
Wir können nicht die übliche Methode  first / next  verwenden, denn zu
jedem Satz ist eine Zusatz-Erg.Menge (ZM) zu bilden - dadurch wird
dann die HM geschlossen. Nach Verarb. der ZM ist zur HM zurückzukehren
und in dieser dann zum nächsten Satz zu gehen. Das ginge in a99, in
acon aber nicht!  [Evtl. wird das noch geändert!]
Lösung: Aus der HM wird mittels des Befehls
           var i,
        eine Nummernliste erstellt, in der die internen Satznummern
        durch ',' getrennt vorliegen
        Aber ACHTUNG: Die Liste wird in einer $-Var. gespeichert, das
        beschränkt die Größe der Erg.Menge auf etwa 8-10000. Will man
        größere erschlagen können, muß man die Methodik umstellen
        auf Speicherung in einer Datei und dann zeilenweises Einlesen.

Problem 2: Die folgenden drei je spezifischen Aktionen können
nicht Teil des erwünschten, allgemeingültigen Unterprogramms sein:

ZMget : Bildung der zu einem HM-Satz gehörigen ZM
HMact : Ausführung der gewünschten Aktion am HM-Satz
ZMact : ... am verknüpften ZM-Satz

Lösung: Unser Unterprogramm soll  EXTACT  heißen, d.h. es beginnt mit
der Zeile  :EXTACT  und endet mit  return. (Der Name leitet sich ab
von "extended action", wie man die Sache auch bezeichnen könnte.)
Das Unterprogramm enthält nicht selber die drei Aktionen, sondern
die liegen als Unterprogramme "weiter oben" im Haupt-FLEX, unter den
o.g. Namen, denn sie müssen spezifisch für die jeweilige konkrete
Aufgabe sein.
Weil aber verschachtelte Unterprogramme nicht möglich sind, müssen
die drei Unterprogramme mit "jump ..." aufgerufen werden, d.h. sie
sind keine echten Unterprogramme, sondern werden jeweils mit einem
"jump ..." beendet, der zurück in das Unterprogramm  EXTACT hinter den
jeweiligen Aufruf führt: :HMact endet mit  jump HMactRet  und führt
damit zu  :HMactRet  unter  jump HMact, usw.

Was ist zu tun?

Im Haupt-FLEX sieht der Ablauf so aus:
und hier muß man die "AKTIONen" selber geeignet programmieren!,
d.h. NUR das hier, zwischen ANFANG und ENDE, ist der variable Teil,
den man in den eigenen FLEX bzw. Job einbauen muss:

(Also das folgende Muster kopieren und geeignet modifizieren!)


// *** ANFANG des eigenen .flx oder .job ************************
// ... Vorbereitende AKTIONen ...

// Fuer acon:
var m
if %ac-% echo off

//  Wenn Gesamtbank gewuenscht, dann Flag $gF setzen:
// $gF=1

// Sonst muss jetzt eine Erg.Menge vorliegen, evtl. geordnet.

exp f <dateiname>   // Ausgabedatei oeffnen
exp p utf   // diese 2 Zeilen nur für Wandlung von ASCII nach UTF-8
exp wA      // Bei #-A in utf.apr wird der zu schreibende Text umcodiert

// der Aufruf des Unterprogramms:
perform EXTACT
mes Erledigt!

// ... nachbereitende Aktionen des Hauptteils ...

end

// An das Ende des eigenen Jobs kommt noch dieser Teil,
// ebenfalls selbst zu schreiben, weil spezifisch.

// ###############
//  Diese drei Abschnitte sind aufgabenspezifisch auszufuellen:

//  1. Bildung der Sub-Erg.Menge  ZM
:ZMfind
// *** hier AKTION zur Bildung der ZM-Erg.Menge, evtl. mit Ordnung ***
// i.d.R. mit "var ..." einen Suchbefehl machen und dann "find"
//  zurueck in das UP
jump ZMfindRet

//  2. Verarb. d. Satzes aus der HM (ist jetzt der aktive Satz)
:HMact
// *** hier AKTIONen mit dem HM-Satz ***
// evtl. bestimmte Sätze ausschließen, z.B. mit
// if not #20 jump HMnext
// i.d.R. mit "write ..." die Ausgabe erzeugen
jump HMactRet

//  3. Export des aktuellen Satzes der ZM (ist jetzt aktiver Satz)
:ZMact
// *** hier AKTIONen mit dem ZM-Satz  ***
// i.d.R. mit "write ..." die Ausgabe erzeugen
jump ZMactRet

// ################

//  jetzt noch die Datei hinzunehmen, in der :EXTACT ist:
include extact.inc

// *** ENDE des eigenen FLEXjobs *********************************


 ================ extact.inc =====================================

==>Mit  X getfile extact.inc  können Sie sich die Datei holen!
  oder von hier kopieren:

// *** Beginn extact.inc *****************************************
//  Label fuer den Aufruf mit  perform EXTACT  zur Anwendung auf die
//  aktuelle Erg.Menge, die in der vorliegenden Reihenfolge
//  abgearbeitet werden soll

:EXTACT
//  Die internen Nummern der HM in $hm ablegen, mit , getrennt
var i,
ins $hm
//  Diese Liste wird dann abgearbeitet von vorn nach hinten
//  ACHTUNG: die Erg.Menge kann fuer diese Methode nicht groesser als
//  8-10.000 Saetze sein.

// Wenn $gF besetzt, dann Gesamtbank abarb.

if $gF first #;if del jump HMgesamt

:HMloop
//  die erste (bzw. naechste) Nummer nehmen, # davorsetzen
//  ($hm beginnt mit dieser Nr.)
//  und den HM-Satz mit dieser Nr. laden
//  - falls nicht $gF gesetzt, dann ist jetzt naechste Satz schon da
if not $gF var "#" $hm (e",");f1nd

//  Die HM-Aktion ausfuehren
jump HMact

:HMactRet
//  Zu dem Satz nun die zusaetzliche Menge (ZM) bilden
// Vorher  Objekt 2 einschalten - damit dann  next #  klappt
// aber 1 nach 2 kopieren, damit unter :ZMfind zugaenglich
copy obj 1 2
set obj 2
// d.h. die ZM-Saetze werden in Obj.2 geladen
jump ZMfind
//  (von dort Ruecksprung mit  jump ZMfindRet)
:ZMfindRet
// "less than 1"?  d.h. ZM ist leer
if l1 set obj 1;jump HMnext

//  Die ZM ist nicht leer, also abarbeiten

first
:ZMloop
// die ZM-Aktion  :ZMact  ausfuehren (im HauptFLEX)
jump ZMact
// von dort zurueck mit  jump ZMactRet
:ZMactRet
// naechsten Satz der ZM
next
if yes jump ZMloop
// keiner mehr da - Die ZM schliessen und loeschen
close res
// ZM Ende, jetzt wieder Objekt 1
set obj 1

//  Hauptschleife geht weiter, momentan erste Nr. der HM wegnehmen
:HMnext
// Wenn Gesamtbank:
if $gF jump HMgesamt

// Naechsten Satz der Erg.Menge
var $hm (b",")
//  verkuerzte Liste wieder in $hm
ins $hm
//  Ist noch was da? Dann weiter in Hauptschleife mit dem naechsten Satz
if $hm jump HMloop
jump HMend

// naechsten Satz der Gesamtbank, etwas schwierig wg. unbesetzter Nummern etc.
:HMgesamt
next #
// Ende? (a99: cancel, acon: no)
if no jump HMend
if cancel jump HMend

if del jump HMgesamt
jump HMloop

:HMend
return
end
// **** ENDE  extact.inc  *****************************************


Es wurden uns ein paar Verbesserungswünsche mitgeteilt, die wir
noch umsetzen konnten.

Geben Sie zuerst in a99 diese zwei Befehle:

  X getfile extact.ini
     das ist die eigentliche Funktion :EXTACT,
     diese Datei erfordert *keinen* Eingriff

  X getfile extact.flx
     das ist ein Muster zum Abwandeln! Darin wird :EXTACT aufgerufen
     Ausführliche Hinweise stehen drin.

Dann haben Sie die zwei Dateien in Ihrem FLEX-Ordner.


Um ein *eigenes Projekt* zu realisieren, so vorgehen:

1. Kopie von  extact.flx machen, sagen wir  mypro.flx

2. mypro.flx bearbeiten: (darin ist alles kommentiert)

   A. Drei Flags setzen, und zwar für diese Optionen:
      $gF : Erg.Menge oder Gesamtbank verarbeiten
      $mF : Hauptsatzdaten immer ausgeben,
             oder nur wenn Unterdaten existieren?
      $hF : Hauptsatz über oder unter den Untersätzen auswerfen

   B. Drei Funktionen ergänzen:
      :ZMfind: Funktion für das Bilden der Zusatz-Erg.Menge
      :HMact : Aktion für den jeweiligen Hauptsatz
      :ZMact : Aktion für die zusätzlichen (nachgladenen) Sätze

Die Aktionen werden zumeist write-Befehle sein, um die erwünschten
Datenelemente in der erwünschten Form auszugeben, es können aber auch
andere Aktionen sein, die man mit den Datensätzen durchführen will,
also auch Änderungen an Haupt- bzw. Nachladesätzen.
Weitere Tips in den Dateien.

3. Vor dem Start:  Mit  Export / Andere Exportdatei
    in a99 einen Dateinamen fuer den Output vorgeben!

4. Schließlich mit   X mypro   starten!

(Solange kein "put"-Befehl vorkommt, kann nix schiefgehen.)


Trick 77: RAK = Register-Abschnitts-Kopie  
                Reg.Abschnitt in eine andere Indexdatei kopieren

Aufgabe: Schnell mal eben einen Registerabschnitt kopieren von einem
Index (z.B. .adx) in einen anderen (z.B. .aex).

 

Warum das?
Konkreter Anlaß war die Beobachtung, daß die Expansion einer
Suche nicht klappt, wenn das ALL-Register benutzt wird. Z.B. würde
man mit  find all &schiller  die Räuber nicht erwischen, wenn sie
(d.h. das Wort "raeuber") in Unterdatensätzen vorkommen, die den
Namen "Schiller" nicht enthalten.
Das kommt, weil das ALL-Register im Index .aex liegt, das Expansions-
Register aber in .adx: Das sind dort die Eintraege, die mit | beginnen
im Register 10.
Ob und wann diese Unzulänglichkeit behebbar sein wird, das steht noch
abzuwarten. Immerhin sind fast 4 Jahre verstrichen, seitdem das ALL-
Register entwickelt wurde, und erst jetzt fiel das Problem auf.

Was aber, so die Idee zum Trick, wenn das Expansionsregister einfach
irgendwie in .aex rüberkopiert werden könnte? Dann möcht's doch
gehen!? Ja, das tut es!
Das ist zwar nett, aber natürlich wird der Einwand sofort kommen:

Alsbald nach solchem Kopieren können sich schon wieder Einträge ändern!
Neue kommen hinzu, andere verschwinden. Und schon ist die Expansion
unzuverlässig - das ist schlimmer, als wenn's sie gar nicht gibt.
Richtig. Der Trick ist ein Behelf, mehr nicht. Aber was jahrelang gar
nicht auffiel, mag wohl damit erst einmal ein paar Wochen hingehen,
wenn man den Vorgang angemessen häufig wiederholt, vielleicht täglich
oder alle paar Stunden.

Das konkrete Beispiel soll deshalb mehr zur Veranschaulichung der
Methode dienen, nicht als wirkliche Lösung dieses speziellen Problems.
(FLEXperten seien angespornt, die Sache noch zu erweitern um eine
Routine, die zuerst aus .aex die bereits vorhandene Kopie des
Abschnitts wieder löscht, bevor der aktuelle Stand hineinkopiert wird.
Denn sonst bleiben Einträge stehen, die nicht mehr stimmen. Schön
wär's, man könnte das auch mit acon machen - das geht aber nicht,
weil acon den Modus f3 von qrix nicht kennt. Man müßte f1 nehmen
und die Prozedur etwas umständlicher umschreiben.)

Es folgt nun der FLEX  trix.flx, der den Transfer des Expansions-
registers aus .adx nach .aex leistet. Man startet ihn in a99 mit
dem Aufruf  X trix.


---------------------------------------------------

  trix.flx : "transfer index" : SR-Register von .adx in .aex kopieren
  2014-09-12
  Verallgemeinerbar: Registerabschnitt in einen anderen Index kopieren
  (wozu auch immer)

  SR-Eintraege aus .adx in Datei trix.dat schreiben

open x trix.dat
  Modus 3 fuer qrix einstellen und Separator --- für Von/Bis-Suche
qri f3
qri d---
  Den Abschnitt in die Datei schreiben
Qri |: |0---|z
close x

  Datei trix.dat dann zeilenweise einlesen und in .aex einfuegen.
  Die Dateizeilen haben die Form  ih||iu, wobei ih die Nummer des
  Datensatzes ist, in dem "Schiller" steht, iu diejenige eines
  Untersatzes, in dem "Räuber" steht.

open trix.dat
  zur Sicherheit
set tbl lock

:srloop
  Zeile lesen
get
  Dateiende
if cancel jump ende

ins $q

  Zeile zerlegen :  aus  ih||iu  soll  ih ~e:|iu  werden

var $q (e"|")
ins $n
var $q (b"|")
ins $q

  Zeile erstellen und einfuegen
var $n " ~e:" $q
ixadd
  Schleife
jump srloop

:ende
  flush index
close index
set tbl fre

close
del trix.dat
mes Done




2014-06-16