summaryrefslogtreecommitdiff
path: root/system/base/unknown/src/SPOLMAN5.ELA
blob: 99d4ec2c2feed4dc569bd5f991ce513b2496edf2 (plain)
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
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
PACKET queue handler DEFINES enter into que,
                             exists in que,
                             all in que,
                             erase from que, 
                             erase last top of que,
                             get top of que, 
                             restore ,
                             list que, 
                             info, killer,first, 
                             que status, 
                             que empty,
                             set entry types,
                             change entry types,
                             initialize que:
 
 
LET que size    = 100, 
 
    empty       =   0, 
    used        =   1,
    blocked     =   2, 
    nil         =   0,
    user  error =  99,
    unused char =   ""0"", 
    used char   =   ""1"", 
    blocked char=   ""2"", 
    ENTRY       = STRUCT(TEXT title, TASK origin, TEXT origin name, 
                         DATASPACE space, INT storage,    acc code ) ; 
 
ROW que size ENTRY VAR que ; 
 
TEXT VAR status list; 
BOOL VAR n ok := FALSE; 
INT  VAR top of que,
         first que entry, 
         last que entry,
         index ;
 
.entry: que[index]. ;
 
PROC initialize que : 
  FOR index FROM 1 UPTO que size REP 
    forget( entry.space ); 
    entry.acc code := empty
  END REP ; 
  first que entry := nil;
  last que entry  := nil; 
  top of que      := nil;
  index           := nil; 
  status list     := que size * unused char; 
END PROC initialize que ; 
 
initialize que ; 

(****************** Interne Queue-Zugriffsoperationen **********************)
 
INT PROC next (INT CONST pre) : 
  pre MOD que size + 1 
END PROC next ; 
 
PROC block (INT CONST entry number) : 
  que [entry number].acc code := blocked; 
  replace (status list,entry number,blocked char); 
ENDPROC block; 
 
PROC unblock (INT CONST entry number) : 
  que [entry number].acc code := used; 
  replace (status list,entry number,used char); 
ENDPROC unblock; 
 
PROC to next que entry: 
  REP 
    IF index = last que entry OR index = nil
      THEN index := nil ; LEAVE to next que entry 
    FI ;
    index := next(index)
  UNTIL entry.acc code <> empty PER 
END PROC to next que entry ; 
 
PROC to first que entry : 
  index := first que entry 
END PROC to first que entry ; 
 
PROC search que entry (TEXT CONST title, TASK CONST origin) : 
 
  check if index identifies entry ;
  IF last que entry = nil 
    THEN index := nil 
    ELSE index := last que entry ; 
         REPEAT 
           IF is wanted entry 
             THEN LEAVE search que entry 
           FI ; 
           IF index = first que entry 
             THEN index := nil 
             ELSE index DECR 1 ; 
                  IF index = 0 
                    THEN index := que size 
                  FI 
           FI 
         UNTIL index = nil PER 
  FI. 
 
is wanted entry: 
 
  entry.acc code <> empty CAND 
  entry.title    =  title CAND 
 (entry.origin   =  origin OR 
  origin = niltask ).
 
check if index identifies entry: 
 
  IF index <> nil CAND is wanted entry 
    THEN LEAVE search que entry 
  FI 
 
END PROC search que entry ; 
 
PROC exec erase :
 
    forget (entry.space) ; entry.acc code := empty ; 
    replace (status list,index,unused char); 
    try to cut off queue ends. 
 
try to cut off queue ends: 
 
  WHILE first entry is not valid REP 
    check if que empty ; 
    first que entry := next(first que entry) 
  END REP ; 
  WHILE last entry is not valid REP 
    make index invalid if necessary ; 
    last que entry DECR 1 ; 
    IF last que entry = 0 
      THEN last que entry := que size 
    FI 
  END REP . 
 
first entry is not valid: 
     que [first que entry].acc code = empty. 
 
last entry is not valid: 
     que [last que entry].acc code = empty. 
 
check if que empty: 
     IF first que entry = last que entry 
       THEN first que entry := nil ;
            last que entry  := nil ; 
            index := nil ; 
            LEAVE try to cut off queue ends
     FI.

make index invalid if necessary: 
     IF index = last que entry 
       THEN index := nil 
     FI. 
 
END PROC exec erase ;
 
