MODULE XMLObjects; (** AUTHOR "swalthert"; PURPOSE "XML collections and enumerators"; *) IMPORT Strings; TYPE String = Strings.String; Collection* = OBJECT PROCEDURE GetNumberOfElements*(): LONGINT; BEGIN RETURN 0 END GetNumberOfElements; PROCEDURE GetEnumerator*(): Enumerator; BEGIN RETURN NIL END GetEnumerator; PROCEDURE Add*(p: ANY); END Add; PROCEDURE Remove*(p: ANY); END Remove; END Collection; ListElem = OBJECT VAR elem: ANY; next: ListElem; PROCEDURE &Init*(elem : ANY); BEGIN SELF.elem := elem; next := NIL; END Init; END ListElem; List* = OBJECT (Collection) VAR first, last: ListElem; nofElems: LONGINT; PROCEDURE & Init*; BEGIN nofElems := 0 END Init; PROCEDURE GetNumberOfElements*(): LONGINT; BEGIN RETURN nofElems END GetNumberOfElements; PROCEDURE GetEnumerator*(): Enumerator; VAR le: ListEnumerator; BEGIN NEW(le, SELF); RETURN le END GetEnumerator; PROCEDURE Add*(p: ANY); VAR newListElem: ListElem; BEGIN {EXCLUSIVE} IF p # NIL THEN NEW(newListElem, p); IF last = NIL THEN first := newListElem; last := newListElem ELSE last.next := newListElem; last := last.next END; INC(nofElems) END END Add; PROCEDURE Remove*(p: ANY); VAR le: ListElem; BEGIN {EXCLUSIVE} IF (p # NIL) & (first # NIL) THEN IF first.elem = p THEN first := first.next; DEC(nofElems) ELSE le := first; WHILE (le.next # NIL) & (le.next.elem # p) DO le := le.next END; IF le.next # NIL THEN (* le.next.elem = o *) le.next := le.next.next; DEC(nofElems) END END END END Remove; END List; PTRArray* = POINTER TO ARRAY OF ANY; ArrayCollection* = OBJECT (Collection) VAR elems: PTRArray; nofElems: LONGINT; PROCEDURE &Init*; BEGIN nofElems := 0; NEW(elems, 1) END Init; PROCEDURE GetNumberOfElements*(): LONGINT; BEGIN RETURN nofElems END GetNumberOfElements; PROCEDURE GetEnumerator*(): Enumerator; VAR ace: ArrayEnumerator; BEGIN NEW(ace, elems); RETURN ace END GetEnumerator; PROCEDURE Grow; VAR i: LONGINT; oldElems: PTRArray; BEGIN oldElems := elems; NEW(elems, 2 * LEN(elems)); FOR i := 0 TO nofElems - 1 DO elems[i] := oldElems[i] END END Grow; PROCEDURE Add*(p: ANY); BEGIN {EXCLUSIVE} IF p # NIL THEN IF nofElems = LEN(elems) THEN Grow() END; elems[nofElems] := p; INC(nofElems) END END Add; PROCEDURE Remove*(p: ANY); VAR i: LONGINT; BEGIN {EXCLUSIVE} i := 0; WHILE (i < nofElems) & (elems[i] # p) DO INC(i) END; IF i < nofElems THEN WHILE (i < nofElems - 1) DO elems[i] := elems[i + 1]; INC(i) END; DEC(nofElems); elems[nofElems] := NIL END END Remove; PROCEDURE GetElement*(i: LONGINT): ANY; BEGIN IF (0 <= i) & (i < nofElems) THEN RETURN elems[i] ELSE RETURN NIL END END GetElement; PROCEDURE Invert*(ptr1, ptr2: ANY): BOOLEAN; VAR pos1, pos2, i: LONGINT; ptr: ANY; BEGIN {EXCLUSIVE} i := 0; pos1 := -1; pos2 := -1; WHILE (i < nofElems) & ((pos1 < 0) OR (pos2 < 0)) DO IF elems[i] = ptr1 THEN pos1 := i END; IF elems[i] = ptr2 THEN pos2 := i END; INC(i) END; IF (pos1 >= 0) & (pos2 >= 0) & (pos1 # pos2) THEN ptr := elems[pos1]; elems[pos1] := elems[pos2]; elems[pos2] := ptr; RETURN TRUE END; RETURN FALSE END Invert; PROCEDURE GetElementPos*(ptr: ANY): LONGINT; VAR i: LONGINT; BEGIN WHILE i < nofElems DO IF elems[i] = ptr THEN RETURN i END; INC(i) END; RETURN -1 END GetElementPos; PROCEDURE MoveUp*(ptr: ANY; i: LONGINT): BOOLEAN; VAR p: ANY; BEGIN {EXCLUSIVE} IF ptr # NIL THEN i := GetElementPos(ptr) END; IF (i > 0) & (i < nofElems) THEN p := elems[i]; elems[i] := elems[i-1]; elems[i-1] := p; RETURN TRUE END; RETURN FALSE END MoveUp; PROCEDURE MoveDown*(ptr: ANY; i: LONGINT): BOOLEAN; VAR p: ANY; BEGIN {EXCLUSIVE} IF ptr # NIL THEN i := GetElementPos(ptr) END; IF (i >=0) & (i < nofElems-1) THEN p := elems[i]; elems[i] := elems[i+1]; elems[i+1] := p; RETURN TRUE END; RETURN FALSE END MoveDown; END ArrayCollection; Enumerator* = OBJECT PROCEDURE HasMoreElements*(): BOOLEAN; BEGIN RETURN FALSE END HasMoreElements; PROCEDURE GetNext*(): ANY; BEGIN RETURN NIL END GetNext; PROCEDURE Reset*; END Reset; END Enumerator; ListEnumerator* = OBJECT (Enumerator) VAR coll: List; current: ListElem; PROCEDURE & Init*(list: List); BEGIN coll := list; current := list.first END Init; PROCEDURE HasMoreElements*(): BOOLEAN; BEGIN RETURN current # NIL END HasMoreElements; PROCEDURE GetNext*(): ANY; VAR p: ANY; BEGIN IF HasMoreElements() THEN p := current.elem; current := current.next; ELSE p := NIL; END; RETURN p END GetNext; PROCEDURE Reset*; BEGIN Init(coll) END Reset; END ListEnumerator; ArrayEnumerator* = OBJECT (Enumerator) VAR array: PTRArray; current: LONGINT; PROCEDURE & Init*(array: PTRArray); BEGIN SELF.array := array; current := 0 END Init; PROCEDURE HasMoreElements*(): BOOLEAN; BEGIN RETURN (current < LEN(array)) & (array[current] # NIL) END HasMoreElements; PROCEDURE GetNext*(): ANY; VAR p: ANY; BEGIN IF HasMoreElements() THEN p := array[current]; INC(current); ELSE p := NIL; END; RETURN p END GetNext; PROCEDURE Reset*; BEGIN Init(array) END Reset; END ArrayEnumerator; Dictionary* = OBJECT PROCEDURE GetNumberOfElements*(): LONGINT; BEGIN RETURN 0 END GetNumberOfElements; PROCEDURE Get*(key: ARRAY OF CHAR): ANY; END Get; PROCEDURE GetEnumerator*(): Enumerator; BEGIN RETURN NIL END GetEnumerator; PROCEDURE Add*(key: ARRAY OF CHAR; p: ANY); END Add; PROCEDURE Remove*(key: ARRAY OF CHAR); END Remove; END Dictionary; StringArray = POINTER TO ARRAY OF String; ArrayDict* = OBJECT (Dictionary) VAR nofElems: LONGINT; keys: StringArray; elems: PTRArray; PROCEDURE & Init*; BEGIN nofElems := 0; NEW(keys, 16); NEW(elems, 16) END Init; PROCEDURE GetNumberOfElements*(): LONGINT; BEGIN RETURN nofElems END GetNumberOfElements; PROCEDURE Get*(key: ARRAY OF CHAR): ANY; VAR i: LONGINT; BEGIN i := 0; WHILE (i < nofElems) & (keys[i]^ # key) DO INC(i) END; IF i < nofElems THEN RETURN elems[i] ELSE RETURN NIL END END Get; PROCEDURE GetEnumerator*(): Enumerator; VAR ace: ArrayEnumerator; BEGIN NEW(ace, elems); RETURN ace END GetEnumerator; PROCEDURE Grow; VAR i: LONGINT; oldKeys: StringArray; oldElems: PTRArray; BEGIN oldKeys := keys; oldElems := elems; NEW(keys, 2 * LEN(keys)); NEW(elems, 2 * LEN(elems)); FOR i := 0 TO nofElems - 1 DO keys[i] := oldKeys[i]; elems[i] := oldElems[i] END END Grow; PROCEDURE Add*(key: ARRAY OF CHAR; p: ANY); BEGIN {EXCLUSIVE} IF Get(key) = NIL THEN IF nofElems = LEN(elems) THEN Grow() END; NEW(keys[nofElems], StringLength(key) + 1); COPY(key, keys[nofElems]^); elems[nofElems] := p; INC(nofElems) END END Add; PROCEDURE Remove*(key: ARRAY OF CHAR); VAR i: LONGINT; BEGIN {EXCLUSIVE} i := 0; WHILE (i < nofElems) & (keys[i]^ # key) DO INC(i) END; IF i < nofElems THEN WHILE (i < nofElems - 1) DO elems[i] := elems[i + 1]; keys[i] := keys[i + 1]; INC(i) END; DEC(nofElems); keys[nofElems] := NIL; elems[nofElems] := NIL END END Remove; END ArrayDict; PROCEDURE StringLength(CONST string: ARRAY OF CHAR): LONGINT; VAR i, l: LONGINT; BEGIN i := 0; l := LEN(string); WHILE (i < l) & (string[i] # 0X) DO INC(i) END; RETURN i END StringLength; END XMLObjects.