system/setup/3.1/src/setup eumel 3: modulkonfiguration

Raw file
Back to index

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
(**************************************************************************)
(***** Ergänzung des SHards um ein Modul (mit Dialog)     *****************)
(***** Copyright (c) 1987, 1988 by                        *****************)
(***** Lutz Prechelt, Karlsruhe                           *****************)
(**************************************************************************)

PACKET setup eumel modulkonfiguration     (* Copyright (c) by         *)
DEFINES configurate module,               (* Lutz Prechelt, Karlsruhe *)
        print configuration,              (* Eumel 1.8.1              *)
        give me, take you,                (* Stand : 12.07.88   3.2   *)
        new index,                        
        perform dtcb dialogue,
        perform ccb  dialogue,
        (* für Modulprogrammierer : *)
        write info,
        channel free,
        reserve channel,
        channels of this module,
        buffer address :

(* Dieses Modul führt den kompletten Dialog mit dem Benutzer durch, der
   nötig ist, um alle Kanäle, die mit demselben Modul laufen sollen, zu 
   konfigurieren. 
   Verfahren : 
      im alten SHard den dtcb suchen 
      dtcb und Modul im neuen SHard eintragen
      dtcb mit oder ohne Vorbild konfigurieren 
      alle ccbs zu dem Modul im alten SHard suchen und Kanalnummern merken
      Auswahl einer Kanalmenge durch Benutzer mit alten als Vorschlag
      ccbs in neuen SHard kopieren
      ccbs mit oder ohne Vorbild konfigurieren
      Kanaltabelle auf den neuen Stand bringen
      neuen Shard und seine geänderte Länge zurückgeben 

   Dabei kann der "Dialog" bei geeigneten Rahmenbedingungen durch bloßes
   Übertragen der Werte aus einem Vorlage-SHard ersetzt werden, wenn der
   Benutzer dies wünscht (want automatic mode). Dann geht alles von selbst.
   (....kaufen Sie Setup-Eumel und es geht alles wie von selbst !)

Format des SHard-Hauptmoduls : 
   1. (Byte 0-2)     jmp boot (3 Byte)
   2. (Byte 3)       reserviert
   3. (Byte 4)       SHard-Version
   4. (Byte 5)       SHard-Release
   5. (Byte 6/7)     SHardlänge (2 Byte)
   6. (Byte 8/9)     Verweis auf Bad-Block Tabelle (2 Byte)
   7. (Byte 10/11)   Verweis auf Kanaltabelle
   8. (Byte 16-175)  Eumelleiste
   9. (Byte 176-299) SHardleiste
  10. (ab Byte 300)  Shardhauptmodulroutinen und -daten
  11. (danach)       Rumpf des Hauptmoduls mit Bad-Block-Tabelle,
                     Kanaltabelle, Routinen und Daten
  12. (danach)       Folge der Module (bis Byte SHardlänge - 1)

Kanaltabelle:
        feste Länge 40 Einträge "nr of channels total" (Kanal 0 bis Kanal 39)
        jeder Eintrag besteht aus : (alles 2 Byte) 
        offset dtcb, offset ccb 
 
Achtung : Dieses Programm schmiert bei SHards über 32767 Byte Länge
          eventuell ab (es hat noch niemand probiert) !

Abkürzungen: cb steht für control block und meint entweder ccb oder dtcb 
 
Implementationsanmerkung :
Bei der Verwendung von THESAURUS wird von dem Wissen über die Art der
Implementation derselben Gebrauch gemacht, indem folgende Annahmen in den
Code eingehen:
1. Bei einem THESAURUS, in dem nicht gelöscht wurde, ist highest entry gleich
   der Kardinalität
2. außerdem entspricht dann die Nummer (link) eines Eintrags seinem
   Eintragszeitpunkt, d.h. der Position in der Eintragsfolge
3. + und - liefert THESAURi, in denen nicht gelöscht wurde und die Eintrags-
   reihenfolge ist wie von den Parametern vorgegeben (bei + links zuerst)
4. certain und ONE liefern THESAURi, in denen nicht gelöscht wurde.
*)

(************************* Daten ********************************)

LET    nr of channels total          = 40,  (* SHard Tabellenlänge *)
       mdts                          = 40,  (* max dialogtable size in INTs *)
       mchm                          = 20,  (* max channels for module *)
       offset sh version             = 4,
       offset sh structureversion    = 5,
       offset shardlength            = 6,

       do name = "PrOgRaM tO Do";

LET  UNSIGNED  = INT,
     VARIABLES = ROW mdts ROW mchm INT;