PROC exec first: 
  IF next (last que entry) = first que entry 
    THEN errorstop ("Queue ist voll - vorziehen unmoeglich") 
  ELIF index = top of que 
    THEN errorstop ("Auftrag wird bereits bearbeitet") 
  ELIF entry.acc code = empty 
    THEN errorstop ("undefinierter Queue-Eintrag. /exec first") 
    ELSE first que entry DECR 1 ; 
         IF first que entry = 0 
           THEN first que entry := que size 
         FI ; 
         que[first que entry] := que[index] ; 
         replace (status list,first que entry,code (entry.acc code)); 
         exec erase 
  FI 
END PROC exec first ; 
 
PROC erase last top of que: 
  IF top of que <> nil 
    THEN index := top of que; exec erase;
         top of que := nil 
  FI 
END PROC erase last top of que;
 
 
(******************  Behandlung von DATASPACE-typen  ***********************)
 
LET semicolon = ";" , 
    colon     = ":" , 
    quote     = """"; 
TEXT VAR entry types ::   ""   ; 
 
BOOL PROC no permitted type (DATASPACE CONST ds) : 
  TEXT CONST type nr :: semicolon + text(type(ds)) + colon; 
  INT  CONST t pos   :: pos (entry types,type nr) ; 
  entry types <> "" CAND t pos = 0 
END PROC no permitted type ; 
 
TEXT PROC record of que entry: 
  IF entry.acc code = empty 
    THEN errorstop ("undefinierter Queue-Eintrag. /record");"" 
    ELSE TEXT VAR record :: "" ; 
         record CAT storage in k ; 
         record CAT type of entry ; 
         record CAT name of entry ; 
         record CAT origin of entry ; 
         IF entry.acc code = blocked THEN record CAT "- blocked -" FI;
         record
  FI. 
 
storage in k: 
 
  text (entry.storage,3) + " K  ". 
 
type of entry: 
 
  IF entry types = "" 
    THEN 12 * "?" 
    ELSE TEXT CONST type nr :: semicolon + text(type(entry.space)) + colon ; 
         INT CONST semi colon pos :: pos (entry types, type nr), 
                   start type     :: semi colon pos + LENGTH type nr , 
                   end type       :: pos(entrytypes,semicolon,starttype)-1; 
         IF semi colon pos = 0 
           THEN 12 * "?" 
           ELSE text( subtext(entry types, starttype, endtype),12)
         FI 
  FI. 
 
name of entry: 
 
  text (quote+ entry.title +quote, 20) .
 
origin of entry: 
 
  IF entry.origin = niltask 
    THEN 20 * " "
    ELSE text (" TASK: "+entry.origin name,20) 
  FI 
 
END PROC record of que entry ;
 
PROC set entry types (TEXT CONST t) : 
  check if void ;
  IF first char is no semicolon
    THEN entry types := semicolon
    ELSE entry types := "" 
  FI;
  entry types CAT t ; 
  IF last char is no semicolon
    THEN entry types CAT semicolon 
  FI.

check if void: 
  IF t = "" 
    THEN entry types := ""; 
         LEAVE set entry types 
  FI. 
 
first char is no semicolon: 
  (t SUB 1) <> semicolon. 
 
last char is no semicolon: 
  (t SUB length(t)) <> semicolon 
 
END PROC set entry types ; 
 
PROC change entry types: 
  TEXT VAR t :: entry types;
  line;putline("Entrytypes :");
  editget(t); 
  set entry types (t) 
END PROC change entry types; 
 
 
(************************ Std Zugriffe auf Queue ***************************)
 
 
PROC erase from que (TEXT CONST title, TASK CONST origin) : 
  search que entry (title, origin) ; 
  IF index = nil 
    THEN errorstop ("Auftrag existiert nicht. /erase")
  ELIF index = top of que 
    THEN errorstop (user error, "Dieser Auftrag wird bereits bearbeitet") 
    ELSE exec erase 
  FI 
END PROC erase from que ; 
 
BOOL PROC exists in que (TEXT CONST title, TASK CONST origin) : 
  search que entry (title, origin) ; 
  index <> nil 
END PROC exists in que ; 
 
PROC info (BOOL CONST b) : n ok := b ENDPROC info; 
 
THESAURUS PROC all in que (TASK CONST origin) : 
 
  THESAURUS VAR result := empty thesaurus ; 
  to first que entry ; 
  WHILE index <> 0 REP 
    IF entry.origin = origin OR origin = niltask 
      THEN insert (result, entry.title)
    FI ; 
    to next que entry
  END REP ; 
  result 
 
END PROC all in que ; 
 
PROC enter into que (TEXT CONST title, TASK CONST origin, 
                     DATASPACE CONST space ):
 
  IF next(last que entry) = first que entry 
    THEN errorstop ("Queue zu voll")
  ELIF no permitted type (space)  OR title = ""
    THEN errorstop (user error, "Auftrag wird nicht angenommen")
    ELSE last que entry := next(last que entry); 
         index := last que entry;
         entry := ENTRY: 
            ( title, origin,task name, space, storage(space), used ) ; 
         IF first que entry = nil 
           THEN first que entry := 1 
         FI ; 
         replace (status list,last que entry,used char); 
  FI. 
 
task name : 
  TEXT VAR name of task :: name (origin); 
  IF name of task = "stemmer" AND n ok THEN "stemmi" ELSE name of task FI. 
 
END PROC enter into que ; 
 
PROC get top of que (DATASPACE VAR top space) : 
  forget (top space) ;
  IF que empty 
    THEN errorstop ("kein Auftrag vorhanden. /get") 
    ELSE erase last top of que; 
         top of que := first que entry; 
         IF que [top of que].acc code = blocked THEN 
            wrap around if necessary
         ELSE top space := que [first que entry].space ; FI; 
  FI . 
 
wrap around if necessary : 
 
  IF entry is allowed to be printed THEN 
     give it to spool manager 
  ELSE enter into end of queue FI. 
 
entry is allowed to be printed : 
  pos (status list,used char) = nil. 
 
give it to spool manager : 
  top space := que [first que entry].space; 
  que [first que entry].acc code := used. 
 
enter into end of queue : 
  top space := que [first que entry].space; 
  enter into que (que [first que entry].title,que [first que entry].origin 
                  ,top space); 
  index := first que entry; 
  IF entry.acc code = blocked THEN block (index) FI; 
  get top of que (top space). 
 
END PROC get top of que ; 
 
PROC restore:
  top of que := nil 
END PROC restore ; 
 
BOOL PROC que empty:                         (* 'top of que' gilt nicht *)
  first que entry = last que entry AND 
  top of que      = last que entry. 
END PROC que empty ; 
 
PROC que status (INT VAR size, TEXT VAR top title, 
                 TASK VAR top origin, TEXT VAR top origin name ): 
 
  size := last que entry - first que entry ;  (* geloeschte Eintraege *)
  IF size < 0                                 (* zaehlen mit !!       *)
    THEN size INCR que size                   (* (aber nicht 'top' )  *)
  FI ; 
  IF top of que <> nil 
    THEN top title       := que [top of que].title ; 
         top origin      := que [top of que].origin ; 
         top origin name := que [top of que].origin name
    ELSE size INCR 1 ; 
         top title       := "" ; 
         top origin      := niltask ;
         top origin name := "" 
  FI 
END PROC que status ;

TEXT VAR sep :: 79 * "_", record :: "", 
         ask :: "editieren (e),kopieren (k),loeschen (l)," + 
                "vorziehen (v),duplizieren (d),"13""10"" + 
                "print --> quickprint (q),blockieren (b),freigeben (f)," + 
                "weiter (w) ? "; 
 
PROC info : 
 
     to first que entry; 
     WHILE index <> nil REP 
       record := record of que entry; 
       WHILE index <> top of que REPEAT 
         ask user what to do; 
         out (input char); 
         exec command
       UNTIL command index = 1 PER; 
       to next que entry; 
     PER. 
 
ask user what to do : 
 
     out (""13""10"");out (sep);out (""13""10""13""10""); 
     out (record); 
     out (""13""10""10"");out (ask); 
     INT VAR command index; TEXT VAR input char; 
     REPEAT 
       inchar (input char); 
       command index := pos ("w eklvdqbf",input char); 
     UNTIL command index > 0 PER. 
 
exec command : 
 
     SELECT command index OF 
      CASE 3 : INT VAR old dataspace type := type (entry.space); 
               type (entry.space,1003); 
               FILE VAR f :: sequentialfile (modify,entry.space); 
               edit (f); line (2); 
               type (entry.space,old dataspace type) 
      CASE 4 : forget (entry.title,quiet); 
               copy (entry.space,entry.title); 
               type (old (entry.title),1003) 
      CASE 5 : exec erase ;command index := 1 
      CASE 6 : exec first ;command index := 1
      CASE 7 : INT VAR dummy no := index; 
               enter into que (que [dummy no].title,que [dummy no].origin, 
                               que [dummy no].space) 
      CASE 8 : type (entry.space,1103) ;record := record of que entry; 
      CASE 9 : block (index) ;record := record of que entry;
      CASE 10: unblock (index); record := record of que entry; 
     ENDSELECT. 
 
ENDPROC info; 
 
PROC list que (FILE VAR f, DATASPACE VAR ds) : 
  open listfile ;
  to first que entry ; 
  WHILE index <> nil REP 
    TEXT VAR record :: record of que entry ; 
    IF index = top of que 
      THEN record := text(record,60) ; 
           record CAT ""15"wird bearbeitet"14""
    FI ;
    putline (f,record) ;
    to next que entry
  END REP.
 
open listfile:
 
  forget (ds) ; 
  ds := nilspace ; 
  f := sequentialfile (output,ds) ; 
  headline (f, name(myself) + " - Queue") ; 
  line (f)

END PROC list que ; 
 
PROC killer : info ENDPROC killer; 
PROC first  : info ENDPROC first; 
 
END PACKET queue handler ; 
 
(***************************************************************************)
(*   Programm zur Verwaltung einer Servertask                              *)
(*        (benutzt 'queue handler')                                        *)
(*        Autor: A.Vox                                                     *)
(*        Stand: 3.6.85                                                    *)
(*                                                                         *)
(***************************************************************************)
PACKET spool manager DEFINES server status, 
                             server modus, 
                             server task, 
                             server channel, 
                             server routine, 
                             server fail msg, 
 
                             log edit, 
                             logline, 
                             logfilename,
                             check, 
                             feed server if hungry, 
                             check if server vanished, 
 
                             spool manager, 
                             get title and origin, 

                             start, 
                             stop, 
                             pause, 
                             spool info, 
                             list, 
                             spool maintenance: 
 
 
     LET user error = 99;
 
     LET { Status: }       { Modus: }
         init = 0,         active  = 0,
         work = 1,         paused  = 1, 
         wait = 2,         stopped = 2,
         dead = 3;
 
     LET cmd form feed             = ""12""; 
 
INT VAR status :: init,
        modus  :: stopped;
 
TASK VAR server  :: niltask; 
TEXT VAR routine :: "", 
         fail msg:: ""; 
INT VAR channel  :: 0;
(************ Globale Variablen fuer alle 'que status'-Aufrufe ************) 
 
INT  VAR que size; 
TEXT VAR actual title, 
         actual origin name; 
TASK VAR actual origin; 
 
 
(*********** Zugriffsoperationen auf wichtige Paketvariablen **************)
 
TASK PROC  servertask    : server       END PROC servertask; 
INT  PROC  serverstatus  : status       END PROC serverstatus; 
INT  PROC  servermodus   : modus        END PROC servermodus; 
TEXT PROC  serverroutine : routine      END PROC serverroutine; 
TEXT PROC  serverfailmsg : fail msg     END PROC serverfailmsg;
INT  PROC  serverchannel : channel      END PROC serverchannel; 
 
PROC serverroutine (TEXT CONST neu): 
  routine := neu 
END PROC serverroutine; 
 
PROC serverfailmsg (TEXT CONST neu): 
  failmsg := neu 
END PROC serverfailmsg; 
 
PROC serverchannel (INT CONST neu): 
  channel := neu 
END PROC serverchannel; 
 
(************************* Basic Spool Routines ***************************) 
 
TEXT CONST logfilename :: "Vorkommnisse"; 
FILE VAR logfile; 
 
TEXT VAR fail title  :: "" ;
TASK VAR fail origin :: niltask ; 
REAL VAR fail time   :: 0.0 ; 
 
PROC logline (TEXT CONST mess): 
  logfile := sequential file(output, logfilename) ; 
  clear file if too large ; 
  put(logfile, date);
  put(logfile, time of day); 
  put(logfile, " : ");
  putline(logfile, mess) 
END PROC logline ; 
 
PROC log edit: 
  enable stop ; 
  IF NOT exists(logfilename) 
    THEN errorstop ("keine Eintragungen vorhanden") 
    ELSE logfile := sequentialfile(modify,logfilename) ; 
         position to actual page; 
         edit(logfile);
         line (2); 
         forget (logfilename); 
  FI. 
 
position to actual page: 
 
  INT CONST begin of last page :: lines(logfile)-22 ; 
  logfile := sequential file(modify,logfilename); 
  IF begin of last page < 1 
    THEN toline(logfile,1) 
    ELSE toline(logfile,begin of last page) 
  FI
 
END PROC logedit; 
 
PROC clear file if too large: 
  IF lines(logfile) > 1000 
    THEN modify (logfile) ; 
         toline (logfile, 900) ; 
         remove (logfile, 900) ; 
         clear removed (logfile) ;
         output (logfile) 
  FI 
END PROC clear file if too large ; 
 
PROC end server (TEXT CONST mess): 
  access catalogue; 
  IF exists (server) CAND son(myself) = server 
    THEN end(server) 
  FI; 
  failtime := clock(1); 
  que status (que size, fail title, fail origin, actual origin name) ; 
  logline (mess) ; 
  IF fail title <> "" 
    THEN logline(""""+fail title+""" von Task: "+actual origin name) 
    ELSE logline("kein Auftrag betroffen") 
  FI ; 
  status := dead ; 
  server := niltask 
