 MODULE Kalender; (* Copyright 1993 by Kai Hofmann *)

 (*$ StackChk       := FALSE *)
 (*$ RangeChk       := FALSE *)
 (*$ OverflowChk    := FALSE *)
 (*$ NilChk         := FALSE *)
 (*$ CaseChk        := FALSE *)
 (*$ ReturnChk      := FALSE *)
 (*$ LargeVars      := FALSE *)
 (*$ EntryClear     := TRUE  *)
 (*$ Volatile       := TRUE  *)
 (*$ StackParms     := TRUE  *)
 (*$ CStrings       := TRUE  *)


 FROM SYSTEM		IMPORT	ADR,LONGSET;
 FROM ExecD		IMPORT	MsgPortPtr;
 FROM ExecL		IMPORT	Wait;
 FROM Arts		IMPORT	returnVal,wbStarted,Assert,Terminate;
 FROM InOut		IMPORT	WriteCard,WriteLn,WriteString,WriteInt;
 FROM FileSystem	IMPORT	Lookup, Close, ReadChar, File, Response,
				WriteChar;
 FROM Storage		IMPORT	ALLOCATE,DEALLOCATE;
 FROM String		IMPORT	first,last,noOccur,Occurs,Insert,Delete,Copy,
				Concat,Length,CopyPart;
 FROM Conversions	IMPORT	ValToStr,StrToVal;
 FROM Datum		IMPORT	GetDate,maxDays,wtstring,wochentag,tagdiff,
				Weekday,GetWeek,monat;
 FROM Text		IMPORT	normal,reverse,normc2,revc2,normc1,revc1;
 FROM Window2		IMPORT	action2,action2ptr,action2mem,OpenWin2,
				CloseWin2,ClearWin2,OutputWin2,HandleAction2;
 FROM Commands		IMPORT	CheckOption,GetOptionParam,Killstr,
				string, strptr;
 FROM ARexx		IMPORT	OpenRexxPort,CloseRexxPort,SendRexxMsg;
 FROM LocaleL		IMPORT	localeBase;


 CONST
	maxstr	= 173 (* 80 *);


 TYPE
 	VERSION	= ARRAY [1..35] OF CHAR;
	tstring = ARRAY [1..maxstr] OF CHAR;
	point	= POINTER TO lines;
	lines	= RECORD
			Tag,Monat : SHORTCARD;
			Jahr	  : CARDINAL;
			Text	  : tstring;
			last	  : point;
			next	  : point;
		  END;


 VAR
	Version					:= VERSION{"$VER: Kalender 2.2 (15.01.1994)"};
	Wochentag,Tag,Monat,OTag,OMonat,t,m	: SHORTCARD;
	Jahr,OJahr,j				: CARDINAL;
	ZeitRaum				: CARDINAL;
	language				: SHORTCARD;
	already,mark,nodata			: BOOLEAN;
	saveflag,save				: BOOLEAN;
	filename,path,argstr,arg,file		: tstring;
	wurzel,stat				: point;
	window2					: SHORTCARD;
	x,y					: SHORTCARD;
	set					: LONGSET;
	cptr					: strptr;
	cquot,err,sign				: BOOLEAN;
	zr					: LONGINT;
	i					: INTEGER;
	date1,date2,state,line			: tstring;
	slen					: SHORTCARD;
	port					: MsgPortPtr;


 PROCEDURE delete(VAR wurzel,zeiger : point);

 BEGIN
   IF (wurzel # NIL) AND (zeiger # NIL) THEN
     IF zeiger = wurzel THEN
       wurzel := zeiger^.next;
       wurzel^.last := NIL;
       DEALLOCATE(zeiger,SIZE(lines));
     ELSE
       IF zeiger^.next # NIL THEN
         zeiger^.next^.last := zeiger^.last;
       END;
       zeiger^.last^.next := zeiger^.next;
       DEALLOCATE(zeiger,SIZE(lines));
     END;
     zeiger := NIL;
   END;
 END delete;


 PROCEDURE insert(VAR wurzel : point; Tag,Monat : SHORTCARD;
					Jahr : CARDINAL; Text : tstring);

 VAR
	new,zeiger	: point;

 BEGIN
   ALLOCATE(new,SIZE(lines));
   new^.Tag   := Tag;
   new^.Monat := Monat;
   new^.Jahr  := Jahr;
   new^.Text  := Text;
   new^.last  := NIL;
   new^.next  := NIL;
   IF wurzel = NIL THEN
     wurzel := new;
   ELSIF (wurzel^.Monat > Monat) OR ((wurzel^.Monat = Monat) AND (wurzel^.Tag > Tag)) THEN
     new^.next := wurzel;
     wurzel^.last := new;
     wurzel := new;
   ELSE
     zeiger := wurzel;
     WHILE (zeiger # NIL) AND (zeiger^.Monat < Monat) DO
       IF zeiger^.next = NIL THEN
         zeiger^.next := new;
         new^.last := zeiger;
         RETURN;
       END;
       zeiger := zeiger^.next;
     END;

     IF zeiger^.Monat = Monat THEN
       WHILE (zeiger # NIL) AND (zeiger^.Tag <= Tag) DO
         IF zeiger^.next = NIL THEN
           zeiger^.next := new;
           new^.last := zeiger;
           RETURN;
         ELSIF (zeiger^.next # NIL) AND (zeiger^.next^.Monat > Monat) THEN
           new^.next := zeiger^.next;
           new^.last := zeiger;
           zeiger^.next^.last := new;
           zeiger^.next := new;
           RETURN;
	 END;
         zeiger := zeiger^.next;
       END;
     END;

     new^.next := zeiger;
     new^.last := zeiger^.last;
     zeiger^.last := new;
     new^.last^.next := new;
   END;
 END insert;


 PROCEDURE konvdate(VAR Tag,Monat : SHORTCARD; VAR Jahr : CARDINAL; VAR txt : ARRAY OF CHAR);

 VAR
	i : SHORTCARD;

 BEGIN
   i := 0;
   Tag := SHORTCARD(txt[i])-48;
   INC(i);
   IF txt[i] # "." THEN
     Tag := Tag*10+(SHORTCARD(txt[i])-48);
     INC(i);
   END;
   INC(i);
   Monat := SHORTCARD(txt[i])-48;
   INC(i);
   IF txt[i] # "." THEN
     Monat := Monat*10+SHORTCARD(txt[i])-48;
     INC(i);
   END;
   INC(i);
   WHILE txt[i] = " " DO
     INC(i);
   END;
   Jahr := 0;
   IF txt[i] # ":" THEN
     Jahr := CARDINAL(txt[i])-48;
     INC(i);
     Jahr := Jahr*10+CARDINAL(txt[i])-48;
     INC(i);
     IF txt[i] # " " THEN
       Jahr := Jahr*10+CARDINAL(txt[i])-48;
       INC(i);
       Jahr := Jahr*10+CARDINAL(txt[i])-48;
       INC(i);
     END;
     WHILE txt[i] = " " DO
       INC(i);
     END;
   END;
   INC(i);
   WHILE txt[i] = " " DO
     INC(i);
   END;
   Delete(txt,0,i);
 END konvdate;


 PROCEDURE ReadDaten(VAR wurzel : point; filename : tstring) : BOOLEAN;

   PROCEDURE ReadLines(VAR wurzel : point; VAR Daten : File);

   VAR
	data			: CHAR;
	daten			: tstring;
	i			: SHORTCARD;
	Tag,Monat		: SHORTCARD;
	Jahr			: CARDINAL;

   BEGIN
     REPEAT
       ReadChar(Daten,data);
       WHILE (NOT Daten.eof) AND ((CARDINAL(data) = 10) OR (data = " ")) DO
         ReadChar(Daten,data)
       END;
       IF NOT Daten.eof THEN
         i := 1;
         WHILE (CARDINAL(data) # 10) AND (i<maxstr) DO
           daten[i] := data;
           INC(i);
           ReadChar(Daten,data);
         END;
         IF CARDINAL(data) # 10 THEN
           REPEAT
             ReadChar(Daten,data);
           UNTIL CARDINAL(data) = 10;
         END;
         daten[i] := CHAR(0);
         konvdate(Tag,Monat,Jahr,daten);
         insert(wurzel,Tag,Monat,Jahr,daten);
       END;
     UNTIL Daten.eof OR (Daten.res # done);
   END ReadLines;

 VAR
	Daten	: File;
	ok	: BOOLEAN;

 BEGIN
   Lookup(Daten,filename,1024,FALSE);
   IF Daten.res = done THEN
     ok := TRUE;
     ReadLines(wurzel,Daten);
   ELSE
     ok := FALSE;
   END;
   Close(Daten);
   RETURN(ok);
 END ReadDaten;


 PROCEDURE format(z : CARDINAL; VAR c : ARRAY OF CHAR; l : SHORTCARD);

 VAR
	i : SHORTCARD;

 BEGIN
   IF (z > 0) OR (l > 0) THEN
     FOR i := HIGH(c) TO 1 BY -1 DO
       c[i] := c[i-1];
     END;
     c[0] := CHAR((z MOD 10)+48);
     format(z DIV 10,c,l-1);
   END;
 END format;


 PROCEDURE WriteDaten(wurzel : point; filename : tstring);

 VAR
	Daten : File;

   PROCEDURE WriteLines(zeiger : point; VAR Daten : File);

     PROCEDURE WriteLine(zeiger : point; VAR Daten : File);

     VAR
	data	: ARRAY [1..5] OF CHAR;
	i	: SHORTCARD;

     BEGIN
       data := "";
       format(zeiger^.Tag,data,2);
       i := 1;
       WHILE data[i] > CHAR(0) DO
         WriteChar(Daten,data[i]);
         INC(i);
       END;
       WriteChar(Daten,".");
       data := "";
       format(zeiger^.Monat,data,2);
       i := 1;
       WHILE data[i] > CHAR(0) DO
         WriteChar(Daten,data[i]);
         INC(i);
       END;
       WriteChar(Daten,".");
       IF zeiger^.Jahr > 0 THEN
         data := "";
         format(zeiger^.Jahr,data,4);
         i := 1;
         WHILE data[i] > CHAR(0) DO
           WriteChar(Daten,data[i]);
           INC(i);
         END;
       ELSE
         WriteChar(Daten," ");
         WriteChar(Daten," ");
         WriteChar(Daten," ");
         WriteChar(Daten," ");
       END;
       WriteChar(Daten," ");
       WriteChar(Daten,":");
       WriteChar(Daten," ");
       i := 1;
       WHILE zeiger^.Text[i] > CHAR(0) DO
         WriteChar(Daten,zeiger^.Text[i]);
         INC(i);
       END;
       WriteChar(Daten,CHAR(10));
     END WriteLine;

   BEGIN
     WHILE zeiger # NIL DO
       WriteLine(zeiger,Daten);
       zeiger := zeiger^.next;
     END;
   END WriteLines;

 BEGIN
   Lookup(Daten,filename,1024,TRUE);
   IF Daten.res = done THEN
     WriteLines(wurzel,Daten);
   END;
   Close(Daten);
 END WriteDaten;


 PROCEDURE search(zeiger : point; Tag,Monat : SHORTCARD) : point;

 BEGIN
   WHILE zeiger # NIL DO
     IF zeiger^.Monat > Monat THEN
       RETURN(zeiger);
     ELSIF zeiger^.Monat = Monat THEN
       IF zeiger^.Tag >= Tag THEN
         RETURN(zeiger);
       END;
     END;
     zeiger := zeiger^.next;
   END;
   RETURN(NIL);
 END search;


 PROCEDURE searchStatus(Line : point) : point;

 BEGIN
   Line := search(Line,0,0);
   RETURN(Line);
 END searchStatus;


 PROCEDURE specialtext(VAR str : ARRAY OF CHAR; Tag,Monat : SHORTCARD; Jahr : CARDINAL; jahr : CARDINAL; insertstr : ARRAY OF CHAR) : SHORTCARD;

 VAR i			: INTEGER;
     istr		: tstring;
     err		: BOOLEAN;
     wt			: wtstring;
     del		: SHORTCARD;
     dcount,count	: SHORTCARD;
     wlen		: SHORTCARD;

   PROCEDURE insl(VAR wt : wtstring; wlen : SHORTCARD);

   VAR
	len : SHORTCARD;

   BEGIN
     len := SHORTCARD(Length(wt));
     WHILE len < wlen DO
       wt[len+1] := ' ';
       wt[len+2] := CHAR(0);
       INC(len);
     END;
   END insl;

 BEGIN
    count := 0;
    i := Occurs(str,first,"%",FALSE);
    WHILE i # last DO
      istr := "";
      del := 2;
      CASE str[i+1] OF
        "d" : ValToStr(Tag,FALSE,istr,10,2,"0",err);
	      Insert(str,i+2,istr);|
        "m" : ValToStr(Monat,FALSE,istr,10,2,"0",err);
	      Insert(str,i+2,istr);|
	"o" : wlen := monat(Monat,wt,language);
	      IF str[i+2] = 'l' THEN
	        insl(wt,wlen);
	        del := 3;
	      END;
              Insert(str,i+INTEGER(del),wt);|
        "y" : ValToStr(Jahr,FALSE,istr,10,4,"0",err);
	      Insert(str,i+2,istr);|
        "w" : wlen := wochentag(Weekday(Tag,Monat,jahr),wt,language);
	      IF str[i+2] = 'l' THEN
	        insl(wt,wlen);
	        del := 3;
	      END;
	      Insert(str,i+INTEGER(del),wt);|
        "n" : ValToStr(Weekday(Tag,Monat,jahr),FALSE,istr,10,1,"0",err);
	      Insert(str,i+2,istr);|
        "e" : ValToStr(GetWeek(Tag,Monat,jahr),FALSE,istr,10,2,"0",err);
	      Insert(str,i+2,istr);|
	"t" : Insert(str,i+2,insertstr);|
        "0" : (* use locale.library *) |
	"1" : Insert(str,i+2,date1);|
	"2" : Insert(str,i+2,date2);
      ELSE
        del := 0;
        INC(dcount);
      END;
      Delete(str,i,del);
      i := Occurs(str,first,"%",FALSE);
      count := dcount;
      WHILE count > 0 DO
        i := Occurs(str,i+1,"%",FALSE);
        DEC(count);
      END;
    END;
    RETURN(Length(str));
 END specialtext;


 PROCEDURE GetNumberOf(zeiger : point; Tag,Monat : SHORTCARD; VAR maxx : SHORTCARD) : SHORTCARD;

 VAR
	anz			: CARDINAL;
	len			: CARDINAL;
	txt			: tstring;

 BEGIN
   anz := 0;
   zeiger := search(zeiger,Tag,Monat);
   WHILE zeiger # NIL DO
     IF (zeiger^.Monat = Monat) AND (zeiger^.Tag = Tag) THEN
       IF (Occurs(zeiger^.Text,first,"%k",FALSE) # last) AND (zeiger^.Jahr > 0) THEN
         IF (zeiger^.Jahr < Jahr) OR ((zeiger^.Jahr = Jahr) AND (zeiger^.Monat < Monat)) OR ((zeiger^.Jahr = Jahr) AND (zeiger^.Monat =Monat) AND (zeiger^.Tag < Tag)) THEN
           delete(wurzel,zeiger);
           saveflag := TRUE;
         ELSE
           INC(anz);
           Copy(txt,line);
           len := specialtext(txt,Tag,Monat,Jahr,Jahr,zeiger^.Text);
         END;
       ELSE
         INC(anz);
         Copy(txt,line);
         len := specialtext(txt,Tag,Monat,Jahr,Jahr,zeiger^.Text);
       END;
       IF len > maxx THEN
         maxx := len;
       END;
       zeiger := zeiger^.next;
     ELSIF (zeiger^.Monat = Monat) AND (zeiger^.Tag < Tag) THEN
       zeiger := zeiger^.next;
     ELSIF (zeiger^.Monat > Monat) OR
			((zeiger^.Monat = Monat) AND (zeiger^.Tag > Tag)) THEN
       zeiger := NIL;
     END;
   END;
   RETURN(anz);
 END GetNumberOf;


 PROCEDURE GetOutDays(zeiger : point; Tag,Monat : SHORTCARD; Jahr : CARDINAL;
					ZeitRaum : CARDINAL; VAR x : SHORTCARD) : SHORTCARD;

 VAR
	days	: CARDINAL;
	anz	: SHORTCARD;

 BEGIN
   anz := 0;
   days := 0;
   zeiger := search(zeiger,Tag,Monat);
   WHILE days < ZeitRaum DO
     anz := anz + GetNumberOf(zeiger,Tag,Monat,x);
     INC(Tag);
     IF Tag > maxDays(Monat,Jahr) THEN
       Tag := 1;
       INC(Monat);
       IF Monat > 12 THEN
         Monat := 1;
         INC(Jahr);
         zeiger := wurzel;
       END;
     END;
     INC(days);
   END;
   RETURN(anz);
 END GetOutDays;


 PROCEDURE formattext(VAR zeiger : point; VAR text : tstring; Tag,Monat : SHORTCARD;
				Jahr : CARDINAL; VAR saveflag : BOOLEAN) : BOOLEAN;

 VAR
	i,j	: INTEGER;
	str	: ARRAY [1..2] OF CHAR;
	err,ofl	: BOOLEAN;
	len	: SHORTCARD;
	tx	: tstring;

 BEGIN
   ofl := TRUE;
   Copy(text,line);
   IF zeiger^.Jahr > 0 THEN
     len := specialtext(text,zeiger^.Tag,zeiger^.Monat,zeiger^.Jahr,Jahr,zeiger^.Text);
   ELSE
     len := specialtext(text,zeiger^.Tag,zeiger^.Monat,Jahr,Jahr,zeiger^.Text);
   END;
   i := Occurs(text,first,"%",TRUE);
   IF i # last THEN
     CASE text[i+2] OF
       "j" : str := "";
             IF zeiger^.Jahr > 0 THEN
               j := Jahr-zeiger^.Jahr;
               ValToStr(j,FALSE,str,10,2," ",err);
             END;
             Insert(text,i+2,str); |
       "k" : IF tagdiff(zeiger^.Tag,zeiger^.Monat,0,Tag,Monat,0) = 0 THEN
	       saveflag := TRUE;
             END; |
       "h" : IF tagdiff(zeiger^.Tag,zeiger^.Monat,0,Tag,Monat,0) # 0 THEN
               ofl := FALSE;
             END; |
       "'" : j := Occurs(text,i+3,"'",TRUE);
	     IF j # last THEN
	       CopyPart(tx,text,i+2,j-(i+2));
	       Delete(text,i+2,j-(i+1));
	       IF tagdiff(zeiger^.Tag,zeiger^.Monat,0,Tag,Monat,0) = 0 THEN
	         IF ~SendRexxMsg(port,"REXX",tx) THEN
	           Concat(text," (ERROR!)");
	         END;
	       END;
	     END;
     ELSE
     END;
     Delete(text,i,2);
   END;
   RETURN(ofl);
 END formattext;


 PROCEDURE OutDays(zeiger : point; Tag,Monat : SHORTCARD; Jahr : CARDINAL;
					ZeitRaum : CARDINAL; mark : BOOLEAN);

 VAR
	anz	: SHORTCARD;
	x	: SHORTCARD;

   PROCEDURE textoutput(VAR zeiger : point; Tag,Monat : SHORTCARD;
		Jahr : CARDINAL; VAR saveflag : BOOLEAN; mark : BOOLEAN);

   VAR
	ptr	: point;
	text	: tstring;
	sf	: BOOLEAN;

   BEGIN
     sf := FALSE;
     IF formattext(zeiger,text,Tag,Monat,Jahr,sf) THEN
       IF mark AND (tagdiff(Tag,Monat,0,zeiger^.Tag,zeiger^.Monat,0) = 0) THEN
         IF sf THEN
           WriteString(revc1);
           saveflag := TRUE;
           ptr := zeiger;
           zeiger := zeiger^.last;
           delete(wurzel,ptr);
         ELSE
           WriteString(normc1);
         END;
       ELSIF mark AND (tagdiff(Tag,Monat,0,zeiger^.Tag,zeiger^.Monat,0) = 1) THEN
         WriteString(normc2);
       END;
       WriteString(text); WriteString(normal); WriteLn;
     END;
   END textoutput;

   PROCEDURE windowoutput(VAR zeiger : point; Tag,Monat : SHORTCARD;
		Jahr : CARDINAL; VAR saveflag : BOOLEAN; mark : BOOLEAN);

   VAR
	ptr	: point;
	text	: tstring;
	sf	: BOOLEAN;
	col	: SHORTCARD;
	rev	: BOOLEAN;

   BEGIN
     rev := FALSE;
     col := 1;
     IF mark AND (tagdiff(zeiger^.Tag,zeiger^.Monat,0,Tag,Monat,0) = 0) THEN
       col := 2;
     ELSIF mark AND (tagdiff(Tag,Monat,0,zeiger^.Tag,zeiger^.Monat,0) = 1) THEN
       col := 3;
     END;
     sf := FALSE;
     IF formattext(zeiger,text,Tag,Monat,Jahr,sf) THEN
       IF sf THEN
         rev := TRUE;
         saveflag := TRUE;
         ptr := zeiger;
         zeiger := zeiger^.last;
         delete(wurzel,ptr);
       END;
       OutputWin2(text,col,rev);
     END;
   END windowoutput;

 BEGIN
   zeiger := search(zeiger,Tag,Monat);
   anz := GetOutDays(zeiger,Tag,Monat,Jahr,ZeitRaum,x);
   IF anz > 0 THEN
     IF ~wbStarted AND (slen > 0) THEN
       WriteString(state); WriteLn;
       WriteLn;
     END;
   END;
   WHILE anz > 0 DO
     IF wbStarted THEN
       windowoutput(zeiger,Tag,Monat,Jahr,saveflag,mark);
     ELSE
       textoutput(zeiger,Tag,Monat,Jahr,saveflag,mark);
     END;
     IF zeiger = NIL THEN
       zeiger := wurzel;
       zeiger := search(zeiger,1,1);
       INC(Jahr);
     END;
     zeiger := zeiger^.next;
     IF zeiger = NIL THEN
       zeiger := wurzel;
       zeiger := search(zeiger,1,1);
       INC(Jahr);
     END;
     DEC(anz);
   END;
 END OutDays;

 BEGIN
   IF Version[0] # CHAR(0) THEN
   END;
   (* Init *)
   wurzel   := NIL;
   (* Setups *)
   path     := "s:";
   filename := "Kalender.dat";
   language := 2;
   saveflag := FALSE;
   save := TRUE;
   ZeitRaum := 31;
   already := FALSE;
   mark := FALSE;
   nodata := FALSE;
   date1 := "%d.%m.";
   date2 := "%d.%m.%y";
   line := "%1 : %t";
   state := "Terminübersicht am %w, den %d.%m.%y";
   port := OpenRexxPort();
   (* get options *)
   IF ~wbStarted AND CheckOption("?") THEN
     WriteString("HELP/S,PATH/K,FILE/K,SHOW/N/K,LANGUAGE/N/K,ONCE/S,MARK/T,INSERT ''d.m.[y] : text''/K/F,STATUS ''...''/K,DATE1 ''%d.%m.%y''/K,DATE2 ''%d.%m.''/K,LINE ''%1 : %t''/K,NOSAVE/S,NODATA/S"); WriteLn;
     Terminate;
   END;
   IF ~wbStarted AND CheckOption("HELP") THEN
     WriteString("Kalender version 2.1, Copyright (C) 1993 Kai Hofmann"); WriteLn;
     WriteString("Kalender comes with ABSOLUTELY NO WARRANTY; for details see the 'COPYING'-file"); WriteLn;
     WriteString("This is free software, and you are welcome to redistribute it"); WriteLn;
     WriteString("under certain conditions; see 'COPYING'-file for details."); WriteLn;
     WriteLn;
     WriteString("for detail HELP see Kalender.doc file!"); WriteLn;
     WriteString("or contact me (only email - sorry!): i07m@alf.zfn.uni-bremen.de"); WriteLn;
     Terminate;
   END;
   IF CheckOption("PATH") THEN
     cptr := GetOptionParam("PATH",cquot);
     IF cptr # NIL THEN
       Copy(path,cptr^);
       Killstr(cptr);
     END;
   END;
   Assert(((path[Length(path)] = '/') OR (path[Length(path)] = ":") OR (Length(path) = 0)),ADR("Wrong path!"));
   IF CheckOption("FILE") THEN
     cptr := GetOptionParam("FILE",cquot);
     IF cptr # NIL THEN
       Copy(filename,cptr^);
       Killstr(cptr);
     END;
   END;
   Assert(Length(filename) # 0,ADR("Wrong filename!"));

   Copy(file,filename);
   (* Read data *)
   Insert(file,0,path);
   IF ~ReadDaten(wurzel,file) THEN
     Assert(ReadDaten(wurzel,filename),ADR("File not found!"));
   END;
   (* Handle saved status *)
   stat := searchStatus(wurzel);
   (* Get actual date *)
   GetDate(Wochentag,Tag,Monat,Jahr);
   OTag := Tag;
   OMonat := Monat;
   OJahr := Jahr-1;
   (* options *)
   WHILE (stat # NIL) AND (stat^.Monat = 0) DO
     CASE stat^.Tag OF
       1 : Copy(argstr,stat^.Text);
           konvdate(OTag,OMonat,OJahr,argstr);|
       2 : Copy(date1,stat^.Text);|
       3 : Copy(date2,stat^.Text);|
       4 : Copy(state,stat^.Text);|
       5 : StrToVal(stat^.Text,zr,sign,10,err);
	   ZeitRaum := CARDINAL(zr);|
       6 : StrToVal(stat^.Text,zr,sign,10,err);
           language := SHORTCARD(zr)+1;|
       7 : mark := TRUE;|
       8 : Copy(line,stat^.Text);
     ELSE
     END;
     stat := stat^.next;
   END;
   IF CheckOption("ONCE") THEN
     IF tagdiff(Tag,Monat,Jahr,OTag,OMonat,OJahr) < 0 THEN
       already := FALSE;
       stat := searchStatus(wurzel);
       WHILE (stat # NIL) AND (stat^.Monat = 0) AND (stat^.Tag # 1) DO
         stat := stat^.next;
       END;
       IF (stat # NIL) AND (stat^.Monat = 0) AND (stat^.Tag = 1) THEN
	 delete(wurzel,stat);
       END;
       argstr := "";
       format(Tag,argstr,2);
       Concat(argstr,".");
       arg := "";
       format(Monat,arg,2);
       Concat(argstr,arg);
       Concat(argstr,".");
       arg := "";
       format(Jahr,arg,4);
       Concat(argstr,arg);
       insert(wurzel,1,0,0,argstr);
       saveflag := TRUE;
     ELSE
       already := TRUE;
       returnVal := 5;
     END;
   END;
   IF CheckOption("SHOW") THEN
     cptr := GetOptionParam("SHOW",cquot);
     IF cptr # NIL THEN
       StrToVal(cptr^,zr,sign,10,err);
       ZeitRaum := CARDINAL(zr);
       stat := searchStatus(wurzel);
       WHILE (stat # NIL) AND (stat^.Monat = 0) AND (stat^.Tag # 5) DO
         stat := stat^.next;
       END;
       IF (stat # NIL) AND (stat^.Monat = 0) AND (stat^.Tag = 5) THEN
	 delete(wurzel,stat);
       END;
       ValToStr(ZeitRaum,FALSE,arg,10,5,'0',err);
       insert(wurzel,5,0,0,arg);
       saveflag := TRUE;
       Killstr(cptr);
     END;
   END;
   IF (ZeitRaum = 0) OR (ZeitRaum > 366) THEN
     ZeitRaum := 31;
   END;
   IF CheckOption("LANGUAGE") THEN
     cptr := GetOptionParam("LANGUAGE",cquot);
     IF cptr # NIL THEN
       StrToVal(cptr^,zr,sign,10,err);
       language := SHORTCARD(zr)+1;
       IF language > 4 THEN
         language := 1;
       END;
       stat := searchStatus(wurzel);
       WHILE (stat # NIL) AND (stat^.Monat = 0) AND (stat^.Tag # 6) DO
         stat := stat^.next;
       END;
       IF (stat # NIL) AND (stat^.Monat = 0) AND (stat^.Tag = 6) THEN
	 delete(wurzel,stat);
       END;
       ValToStr(language-1,FALSE,arg,10,3,'0',err);
       insert(wurzel,6,0,0,arg);
       saveflag := TRUE;
       Killstr(cptr);
     END;
   END;
   IF localeBase # NIL THEN
     language := 0;
   END;
   IF CheckOption("MARK") THEN
     mark := ~mark;
     stat := searchStatus(wurzel);
     WHILE (stat # NIL) AND (stat^.Monat = 0) AND (stat^.Tag # 7) DO
       stat := stat^.next;
     END;
     IF (stat # NIL) AND (stat^.Monat = 0) AND (stat^.Tag = 7) THEN
       delete(wurzel,stat);
     ELSE
       insert(wurzel,7,0,0,"");
     END;
     saveflag := TRUE;
   END;

   IF CheckOption("STATUS") THEN
     cptr := GetOptionParam("STATUS",cquot);
     IF cptr # NIL THEN
       Assert(cquot,ADR("STATUS parameter not quoted!"));
       Copy(state,cptr^);
       stat := searchStatus(wurzel);
       WHILE (stat # NIL) AND (stat^.Monat = 0) AND (stat^.Tag # 4) DO
         stat := stat^.next;
       END;
       IF (stat # NIL) AND (stat^.Monat = 0) AND (stat^.Tag = 4) THEN
	 delete(wurzel,stat);
       END;
       insert(wurzel,4,0,0,state);
       saveflag := TRUE;
       Killstr(cptr);
     END;
   END;
   slen := specialtext(state,Tag,Monat,Jahr,Jahr,"");
   IF CheckOption("DATE1") THEN
     cptr := GetOptionParam("DATE1",cquot);
     IF cptr # NIL THEN
       Assert(cquot,ADR("DATE1 parameter not quoted!"));
       Copy(date1,cptr^);
       stat := searchStatus(wurzel);
       WHILE (stat # NIL) AND (stat^.Monat = 0) AND (stat^.Tag # 2) DO
         stat := stat^.next;
       END;
       IF (stat # NIL) AND (stat^.Monat = 0) AND (stat^.Tag = 2) THEN
	 delete(wurzel,stat);
       END;
       insert(wurzel,2,0,0,date1);
       saveflag := TRUE;
       Killstr(cptr);
     END;
   END;
   IF CheckOption("DATE2") THEN
     cptr := GetOptionParam("DATE2",cquot);
     IF cptr # NIL THEN
       Assert(cquot,ADR("DATE2 parameter not quoted!"));
       Copy(date2,cptr^);
       stat := searchStatus(wurzel);
       WHILE (stat # NIL) AND (stat^.Monat = 0) AND (stat^.Tag # 3) DO
         stat := stat^.next;
       END;
       IF (stat # NIL) AND (stat^.Monat = 0) AND (stat^.Tag = 3) THEN
	 delete(wurzel,stat);
       END;
       insert(wurzel,3,0,0,date2);
       saveflag := TRUE;
       Killstr(cptr);
     END;
   END;
   IF CheckOption("LINE") THEN
     cptr := GetOptionParam("LINE",cquot);
     IF cptr # NIL THEN
       Assert(cquot,ADR("LINE parameter not quoted!"));
       Copy(line,cptr^);
       stat := searchStatus(wurzel);
       WHILE (stat # NIL) AND (stat^.Monat = 0) AND (stat^.Tag # 8) DO
         stat := stat^.next;
       END;
       IF (stat # NIL) AND (stat^.Monat = 0) AND (stat^.Tag = 8) THEN
	 delete(wurzel,stat);
       END;
       insert(wurzel,8,0,0,line);
       saveflag := TRUE;
       Killstr(cptr);
     END;
   END;
   IF CheckOption("NODATA") THEN
     nodata := TRUE;
   END;
   IF CheckOption("NOSAVE") THEN
     save := FALSE;
   END;
   IF ~wbStarted AND CheckOption("INSERT") THEN
     cptr := GetOptionParam("INSERT",cquot);
     Assert(cquot,ADR("INSERT parameter not quoted!"));
     IF cptr # NIL THEN
       Copy(argstr,cptr^);
       konvdate(t,m,j,argstr);
       IF j > 0 THEN
         Assert((maxDays(m,j) > 0) AND (maxDays(m,j)+1 > t),ADR("Wrong date!"));
       ELSE
         Assert((maxDays(m,Jahr) > 0) AND (maxDays(m,Jahr)+1 > t),ADR("Wrong date!"));
       END;
       insert(wurzel,t,m,j,argstr);
       saveflag := TRUE;
       Killstr(cptr);
     END;
   ELSE
     (* Make output *)
     IF ~already THEN
       y := GetOutDays(wurzel,Tag,Monat,Jahr,ZeitRaum,x);
       IF wbStarted THEN
         IF y > 0 THEN
           window2 := OpenWin2(y,x,ADR(state));
         ELSIF nodata THEN
           window2 := OpenWin2(1,19,ADR(state));
           OutputWin2("No data for output!",1,FALSE);
         END;
       END;
       OutDays(wurzel,Tag,Monat,Jahr,ZeitRaum,mark);
       IF (y = 0) AND (~wbStarted) AND nodata THEN
         WriteString("No data for output!"); WriteLn;
       END;
     END;
   END;
   (* Save data if required *)
   IF saveflag AND save THEN
     WriteDaten(wurzel,file);
   END;
   IF wbStarted AND ~already AND ((y > 0) OR nodata) THEN
     REPEAT
       set := Wait(LONGSET{window2});
     UNTIL HandleAction2()^.Action = close;
     CloseWin2;
   END;
   CloseRexxPort(port);
 END Kalender.