TEXT CONST variables var xxv :: "ROW " + text (mdts) + " ROW "+
                                text (mchm) + " INT VARxxv;";

VARIABLES VAR v;             (* siehe give me / take you *)

INT  VAR max index;          (* Information für new index *)

INT  VAR channels of module; (* Information für channels of this module *)

TEXT VAR actual info;        (* fuer write info *)

ROW 256 INT VAR channel table of new shard;  (* für channel free *)

DATASPACE VAR dummy ds;      (* für print configuration *)

REAL VAR new shard length;

(***************************************************************************)
(************* Hier geht's los...... ***************************************)
(***************************************************************************)

(******************** configurate module **********************************)

PROC configurate module (MODUL VAR  new shard, MODUL CONST old shard,
                         BOOL CONST old shard valid, want automatic mode,
                         TEXT CONST modulname) :
  do configurate module (new shard, old shard, old shard valid,
                      want automatic mode, modulname, FALSE)
END PROC configurate module;

(********************** print configuration *******************************)

PROC print configuration (MODUL CONST old shard, TEXT CONST modulname) :
  (* Es ist hier schon sichergestellt, daß old shard valid ist und das Modul
     auch im SHard enthalten
  *)
  forget (dummy ds); dummy ds := nilspace;
  BOUND MODUL VAR dummy :: dummy ds;
  do configurate module (dummy, old shard, TRUE, FALSE, modulname, TRUE);
  forget (dummy ds).
END PROC print configuration;


(******************* do configurate module *********************************)

PROC do configurate module (MODUL VAR  new shard, MODUL CONST old shard,
                            BOOL CONST old shard valid, want automatic mode,
                            TEXT CONST modulname,
                            BOOL CONST print configuration only):
  (* In dieser Prozedur ist die Beschränkung auf Module mit unter 32kB
     Länge ausgenutzt.
     Ist kein alter SHard vorhanden, so muss ein leerer SHard übergeben
     werden (d.h. alle Einträge in der Kanaltabelle sind 0).
     Ein alter SHard darf keinesfalls unterschiedliche releases desselben
     Modultyps enthalten.
     Resultierende SHardgesamtlängen von über 32k sind noch nicht getestet.
  *)
  BOUND MODUL VAR m;
  INT VAR  (***** Daten über das neue Modul *****)
           sh version, sh structure version, release,
           max ccb, nr of ccbs,
           dtcb table entries, offset dtcb table, (* Variablentabellen *)
           ccb  table entries, offset ccb  table,
           muster ccb length, offset muster ccb, (* Muster-ccb im Modul *)
           module body length,  (* Länge des zu kopierenden Modulrumpfs *)
           offset module body, offset dtcb;
  TEXT VAR modultyp; (* 4 Byte *)
  INT VAR  (***** Daten über den alten SHard *****)
           old release :: -2;  (* garantiert inkompatibel *)
  REAL VAR offset old dtcb :: 0.0;
  ROW nr of channels total REAL VAR offset old ccb;
  BOOL VAR old cbs valid :: FALSE;
  THESAURUS VAR old channels :: empty thesaurus;
  (***** Daten über den neuen SHard *****)
  REAL VAR dtcb location;
  ROW nr of channels total REAL VAR ccb location;
  (***** Sonstige Daten *****)
  INT  VAR i, k, kanal, ccb count;
  BOOL VAR automatic mode, configurate :: NOT print configuration only;
  reset direction (FALSE); (* zur Sicherheit *)
  IF configurate
  THEN new shard length := unsigned (int (new shard, offset shard length)) FI;
  connect module;
  get module data;
  test sh version compatibility;      (* ggf. LEAVE *)
  (* Bisher wurde nur gelesen, ab jetzt darf nicht mehr abgebrochen werden *)
  search old shard for module and find all old ccbs;
  test release compatibility;         (* ggf. LEAVE *)
  IF configurate
  THEN write module with dtcb to shard;
       perhaps set automatic mode;
  FI;
  configurate dtcb;
  IF configurate
  THEN kopf;
       select channels;
       write ccbs to shard;
  ELSE nr of ccbs := highest entry (old channels)
  FI;
  configurate ccbs;
  IF configurate
  THEN make entries in channeltable of new shard;
       int (new shard, offset shardlength, unsigned (new shard length))
  FI.

connect module :
  m := old (modulname);
  actual info := info (m);
  IF configurate
  THEN kopf
  ELSE put ("-----"); put (modulname); putline ("-----")
  FI.

get module data :
  (* Format des Moduls in den ersten Bytes:
     Byte    Entry
     0/1     offset dtcb variablen tabelle
     2/3     offset ccb  variablen tabelle
     4/5     offset muster-ccb
     6/7     offset modulrumpf
     8/9     offset dtcb
     10/11   max anzahl ccbs
     die tabellen enthalten im ersten Wort die Anzahl ihrer Einträge
     der modulrumpf und der ccb ihre Länge in Byte
     die Länge der Tabellen ergibt sich aus den offset-Differenzen.
     dtcb-Format : Modultyp (4 Byte)
                   SHardversion (1 Byte)
                   SHardstrukturversion (1 Byte)
                   Modulrelease (2 Byte)     ....
  *)
  max ccb := int (m, 10);
  offset dtcb table  := int (m, 0);
  dtcb table entries := int (m, offset dtcb table);
  offset ccb table   := int (m, 2);
  ccb  table entries := int (m, offset ccb table);
  offset muster ccb  := int (m, 4);
  muster ccb length  := int (m, offset muster ccb);
  offset module body := int (m, 6);
  module body length := int (m, offset module body);
  offset dtcb        := int (m, 8);
(*****
put ("  offset dtcb table:"); put(       offset dtcb table); line;
put ("  dtcb table entrie:"); put(      dtcb table entries); line;
put ("  offset ccb table :"); put(       offset ccb table);  line;
put ("  ccb  table entrie:"); put(      ccb  table entries); line;
put ("  offset muster ccb:"); put(       offset muster ccb); line;
put ("  muster ccb length:"); put(       muster ccb length); line;
put ("  offset module bod:"); put(      offset module body); line;
put ("  module body lengt:"); put(      module body length); line;
put ("  offset dtcb      :"); put(       offset dtcb);       line;*****)
  modultyp            := text (m, offset dtcb, 4);
  sh version          := byte (m, offset dtcb + 4);
  sh structureversion := byte (m, offset dtcb + 5);
  release             := int  (m, offset dtcb + 6).

test sh version compatibility :
  IF configurate AND NOT version is compatible
  THEN putline ("Das Modul ist mit dieser SHard-Version nicht mehr verträglich.");
       putline (""10""10""15"  Installation des Moduls wird abgebrochen.  "14""7""13""10"");
       go on;
       LEAVE do configurate module
  FI.

version is compatible:
  (* Kompatibel, wenn das Modul eine ältere oder gleiche sh version verlangt
     und die gleiche sh structureversion
  *)
  sh version <= byte (new shard, offset sh version) CAND
  sh structure version = byte (new shard, offset sh structureversion).

search old shard for module and find all old ccbs :
  (* Es werden alle Kanäle des alten SHard untersucht, ob der dortige Treiber
     den gleichen Modultyp hat und in diesem Fall die Kanalnummer in
     "old channels" gesammelt, sowie offset old ccb gemerkt, im Nichterfolgs-
     falle wird offset old ccb auf diesem Kanal 0 gesetzt.
     Es werden auch alle verketteten Treiber untersucht.
     Auch old cbs valid und offset old dtcb werden ggf. gesetzt.
  *)
  IF NOT old shard valid
  THEN LEAVE search old shard for module and find all old ccbs  FI;
  IF configurate THEN put ("Ich untersuche den alten SHard :")  FI;
  FOR kanal FROM 0 UPTO nr of channels total - 1 REP
    IF configurate THEN cout (kanal)  FI;
    collect ccbs on this channel
  PER;
  IF configurate THEN put (""13""5"")  FI.  (* Zeile löschen *)

collect ccbs on this channel :
  REAL VAR p dtcb :: sh dtcb offset (old shard, kanal),
           p ccb  :: sh ccb offset (old shard, kanal);
  WHILE p dtcb <> 0.0 AND p ccb <> 0.0 REP
    BOOL CONST success :: text (old shard, p dtcb, 4) = modultyp;
    IF success
    THEN offset old dtcb := p dtcb;
         old release     := int (old shard, p dtcb + 6.0);
         insert (old channels, text (kanal));
         offset old ccb [kanal+1] := p ccb
    ELSE p dtcb := unsigned (int (old shard, p ccb + 2.0));  (* verkettet *)
         p ccb  := unsigned (int (old shard, p ccb + 4.0))
    FI
  UNTIL success  PER;
  old cbs valid := old shard valid AND offset old dtcb <> 0.0 AND
                   (release = old release + 1 OR release = old release).

test release compatibility:
  IF print configuration only AND NOT old cbs valid
  THEN putline ("Kein Zugriff auf die Konfigurationsdaten möglich");
       LEAVE do configurate module
  FI.

write module with dtcb to shard :
  put ("Modul """ + modulname + """ wird in den SHard eingetragen :");
  IF int (new shard length MOD 2.0) <> offset module body MOD 2
  THEN new shard length INCR 1.0  FI;   (* kopiert so schneller *)
  dtcb location := new shard length +
                      real (offset dtcb - offset module body);
  copy (m, real (offset module body), new shard, new shard length,
        module body length);
  new shard length INCR real (module body length).

perhaps set automatic mode :
  IF old cbs valid AND old release = release
  THEN automatic mode := want automatic mode
  ELSE automatic mode := FALSE  FI.

configurate dtcb :
  IF configurate
  THEN kopf;
       putline ("Konfiguration des Treibers :");
       get new channel table (new shard, channel table of new shard);
  FI;
  perform dtcb dialogue (m, real (offset dtcb table+2), dtcb table entries,
                         new shard, dtcb location,
                         old shard, offset old dtcb,
                         old cbs valid, release = old release,
                         dtcb refinements (m), dtcb abfragen (m),
                         automatic mode, print configuration only).

select channels :
  ccb count := highest entry (old channels);
  k := min (ccb count, max ccb); (* .... Mutter der Porzellankiste *)
  nr of ccbs := max (k, 1);
  IF automatic mode THEN LEAVE select channels  FI;
  IF max ccb > 1
  THEN REP
         editget ("Wieviele Kanäle mit diesem Treiber (1 bis " +
                  text (max ccb) + ") : ", nr of ccbs);
         out (""13"")
       UNTIL nr of ccbs IN range (1, max ccb)  PER;
       out (""10""10"")
  ELSE nr of ccbs := 1  FI;
  IF nr of ccbs < ccb count  (* weniger als früher *)
  THEN put ("Wählen Sie mindestens"); putline (x kanäle aus deren);
       putline ("Werte nicht als Vorbesetzung angeboten werden sollen"10"");
       REP
         THESAURUS CONST help :: certain (old channels, empty thesaurus);
         IF NOT enough refused THEN out (""7"")  FI
       UNTIL enough refused  PER;
       old channels := old channels - help;
       out (""3""3""3""4"")  (* clear screen from incl. "Wählen..." on *)
  FI.

x kanäle aus deren :
  IF ccb count - nr of ccbs > 1
  THEN text (ccb count - nr of ccbs) + " Kanäle aus, deren"
  ELSE "einen Kanal aus, dessen"  FI.

enough refused :
  highest entry (help) >= ccb count - nr of ccbs.

write ccbs to shard :
  (* Ausserdem wird hier ccb location vorbereitet *)
  out ("Die Kanäle werden in den neuen SHard eingetragen : ");
  FOR i FROM 1 UPTO nr of ccbs REP
    ccb location [i] := new shard length;
    copy (m, real (offset muster ccb + 2), new shard, new shard length,
         muster ccb length);
    new shard length INCR real (muster ccb length)
  PER.

configurate ccbs :
  (*put (old shard valid); put ("Release:"); put (release); put ("  old release:"); put (old release);
    put (old cbs valid); pause;*)
  IF configurate
  THEN out (""13""10"Konfiguration der Kanäle:"13""10"");
       get new channel table (new shard, channel table of new shard)  
  FI;
  ccb count := 0;
  FOR kanal FROM 0 UPTO nr of channels total REP
    IF old channels CONTAINS text (kanal)
    THEN ccb count INCR 1;
         offset old ccb [ccb count] := offset old ccb [kanal+1]
    FI
  PER;
  FOR i FROM ccb count + 1 UPTO nr of ccbs REP
    offset old ccb [i] := 0.0
  PER;
  perform ccb dialogue (m, real (offset ccb table+2), ccb table entries,
                        new shard, ccb location,
                        old shard, offset old ccb,
                        nr of ccbs,
                        offset old dtcb <> 0.0, release = old release,
                        ccb refinements (m), ccb abfragen (m),
                        automatic mode, print configuration only).

make entries in channeltable of new shard :
  kopf;
  out ("Konfigurationsdaten werden in den neuen SHard eingetragen : ");
  FOR i FROM 1 UPTO nr of ccbs REP
    cout (i);
    kanal := (*v[1][i]falsch???!!!*) byte (new shard, ccb location [i]);
    make entry in channeltable of new shard
  PER.

make entry in channeltable of new shard :
  IF NOT channel free (kanal)
  THEN (* dtcb/ccb Adresse aus channel table nach neuem ccb umtragen. *)
       int (new shard, ccb location [i] + 2.0,
            unsigned (sh dtcb offset (new shard, kanal)));
       int (new shard, ccb location [i] + 4.0,
            unsigned (sh ccb offset (new shard, kanal)));
  ELSE (* Folge-dtcb/ccb Adresse auf 0 setzen *)
       int (new shard, ccb location [i] + 2.0, 0);
       int (new shard, ccb location [i] + 4.0, 0);
  FI;
  (* Jetzt neue Adresse in channel table eintragen *)
  sh dtcb offset (new shard, kanal, dtcb location);
  sh ccb  offset (new shard, kanal, ccb location [i]);
  k := byte (new shard, ccb location [i] + 1.0);  (* Zusatzkanalnummer *)
  IF k <> 255  (* 255 = kein Zusatzkanal vorhanden *)
  THEN (* IF NOT channel free (k) THEN alter eintrag futsch !!! *)
       sh dtcb offset (new shard, k, dtcb location);
       sh ccb  offset (new shard, k, ccb location [i])
  FI.

kopf :
  write head ("""" + modulname + """ in den SHard aufnehmen");
  out (actual info);
  out (""13""10"").
END PROC do configurate module;


(********************* perform dialogue ************************************)

PROC perform dtcb dialogue
   (MODUL VAR m,          REAL CONST offset dialogue table, 
    INT CONST dialogue table entries,
    MODUL VAR   dtcb,     REAL CONST offset dtcb,
    MODUL CONST old dtcb, REAL CONST offset old dtcb,
    BOOL CONST old dtcb valid, same release,
    TEXT CONST refinements, INT CONST count,
    BOOL CONST automatic mode, print configuration only):
  ROW nr of channels total REAL VAR offset cb, offset old cb;
  offset cb [1]     := offset dtcb;
  offset old cb [1] := offset old dtcb;
  perform dialogue (TRUE, m, offset dialogue table, dialogue table entries,
                    dtcb, offset cb, old dtcb, offset old cb, 1,
                    old dtcb valid, same release, refinements, count,
                    automatic mode, print configuration only).
END PROC perform dtcb dialogue;

PROC perform ccb dialogue
   (MODUL VAR m,         REAL CONST offset dialogue table, 
    INT CONST dialogue table entries,
    MODUL VAR   ccb,     ROW nr of channels total REAL CONST offset ccb,
    MODUL CONST old ccb, ROW nr of channels total REAL CONST offset old ccb,
    INT CONST nr of ccbs, BOOL CONST old ccbs valid, same release,
    TEXT CONST refinements, INT CONST count,
    BOOL CONST automatic mode, print configuration only) : 
  perform dialogue (FALSE, m, offset dialogue table, dialogue table entries,
                    ccb, offset ccb, old ccb, offset old ccb, nr of ccbs,
                    old ccbs valid, same release, refinements, count,
                    automatic mode, print configuration only).
END PROC perform ccb dialogue;


PROC perform dialogue
  (BOOL CONST is dtcb,
  MODUL VAR m,       REAL CONST offset dialogue table, 
  INT CONST dialogue table entries,
  MODUL VAR   cb,     ROW nr of channels total REAL CONST offset cb,
  MODUL CONST old cb, ROW nr of channels total REAL CONST offset old cb,
  INT CONST nr of cbs, BOOL CONST old cb valid, same release,
  TEXT CONST refinements, INT CONST refinement count,
  BOOL CONST automatic mode, print configuration only) : 
  (* Konfigurationsdialog für einen (Satz von) Kontrollblock(s) oder bloßes
     Anzeigen der Konfigurationsdaten derselben.

  1. bei NOT print configuration only:
     Führt den Dialog für eine Tabelle (also ccb oder dtcb Variablentabelle) 
     durch und bestückt den controlblock entsprechend. 
     Es wird gleich eine ganze Tabelle von controlblocks (max. mchm Stück)
     abgearbeitet und zwar nr of cbs Stück; im Falle is dtcb wird natürlich
     nur der Eintrag 1 der Tabellen benutzt (vom Aufrufer).
     Das Eingabemodul ist m mit der zu bearbeitenden Tabelle an der Stelle
     offset dialogue table. Die Tabelle enthält dialogue table entries
     Einträge (max. mdts Stück !)
     Die Ausgabe des Prozesses landet im Modul cb ab den Stellen offset cb.
     cb ist dabei jeweils der neue SHard, damit man nicht das Modul ändert.
     Die Vorlagen zum Abgucken liefert, falls old cb valid ist, das
     Modul old cb (der alte SHard) ab offset old cb, dabei ist die Struktur
     gleich der neuen, wenn same release gilt, andernfalls sind die
     Vorversionsoffsets zu benutzen (Versionsnummer um genau 1 erhöht).
     Bei automatic mode werden nur still diese Vorgabewerte übernommen.
     Die Elan-Teile für den Dialog liefert schliesslich der Text refinements,
     er enthält refinement count Abfragen der Namen r1, r2, .....
     Wenn refinent count = 0 ist, passiert hier eigentlich nichts,
     deshalb sollte dann
     für eine korrekte Initialisierung auch die Variablentabelle leer sein;
     ist sie es allerdings doch nicht, werden hier noch die Standardwerte in
     die ccbs eingetragen und nur der leere Dialog unterdrückt.
     Vor Beginn/Nach Ende des gesamten Dialogs wird das refinement
     dialoguestart/dialogueend aufgerufen; bei NOT is dtcb vor/nach dem Dialog
     jedes Kanals auch noch channelstart/channelend.

  2. bei print configuration only:
     Die Daten zum new shard werden überhaupt nicht benutzt, von den
     refinements wird nur für jeden Kanal einmal "print configuration"
     aufgerufen.
  *)
  REAL VAR table byte :: offset dialogue table;
  ROW mdts INT VAR offset, old offset, length;
  INT  VAR i, k;
  BOOL VAR configurate :: NOT print configuration only;
  TEXT VAR program, t;
  IF print configuration only       (* Hier wird evtl. schon verlassen *)
  THEN startup for print
  ELSE startup for dialogue  FI;
  IF refinement count > 0 THEN build program  FI;
  build data in v;
  IF refinement count > 0 THEN do program  FI;
  IF configurate THEN put values in cb  FI.

startup for print :
  IF refinement count = 0 OR dialogue table entries = 0
  THEN LEAVE perform dialogue  FI.

startup for dialogue:
  IF refinement count = 0
  THEN putline ("Keine Konfiguration notwendig.");
       IF dialogue table entries = 0
       THEN pause (20); LEAVE perform dialogue  FI
  ELSE putline ("Die Konfiguration wird vorbereitet.")  FI.

build program:
  max index := refinement count;  (* damit new index bescheid weiss *)
  program := variables var xxv;
  program cat main part;
  perhaps program cat data refinements;
  program CAT refinements.

program cat main part :
  program CAT "LET UNSIGNED=INT;giveme(xxv);INT VARxxi::1,actchannel;";
  IF print configuration only OR automatic mode
  THEN program cat main part for print or automatic mode
  ELSE program cat main part for dialogue  FI.

program cat main part for print or automatic mode:
  (* Leider muss man, wenn man den Modulprogrammierer bei den .ccb und .dtcb
     Teilen nicht zu stark reglementieren will, einiges mitübersetzen, was
     dann gar nicht benutzt wird (z.B. alle Refinements).
           Und der Gedanke macht ihn blaß,
           wenn er fragt: was kostet das ?
                                     Wilhelm Busch
  *)
  program CAT "FORactchannelFROM 1 UPTOchannelsofthismoduleREP";
  IF print configuration only
  THEN program CAT "printconfigurationPER."
  ELSE (* automatic mode: *) program CAT "automaticPER;takeyou(xxv)."
  FI;
  program CAT " xxa:actchannel. thischannel:";
  IF NOT is dtcb THEN program CAT "channelstart;"  FI;
  FOR i FROM 1 UPTO refinement count REP
    program CAT "r";         (* Alle in this channel aufrufen, damit  *)
    program CAT text (i);    (* "LEAVE this channel" kein Fehler ist. *)
    program CAT ";"
  PER;
  IF NOT is dtcb
  THEN program CAT "channelend"  FI;
  program CAT ". ".

program cat main part for dialogue:
  program CAT "dialoguestart;FORactchannelFROM 1 UPTOchannelsofthismoduleREP";
  program CAT "thischannelPER;dialogueend;takeyou(xxv). ";
  program CAT "xxa:actchannel. thischannel:";
  IF NOT is dtcb THEN program CAT "channelstart;"  FI;
  program CAT "REP SELECTxxiOF ";
  FOR i FROM 1 UPTO refinement count REP
    program CAT "CASE ";
    program CAT text (i);
    program CAT ":r";
    program CAT text (i);
    program CAT " "
  PER;
  program CAT "ENDSELECT UNTIL NOTnewindex(xxi)PER";
  IF NOT is dtcb
  THEN program CAT ";channelend;reservechannel(xxv[1][xxa])"  FI;
  program CAT ". ".

perhaps program cat data refinements :
  FOR i FROM 1 UPTO dialogue table entries REP
    IF configurate THEN cout (i)  FI;
    read start of next table entry; (* must be done in autom. mode, too,  *)
    t := next variable name;        (* to get offset/oldoffset/length [i] *)
    program CAT t;
    program CAT ":xxv[";
    program CAT text (i);
    program CAT "][xxa]. ";  (* Das war der normale Eintrag "varname" *)
    program CAT t;           (* Jetzt der für alle Kanäle "varname k" *)
    program CAT "k:xxv[";
    program CAT text (i);
    program CAT "]. "
  PER.

read start of next table entry :
  (* Format der Einträge in den Variablentabellen:
     dw offset in cb
     dw offset in old cb (oder ffffh falls neu)
     db Typ (d.h. Länge und ist 1 oder 2)
     db Namenslänge
     db ...(Name)...
  *)
  INT CONST length of variable :: byte (m, table byte + 4.0),
            length of name     :: byte (m, table byte + 5.0);
  old offset [i] := int (m, table byte + 2.0);  (* Diese Sammlung *)
  offset [i]     := int (m, table byte);  (* bereitet das Datenholen vor *)
  length [i]     := length of variable;
  IF length of variable < 1 OR length of variable > 2
  THEN errorstop ("invalid variablelength : " + text (length of variable))
  FI;
  table byte INCR 6.0.

next variable name:
  table byte INCR real (length of name);
  text (m, table byte - real (length of name), length of name).

build data in v :
  FOR k FROM 1 UPTO nr of cbs REP  (* Kanäle *)
    IF configurate THEN cout (k)  FI;
    FOR i FROM 1 UPTO dialogue table entries REP  (* Variablen *)
      v[i][k] := next init value
    PER
  PER.

next init value :
  IF old cb valid CAND old cb present CAND value accessible
  THEN value from old cb
  ELSE value from new cb  FI.

old cb present :
  offset old cb [k] > 0.0.

value accessible :
  same release OR
  (* Ein release zuvor und Variable gibts schon: *) old offset [i] <> -1.

value from old cb :
  IF length [i] = 1
  THEN byte (old cb, offset old cb [k] + real (offset of old value))
  ELSE int  (old cb, offset old cb [k] + real (offset of old value))
  FI.

value from new cb :
  IF length [i] = 1
  THEN byte (cb, offset cb [k] + real (offset [i]))
  ELSE int  (cb, offset cb [k] + real (offset [i]))  FI.

offset of old value :
  IF same release
  THEN offset [i]
  ELSE old offset [i]  FI.

do program :
  reset direction (TRUE);
  channels of module := nr of cbs;
  IF setup testing
    THEN (* für diesen THEN-Teil beim abgespeckten Eumel
            setup eummel mini eumel dummies insertieren *)
         forget (do name, quiet);
         FILE VAR f := sequentialfile (output, do name);
         putline (f, program);
         (*edit (do name);*)
         run (do name);
         forget(do name, quiet);
    ELSE do (program);
  FI;
  program := "";  (* Platz sparen *)
  reset direction (FALSE).

put values in cb :
  FOR k FROM 1 UPTO nr of cbs REP
    cout (k);
    FOR i FROM 1 UPTO dialogue table entries REP
      IF length [i] = 1 THEN put byte ELSE put int  FI
    PER;
  PER.

put byte :
  byte (cb, offset cb [k] + real (offset [i]), v[i][k]).

put int :
  int  (cb, offset cb [k] + real (offset [i]), v[i][k]).
END PROC perform dialogue;

(****************** give me, take you, new index ***************************)

(* Diese Prozeduren werden aus dem do beim perform dialogue heraus aufgerufen
   Sie dienen zur Kommunikation mit den Paketdaten dieses Pakets (give me,
   take you) oder zur Verkleinerung des do-Programms (new index)
*)

PROC give me (VARIABLES VAR variables) :
  (* Der Sinn dieser Prozedur besteht in Folgendem :
     bei perform dialogue wird in dem do, das die refinements des
     SHard-Moduls ausführt, eine Datenstruktur vom Typ VARIABLES aufgebaut,
     die alle in den Variablentabellen des Moduls aufgeführten Variablen
     enthält und einzeln über passend benannte refinements zugänglich macht.
     Diese Datenstruktur wird zuvor in diesem Paket hier initialisiert mit
     Initwerten aus der Variablentabelle oder wenn möglich mit den
     entsprechenden Werten aus dem alten SHard. Mit give me fordert das
     do-Programm die initialisierte Datenstruktur aus diesem Paket hier an.
     Im do wird am Schluss mit take you diese Datenstruktur an dieses Paket
     (und damit an perform dialogue) zurückgegeben, damit die durch den
     Dialog gesetzten Werte in den neuen SHard eingetragen werden können.
     Eine alternative Methode, diese Kommunikation zu realisieren, wäre die
     Benutzung von BOUND VARIABLES VARs mit demselben Datenraum.
   *)
  variables := v
END PROC give me;

PROC take you (VARIABLES CONST variables) :
  (* Gegenstück zu give me, siehe dort *)
  v := variables
END PROC take you;

BOOL PROC new index (INT VAR index) :
  (* Verändert den Index je nach der direction und fragt bei down am Ende,
     ob fertig. Liefert, ob es noch weitergehen soll (falls nein: index = 1)
  *)
  LET up     = ""3"",
      down   = ""10"",
      error  = ""0"";
  TEXT CONST old direction :: direction;
  reset direction (TRUE);
  IF old direction = error   (* Bei Fehlern immer stehenbleiben *)
  THEN TRUE
  ELIF index = max index     (* am Schluss aufhören oder nach 1 springen *)
  THEN perhaps end
  ELIF index = 1 AND old direction = up  (* bei 1 und up an den Schluss *)
  THEN index := max index; TRUE
  ELSE normal new index     (* sonst je nach direction up oder down *)
  FI.

perhaps end :  (* index = max index *)
  IF old direction = up AND max index > 1    (* hoch vom Ende *)
  THEN index DECR 1;
       TRUE
  ELIF old direction = up
  THEN TRUE
  ELIF old direction = down                  (* runter am Ende *)
  THEN index := 1;
       TRUE
  ELSE reset direction (FALSE);          (* normal oder runter ans Ende *)
       index := 1;
       BOOL CONST ready :: yes (1, 23, "Fertig", FALSE);
       reset direction (TRUE);
       NOT ready
  FI.

normal new index :
  IF old direction = up
  THEN index DECR 1; TRUE
  ELSE index INCR 1; TRUE  FI.
END PROC new index;

(******************** channel (table) handling *****************************)

BOOL PROC channel free (INT CONST nr,
                        ROW 256 INT CONST channel table of shard) :
  IF nr < 0 OR nr > nr of channels total
  THEN FALSE
  ELSE channel table of shard [index ccb offset] = 0  FI.

index ccb offset :
  2 * nr + 1 + 1.
END PROC channel free;

BOOL PROC channel free (INT CONST nr) :
  channel free (nr, channel table of new shard).
END PROC channel free;

PROC reserve channel (INT CONST nr,
                      ROW 256 INT VAR channel table of shard) :
  IF nr >= 0 AND nr < nr of channels total
  THEN channel table of shard [index ccb offset] := 1  (* nichtnull *)  FI.

index ccb offset :
  2 * nr + 1 + 1.  (* Start nicht bei 0 und ccb hinter dtcb *)
END PROC reserve channel;

PROC reserve channel (INT CONST nr) :
  reserve channel (nr, channel table of new shard).
END PROC reserve channel;

(*THESAURUS PROC free channels (ROW 256 INT VAR channel table of shard):
  (* Liefert einen THESAURUS, der die Klartextform genau aller in
     channel table of shard als frei angegebenen Kanäle enthält.
  *)
  INT VAR i;
  THESAURUS VAR result :: empty thesaurus;
  FOR i FROM 1 UPTO nr of channels total REP
    IF channel free (i, channel table of shard)
    THEN insert (result, text (i))  FI
  PER;
  result.
END PROC free channels;*)

INT PROC channels of this module :
  channels of module.
END PROC channels of this module;

(********************* write info, buffer adress **************************)

PROC write info :
  putline (actual info)
END PROC write info;

INT PROC buffer address (INT CONST buffer size):
  IF new shard length MOD 2.0 <> 0.0 THEN new shard length INCR 1.0 FI;
  INT CONST buf adr := unsigned (new shard length);
  new shard length INCR real (buffer size);
  IF new shard length >= 65536.0 OR buffer size > 1024
    THEN errorstop ("zu großer Puffer verlangt")
  FI;
  buf adr
END PROC buffer address;

(************************* Hilfsprozeduren *******************************)

PROC elan (INT CONST mode, DATASPACE CONST source, TEXT CONST line,
           INT VAR start module nr, BOOL CONST new init, ins, dump, lst,
           sys, coder, rt check, sermon) :
  EXTERNAL 256
END PROC elan;

PROC do (TEXT CONST long line) :
  DATASPACE VAR ds;
  INT VAR module nr :: 0;
  elan (2, ds, long line, module nr, FALSE, FALSE, FALSE, FALSE,
        FALSE, FALSE, FALSE, FALSE);
  forget (ds);
  no do again
END PROC do;

PROC go on :
  put ("   >>>>> Taste drücken zum Weitermachen  ");
  REPEAT UNTIL incharety (2) = ""  PER;
  pause;
  line.
END PROC go on;

END PACKET setup eumel modulkonfiguration;