END PROC end server; 
 
PROC check (TEXT CONST title, TASK CONST origin): 
  check if server vanished ; 
  IF less than 3 days ago AND 
     was failure          AND 
     title matches        AND 
     origin matches 
    THEN fail origin := myself ; 
         errorstop (user error, """"+fail title+""" abgebrochen")
  FI. 
 
less than 3 days ago: 
  clock(1) < fail time + 3.0 * day. 
 
origin matches: 
  (origin = fail origin OR origin = niltask). 
 
title matches: 
  (title  = fail title  OR title  = ""). 
 
was failure: 
  fail title <> ""
 
END PROC check ; 
 
PROC start server: 
  begin (PROC server start,server) ; 
  status := init 
END PROC start server; 
 
PROC server start: 
  disable stop ; 
  IF channel <> 0 
    THEN continue (channel) ; 
  FI ;
  command dialogue (FALSE) ; 
  out (cmd form feed); 
  do (routine) ; 
  IF is error 
    THEN call(logline code, "Server-Fehler :",father); 
         call(logline code, error message, father) ; 
         call(logline code, "Zeile: " + text(errorline) +
                            " Code: " + text(errorcode)  ,father) 
    ELSE call(logline code, "Ende des Server-Programms erreicht",father) 
  FI ; 
  IF online 
    THEN out (fail msg) 
  FI ; 
  call (terminate code,fail msg, father) ;
  end (myself) 
END PROC server start ;
 
PROC check if server vanished: 
  IF NOT (server = nil task) CAND NOT exists (server) 
    THEN end server ("Server gestorben :") ; 
         start server 
  FI 
END PROC check if server vanished; 
 
 
(*************************** Manager Routines *****************************)
 
   LET ack              = 0,
       second phase ack = 5,
       not existing nak = 6,
 
       begin code       = 4, 
       fetch code       = 11, 
       save code        = 12,
       exists code      = 13, 
       erase code       = 14, 
       list code        = 15, 
       all code         = 17, 
       clear code       = 18, 
       release code     = 20, 
       check code       = 22, 
 
       terminate code   = 25, 
       logline code     = 26, 
       get title code   = 27, 
 
       continue code    = 100; 
 
 
DATASPACE VAR packet space ; 
INT VAR reply ; 
BOUND STRUCT(TEXT f name,a,b) VAR msg ; 
.f name: msg.f name. ; 
 
TEXT VAR save title :: "";
FILE VAR listfile; 
 
PROC get title and origin (TEXT VAR title, origin): 
  forget (packet space) ; 
  packet space := nilspace ; 
  call (father, get title code, packet space, reply) ;
  IF reply = ack 
    THEN msg := packet space ; 
         title := msg.f name ; 
         origin := msg.a ; 
         forget (packet space)
    ELSE forget (packet space) ; 
         errorstop ("'get title' nicht erfolgreich. Antwort="+text(reply)) 
  FI 
END PROC get title and origin; 
 
PROC feed server if hungry:
  check if server vanished ; 
  IF status = wait AND NOT que empty 
    THEN get top of que (packet space) ; 
         send (server, ack, packet space, reply) ; 
         forget (packet space) ;
         IF reply = ack 
           THEN status := work 
           ELSE restore ; 
                end server ("Server nimmt keinen Auftrag an") ; 
                start server 
         FI 
  FI 
ENDPROC feed server if hungry;
 
PROC server request (DATASPACE VAR ds, INT CONST order, phase) : 
 
  enable stop ; 
  msg := ds ; 
  SELECT order OF 
    CASE terminate code: terminate 
    CASE logline code:   logline (f name)   ;send(server, ack, ds)
    CASE get title code: send title 
    OTHERWISE 
      IF order = fetch code CAND f name = "-" 
        THEN send top of que 
        ELSE freemanager (ds,order,phase,server) 
      FI 
  END SELECT ; 
  forget(ds). 
 
terminate: 
  end server ("Server terminiert :") ; 
  start server.
 
send title: 
  forget (ds) ; 
  ds := nilspace ; 
  msg := ds ; 
  que status (que size, msg.f name, actual origin, msg.a) ; 
  send (server, ack, ds).
 
send top of que: 
  status := wait ; 
  erase last top of que ;
  IF modus = active 
    THEN feed server if hungry
  FI 
 
END PROC server request; 
 
PROC spool manager(DATASPACE VAR ds, INT CONST order, phase, 
                   TASK CONST order task) : 
 
  IF ordertask < myself 
    THEN server request (ds,order,phase) 
  ELIF ordertask = supervisor
    THEN system request 
  ELSE spool command (ds,order,phase,order task) 
  FI; 
  check storage; 
  error protocol. 
 
check storage: 
  INT VAR size, used; 
  storage(size,used); 
  IF used > size 
    THEN logline("Speicher-Engpass :"); 
         initialize que; 
         logline("Queue geloescht !!"); 
         stop 
  FI. 
 
error protocol: 
  IF is error AND error code <> user error 
    THEN logline ("Spool-Fehler :") ; 
         logline (errormessage) ; 
         logline ("   Zeile: " + text(errorline) + 
                  "   Code: "  + text(errorcode) ) 
  FI. 
 
system request: 
  IF order > continue code 
    THEN call (supervisor,order,ds,reply) ; 
         forget(ds) ; 
         IF reply = ack 
           THEN spool maintenance 
         FI 
  FI 
 
END PROC spool manager; 
 
PROC spool command (DATASPACE VAR ds, INT CONST order, phase, 
                    TASK CONST order task): 
 
  enable stop ; 
  check if server vanished ;
  msg := ds ; 
  SELECT order OF 
    CASE begin code : special begin 
    CASE fetch code:  y get logfile 
    CASE save code :  y save 
    CASE exists code: y exists 
    CASE erase code:  y erase 
    CASE list code:   y list 
    CASE all code:    y all 
    CASE release code, 
         clear code:  y restart 
    CASE check code:  y check 
    OTHERWISE errorstop (user error, "Kein Kommando fuer SPOOLER") 
  END SELECT. 
 
special begin : 
   INT VAR dummy; 
   call (public,begin code,ds,dummy); 
   send (order task,ack,ds). 
 
y get logfile: 
  forget(ds) ; 
  ds := old(logfilename) ; 
  send (ordertask, ack, ds). 
 
y erase: 
  IF NOT exists in que (f name,ordertask) 
    THEN manager message(""""+f name+""" steht nicht in der Queue")
  ELIF phase = 1 
    THEN manager question (""""+f name+""" aus der Queue loeschen") 
    ELSE erase from que (f name,ordertask) ; 
         send (ordertask, ack, ds) 
  FI. 
 
y save: 
  IF phase = 1 
    THEN save title := f name ; 
         send (order task,second phase ack,ds); 
    ELSE enter into que (save title, ordertask, ds) ; 
         IF modus = active 
           THEN feed server if hungry
         FI ; 
         send (order task,ack,ds); 
  FI. 
 
y list: 
  list que (listfile,ds) ; 
  send (ordertask, ack, ds). 
 
y all: 
  forget(ds) ; 
  ds := nilspace ; 
  BOUND THESAURUS VAR all names := ds ; 
  all names := all in que (ordertask) ; 
  send (ordertask, ack, ds). 
 
y exists: 
  IF exists in que (f name,ordertask) 
    THEN send (ordertask, ack, ds) 
    ELSE send (ordertask, not existing nak, ds) 
  FI. 
 
y check: 
  check (f name,ordertask) ; 
  questatus (que size, actual title, actual origin, actual origin name) ; 
  IF there is a title   AND
     is actual origin   AND 
     is actual title 
    THEN manager message (""""+f name+""" wird soeben bearbeitet") 
  ELIF exists in que (f name,ordertask) 
    THEN manager message (""""+f name+""" steht noch in der Queue") 
    ELSE errorstop (usererror, """"+f name+""" steht nicht in der Queue") 
  FI. 
 
  there is a title:  actual title <> "" .
  is actual origin:  ordertask = actual origin .
  is actual title : (f name = "" OR f name = actual title) . 
 
y restart: 
  questatus (que size, actual title, actual origin, actual origin name) ;
  IF actual origin = ordertask 
    THEN IF phase = 1 
           THEN manager question (""""+actual title+""" unterbrechen") 
           ELSE end server ("unterbrochen durch Auftraggeber :") ; 
                start server ; 
                IF order = clear code 
                  THEN restore 
                  ELSE erase last top of que
                FI ; 
                manager message ("Auftrag unterbrochen") 
         FI
    ELSE errorstop (usererror, "kein eigener Auftrag") 
  FI

END PROC spool command ; 
 
PROC start: 
  IF modus = stopped 
    THEN start server ; 
         modus := active; 
         message ("Server aktiviert") 
  ELIF modus = paused 
    THEN modus := active ; 
         message ("'Pause'-Modus zurueckgesetzt") ; 
         feed server if hungry
    ELSE message ("Server bereits aktiv") 
  FI 
END PROC start; 
 
PROC stop: 
  IF modus <> stopped 
    THEN end server ("Gestoppt :"); 
         modus := stopped ;
         status := init ; 
         message ("Server gestoppt") 
    ELSE message ("Server bereits gestoppt") 
  FI 
END PROC stop; 
 
PROC pause: 
  IF modus = active 
    THEN modus := paused ; 
         message ("'Pause'-Modus gesetzt")
  ELIF modus = paused 
    THEN message ("'Pause'-Modus bereits gesetzt")
    ELSE errorstop ("Server ist gestoppt") 
  FI 
END PROC pause; 
 
PROC message (TEXT CONST mess): 
  say(""13""10"") ; 
  say(mess) ; 
  say(""13""10"") 
END PROC message ; 
 
PROC list: 
  list que(listfile,packet space) ; 
  show(listfile) 
END PROC list; 
 
PROC spool maintenance: 
  command dialogue (TRUE);
  IF exists(logfilename) 
    THEN logedit 
  FI; 
  WHILE online REP
    get command ("gib spool kommando :") ;
    do command 
  END REP ; 
  command dialogue (FALSE) ; 
  break ; 
  set autonom 
END PROC spool maintenance ;
 
PROC spoolinfo: 
  check if server vanished ;
  que status (que size, actual title, actual origin, actual origin name) ; 
  line(2) ; 
  putline("Queue :") ; 
  put("Auslastung :");put(que size); line;
  IF actual title <> "" 
    THEN put("Aktueller Auftrag :");putline(actual title); 
         put("         von Task :");putline(actual origin name) 
  FI ; 
  line ; 
  putline("Server :"); 
  put("Status :"); 
  SELECT status OF 
    CASE init : putline("initialisiert") 
    CASE work : putline("arbeitet") 
    CASE wait : putline("wartet")
    OTHERWISE   putline("gestorben")
  END SELECT ;
  put("Modus  :"); 
  SELECT modus OF 
    CASE active : putline("aktiv") 
    CASE paused : putline("pausierend") 
    OTHERWISE     putline("gestoppt") 
  END SELECT ; 
  put("Kanal  :");put(pcb(server,4));
  line(2) 
END PROC spool info 
 
END PACKET spool manager;