12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576 |
- MODULE TextUtilities; (** AUTHOR "TF"; PURPOSE "Utilities for the Unicode text system"; *)
- IMPORT
- SYSTEM, (* for Oberon Text colors *)
- Configuration, Commands, Codecs, FP1616,
- KernelLog, Texts, Streams, Files, UTF8Strings, XML, XMLScanner, XMLParser, XMLObjects, Repositories, Strings, WMGraphics,
- UnicodeProperties;
- CONST
- Ok* = 0;
- FileNotFound* = Files.FileNotFound;
- FileCreationError* = 2;
- CodecNotFound* = 3;
- CR = 0DX; LF = 0AX; TAB = 09X;
- (** FormatDescriptor features *)
- LoadUnicode* = 0;
- StoreUnicode* = 1;
- LoadFormated* = 2;
- StoreFormatted* = 3;
- BufferedAttributes=256; (* number of attributes buffered before updates must take place *)
- TYPE
- Char32 = Texts.Char32;
- Text = Texts.Text;
- LoaderProc* = PROCEDURE {DELEGATE} (text : Text; filename : ARRAY OF CHAR; VAR res : WORD);
- TYPE
- FormatDescriptor = OBJECT
- VAR name : Strings.String;
- loadProc, storeProc : Strings.String;
- END FormatDescriptor;
- AttributesBuf*=RECORD
- attributes: POINTER TO ARRAY OF Texts.Attributes;
- positions: POINTER TO ARRAY OF LONGINT;
- length: LONGINT;
- END;
- TextWriter* = OBJECT (Streams.Writer);
- VAR text : Texts.Text;
- ucs32buf : POINTER TO ARRAY OF LONGINT;
- fontName : ARRAY 32 OF CHAR;
- fontSize, x, fontVOff : LONGINT; fontColor, fontBgColor: WMGraphics.Color;
- fontStyle : SET;
- currentAttributes- : Texts.Attributes;
- oldBytes : ARRAY 7 OF CHAR;
- nofOldBytes : LONGINT;
- attributesBuf: AttributesBuf;
- PROCEDURE &Init*(text : Texts.Text);
- BEGIN
- SELF.text := text;
- nofOldBytes := 0;
- currentAttributes := GetDefaultAttributes();
- fontColor := currentAttributes.color;
- fontBgColor := currentAttributes.bgcolor;
- fontVOff := currentAttributes.voff;
- COPY(currentAttributes.fontInfo.name, fontName);
- fontSize := currentAttributes.fontInfo.size;
- fontStyle := currentAttributes.fontInfo.style;
- NEW(attributesBuf.attributes,BufferedAttributes);
- NEW(attributesBuf.positions,BufferedAttributes);
- attributesBuf.length := 0;
- InitWriter (Add, 128 * 1024);
- END Init;
- PROCEDURE Add(CONST buf: ARRAY OF CHAR; ofs, len: LONGINT; propagate: BOOLEAN; VAR res: WORD);
- VAR
- p, i, idx, pos : LONGINT;
- nextAttribute: LONGINT;
- pieceOffset, pieceLength: LONGINT;
- nextAttributes: Texts.Attributes;
- BEGIN
- pieceOffset := ofs; pieceLength := len;
- IF (ucs32buf = NIL) OR (pieceLength >= LEN(ucs32buf)) THEN NEW(ucs32buf, pieceLength + 1) END;
- p := pieceOffset; idx := 0;
- (* complete an unfinished character *)
- IF nofOldBytes > 0 THEN
- FOR i := nofOldBytes TO ORD(UTF8Strings.CodeLength[ORD(oldBytes[0])]) - 1 DO
- oldBytes[i] := buf[p]; INC(p)
- END;
- i := 0; IF UTF8Strings.DecodeChar(oldBytes, i, ucs32buf[idx]) THEN INC(idx) END;
- nofOldBytes := 0
- END;
- WHILE (p < pieceOffset + pieceLength) & (ORD(UTF8Strings.CodeLength[ORD(buf[p])]) <= pieceOffset+pieceLength) &
- UTF8Strings.DecodeChar(buf, p, ucs32buf[idx]) DO INC(idx) END;
- ucs32buf[idx] := 0;
- IF (p < pieceOffset + pieceLength) & (ORD(UTF8Strings.CodeLength[ORD(buf[p])]) >= pieceOffset+pieceLength) THEN (* could not be decoded because of missing bytes. ignore other problems *)
- WHILE p < pieceOffset+pieceLength DO oldBytes[i] := buf[p]; INC(p); INC(i) END;
- nofOldBytes := i;
- KernelLog.String("Update within UTF sequence "); KernelLog.Ln;
- END;
- IF len > 0 THEN
- text.AcquireWrite;
- pos := text.GetLength();
- text.InsertUCS32(text.GetLength(), ucs32buf^);
- pieceOffset := 0; nextAttribute := 0;
- WHILE nextAttribute < attributesBuf.length DO
- nextAttributes := attributesBuf.attributes[nextAttribute];
- pieceLength:= attributesBuf.positions[nextAttribute]-pieceOffset;
- text.SetAttributes(pos+pieceOffset,pieceLength,currentAttributes);
- INC(pieceOffset, pieceLength);
- currentAttributes := nextAttributes;
- INC(nextAttribute);
- END;
- text.SetAttributes(pieceOffset+pos, text.GetLength()-pos-pieceOffset, currentAttributes);
- text.ReleaseWrite;
- attributesBuf.length := 0;
- END;
- END Add;
- (** Write end-of-line character *)
- PROCEDURE Ln*; (** overwrite Ln^ *)
- BEGIN
- Char(CHR(Texts.NewLineChar));
- END Ln;
- PROCEDURE SetAttributes*(attributes: Texts.Attributes);
- VAR i: LONGINT;
- BEGIN
- IF attributesBuf.length = LEN(attributesBuf.attributes) THEN Update(); END;
- i := attributesBuf.length;
- attributesBuf.attributes[i] := attributes;
- attributesBuf.positions[i] := Pos()-sent;
- INC(i);
- attributesBuf.length := i;
- END SetAttributes;
- PROCEDURE NewAttributes(): Texts.Attributes;
- VAR attributes: Texts.Attributes;
- BEGIN
- NEW(attributes); attributes.Set(fontColor, fontBgColor, fontVOff, fontName, fontSize, fontStyle);
- RETURN attributes
- END NewAttributes;
- PROCEDURE SetFontName* (CONST name : ARRAY OF CHAR);
- BEGIN
- COPY(name, fontName);
- SetAttributes(NewAttributes());
- END SetFontName;
- PROCEDURE SetFontSize* (size : LONGINT);
- BEGIN
- fontSize := size;
- SetAttributes(NewAttributes());
- END SetFontSize;
- PROCEDURE SetFontStyle* (style : SET);
- BEGIN
- fontStyle := style;
- SetAttributes(NewAttributes());
- END SetFontStyle;
- PROCEDURE SetFontColor* (color : WMGraphics.Color);
- BEGIN
- fontColor := color;
- SetAttributes(NewAttributes());
- END SetFontColor;
- PROCEDURE SetBgColor* (bgColor : LONGINT);
- BEGIN
- fontBgColor := bgColor;
- SetAttributes(NewAttributes());
- END SetBgColor;
- PROCEDURE SetVerticalOffset* (voff : LONGINT);
- BEGIN
- fontVOff := voff;
- SetAttributes(NewAttributes());
- END SetVerticalOffset;
- PROCEDURE AddObject*(obj : ANY);
- VAR op : Texts.ObjectPiece;
- BEGIN
- Update;
- NEW(op); op.object := obj;
- text.AcquireWrite;
- text.InsertPiece(text.GetLength(), op);
- text.ReleaseWrite;
- END AddObject;
- END TextWriter;
- TextReader* = OBJECT (Streams.Reader)
- VAR
- reader: Texts.TextReader;
- remainder: LONGINT;
- PROCEDURE &Init*(text : Texts.Text);
- BEGIN
- remainder := 0;
- NEW (reader, text);
- InitReader (Receive, Streams.DefaultReaderSize);
- END Init;
- PROCEDURE Receive (VAR buf: ARRAY OF CHAR; ofs, size, min: LONGINT; VAR len: LONGINT; VAR res: WORD);
- VAR ucs32, prevofs: LONGINT;
- BEGIN
- reader.text.AcquireRead;
- len := 0; res := Streams.Ok;
- WHILE len < size DO
- IF remainder # 0 THEN
- ucs32 := remainder; remainder := 0;
- ELSE
- reader.ReadCh (ucs32);
- END;
- prevofs := ofs;
- IF (ucs32 = 0) OR ~UTF8Strings.EncodeChar (ucs32, buf, ofs) THEN
- remainder := ucs32;
- IF len < min THEN res := Streams.EOF END;
- reader.text.ReleaseRead;
- RETURN
- END;
- INC (len, ofs - prevofs);
- END;
- reader.text.ReleaseRead;
- END Receive;
- PROCEDURE CanSetPos*() : BOOLEAN;
- BEGIN
- RETURN TRUE;
- END CanSetPos;
- PROCEDURE SetPos*(pos: Streams.Position);
- BEGIN
- reader.text.AcquireRead;
- reader.SetPosition(pos); (* pos is clipped *)
- received := reader.GetPosition(); (* this effects that Streams.Reader.Pos() returns the correct location in the text *)
- Reset;
- remainder := 0;
- reader.text.ReleaseRead;
- END SetPos;
- END TextReader;
- TYPE
- LongintArray = POINTER TO ARRAY OF LONGINT;
- Operation = RECORD op, pos, len : LONGINT END;
- Operations = POINTER TO ARRAY OF Operation;
- TextSelection*=OBJECT
- VAR text* : Texts.Text;
- from*, to* : Texts.TextPosition;
- END TextSelection;
- TextPositionKeeper* = OBJECT(Texts.TextPosition);
- VAR positions : LongintArray;
- nofPositions : LONGINT;
- operations : Operations;
- nofOperations, nofDeleted : LONGINT;
- PROCEDURE &New*(t : Texts.Text);
- BEGIN
- New^(t);
- NEW(positions, 256); NEW(operations, 256);
- nofOperations := 0; nofPositions := 0; nofDeleted := 0
- END New;
- PROCEDURE GrowOperations;
- VAR i : LONGINT;
- t : Operations;
- BEGIN
- NEW(t, nofOperations * 2);
- FOR i := 0 TO nofOperations - 1 DO t[i] := operations[i] END;
- operations := t
- END GrowOperations;
- PROCEDURE Cleanup;
- VAR i, j, p, op, pos : LONGINT;
- BEGIN
- IF nofOperations = 0 THEN RETURN END;
- FOR i := 0 TO nofPositions - 1 DO
- p := positions[i];
- IF p >= 0 THEN
- FOR j := 0 TO nofOperations - 1 DO
- op := operations[j].op; pos := operations[j].pos;
- IF (p >= pos) & (op = Texts.OpInsert) THEN INC(p, operations[j].len)
- ELSIF (p >= pos) & (p <= pos + operations[j].len) & (op = Texts.OpDelete) THEN p := pos
- ELSIF (p > pos) & (op = Texts.OpDelete) THEN DEC(p, operations[j].len);
- END
- END;
- IF p < 0 THEN p := 0 END;
- positions[i] := p
- END
- END;
- nofOperations := 0
- END Cleanup;
- (** Listens for text changes *)
- PROCEDURE Changed*(op, pos, len : LONGINT);
- CONST MaxOperations = 4096;
- BEGIN
- IF nofOperations > MaxOperations THEN Cleanup END;
- IF nofOperations >= LEN(operations) THEN GrowOperations END;
- operations[nofOperations].op := op;
- operations[nofOperations].pos := pos;
- operations[nofOperations].len := len;
- INC(nofOperations)
- END Changed;
- PROCEDURE GrowPositions;
- VAR i : LONGINT;
- t : LongintArray;
- BEGIN
- NEW(t, nofPositions * 2);
- FOR i := 0 TO nofPositions - 1 DO t[i] := positions[i] END;
- positions := t
- END GrowPositions;
- PROCEDURE DeletePos*(index : LONGINT);
- BEGIN
- positions[index] := -1;
- INC(nofDeleted)
- END DeletePos;
- PROCEDURE AddPos*(pos : LONGINT) : LONGINT;
- VAR i : LONGINT;
- BEGIN
- ASSERT(pos >= 0);
- Cleanup;
- IF nofDeleted > 0 THEN
- i := 0; WHILE (i < nofPositions) & (positions[i] >= 0) DO INC(i) END;
- ASSERT(i < nofPositions);
- positions[i] := pos;
- DEC(nofDeleted);
- RETURN i
- ELSE
- IF nofPositions >= LEN(positions) THEN GrowPositions END;
- positions[nofPositions] := pos;
- INC(nofPositions);
- RETURN nofPositions - 1
- END
- END AddPos;
- (** throw away all positions *)
- PROCEDURE Clear*;
- BEGIN
- nofPositions := 0; nofOperations := 0
- END Clear;
- (** Returns position in elements from the text start *)
- PROCEDURE GetPos*(index : LONGINT):LONGINT;
- BEGIN
- Cleanup;
- RETURN positions[index]
- END GetPos;
- (** Change the position associated with index*)
- PROCEDURE SetPos*(index, pos : LONGINT);
- BEGIN
- Cleanup;
- positions[index] := pos
- END SetPos;
- END TextPositionKeeper;
- OberonDecoder = OBJECT(Codecs.TextDecoder)
- VAR errors : BOOLEAN;
- in : Streams.Reader;
- text : Texts.Text;
- buffer : Strings.Buffer;
- string: Strings.String;
- reader, sreader : Streams.StringReader;
- PROCEDURE Error(CONST x : ARRAY OF CHAR);
- BEGIN
- KernelLog.String("Oberon Decoder Error: ");
- KernelLog.String(x); KernelLog.Ln;
- errors := TRUE
- END Error;
- PROCEDURE LoadLibrary(buf: Strings.Buffer; pos:LONGINT; VARflen:LONGINT);
- END LoadLibrary;
- PROCEDURE IndexToColor(index: LONGINT): LONGINT;
- BEGIN
- RETURN
- ASH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, index) * {5..7}), 23-7) +
- ASH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, index) * {2..4}), 15-4) +
- ASH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, index) * {0..1}), 7-1)
- END IndexToColor;
- PROCEDURE InsertPiece(ofs, len : LONGINT; attr : Texts.Attributes);
- VAR i, j, m : LONGINT; ch, last : CHAR; tempUCS32 : ARRAY 1024 OF Char32;
- oldpos : LONGINT;
- BEGIN
- m := LEN(tempUCS32) - 1;
- sreader.SetPos(ofs);
- oldpos := text.GetLength();
- FOR j := 0 TO len - 1 DO
- ch := sreader.Get();
- IF i = m THEN tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32); i := 0 END;
- IF (last # CR) OR (ch # LF) THEN
- IF ch = CR THEN tempUCS32[i] := ORD(LF)
- ELSE tempUCS32[i] := OberonToUni(ORD(ch))
- END;
- INC(i)
- END;
- last := ch
- END;
- tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32);
- IF attr # NIL THEN text.SetAttributes(oldpos, len, attr) END
- END InsertPiece;
- PROCEDURE Open*(in : Streams.Reader; VAR res : WORD);
- CONST DocBlockId = 0F7X; OldTextBlockId = 1X; TextBlockId = 0F0X; OldTextSpex = 0F0X; TextSpex = 1X; LibBlockId = 0DBX;
- VAR
- ch: CHAR;
- tempInt : LONGINT;
- buflen: LONGINT;
- attr : Texts.Attributes;
- tattr : Texts.FontInfo;
- fonts : ARRAY 256 OF Texts.FontInfo;
- col: SHORTINT;
- voff: SHORTINT;
- lib :SHORTINT;
- type, tag: CHAR;
- len, flen, n, off, hlen, tlen, pos, templen: LONGINT;
- x, y, w, h: INTEGER;
- temp: ARRAY 4096 OF CHAR;
- name, lName: ARRAY 32 OF CHAR;
- oberonColors : ARRAY 16 OF LONGINT;
- BEGIN
- errors := FALSE;
- res := -1;
- IF in = NIL THEN Error("Input Stream is NIL"); RETURN; END;
- SELF.in := in;
- (* write stream into buffer for further processing *)
- NEW(buffer, 64 * 1024);
- REPEAT
- in.Bytes(temp, 0, 4096, buflen);
- buffer.Add(temp, 0, buflen, FALSE, res);
- UNTIL (in.res # Streams.Ok);
- (* define Oberon Colors *)
- oberonColors[0] := LONGINT(0FFFFFFFFH); oberonColors[1] := LONGINT(0FF0000FFH); oberonColors[2] := 000FF00FFH; oberonColors[3] := 00000FFFFH;
- oberonColors[4] := LONGINT(0FF00FFFFH); oberonColors[5] := LONGINT(0FFFF00FFH); oberonColors[6] := 000FFFFFFH; oberonColors[7] := LONGINT(0AA0000FFH);
- oberonColors[8] := 000AA00FFH; oberonColors[9] := 00000AAFFH; oberonColors[10] := LONGINT(0A6BCF3FFH); oberonColors[11] := 0008282FFH;
- oberonColors[12] := LONGINT(08A8A8AFFH); oberonColors[13] := LONGINT(0BEBEBEFFH); oberonColors[14] := 07B7B7BFFH; oberonColors[15] := 0000000FFH;
- NEW(text);
- text.AcquireWrite;
- string := buffer.GetString();
- NEW(reader, buffer.GetLength());
- reader.SetRaw(string^, 0, buffer.GetLength());
- ch := reader.Get();
- IF ch = DocBlockId THEN (* skip doc header *)
- reader.RawString(name); reader.RawInt(x); reader.RawInt(y); reader.RawInt(w); reader.RawInt(h);
- ch := reader.Get();
- IF ch = 0F7X THEN (* skip meta info *)
- ch := reader.Get(); IF ch = 08X THEN reader.RawLInt(len); reader.Bytes(temp, 0, len, templen); ch := reader.Get(); END;
- END
- END;
- pos := reader.Pos();
- IF (ch = TextBlockId) OR (ch = OldTextBlockId) THEN
- type := reader.Get();
- reader.RawLInt(hlen);
- NEW(sreader, buffer.GetLength());
- tempInt := pos - 1 + hlen - 4;
- sreader.SetRaw(string^, 0, buffer.GetLength());
- sreader.SetPos(tempInt);
- sreader.RawLInt(tlen);
- IF (type = TextSpex) OR (type = OldTextSpex) THEN (*T.obs := NIL; flen := 0 *)
- ELSE (* NEW(T.obs); Objects.OpenLibrary(T.obs); *)
- tempInt := pos - 1 + hlen + tlen;
- sreader.SetPos(tempInt);
- tag := sreader.Get();
- IF tag = LibBlockId THEN LoadLibrary(buffer, pos - 1 + hlen + tlen + 1, flen) END;
- INC(flen)
- END;
- n := 1;
- off := pos - 1 + hlen;
- WHILE reader.Pos() < pos - 1 + hlen - 5 DO
- reader.RawSInt(lib);
- IF lib = n THEN
- reader.RawString(lName);
- NEW(fonts[n]);
- COPY(lName, fonts[n].name);
- DecodeOberonFontName(lName, fonts[n].name, fonts[n].size, fonts[n].style);
- tattr := fonts[n];
- INC(n)
- ELSE
- IF (lib >= 0) & (lib < 255) & (fonts[lib] # NIL) THEN
- tattr := fonts[lib];
- END
- END;
- reader.RawSInt(col);
- reader.RawSInt(voff); voff := - voff;
- reader.RawLInt(len);
- IF len < 0 THEN KernelLog.Enter; KernelLog.String(" LoadAscii (T, f);"); KernelLog.Int(len, 0); KernelLog.Exit; RETURN END;
- NEW(attr);
- CASE col OF
- 0..15 : attr.color := oberonColors[col]
- ELSE attr.color := IndexToColor(col) * 100H + 0FFH
- END;
- attr.voff := voff;
- NEW(attr.fontInfo);
- IF tattr # NIL THEN
- COPY(tattr.name, attr.fontInfo.name);
- attr.fontInfo.style := tattr.style;
- attr.fontInfo.size := tattr.size
- END;
- IF lib > 0 THEN (* ignore objects for now *)
- InsertPiece(off, len, attr)
- END;
- off := off + len
- END;
- res := 0;
- ELSE Error("Not an Oberon File Format!");
- END;
- text.ReleaseWrite;
- END Open;
- PROCEDURE GetText*() : Texts.Text;
- BEGIN
- RETURN text;
- END GetText;
- (* map oberon to unicode *)
- PROCEDURE OberonToUni(ch : LONGINT) : LONGINT;
- VAR ret : LONGINT;
- BEGIN
- CASE ch OF
- 128 : ret := 0C4H;
- | 129 : ret:= 0D6H;
- | 130 : ret:= 0DCH;
- | 131 : ret:= 0E4H;
- | 132 : ret:= 0F6H;
- | 133 : ret:= 0FCH;
- | 134 : ret:= 0E2H;
- | 135 : ret:= 0EAH;
- | 136 : ret:= 0EEH;
- | 137 : ret:= 0F4H;
- | 138 : ret:= 0FBH;
- | 139 : ret:= 0E0H;
- | 140 : ret:= 0E8H;
- | 141 : ret:= 0ECH;
- | 142 : ret:= 0F2H;
- | 143 : ret:= 0F9H;
- | 144 : ret:= 0E9H;
- | 145 : ret:= 0EBH;
- | 146 : ret:= 0EFH;
- | 147 : ret:= 0E7H;
- | 148 : ret:= 0E1H;
- | 149 : ret:= 0F1H;
- | 150 : ret:= 0DFH;
- | 151 : ret:= 0A3H;
- | 152 : ret:= 0B6H;
- | 153 : ret:= 0C7H;
- | 154 : ret:= 2030H;
- | 155 : ret:= 2013H;
- ELSE
- ret := ch
- END;
- RETURN ret
- END OberonToUni;
- END OberonDecoder;
- OberonEncoder = OBJECT(Codecs.TextEncoder)
- VAR out, w: Streams.Writer;
- w2: Streams.StringWriter;
- string: Strings.String;
- buffer : Strings.Buffer;
- oberonColors : ARRAY 16 OF LONGINT;
- fonts : ARRAY 256 OF Texts.FontInfo;
- font : Texts.FontInfo;
- nofFonts, hLen : LONGINT;
- firstPiece : BOOLEAN;
- voff: LONGINT;
- color : LONGINT;
- PROCEDURE Open*(out : Streams.Writer);
- BEGIN
- IF out = NIL THEN KernelLog.String("Oberon Encoder Error: output stream is NIL");
- ELSE SELF.out := out;
- END;
- END Open;
- PROCEDURE ColorToIndex(col: LONGINT): LONGINT;
- BEGIN
- RETURN SYSTEM.VAL(LONGINT,
- SYSTEM.VAL(SET, ASH(col, 7-23)) * {5..7} +
- SYSTEM.VAL(SET, ASH(col, 4-15)) * {2..4} +
- SYSTEM.VAL(SET, ASH(col, 1-7)) * {0..1})
- END ColorToIndex;
- PROCEDURE GetOberonColor(color : LONGINT):LONGINT;
- VAR i: LONGINT;
- BEGIN
- i := 0; WHILE i < LEN(oberonColors) DO IF oberonColors[i] = color THEN RETURN i END; INC(i) END;
- RETURN ColorToIndex(color DIV 100H)
- END GetOberonColor;
- PROCEDURE WritePiece(len: LONGINT);
- VAR i :LONGINT; oname : ARRAY 32 OF CHAR;
- BEGIN
- IF (font # NIL) THEN
- i := 0; WHILE (i < nofFonts) & (~fonts[i].IsEqual(font)) DO INC(i) END;
- IF (i = nofFonts) THEN
- IF ToOberonFont(font.name, font.size, font.style, oname) THEN
- w.RawSInt(SHORT(SHORT(i+1)));
- IF i = nofFonts THEN w.RawString(oname); fonts[nofFonts] := font; INC(nofFonts) END
- ELSE
- w.RawSInt(1);
- IF firstPiece THEN
- w.RawString("Oberon10.Scn.Fnt");
- NEW(fonts[nofFonts]);
- fonts[nofFonts].name := "Oberon"; fonts[nofFonts].size := 10; fonts[nofFonts].style := {};
- INC(nofFonts)
- END;
- END
- ELSE w.RawSInt(SHORT(SHORT(i+1)));
- END
- ELSE
- w.RawSInt(1);
- IF firstPiece THEN
- w.RawString("Oberon10.Scn.Fnt");
- NEW(fonts[nofFonts]);
- fonts[nofFonts].name := "Oberon"; fonts[nofFonts].size := 10; fonts[nofFonts].style := {};
- INC(nofFonts)
- END;
- END;
- firstPiece := FALSE;
- w.RawSInt(SHORT(SHORT(GetOberonColor(color))));
- w.RawSInt(SHORT(SHORT(-voff)));
- w.RawLInt(len);
- END WritePiece;
- PROCEDURE WriteText*(text : Texts.Text; VAR res : WORD);
- CONST TextBlockId = 0F0X;
- VAR r: Texts.TextReader;
- ch :Char32;
- startPos, i, len, tempInt : LONGINT;
- BEGIN
- (* define Oberon colors *)
- oberonColors[0] := LONGINT(0FFFFFFFFH); oberonColors[1] := LONGINT(0FF0000FFH); oberonColors[2] := 000FF00FFH; oberonColors[3] := 00000FFFFH;
- oberonColors[4] := LONGINT(0FF00FFFFH); oberonColors[5] := LONGINT(0FFFF00FFH); oberonColors[6] := 000FFFFFFH; oberonColors[7] := LONGINT(0AA0000FFH);
- oberonColors[8] := 000AA00FFH; oberonColors[9] := 00000AAFFH; oberonColors[10] := LONGINT(0A6BCF3FFH); oberonColors[11] := 0008282FFH;
- oberonColors[12] := LONGINT(08A8A8AFFH); oberonColors[13] := LONGINT(0BEBEBEFFH); oberonColors[14] := 07B7B7BFFH; oberonColors[15] := 0000000FFH;
- res := -1;
- text.AcquireRead;
- firstPiece := TRUE;
- NEW(r, text);
- NEW(buffer, 1024);
- w := buffer.GetWriter();
- nofFonts := 0;
- w.Char(TextBlockId);
- w.Char(01X); (* simple text *)
- w.RawLInt(0); (* header len place holder *)
- startPos := 1; len := 0;
- REPEAT
- r.ReadCh(ch);
- IF ~r.eot & (ch >= 0) & (ch < 256) THEN
- INC(len);
- IF len < 2 THEN font := r.font; voff := r.voff; color := r.color END;
- IF (r.font # font) OR (r.voff # voff) OR (r.color # color) THEN
- WritePiece(len - startPos);
- font := r.font; voff := r.voff; color := r.color;
- startPos := len;
- END
- END
- UNTIL r.eot;
- WritePiece(len + 1 - startPos);
- w.Char(0X); (* ??? *)
- w.RawLInt(len); (* tLen ? *)
- w.Update;
- hLen := w.Pos();
- (* pure text ... *)
- r.SetPosition(0);
- FOR i := 0 TO text.GetLength() - 1 DO r.ReadCh(ch); IF ch = Texts.NewLineChar THEN ch := 0DH END;
- IF (ch >=0) & (ch < 256) THEN w.Char(CHR(UniToOberon(ch))) END
- END;
- (* fixup header length *)
- w.Update;
- string := buffer.GetString();
- NEW(w2, LEN(string));
- w2.Bytes(string^, 0, LEN(string));
- tempInt := w2.Pos();
- w2.SetPos(2);
- w2.RawLInt(hLen);
- w2.SetPos(tempInt); w2.Update;
- (* write string to output stream *)
- NEW(string, text.GetLength()+hLen);
- w2.GetRaw(string^, len);
- out.Bytes(string^, 0, len); out.Update;
- text.ReleaseRead;
- res := 0
- END WriteText;
- (* map unicode to oberon *)
- PROCEDURE UniToOberon(ch : LONGINT) : LONGINT;
- VAR ret : LONGINT;
- BEGIN
- CASE ch OF
- 0C4H : ret := 128;
- | 0D6H : ret := 129;
- | 0DCH : ret := 130;
- | 0E4H : ret := 131;
- | 0F6H : ret := 132;
- | 0FCH : ret := 133;
- | 0E2H : ret := 134;
- | 0EAH : ret := 135;
- | 0EEH : ret := 136;
- | 0F4H : ret := 137;
- | 0FBH : ret := 138;
- | 0E0H : ret := 139;
- | 0E8H : ret := 140;
- | 0ECH : ret := 141;
- | 0F2H : ret := 142;
- | 0F9H : ret := 143;
- | 0E9H : ret := 144;
- | 0EBH : ret := 145;
- | 0EFH : ret := 146;
- | 0E7H : ret := 147;
- | 0E1H : ret := 148;
- | 0F1H : ret := 149;
- | 0DFH : ret := 150;
- | 0A3H : ret := 151;
- | 0B6H : ret := 152;
- | 0C7H : ret := 153;
- ELSE
- IF ch = 2030H THEN ret := 154
- ELSIF ch = 2013H THEN ret := 155
- ELSE ret := ch
- END
- END;
- RETURN ret
- END UniToOberon;
- END OberonEncoder;
- BluebottleDecoder* = OBJECT(Codecs.TextDecoder)
- VAR errors : BOOLEAN;
- text : Texts.Text;
- doc : XML.Document;
- cont, tc, tc2 : XMLObjects.Enumerator; ptr : ANY; root : XML.Element; str : Strings.String;
- o : Texts.ObjectPiece; attr: Texts.Attributes; fi : Texts.FontInfo;
- stylename, pstylename: ARRAY 64 OF CHAR;
- link : Texts.Link;
- PROCEDURE Error(CONST x : ARRAY OF CHAR);
- BEGIN
- KernelLog.String("Bluebottle Decoder Error: ");
- KernelLog.String(x); KernelLog.Ln;
- errors := TRUE
- END Error;
- PROCEDURE GetUTF8Char(r : Streams.Reader; VAR u : Texts.Char32; VAR pos : LONGINT) : BOOLEAN;
- VAR ch : ARRAY 8 OF CHAR; i : LONGINT;
- BEGIN
- ch[0] := r.Get(); INC(pos);
- FOR i := 1 TO ORD(UTF8Strings.CodeLength[ORD(ch[0])]) - 1 DO ch[i] := r.Get(); INC(pos) END;
- i := 0;
- RETURN UTF8Strings.DecodeChar(ch, i, u)
- END GetUTF8Char;
- PROCEDURE InsertPiece(charContent : XML.CDataSect);
- VAR i, m, tpos: LONGINT; res : WORD; ch, last : Texts.Char32; tempUCS32 : ARRAY 1024 OF Texts.Char32;
- oldpos, len : LONGINT;
- r, sr : Streams.StringReader; token : ARRAY 256 OF CHAR;
- tempInt: LONGINT;
- buffer : Strings.String;
- char : CHAR;
- cStyle : Texts.CharacterStyle;
- pStyle : Texts.ParagraphStyle;
- BEGIN
- m := LEN(tempUCS32) - 1;
- buffer := charContent.GetStr();
- NEW(r, LEN(buffer^));
- r.Set(buffer^);
- oldpos := text.GetLength();
- len := charContent.GetLength();
- tpos := 0;
- REPEAT
- IF GetUTF8Char(r, ch, tpos) THEN
- IF i = m THEN tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32); i := 0 END;
- IF (last # ORD(CR)) OR (ch # ORD(LF)) THEN
- IF ch = ORD(CR) THEN tempUCS32[i] := ORD(LF)
- ELSE tempUCS32[i] := ch
- END;
- INC(i)
- END;
- last := ch;
- END
- UNTIL (tpos >= len) OR (r.res # Streams.Ok);
- tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32);
- (* get style from the System *)
- cStyle := Texts.GetCharacterStyleByName(stylename);
- pStyle := Texts.GetParagraphStyleByName(pstylename);
- (* set attributes to emulate style in non-style supporting applications *)
- IF (attr = NIL) THEN NEW(attr); END;
- attr.voff := 0; attr.color := 0000000FFH; attr.bgcolor := 000000000H;
- IF (attr.fontInfo = NIL) THEN NEW(fi); attr.fontInfo := fi; END;
- attr.fontInfo.name := "Oberon"; attr.fontInfo.size := 10; attr.fontInfo.style := {};
- IF (stylename = "Bold") THEN attr.fontInfo.style := {0};
- ELSIF (stylename = "Highlight") THEN attr.fontInfo.style := {1};
- ELSIF (stylename = "Assertion") THEN attr.fontInfo.style := {0}; attr.color := 00000FFFFH;
- ELSIF (stylename = "Debug") THEN attr.color := 00000FFFFH;
- ELSIF (stylename = "Lock") THEN attr.color := LONGINT(0FF00FFFFH);
- ELSIF (stylename = "Stupid") THEN attr.color := LONGINT(0FF0000FFH);
- ELSIF (stylename = "Comment") THEN attr.color := LONGINT(0808080FFH);
- ELSIF (stylename = "Preferred") THEN attr.fontInfo.style := {0}; attr.color := LONGINT(0800080FFH);
- ELSIF Strings.Match("AdHoc*", stylename) THEN
- NEW(sr, LEN(stylename)); sr.Set(stylename);
- sr.SkipWhitespace; sr.Token(token); (* AdHoc *)
- sr.SkipWhitespace; sr.Token(token); COPY(token, attr.fontInfo.name); (* family *)
- sr.SkipWhitespace; sr.Token(token); Strings.StrToInt(token, attr.fontInfo.size); (* size *)
- sr.SkipWhitespace; sr.Token(token); Strings.StrToInt(token, tempInt); (* style *)
- IF (tempInt = 0) THEN attr.fontInfo.style := {};
- ELSIF (tempInt = 1) THEN attr.fontInfo.style := {0};
- ELSIF (tempInt = 2) THEN attr.fontInfo.style := {1};
- ELSIF (tempInt = 3) THEN attr.fontInfo.style := {0,1};
- ELSE attr.fontInfo.style := {};
- END;
- sr.SkipWhitespace; sr.Token(token); Strings.StrToInt(token, attr.voff); (* voff *)
- sr.SkipWhitespace; sr.Token(token); Strings.HexStrToInt(token, attr.color, res); (* color *)
- sr.SkipWhitespace; sr.Token(token); Strings.HexStrToInt(token, attr.bgcolor, res); (* bgcolor *)
- (* add Ad-Hoc style to the System in case it was not present already *)
- IF cStyle = NIL THEN
- NEW(cStyle);
- COPY(stylename, cStyle.name);
- COPY(attr.fontInfo.name, cStyle.family);
- cStyle.size := FP1616.FloatToFixp(attr.fontInfo.size);
- cStyle.style := attr.fontInfo.style;
- cStyle.baselineShift := attr.voff;
- cStyle.color := attr.color;
- cStyle.bgColor := attr.bgcolor;
- Texts.AddCharacterStyle(cStyle);
- END;
- ELSE
- (* Get the attributes from the style for compatibility *)
- IF (cStyle # NIL) THEN attr := StyleToAttribute(cStyle)
- ELSE token := "Style not present in System: "; Strings.Append(token, stylename); Error(token); END;
- END;
- text.SetAttributes(oldpos, text.GetLength()-oldpos, attr.Clone());
- (* set the style for style supporting applications *)
- text.SetCharacterStyle(oldpos, text.GetLength()-oldpos, cStyle);
- (* Get AdHoc paragraph style & add to system *)
- IF Strings.Match("AdHoc*", pstylename) & (pStyle = NIL) THEN
- NEW(pStyle);
- NEW(sr, LEN(pstylename)); sr.Set(pstylename);
- sr.SkipWhitespace; sr.Token(token); COPY(pstylename, pStyle.name); (* AdHoc *)
- sr.SkipWhitespace; sr.Token(token); Strings.StrToInt(token, tempInt); pStyle.alignment := tempInt; (* alignment *)
- sr.SkipWhitespace; sr.Token(token); Strings.StrToInt(token, tempInt); pStyle.firstIndent := FP1616.FloatToFixp(tempInt); (* first Indent *)
- sr.SkipWhitespace; sr.Token(token); Strings.StrToInt(token, tempInt); pStyle.leftIndent := FP1616.FloatToFixp(tempInt); (* left Indent *)
- sr.SkipWhitespace; sr.Token(token); Strings.StrToInt(token, tempInt); pStyle.rightIndent := FP1616.FloatToFixp(tempInt); (* right Indent *)
- sr.SkipWhitespace; sr.Token(token); Strings.StrToInt(token, tempInt); pStyle.spaceBefore := FP1616.FloatToFixp(tempInt); (* space above *)
- sr.SkipWhitespace; sr.Token(token); Strings.StrToInt(token, tempInt); pStyle.spaceAfter := FP1616.FloatToFixp(tempInt); (* space below *)
- sr.SkipWhitespace; char := sr.Peek(); IF (char = "t") THEN sr.SkipBytes(1); sr.RawString(token); COPY(token, pStyle.tabStops); END; (* tabstops *)
- Texts.AddParagraphStyle(pStyle);
- END;
- (* set the paragraph style *)
- IF (pStyle # NIL) THEN text.SetParagraphStyle(oldpos, text.GetLength()-oldpos, pStyle) END;
- (* set the link *)
- text.SetLink(oldpos, text.GetLength()-oldpos, link);
- END InsertPiece;
- PROCEDURE InsertChar(pos : LONGINT; ch : Texts.Char32);
- VAR bufUCS32 : ARRAY 2 OF Texts.Char32;
- oldpos : LONGINT;
- cStyle : Texts.CharacterStyle;
- pStyle : Texts.ParagraphStyle;
- BEGIN
- bufUCS32[0] := ch; bufUCS32[1] := 0;
- oldpos := text.GetLength();
- text.InsertUCS32(pos, bufUCS32); (* cursor moves automagically *)
- (* get style from the System *)
- cStyle := Texts.GetCharacterStyleByName(stylename);
- pStyle := Texts.GetParagraphStyleByName(pstylename);
- (* set the character style *)
- IF (cStyle # NIL) THEN text.SetCharacterStyle(oldpos, text.GetLength()-oldpos, cStyle) END;
- (* set the paragraph style *)
- IF (pStyle # NIL) THEN text.SetParagraphStyle(oldpos, text.GetLength()-oldpos, pStyle) END;
- (* set the link *)
- IF (link # NIL) THEN text.SetLink(oldpos, text.GetLength()-oldpos, link); KernelLog.String("bonk"); END;
- END InsertChar;
- PROCEDURE MalformedXML(pos, line, row: LONGINT; CONST msg: ARRAY OF CHAR);
- BEGIN
- Error(msg);
- END MalformedXML;
- PROCEDURE Open*(in : Streams.Reader; VAR res : WORD);
- VAR
- scanner : XMLScanner.Scanner; parser : XMLParser.Parser;
- d : XML.Document;
- BEGIN
- res := -1;
- errors := FALSE;
- IF in = NIL THEN Error("Input Stream is NIL"); RETURN; END;
- NEW(scanner, in); NEW(parser, scanner);
- parser.elemReg := Repositories.registry;
- parser.reportError := MalformedXML;
- d := parser.Parse();
- IF errors THEN RETURN END;
- OpenXML(d);
- res := 0;
- END Open;
- PROCEDURE OpenXML*(d : XML.Document);
- VAR lp : Texts.LabelPiece;
- BEGIN
- errors := FALSE;
- doc := d;
- NEW(text);
- text.AcquireWrite;
- NEW(attr);
- root := doc.GetRoot();
- cont := root.GetContents(); cont.Reset();
- WHILE cont.HasMoreElements() DO
- ptr := cont.GetNext();
- IF ptr IS XML.Element THEN
- str := ptr(XML.Element).GetName();
- IF (str # NIL) & (str^ = "Label") THEN
- str := ptr(XML.Element).GetAttributeValue("name");
- IF str # NIL THEN NEW(lp); lp.label := Strings.NewString(str^); text.InsertPiece(text.GetLength(), lp) END;
- ELSIF (str # NIL) & (str^ = "Paragraph") THEN
- tc := ptr(XML.Element).GetContents(); tc.Reset();
- str := ptr(XML.Element).GetAttributeValue("style");
- IF str # NIL THEN COPY(str^, pstylename); END;
- WHILE tc.HasMoreElements() DO
- ptr := tc.GetNext();
- IF ptr IS XML.Element THEN
- str := ptr(XML.Element).GetName();
- IF (str # NIL) & (str^ = "Label") THEN
- str := ptr(XML.Element).GetAttributeValue("name");
- IF str # NIL THEN NEW(lp); lp.label := Strings.NewString(str^); text.InsertPiece(text.GetLength(), lp) END;
- ELSIF (str # NIL) & (str^ = "Span") THEN
- tc2 := ptr(XML.Element).GetContents(); tc2.Reset();
- str := ptr(XML.Element).GetAttributeValue("style"); IF str # NIL THEN COPY(str^, stylename); END;
- str := ptr(XML.Element).GetAttributeValue("link"); IF str # NIL THEN NEW(link, LEN(str^)); COPY(str^, link^); ELSE link := NIL; END;
- WHILE tc2.HasMoreElements() DO
- ptr := tc2.GetNext();
- IF ptr IS XML.CDataSect THEN InsertPiece(ptr(XML.CDataSect)) END;
- END;
- ELSIF (str # NIL) & (str^ = "Object") THEN
- tc2 := ptr(XML.Element).GetContents(); tc2.Reset();
- IF tc2.HasMoreElements() THEN
- NEW(o); o.object := tc2.GetNext(); text.InsertPiece(text.GetLength(), o);
- END
- END
- END
- END;
- (* Insert a newline to finish paragraph *)
- (* InsertChar(text.GetLength(), Texts.NewLineChar); *)
- ELSIF (str # NIL) & (str^ = "Span") THEN
- COPY("Left", pstylename);
- tc := ptr(XML.Element).GetContents(); tc.Reset();
- str := ptr(XML.Element).GetAttributeValue("style"); IF str # NIL THEN COPY(str^, stylename); END;
- str := ptr(XML.Element).GetAttributeValue("link"); IF str # NIL THEN NEW(link, LEN(str^)); COPY(str^, link^); ELSE link := NIL; END;
- WHILE tc.HasMoreElements() DO
- ptr := tc.GetNext();
- IF ptr IS XML.CDataSect THEN InsertPiece(ptr(XML.CDataSect)) END;
- END
- ELSIF (str # NIL) & (str^ = "Object") THEN
- tc := ptr(XML.Element).GetContents(); tc.Reset();
- IF tc.HasMoreElements() THEN
- NEW(o); o.object := tc.GetNext(); text.InsertPiece(text.GetLength(), o);
- END;
- END;
- END
- END;
- text.ReleaseWrite;
- END OpenXML;
- PROCEDURE GetText*() : Texts.Text;
- BEGIN
- RETURN text;
- END GetText;
- END BluebottleDecoder;
- BluebottleEncoder = OBJECT(Codecs.TextEncoder)
- VAR out: Streams.Writer;
- ch :Texts.Char32;
- r: Texts.TextReader;
- changed, pchanged, pOpen : BOOLEAN;
- stylename, pstylename: ARRAY 256 OF CHAR;
- cStyle: Texts.CharacterStyle;
- pStyle: Texts.ParagraphStyle;
- link : Texts.Link;
- (* hStyle: Texts.HighlightStyle; <-- TO DO
- *)
- (* Attributes attributes *)
- family, dfFamily : ARRAY 64 OF CHAR;
- size, dfSize : LONGINT;
- style, dfStyle : LONGINT; (* 0 = regular; 1 = bold; 2 = italic; 3 = bold-italic *)
- voff, dfVoff : LONGINT;
- color, dfColor : LONGINT;
- bgcolor, dfBgcolor : LONGINT;
- (* Set the default attribute values *)
- PROCEDURE Init;
- BEGIN
- dfFamily := "Oberon";
- dfSize := 10;
- dfStyle := 0;
- dfVoff := 0;
- dfColor := 0000000FFH;
- dfBgcolor := 000000000H;
- END Init;
- (* extract the attributes from the current textreader *)
- PROCEDURE RetrieveAttributes;
- VAR tempstring, string: ARRAY 128 OF CHAR;
- BEGIN
- (* Get Character Style if any *)
- IF (r.cstyle # NIL) THEN
- cStyle := r.cstyle;
- COPY(cStyle.name, stylename);
- COPY(cStyle.family, family);
- size := cStyle.size;
- IF (cStyle.style = {}) THEN style := 0; ELSIF (cStyle.style = {0}) THEN style := 1; ELSIF (cStyle.style = {1}) THEN style := 2; ELSIF (cStyle.style = {0,1}) THEN style := 3; ELSE style := 0; END;
- voff := cStyle.baselineShift;
- color := cStyle.color;
- bgcolor := cStyle.bgColor;
- ELSE
- cStyle := NIL;
- (* Get attributes from char *)
- IF (r.font = NIL) THEN (* Fix missing values *)
- family := dfFamily;
- size := dfSize;
- style := dfStyle;
- ELSE
- COPY(r.font.name, family);
- size := r.font.size;
- IF (r.font.style = {}) THEN style := 0; ELSIF (r.font.style = {0}) THEN style := 1; ELSIF (r.font.style = {1}) THEN style := 2; ELSIF (r.font.style = {0,1}) THEN style := 3; ELSE style := 0; END;
- END;
- voff := r.voff;
- color := r.color;
- bgcolor := r.bgcolor;
- (* Find appropriate style *)
- IF (color = 0000000FFH) & (style = 0) THEN stylename := "Normal"
- ELSIF (color = 0000000FFH) & (style = 1) THEN stylename := "Bold"
- ELSIF (color = 0000000FFH) & (style = 2) THEN stylename := "Highlight"
- ELSIF ((color = 00000FFFFH) OR (color = 00000AAFFH)) & (style = 1) THEN stylename := "Assertion"
- ELSIF (color = 00000FFFFH) & (style = 0) THEN stylename := "Debug"
- ELSIF (color = 0FF00FFFFH) & (style = 0) THEN stylename := "Lock"
- ELSIF (color = 0FF0000FFH) & (style = 0) THEN stylename := "Stupid"
- ELSIF ((color = 0808080FFH) OR (color = 08A8A8AFFH)) & (style = 0) THEN stylename := "Comment"
- ELSIF (color = 0800080FFH) & (style = 1) THEN stylename := "Preferred"
- ELSE
- tempstring := "AdHoc"; Strings.Append(tempstring, " ");
- Strings.Append(tempstring, family); Strings.Append(tempstring, " ");
- Strings.IntToStr(size, string); Strings.Append(tempstring, string); Strings.Append(tempstring, " ");
- Strings.IntToStr(style, string); Strings.Append(tempstring, string); Strings.Append(tempstring, " ");
- Strings.IntToStr(voff, string); Strings.Append(tempstring, string); Strings.Append(tempstring, " ");
- Strings.IntToHexStr(color,7, string); Strings.Append(tempstring, string); Strings.Append(tempstring, " ");
- Strings.IntToHexStr(bgcolor,7, string); Strings.Append(tempstring, string);
- COPY(tempstring, stylename);
- (* KernelLog.String("Writing Ad-hoc Style: "); KernelLog.String(tempstring); KernelLog.Ln; *)
- END;
- END;
- (* Get Paragraph Style if any *)
- IF (r.pstyle # NIL) THEN
- pStyle := r.pstyle;
- COPY(pStyle.name, pstylename)
- ELSE
- pStyle := NIL;
- COPY("", pstylename)
- END;
- (* Get Link if any *)
- IF (r.link # NIL) THEN
- link := r.link;
- ELSE
- link := NIL;
- END;
- END RetrieveAttributes;
- PROCEDURE PrintAttributes;
- BEGIN
- KernelLog.String("# family: "); KernelLog.String(family); KernelLog.Ln;
- KernelLog.String("# size: "); KernelLog.Int(size, 0); KernelLog.Ln;
- KernelLog.String("# style: "); KernelLog.Int(style, 0); KernelLog.Ln;
- KernelLog.String("# voff: "); KernelLog.Int(voff, 0); KernelLog.Ln;
- KernelLog.String("# color: "); KernelLog.Hex(color, 0); KernelLog.Ln;
- KernelLog.String("# bgcolor: "); KernelLog.Hex(bgcolor, 0); KernelLog.Ln;
- END PrintAttributes;
- (* Return TRUE if current textreader attributes don't match the chached one *)
- PROCEDURE CompareAttributes():BOOLEAN;
- VAR tempstyle: LONGINT;
- isEqual : BOOLEAN;
- BEGIN
- IF (link = r.link) THEN
- IF r.cstyle # NIL THEN
- isEqual := (stylename = r.cstyle.name);
- RETURN ~isEqual;
- ELSE
- IF (r.font = NIL) THEN
- isEqual := (family = dfFamily) & (size = dfSize) & (style = dfStyle) & (voff = r.voff) & (color = r.color) & (bgcolor = r.bgcolor);
- ELSE
- IF (r.font.style = {}) THEN tempstyle := 0; ELSIF (r.font.style = {0}) THEN tempstyle := 1; ELSIF (r.font.style = {1}) THEN tempstyle := 2; ELSIF (r.font.style = {0,1}) THEN tempstyle := 3; ELSE tempstyle := 0; END;
- isEqual := (family = r.font.name) & (size = r.font.size) & (style = tempstyle) & (voff = r.voff) & (color = r.color) & (bgcolor = r.bgcolor);
- END;
- RETURN ~isEqual;
- END;
- ELSE
- RETURN TRUE;
- END
- END CompareAttributes;
- (* Return TRUE if current textreader paragraphstyle doesn't match the chached one *)
- PROCEDURE CompareParagraphs(): BOOLEAN;
- VAR isEqual : BOOLEAN;
- BEGIN
- IF r.pstyle # NIL THEN
- isEqual := (pstylename = r.pstyle.name);
- RETURN ~isEqual
- ELSIF (r.pstyle = NIL) & (pStyle = NIL) THEN
- RETURN FALSE;
- ELSE
- RETURN TRUE;
- END;
- END CompareParagraphs;
- PROCEDURE WriteParagraph(CONST name : ARRAY OF CHAR);
- BEGIN
- pOpen := TRUE;
- out.String("<Paragraph ");
- out.String('style="'); out.String(name); out.String('"');
- out.String(">")
- END WriteParagraph;
- PROCEDURE CloseParagraph;
- BEGIN
- IF pOpen THEN
- out.String("</Paragraph>");
- pOpen := FALSE;
- END;
- END CloseParagraph;
- PROCEDURE WriteSpan(CONST name: ARRAY OF CHAR);
- BEGIN
- out.String("<Span ");
- out.String('style="'); out.String(name); out.String('"');
- IF link # NIL THEN
- out.String(' link="'); out.String(link^); out.String('"');
- END;
- out.String("><![CDATA[")
- END WriteSpan;
- PROCEDURE CloseSpan;
- BEGIN
- out.String("]]></Span>");
- END CloseSpan;
- PROCEDURE WriteObject(o : ANY);
- BEGIN
- out.Ln;
- out.String("<Object>");
- IF (o # NIL) & (o IS XML.Element) THEN
- o(XML.Element).Write(out, NIL, 1);
- END;
- out.String("</Object>");out.Ln;
- END WriteObject;
- PROCEDURE WriteLabel(CONST label: ARRAY OF CHAR);
- BEGIN
- out.String("<Label ");
- out.String('name="'); out.String(label); out.String('"/>');
- END WriteLabel;
- PROCEDURE Open*(out : Streams.Writer);
- BEGIN
- IF out = NIL THEN KernelLog.String("Bluebottle Encoder Error: output stream is NIL");
- ELSE SELF.out := out;
- END;
- END Open;
- PROCEDURE WriteText*(text : Texts.Text; VAR res : WORD);
- VAR
- buf : Strings.String; rbuf : ARRAY 4 OF CHAR;
- bytesPerChar, length, counter : LONGINT;
- PROCEDURE ExpandBuf(VAR oldBuf: Strings.String; newSize: LONGINT);
- VAR newBuf: Strings.String; i: LONGINT;
- BEGIN
- IF LEN(oldBuf^) >= newSize THEN RETURN END;
- NEW(newBuf, newSize);
- FOR i := 0 TO LEN(oldBuf^)-1 DO
- newBuf[i] := oldBuf[i];
- END;
- oldBuf := newBuf;
- END ExpandBuf;
- BEGIN
- Init;
- res := 1;
- out.String('<?xml version="1.0" encoding="UTF-8"?>'); out.Ln;
- out.String('<?bluebottle format version="0.1" ?>'); out.Ln;
- out.String('<?xml-stylesheet type="text/xsl" href="http://bluebottle.ethz.ch/bluebottle.xsl" ?>'); out.Ln;
- out.String("<Text>"); out.Ln;
- text.AcquireRead;
- NEW(r, text);
- r.ReadCh(ch);
- IF (ch = Texts.LabelChar) THEN WriteLabel(r.object(Texts.LabelPiece).label^) END;
- RetrieveAttributes;
- PrintAttributes;
- IF (pStyle # NIL) & (pstylename # "Left") THEN WriteParagraph(pstylename) END;
- WriteSpan(stylename);
- bytesPerChar := 2;
- length := text.GetLength();
- NEW(buf, length * bytesPerChar); (* UTF8 encoded characters use up to 5 bytes *)
- counter := 0; COPY(" ", rbuf);
- WHILE ~r.eot DO
- WHILE ~UTF8Strings.EncodeChar(ch, buf^, counter) DO
- INC(bytesPerChar);
- ASSERT(bytesPerChar <= 5);
- ExpandBuf(buf, bytesPerChar * length);
- END;
- (* CDATA escape fix *)
- rbuf[0] := rbuf[1]; rbuf[1] := rbuf[2]; rbuf[2] := CHR(ch);
- IF (rbuf = "]]>") THEN
- buf[counter] := 0X;
- out.String(buf^); out.String("]]><![CDATA["); counter := 0;
- buf[counter] := CHR(ch);
- END;
- r.ReadCh(ch);
- IF ch = Texts.ObjectChar THEN
- buf[counter] := 0X; out.String(buf^); counter := 0; COPY(" ", rbuf);
- CloseSpan;
- WriteObject(r.object);
- RetrieveAttributes;
- IF ~r.eot THEN WriteSpan(stylename) END
- ELSIF ch = Texts.LabelChar THEN
- buf[counter] := 0X; out.String(buf^); counter := 0; COPY(" ", rbuf);
- CloseSpan;
- WriteLabel(r.object(Texts.LabelPiece).label^);
- RetrieveAttributes;
- IF ~r.eot THEN WriteSpan(stylename) END
- ELSE
- pchanged := CompareParagraphs();
- changed := CompareAttributes();
- IF pchanged THEN
- RetrieveAttributes;
- IF ~r.eot THEN
- buf[counter] := 0X; out.String(buf^); counter := 0; COPY(" ", rbuf);
- CloseSpan;
- CloseParagraph;
- IF (pStyle # NIL) & (pstylename # "Left") THEN WriteParagraph(pstylename) END;
- WriteSpan(stylename)
- END
- ELSIF changed THEN
- RetrieveAttributes;
- IF ~r.eot THEN
- buf[counter] := 0X; out.String(buf^); counter := 0; COPY(" ", rbuf);
- CloseSpan; WriteSpan(stylename)
- END
- END
- END
- END;
- buf[counter] := 0X;
- out.String(buf^);
- CloseSpan; out.Ln;
- CloseParagraph; out.Ln;
- out.String("</Text>"); out.Ln;
- out.Update;
- text.ReleaseRead;
- res := 0
- END WriteText;
- END BluebottleEncoder;
- UTF8Decoder = OBJECT(Codecs.TextDecoder)
- VAR errors : BOOLEAN;
- in : Streams.Reader;
- text : Texts.Text;
- PROCEDURE Error(CONST x : ARRAY OF CHAR);
- BEGIN
- KernelLog.String("UTF-8 Decoder Error: ");
- KernelLog.String(x); KernelLog.Ln;
- errors := TRUE
- END Error;
- PROCEDURE Open*(in : Streams.Reader; VAR res : WORD);
- VAR i, m: LONGINT;
- tempUCS32 : ARRAY 1024 OF Char32;
- ch, last : Texts.Char32;
- BEGIN
- errors := FALSE;
- res := -1;
- IF in = NIL THEN Error("Input Stream is NIL"); RETURN; END;
- SELF.in := in;
- NEW(text);
- text.AcquireWrite;
- m := LEN(tempUCS32) - 1;
- i := 0;
- REPEAT
- IF GetUTF8Char(in, ch) THEN
- IF i = m THEN tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32); i := 0 END;
- IF (last # ORD(CR)) OR (ch # ORD(LF)) THEN
- IF ch = ORD(CR) THEN tempUCS32[i] := ORD(LF)
- ELSE tempUCS32[i] := ch
- END;
- INC(i)
- END;
- last := ch
- END
- UNTIL (in.res # Streams.Ok);
- tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32);
- (* Set this text explicitly to UTF, which allows it to be reformatted by the bidi formatter *)
- text.SetUTF(TRUE);
- res := 0;
- text.ReleaseWrite
- END Open;
- PROCEDURE GetText*() : Texts.Text;
- BEGIN
- RETURN text;
- END GetText;
- END UTF8Decoder;
- UTF8Encoder = OBJECT(Codecs.TextEncoder)
- VAR out: Streams.Writer;
- PROCEDURE Open*(out : Streams.Writer);
- BEGIN
- IF out = NIL THEN KernelLog.String("UTF-8 Encoder Error: output stream is NIL");
- ELSE SELF.out := out;
- END;
- END Open;
- PROCEDURE WriteText*(text : Texts.Text; VAR res : WORD);
- VAR r : Texts.TextReader; ch : Texts.Char32; i, p : LONGINT; resstr : ARRAY 7 OF CHAR;
- BEGIN
- res := -1;
- text.AcquireRead;
- NEW(r, text);
- FOR i := 0 TO text.GetLength() - 1 DO
- r.ReadCh(ch); p := 0;
- IF (ch > 0) & UTF8Strings.EncodeChar(ch, resstr, p) THEN out.String(resstr) END
- END;
- out.Update;
- text.ReleaseRead;
- res := 0;
- END WriteText;
- END UTF8Encoder;
- ISO88591Decoder = OBJECT(Codecs.TextDecoder)
- VAR errors : BOOLEAN;
- in : Streams.Reader;
- text : Texts.Text;
- PROCEDURE Error(CONST x : ARRAY OF CHAR);
- BEGIN
- KernelLog.String("ISO8859-1 Decoder Error: ");
- KernelLog.String(x); KernelLog.Ln;
- errors := TRUE
- END Error;
- PROCEDURE Open*(in : Streams.Reader; VAR res : WORD);
- VAR i, m: LONGINT;
- tempUCS32 : ARRAY 1024 OF Char32;
- ch, last : CHAR;
- BEGIN
- errors := FALSE;
- res := -1;
- IF in = NIL THEN Error("Input Stream is NIL"); RETURN; END;
- SELF.in := in;
- NEW(text);
- text.AcquireWrite;
- m := LEN(tempUCS32) - 1;
- i := 0;
- REPEAT
- in.Char(ch);
- IF i = m THEN tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32); i := 0 END;
- IF (last # CR) OR (ch # LF) THEN
- IF ch = CR THEN tempUCS32[i] := ORD(LF)
- ELSE tempUCS32[i] := ORD(ch)
- END;
- INC(i)
- END;
- last := ch
- UNTIL (in.res # Streams.Ok);
- tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32);
- res := 0;
- text.ReleaseWrite
- END Open;
- PROCEDURE GetText*() : Texts.Text;
- BEGIN
- RETURN text;
- END GetText;
- END ISO88591Decoder;
- ISO88591Encoder = OBJECT(Codecs.TextEncoder)
- VAR out: Streams.Writer;
- PROCEDURE Open*(out : Streams.Writer);
- BEGIN
- IF out = NIL THEN KernelLog.String("ISO8859-1 Encoder Error: output stream is NIL");
- ELSE SELF.out := out;
- END;
- END Open;
- PROCEDURE WriteText*(text : Texts.Text; VAR res : WORD);
- VAR r : Texts.TextReader; ch : Texts.Char32; i : LONGINT;
- BEGIN
- res := -1;
- text.AcquireRead;
- NEW(r, text);
- FOR i := 0 TO text.GetLength() - 1 DO
- r.ReadCh(ch);
- IF (ch >= 0) & (ch < 256) THEN out.Char(CHR(ch)) END
- END;
- out.Update;
- text.ReleaseRead;
- res := 0;
- END WriteText;
- END ISO88591Encoder;
- HEXDecoder = OBJECT(Codecs.TextDecoder)
- VAR errors : BOOLEAN;
- in : Streams.Reader;
- text : Texts.Text;
- PROCEDURE Error(CONST x : ARRAY OF CHAR);
- BEGIN
- KernelLog.String("HEX Decoder Error: ");
- KernelLog.String(x); KernelLog.Ln;
- errors := TRUE
- END Error;
- PROCEDURE Open*(in : Streams.Reader; VAR res : WORD);
- VAR i, j, m : LONGINT;
- tempUCS32 : ARRAY 1057 OF Char32; (* 1025 *)
- ch : CHAR;
- byte : ARRAY 3 OF CHAR;
- attr: Texts.Attributes; fi : Texts.FontInfo;
- BEGIN
- errors := FALSE;
- res := -1;
- IF in = NIL THEN Error("Input Stream is NIL"); RETURN; END;
- SELF.in := in;
- NEW(text); NEW(attr); NEW(fi);
- fi.name := "Courier";
- fi.size := 10;
- fi.style := {};
- attr.voff := 0;
- attr.color := 0000000FFH;
- attr.bgcolor := 000000000H;
- attr.fontInfo := fi;
- text.AcquireWrite;
- m := LEN(tempUCS32) - 1;
- i := 0; j := 0;
- REPEAT
- in.Char(ch);
- IF (i = m) THEN tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32); i := 0 END;
- Strings.IntToHexStr(ORD(ch), 1, byte);
- tempUCS32[i] := ORD(byte[0]); INC(i);
- tempUCS32[i] := ORD(byte[1]); INC(i);
- tempUCS32[i] := ORD(TAB); INC(i); (* formatting space *)
- INC(j);
- IF (j = 16) THEN j := 0; tempUCS32[i-1] := ORD(LF); END;
- UNTIL (in.res # Streams.Ok);
- tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32);
- res := 0;
- text.SetAttributes(0, text.GetLength(), attr.Clone());
- text.ReleaseWrite
- END Open;
- PROCEDURE GetText*() : Texts.Text;
- BEGIN
- RETURN text;
- END GetText;
- END HEXDecoder;
- HEXEncoder = OBJECT(Codecs.TextEncoder)
- VAR out: Streams.Writer;
- PROCEDURE Open*(out : Streams.Writer);
- BEGIN
- IF out = NIL THEN KernelLog.String("HEX Encoder Error: output stream is NIL");
- ELSE SELF.out := out;
- END;
- END Open;
- PROCEDURE WriteText*(text : Texts.Text; VAR res : WORD);
- VAR r : Texts.TextReader; ch : Texts.Char32; i, j: LONGINT; k : WORD;
- byte : ARRAY 2 OF CHAR;
- BEGIN
- res := -1;
- text.AcquireRead;
- NEW(r, text);
- i := 0;
- FOR i := 0 TO text.GetLength() - 1 DO
- r.ReadCh(ch);
- IF ((ch >= 48) & (ch <= 57)) OR ((ch >= 65) & (ch <= 70)) OR ((ch >= 97) & (ch <= 102)) THEN
- byte[j] := CHR(ch); INC(j);
- END;
- IF (j = 2) THEN j := 0; Strings.HexStrToInt(byte, ch, k); out.Char(CHR(ch)); END;
- END;
- out.Update;
- text.ReleaseRead;
- res := 0;
- END WriteText;
- END HEXEncoder;
- VAR
- unicodePropertyReader : UnicodeProperties.UnicodeTxtReader;
- oberonFontAllocatable*: PROCEDURE( CONST name: ARRAY OF CHAR ): BOOLEAN;
- (* ----------------------------------------------------------------------------------- *)
- (* Return true if the unicode character x should be regarded as a white-space *)
- PROCEDURE IsWhiteSpace*(x : Char32; utf : BOOLEAN) : BOOLEAN;
- BEGIN
- (* lazy initialization of the Unicode Property Reader *)
- IF utf & (unicodePropertyReader = NIL) THEN
- NEW(unicodePropertyReader);
- END;
- (* distinguish between utf-whitespaces and ascii-whitespaces *)
- IF utf THEN
- RETURN (x <= 32) OR
- ((unicodePropertyReader # NIL) & unicodePropertyReader.IsWhiteSpaceChar(x)) OR
- (x = 0A0H) OR (x = 200BH);
- ELSE
- RETURN (x <= 32);
- END;
- END IsWhiteSpace;
- (* Return true if the unicode character x is alpha numeric *)
- PROCEDURE IsAlphaNum*(x:Char32): BOOLEAN;
- BEGIN
- RETURN (ORD("0") <= x) & (x <= ORD("9"))
- OR (ORD("A") <= x) & (x <= ORD("Z") )
- OR (ORD("a") <= x) & (x <= ORD("z") )
- END IsAlphaNum;
- (** Find the position of the next word start to the left *)
- PROCEDURE FindPosWordLeft*(utilreader: Texts.TextReader; pos : LONGINT) : LONGINT;
- VAR ch : Texts.Char32;
- new : LONGINT;
- BEGIN
- utilreader.SetPosition(pos); utilreader.SetDirection(-1);
- utilreader.ReadCh(ch);
- (* special treatment for utf-formatted texts *)
- IF ~utilreader.text.isUTF THEN
- WHILE (IsWhiteSpace(ch,FALSE) & (ch # Texts.NewLineChar)) & (~utilreader.eot) DO
- utilreader.ReadCh(ch)
- END;
- WHILE (IsAlphaNum(ch)) & (~utilreader.eot) DO
- utilreader.ReadCh(ch);
- END;
- ELSE
- WHILE IsWhiteSpace(ch,TRUE) & (ch # Texts.NewLineChar) & ~utilreader.eot DO
- utilreader.ReadCh(ch);
- END;
- WHILE ~IsWhiteSpace(ch,TRUE) & ~utilreader.eot DO
- utilreader.ReadCh(ch);
- END
- END;
- new := utilreader.GetPosition() + 1;
- IF utilreader.eot THEN
- RETURN 0
- ELSIF new = pos THEN
- RETURN new
- ELSE
- RETURN new + 1
- END
- END FindPosWordLeft;
- (** Find the position of the next word start to the right *)
- PROCEDURE FindPosWordRight*(utilreader: Texts.TextReader; pos : LONGINT) : LONGINT;
- VAR ch : Texts.Char32;
- new : LONGINT;
- BEGIN
- utilreader.SetPosition(pos); utilreader.SetDirection(1);
- utilreader.ReadCh(ch);
- (* special treatment for utf-formatted texts *)
- IF ~utilreader.text.isUTF THEN
- WHILE (IsAlphaNum(ch)) & (~utilreader.eot) DO
- utilreader.ReadCh(ch)
- END;
- WHILE (IsWhiteSpace(ch,FALSE) & (ch # Texts.NewLineChar)) & (~utilreader.eot) DO
- utilreader.ReadCh(ch)
- END;
- ELSE
- WHILE ~IsWhiteSpace(ch,TRUE) & ~utilreader.eot DO
- utilreader.ReadCh(ch);
- END;
- WHILE IsWhiteSpace(ch,TRUE) & (ch # Texts.NewLineChar) & ~utilreader.eot DO
- utilreader.ReadCh(ch);
- END;
- END;
- new := utilreader.GetPosition()-1;
- IF utilreader.eot THEN
- RETURN utilreader.text.GetLength()
- ELSIF new = pos THEN
- RETURN new+1
- ELSE
- RETURN new
- END
- END FindPosWordRight;
- (* rearch left until the first NewLineChar is encountered. Return the position of the following character *)
- PROCEDURE FindPosLineStart* (utilreader: Texts.TextReader; pos: LONGINT): LONGINT;
- VAR ch : Texts.Char32;
- BEGIN
- utilreader.SetPosition(pos - 1);
- utilreader.SetDirection(-1);
- utilreader.ReadCh(ch);
- WHILE (ch # Texts.NewLineChar) & (~utilreader.eot) DO utilreader.ReadCh(ch) END;
- IF utilreader.eot THEN RETURN 0
- ELSE RETURN utilreader.GetPosition() + 2
- END
- END FindPosLineStart;
- (** Search right in the text until the first non whitespace is encountered. Return the number of whitespace characters *)
- PROCEDURE CountWhitespace* (utilreader: Texts.TextReader; pos: LONGINT): LONGINT;
- VAR ch : Texts.Char32;
- count : LONGINT;
- BEGIN
- utilreader.SetPosition(pos);
- utilreader.SetDirection(1);
- utilreader.ReadCh(ch);
- count := 0;
- WHILE (IsWhiteSpace(ch,utilreader.text.isUTF)) & (ch # Texts.NewLineChar) & (~utilreader.eot) DO
- INC(count);
- utilreader.ReadCh(ch)
- END;
- RETURN count
- END CountWhitespace;
- (** Procedure to load File without explicit given Format - appropriate Format will be chosen automaticaly *)
- PROCEDURE LoadAuto*(text: Text; CONST fileName: ARRAY OF CHAR; VAR format: LONGINT; VAR res: WORD);
- VAR f : Files.File; re : Files.Reader; ri: Files.Rider; ch: CHAR; fstring: ARRAY 64 OF CHAR; i: LONGINT;
- BEGIN
- (* KernelLog.String("Auto Format.... "); KernelLog.Ln; *)
- text.AcquireWrite;
- res := -1; format := -1;
- f := Files.Old(fileName);
- IF f # NIL THEN
- Files.OpenReader(re, f, 0);
- f.Set(ri, 0);
- f.Read(ri, ch); i := ORD(ch);
- IF (i = 0F0H) OR (i = 0F7H) OR (i = 01H) THEN (* Oberon File Format *)
- format := 0;
- ELSIF (i = 03CH) THEN (* possibly an XML, check further *)
- (* check IF just an XML or BB Format *)
- f.Set(ri, 0);
- Files.ReadString(ri, fstring);
- Strings.UpperCase(fstring);
- IF Strings.Match("<?XML VERSION=*", fstring) THEN
- IF Strings.Match("*<?BLUEBOTTLE FORMAT*", fstring) THEN
- format := 1; (* Bluebottle File Format *)
- ELSE
- format := 2; (* XML - treat as UTF-8 *)
- END;
- ELSE
- format := 2; (* Text/Other - treat as UTF-8 *)
- END;
- ELSE (* Neither Oberon nor XML/BB *)
- format := 2;
- END;
- END;
- text.ReleaseWrite;
- (* call correct loader *)
- CASE format OF
- | 0: LoadOberonText(text, fileName, res);
- | 1: LoadText(text, fileName, res);
- | 2: LoadUTF8(text, fileName, res);
- ELSE
- LoadUTF8(text, fileName, res)
- END
- END LoadAuto;
- (** Procedure to get decoder for the given file - appropriate Format will be chosen automaticaly *)
- PROCEDURE DecodeAuto*( CONST fileName: ARRAY OF CHAR; VAR format: ARRAY OF CHAR): Codecs.TextDecoder;
- VAR reader : Streams.Reader; decoder : Codecs.TextDecoder; fstring : ARRAY 64 OF CHAR; i : LONGINT;
- BEGIN
- reader := Codecs.OpenInputStream(fileName);
- IF (reader # NIL) THEN
- reader.String(fstring);
- i := ORD(fstring[0]);
- IF (i = 0F0H) OR (i = 0F7H) OR (i = 01H) THEN
- COPY("Oberon", format); (* Oberon File Format *)
- ELSIF (i = 03CH) THEN
- (* possibly an XML, check further, check IF just an XML or BB Format *)
- Strings.UpperCase(fstring);
- IF Strings.Match("<?XML VERSION=*", fstring) THEN
- IF Strings.Match("*<?BLUEBOTTLE FORMAT*", fstring) THEN
- COPY("BBT", format); (* Bluebottle File Format *)
- ELSE
- COPY("UTF-8", format); (* XML - treat as UTF-8 *)
- END;
- ELSE
- COPY("UTF-8", format); (* Text/Other - treat as UTF-8 *)
- END;
- ELSE
- COPY("UTF-8", format); (* Neither Oberon nor XML/BB *)
- END;
- ELSE
- COPY("", format); (* Could not open input stream *)
- END;
- decoder := Codecs.GetTextDecoder(format);
- RETURN decoder;
- END DecodeAuto;
- (** Load text using codecs *)
- PROCEDURE Load*(text : Text; CONST filename, format : ARRAY OF CHAR; VAR res : WORD);
- VAR decoder : Codecs.TextDecoder; in: Streams.Reader; t : Text;
- BEGIN
- ASSERT(text # NIL);
- decoder := Codecs.GetTextDecoder(format);
- IF (decoder # NIL) THEN
- in := Codecs.OpenInputStream(filename);
- IF ( in # NIL) THEN
- decoder.Open(in, res);
- IF (res = Ok) THEN
- t := decoder.GetText();
- t.AcquireRead;
- text.AcquireWrite;
- text.CopyFromText(t, 0, t.GetLength(), 0);
- text.ReleaseWrite;
- t.ReleaseRead;
- END;
- ELSE
- res := FileNotFound;
- END;
- ELSE
- res := CodecNotFound;
- END;
- END Load;
- (** Import text in ASCII format. *)
- PROCEDURE LoadAscii*(text : Text; CONST filename : ARRAY OF CHAR; VAR res : WORD);
- BEGIN
- Load(text, filename, "ISO8859-1", res)
- END LoadAscii;
- (** Import text in UTF8 format. *)
- PROCEDURE LoadUTF8*(text : Text; CONST filename : ARRAY OF CHAR; VAR res : WORD);
- BEGIN
- Load(text, filename, "UTF-8", res)
- END LoadUTF8;
- (** import text in UCS16 format *)
- PROCEDURE LoadUCS16*(text : Text; CONST filename : ARRAY OF CHAR; VAR res : WORD);
- VAR f : Files.File; r : Files.Reader;
- i, m : LONGINT;
- tempUCS32 : ARRAY 1024 OF Char32;
- ch, last : Char32; tc1, tc2 : CHAR;
- BEGIN
- text.AcquireWrite;
- res := -1;
- f := Files.Old(filename);
- IF f # NIL THEN
- m := LEN(tempUCS32) - 1;
- Files.OpenReader(r, f, 0);
- i := 0;
- REPEAT
- r.Char(tc1); r.Char(tc2); ch := ORD(tc1) * 256 + ORD(tc2);
- IF i = m THEN tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32); i := 0 END;
- IF (last # ORD(CR)) OR (ch # ORD(LF)) THEN
- IF ch = ORD(CR) THEN tempUCS32[i] := ORD(LF)
- ELSE tempUCS32[i] := ch
- END;
- INC(i)
- END;
- last := ch
- UNTIL (r.res # Streams.Ok);
- tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32);
- res := Ok;
- ELSE
- res := FileNotFound;
- END;
- text.ReleaseWrite;
- END LoadUCS16;
- (** Import an Oberon Text *)
- PROCEDURE LoadOberonText*(text: Text; CONST fileName: ARRAY OF CHAR; VAR res: WORD);
- BEGIN
- Load(text, fileName, "Oberon", res)
- END LoadOberonText;
- (** Import a BBT Text *)
- PROCEDURE LoadText*(text : Texts.Text; CONST filename : ARRAY OF CHAR; VAR res : WORD);
- BEGIN
- Load(text, filename, "BBT", res)
- END LoadText;
- (** store text using codecs *)
- PROCEDURE Store*(text : Text; CONST filename, format : ARRAY OF CHAR; VAR res : WORD);
- VAR file : Files.File; w : Files.Writer; encoder : Codecs.TextEncoder;
- BEGIN
- ASSERT(text # NIL);
- encoder := Codecs.GetTextEncoder(format);
- IF (encoder # NIL) THEN
- file := Files.New(filename);
- IF (file # NIL) THEN
- NEW(w, file, 0);
- text.AcquireRead;
- encoder.Open(w);
- encoder.WriteText(text, res);
- text.ReleaseRead;
- IF (res = Ok) THEN
- Files.Register(file); file.Update;
- END;
- ELSE
- res := FileCreationError;
- END;
- ELSE
- res := CodecNotFound;
- END;
- END Store;
- (** Export text in ASCII format. Objects, attributes and characters > CHR(128) are lost *)
- PROCEDURE ExportAscii*(text : Text; CONST fileName : ARRAY OF CHAR; VAR res : WORD);
- BEGIN
- Store(text, fileName, "ISO8859-1", res)
- END ExportAscii;
- (** Export text in UTF8 format Objects and attributes are lost *)
- PROCEDURE ExportUTF8*(text : Text; CONST fileName : ARRAY OF CHAR; VAR res : WORD);
- BEGIN
- Store(text, fileName, "UTF-8", res)
- END ExportUTF8;
- (** Export text in Oberon format Objects are lost *)
- PROCEDURE StoreOberonText*(text : Text; CONST fileName: ARRAY OF CHAR; VAR res : WORD);
- BEGIN
- Store(text, fileName, "Oberon", res)
- END StoreOberonText;
- (** Export text in Bluebottle format *)
- PROCEDURE StoreText*(text : Texts.Text; CONST fileName : ARRAY OF CHAR; VAR res : WORD);
- BEGIN
- Store(text, fileName, "BBT", res)
- END StoreText;
- (** Text to UTF8 string. Objects and attributes are lost. The String is truncated if buffer is too small *)
- PROCEDURE TextToStr*(text : Text; VAR string : ARRAY OF CHAR);
- VAR i, l, pos : LONGINT; r : Texts.TextReader; ch : Texts.Char32; ok : BOOLEAN;
- BEGIN
- text.AcquireRead;
- COPY("", string);
- NEW(r, text);
- i := 0; l := text.GetLength(); pos := 0; ok := TRUE;
- WHILE (i < l) & ok DO
- r.ReadCh(ch);
- IF (ch > 0) THEN ok := UTF8Strings.EncodeChar(ch, string, pos) END;
- INC(i)
- END;
- text.ReleaseRead
- END TextToStr;
- (** Write <length> characters starting at <start> to stream <w>. Objects and attributes are lost
- Caller MUST HOLD lock!!! *)
- PROCEDURE SubTextToStream*(text : Text; start, length : LONGINT; w : Streams.Writer);
- VAR r : Texts.TextReader; ok : BOOLEAN; ch : Texts.Char32; buffer : ARRAY 6 OF CHAR; i : LONGINT;
- BEGIN
- ASSERT((text # NIL) & (text.HasReadLock()));
- ASSERT((0 <= start) & (length >= 0) & (start + length <= text.GetLength()));
- ASSERT(w # NIL);
- IF (length > 0) THEN
- NEW(r, text);
- r.SetPosition(start);
- ok := TRUE;
- r.ReadCh(ch);
- WHILE (length > 0) & (w.res = Streams.Ok) DO
- ASSERT(ch # 0); (* we already checked start + length <= text.GetLength()) *)
- i := 0;
- ok := UTF8Strings.EncodeChar(ch, buffer, i);
- ASSERT(ok & (i < LEN(buffer))); (* buffer is always large enough *)
- buffer[i] := 0X;
- w.String(buffer);
- r.ReadCh(ch); (* we may read past start + length / end-of-text *)
- DEC(length);
- END;
- END;
- END SubTextToStream;
- (** Text to stream as UTF-8. Objects and attributes are lost. *)
- PROCEDURE TextToStream*(text : Text; w : Streams.Writer);
- VAR length : LONGINT;
- BEGIN
- ASSERT((text # NIL) & (w # NIL));
- text.AcquireRead;
- length := text.GetLength();
- IF (length > 0) THEN
- SubTextToStream(text, 0, length, w);
- END;
- text.ReleaseRead;
- END TextToStream;
- (** Text to UTF8 string. Objects and attributes are lost. The String is truncated if buffer is too small *)
- PROCEDURE SubTextToStrAt*(text : Text; startPos, len : LONGINT; VAR index : LONGINT; VAR string : ARRAY OF CHAR);
- VAR i, length, pos : LONGINT; r : Texts.TextReader; ch : Texts.Char32; ok : BOOLEAN;
- BEGIN
- ASSERT((0 <= index) & (index < LEN(string)));
- text.AcquireRead;
- string[index] := 0X;
- NEW(r, text);
- r.SetPosition(startPos);
- i := 0; length := len; pos := index; ok := TRUE;
- WHILE (i < length) & ok DO
- r.ReadCh(ch);
- IF (ch > 0) THEN ok := UTF8Strings.EncodeChar(ch, string, pos) END;
- INC(i);
- END;
- IF (pos < LEN(string)) THEN
- index := pos;
- ELSE
- index := LEN(string)-1;
- string[index] := 0X;
- END;
- text.ReleaseRead;
- ASSERT((0 <= index) & (index < LEN(string)));
- END SubTextToStrAt;
- (** Text to UTF8 string. Objects and attributes are lost. The String is truncated if buffer is too small *)
- PROCEDURE SubTextToStr*(text : Text; startPos, len : LONGINT; VAR string : ARRAY OF CHAR);
- VAR index : LONGINT;
- BEGIN
- index := 0;
- SubTextToStrAt(text, startPos, len, index, string);
- END SubTextToStr;
- (** insert utf8 string into text *)
- PROCEDURE StrToText*(text : Text; pos : LONGINT; CONST string : ARRAY OF CHAR);
- VAR r : Streams.StringReader;
- i, m: LONGINT;
- tempUCS32 : ARRAY 1024 OF Char32;
- ch, last : Texts.Char32;
- BEGIN
- text.AcquireWrite;
- NEW(r, LEN(string));
- m := LEN(tempUCS32) - 1;
- r.Set(string);
- i := 0;
- REPEAT
- IF GetUTF8Char(r, ch) THEN
- IF i = m THEN tempUCS32[i] := 0; text.InsertUCS32(pos, tempUCS32); INC(pos, m); i := 0 END;
- IF (last # ORD(CR)) OR (ch # ORD(LF)) THEN
- IF ch = ORD(CR) THEN tempUCS32[i] := ORD(LF)
- ELSE tempUCS32[i] := ch
- END;
- INC(i)
- END;
- last := ch
- END
- UNTIL (r.res # Streams.Ok);
- tempUCS32[i] := 0; text.InsertUCS32(pos, tempUCS32);
- text.ReleaseWrite
- END StrToText;
- PROCEDURE IsDigit( ch: CHAR ): BOOLEAN;
- BEGIN
- RETURN (ch >= '0') & (ch <= '9')
- END IsDigit;
- PROCEDURE DecodeOberonFontName(CONST name : ARRAY OF CHAR; VAR fn : ARRAY OF CHAR; VAR size : LONGINT; VAR style : SET);
- VAR i, j: LONGINT; sizeStr : ARRAY 8 OF CHAR;
- BEGIN
- (* first name in oberon font names is capital, all following are non-capital *)
- fn[0] := name[0];
- i := 1; WHILE ~IsDigit(name[i]) DO fn[i] := name[i]; INC(i) END; fn[i] := 0X;
- (* read the size *)
- j := 0; WHILE IsDigit(name[i]) DO sizeStr[j] := name[i]; INC(j); INC(i) END; sizeStr[j] := 0X;
- Strings.StrToInt(sizeStr, size);
- style := {};
- CASE CAP(name[i]) OF
- | "I" : INCL(style, WMGraphics.FontItalic);
- | "B" : INCL(style, WMGraphics.FontBold);
- ELSE
- END
- END DecodeOberonFontName;
- PROCEDURE ToOberonFont(CONST name : ARRAY OF CHAR; size : LONGINT; style : SET; VAR oname : ARRAY OF CHAR) : BOOLEAN;
- VAR str : ARRAY 32 OF CHAR; f: Files.File;
- BEGIN
- COPY(name, oname);
- Strings.IntToStr(size, str); Strings.Append(oname, str);
- IF WMGraphics.FontBold IN style THEN Strings.Append(oname, "b") END;
- IF WMGraphics.FontItalic IN style THEN Strings.Append(oname, "i") END;
- Strings.Append(oname, ".Scn.Fnt");
- f := Files.Old(oname);
- IF f # NIL THEN RETURN TRUE
- ELSE
- IF oberonFontAllocatable # NIL THEN
- RETURN oberonFontAllocatable(oname)
- END;
- RETURN FALSE
- END
- END ToOberonFont;
- PROCEDURE GetUTF8Char*(r : Streams.Reader; VAR u : Texts.Char32) : BOOLEAN;
- VAR ch : ARRAY 8 OF CHAR; i : LONGINT;
- BEGIN
- ch[0] := r.Get();
- FOR i := 1 TO ORD(UTF8Strings.CodeLength[ORD(ch[0])]) - 1 DO ch[i] := r.Get() END;
- i := 0;
- RETURN UTF8Strings.DecodeChar(ch, i, u)
- END GetUTF8Char;
- PROCEDURE WriteUTF8Char*(w : Streams.Writer; ch : Char32);
- VAR str : ARRAY 8 OF CHAR; i : LONGINT;
- BEGIN
- i := 0; IF UTF8Strings.EncodeChar(ch, str, i) THEN w.Bytes(str, 0, i) END
- END WriteUTF8Char;
- (* Style to Attribute Converter *)
- PROCEDURE StyleToAttribute*(style: Texts.CharacterStyle): Texts.Attributes;
- VAR attr: Texts.Attributes; fi: Texts.FontInfo;
- BEGIN
- IF (style = NIL) THEN RETURN NIL END;
- NEW(attr); NEW(fi);
- COPY(style.family, fi.name);
- fi.size := ENTIER(FP1616.FixpToFloat(style.size));
- fi.style := style.style;
- attr.color := style.color;
- attr.bgcolor := style.bgColor;
- attr.voff := ENTIER(FP1616.FixpToFloat(style.baselineShift));
- attr.fontInfo := fi;
- RETURN attr
- END StyleToAttribute;
- (* Attribute To Style Converter, creates style with given name *)
- PROCEDURE AttributeToStyle*(CONST name: ARRAY OF CHAR; attr: Texts.Attributes): Texts.CharacterStyle;
- VAR style: Texts.CharacterStyle;
- BEGIN
- NEW(style);
- COPY(name, style.name);
- IF attr.fontInfo # NIL THEN
- COPY(attr.fontInfo.name, style.family);
- style.size := FP1616.FloatToFixp(attr.fontInfo.size*1.0);
- style.style := attr.fontInfo.style;
- ELSE
- COPY("Oberon", style.family);
- style.size := FP1616.FloatToFixp(12.0);
- style.style := {};
- END;
- style.color := attr.color;
- style.bgColor := attr.bgcolor;
- style.baselineShift := attr.voff;
- RETURN style
- END AttributeToStyle;
- (**
- * -- Bluebottle File Format --
- * Convert Procedure version: 0.1
- * Usage: Convert file1.Mod file2.Mod ... fileN.Mod~
- *)
- PROCEDURE Convert*(context : Commands.Context);
- VAR filename : Files.FileName;
- BEGIN
- context.out.String("-- Oberon To Bluebottle File Converter v0.1 --"); context.out.Ln;
- WHILE context.arg.GetString(filename) DO
- ConvertFile(filename, context);
- END;
- context.out.String("-- all done --"); context.out.Ln;
- END Convert;
- PROCEDURE ConvertAll*(context : Commands.Context);
- VAR enumerator : Files.Enumerator;
- filename : Files.FileName; flags : SET; time, date, size : LONGINT;
- BEGIN
- NEW(enumerator);
- enumerator.Open("", {});
- context.out.String("-- Oberon To Bluebottle File Converter v0.1 --"); context.out.Ln;
- WHILE enumerator.HasMoreEntries() DO
- IF enumerator.GetEntry(filename, flags, time, date, size) THEN
- IF Strings.Match("*.Mod", filename) THEN
- ConvertFile(filename, context);
- END;
- END;
- END;
- context.out.String("-- all done --"); context.out.Ln;
- enumerator.Close;
- END ConvertAll;
- (* Converts the file with the given name into bb file format *)
- PROCEDURE ConvertFile(CONST file: ARRAY OF CHAR; context : Commands.Context);
- VAR ext, ext2: ARRAY 16 OF CHAR; file2 : ARRAY 256 OF CHAR;
- text : Texts.Text; res : WORD;
- BEGIN
- ext2 := "mod"; (* extension for the converted files *)
- Strings.GetExtension(file, file2, ext);
- Strings.Append(file2, "."); Strings.Append(file2, ext2);
- (* check if file is Module *)
- IF (ext = "Mod") THEN
- NEW(text);
- context.out.String("Converting: "); context.out.String(file);
- (* read Oberon Format file *)
- text.AcquireWrite;
- LoadOberonText(text, file, res);
- text.ReleaseWrite;
- IF (res = 0) THEN
- (* write Bluebottle Format File *)
- text.AcquireRead;
- StoreText(text, file2, res);
- text.ReleaseRead;
- IF (res # 0) THEN
- context.error.String("Converter ERROR: Something went wrong... "); context.error.Ln;
- ELSE
- context.out.String(" done"); context.out.Ln;
- END;
- ELSE
- context.error.String("Converter ERROR: Couldn't load Oberon File: "); context.error.String(file); context.error.Ln;
- END;
- ELSE
- context.error.String("Converter ERROR: Wrong Extension: "); context.error.String(file); context.error.Ln;
- END;
- END ConvertFile;
- (* ------------------------------------------------------------------------- *)
- PROCEDURE SkipLine(utilreader: Texts.TextReader; pos: LONGINT): LONGINT;
- VAR ch : Texts.Char32;
- BEGIN
- utilreader.SetPosition(pos );
- utilreader.SetDirection(1);
- utilreader.ReadCh(ch);
- WHILE (ch # Texts.NewLineChar) & (~utilreader.eot) DO utilreader.ReadCh(ch) END;
- RETURN utilreader.GetPosition()
- END SkipLine;
- PROCEDURE IndentText*(text : Texts.Text; from, to : LONGINT; minus : BOOLEAN);
- VAR r : Texts.TextReader;
- p, pto : Texts.TextPosition;
- tab : ARRAY 2 OF Texts.Char32;
- c : Texts.Char32;
- BEGIN
- tab[0] := Texts.TabChar; tab[1] := 0;
- text.AcquireWrite;
- NEW(r, text); NEW(p, text); NEW(pto, text);
- pto.SetPosition(to);
- p.SetPosition(from);
- WHILE p.GetPosition() < pto.GetPosition() DO
- p.SetPosition(FindPosLineStart(r, p.GetPosition()));
- IF minus THEN
- r.SetPosition(p.GetPosition()); r.SetDirection(1);
- r.ReadCh(c);
- IF c = Texts.TabChar THEN
- text.Delete(p.GetPosition(), 1)
- END
- ELSIF SkipLine(r, p.GetPosition()) > p.GetPosition() + 1 THEN
- text.InsertUCS32(p.GetPosition(), tab);
- END;
- p.SetPosition(SkipLine(r, p.GetPosition()))
- END;
- text.ReleaseWrite
- END IndentText;
- PROCEDURE UCS32StrLength*(CONST string: ARRAY OF Char32): LONGINT;
- VAR len: LONGINT;
- BEGIN
- len := 0; WHILE (string[len] # 0) DO INC(len) END;
- RETURN len
- END UCS32StrLength;
- (** returns the position of the first occurrence of pattern (ucs32) in the text or -1 if no occurrence is found *)
- (* Rabin-Karp algorithm, adopted from Sedgewick *)
- (* efficiency could be improved by not seeking so much *)
- PROCEDURE Pos*(CONST pattern: ARRAY OF Char32; from : LONGINT; text : Text): LONGINT;
- CONST
- q = 8204957; (* prime number, {(d+1) * q <= MAX(LONGINT)} *)
- d = 256; (* number of different characters *)
- VAR h1, h2, dM, i, j, m, n: LONGINT; ch : Char32; found : BOOLEAN; r : Texts.TextReader;
- BEGIN (* caller must hold read lock on text *)
- m := UCS32StrLength(pattern); n := text.GetLength();
- IF (from + m > n) THEN RETURN -1 END;
- NEW(r, text); r.SetPosition(from);
- dM := 1; FOR i := 0 TO m-2 DO dM := (d*dM) MOD q END;
- h1 := 0; FOR i := 0 TO m-1 DO h1 := (h1*d + (pattern[i] MOD d)) MOD q END;
- h2 := 0; FOR i := 0 TO m-1 DO r.ReadCh(ch); ch := ch MOD d; h2 := (h2*d + ch) MOD q END;
- i := from; found := FALSE;
- IF (h1 = h2) THEN (* verify *)
- j := 0; r.SetPosition(i); found := TRUE;
- WHILE (j < m) DO
- r.ReadCh(ch);
- IF (ch # pattern[j]) THEN found := FALSE; j := m; END; (* hash values are equal, but strings are not *)
- INC(j);
- END;
- END;
- WHILE ~found & (i < n-m) DO
- r.SetPosition(i); r.ReadCh(ch); ch := ch MOD d; h2 := (h2 + d*q - ch*dM) MOD q;
- r.SetPosition(i + m); r.ReadCh(ch); ch := ch MOD d; h2 := (h2*d + ch) MOD q;
- INC(i);
- IF (h1 = h2) THEN (* verify *)
- j := 0; r.SetPosition(i); found := TRUE;
- WHILE (j < m) DO
- r.ReadCh(ch);
- IF (ch # pattern[j]) THEN found := FALSE; j := m; END; (* hash values are equal, but strings are not *)
- INC(j);
- END;
- END;
- END;
- IF found THEN RETURN i
- ELSE RETURN -1
- END
- END Pos;
- PROCEDURE UpperCaseChar32*(VAR ch : Texts.Char32);
- BEGIN
- (* LONGINT version of IF (ch >= "a") & (ch <= "z") THEN CAP(ch); END; *)
- IF (ch >= 61H) & (ch <= 7AH) THEN ch := ch - 32; END;
- END UpperCaseChar32;
- (* Compare the pattern string of length 'length' with the string at the current position/direction of the text reader 'r' *)
- PROCEDURE Equals(CONST pattern : ARRAY OF Char32; r : Texts.TextReader; length : LONGINT; ignoreCase : BOOLEAN) : BOOLEAN;
- VAR ch, chp : Texts.Char32; equals : BOOLEAN; i : LONGINT;
- BEGIN
- i := 0; equals := TRUE;
- WHILE (i < length) DO
- r.ReadCh(ch); chp := pattern[i];
- IF ignoreCase THEN UpperCaseChar32(ch); UpperCaseChar32(chp); END;
- IF (ch # chp) THEN equals := FALSE; i := length; END; (* hash values are equal, but strings are not *)
- INC(i);
- END;
- RETURN equals;
- END Equals;
- (** More generic version of Pos. Basically the same search algorithm, but can also perform case-insensitive searching and/or
- * backwards directed searching.
- * Returns the position of the first character of the first occurence of 'pattern' in 'text' in search direction or -1 if pattern not found
- *)
- PROCEDURE GenericPos*(CONST pattern: ARRAY OF Char32; from : LONGINT; text : Text; ignoreCase, backwards : BOOLEAN): LONGINT;
- CONST
- q = 8204957; (* prime number, {(d+1) * q <= MAX(LONGINT)} *)
- d = 256; (* number of different characters *)
- VAR h1, h2, dM, i, patternLength, stringLength: LONGINT; ch : Char32; found : BOOLEAN; r : Texts.TextReader;
- BEGIN (* caller must hold read lock on text *)
- patternLength := UCS32StrLength(pattern); stringLength := text.GetLength();
- (* check whether the search pattern can be contained in the text regarding the search direction *)
- IF backwards THEN
- IF (patternLength > from + 1) THEN RETURN -1; END;
- ELSE
- IF (from + patternLength > stringLength) THEN RETURN -1; END;
- END;
- dM := 1; FOR i := 0 TO patternLength-2 DO dM := (d*dM) MOD q END;
- (* calculate hash value for search pattern string *)
- h1 := 0;
- FOR i := 0 TO patternLength-1 DO
- IF backwards THEN
- ch := pattern[patternLength-1-i];
- ELSE
- ch := pattern[i];
- END;
- IF ignoreCase THEN UpperCaseChar32(ch); END;
- ch := ch MOD d;
- h1 := (h1*d + ch) MOD q;
- END;
- (* calculate hash value for the first 'patternLength' characters of the text to be searched *)
- NEW(r, text); r.SetPosition(from);
- IF backwards THEN r.SetDirection(-1); END;
- h2 := 0;
- FOR i := 0 TO patternLength-1 DO
- r.ReadCh(ch);
- IF ignoreCase THEN UpperCaseChar32(ch); END;
- ch := ch MOD d;
- h2 := (h2*d + ch) MOD q;
- END;
- i := from; found := FALSE;
- IF (h1 = h2) THEN (* Hash values match, compare strings *)
- IF backwards THEN
- r.SetDirection(1); r.SetPosition(i - patternLength + 1);
- ELSE
- r.SetPosition(i);
- END;
- found := Equals(pattern, r, patternLength, ignoreCase);
- IF backwards THEN r.SetDirection(-1); END;
- END;
- LOOP
- (* check wether we're finished *)
- IF found THEN EXIT; END;
- IF backwards THEN
- IF (i < patternLength) THEN EXIT; END;
- ELSE
- IF (i >= stringLength-patternLength) THEN EXIT; END;
- END;
- (* remove last character from hash value *)
- r.SetPosition(i); r.ReadCh(ch);
- IF ignoreCase THEN UpperCaseChar32(ch); END;
- ch := ch MOD d;
- h2 := (h2 + d*q - ch*dM) MOD q;
- (* add next character to hash value *)
- IF backwards THEN
- r.SetPosition(i - patternLength);
- ELSE
- r.SetPosition(i + patternLength);
- END;
- r.ReadCh(ch);
- IF ignoreCase THEN UpperCaseChar32(ch); END;
- ch := ch MOD d;
- h2 := (h2*d + ch) MOD q;
- IF backwards THEN
- DEC(i);
- ELSE
- INC(i);
- END;
- IF (h1 = h2) THEN (* verify *)
- IF backwards THEN
- r.SetDirection(1); r.SetPosition(i - patternLength + 1);
- ELSE
- r.SetPosition(i);
- END;
- found := Equals(pattern, r, patternLength, ignoreCase);
- IF backwards THEN r.SetDirection(-1); END;
- END;
- END;
- IF found THEN
- IF backwards THEN RETURN i - patternLength + 1;
- ELSE RETURN i;
- END;
- ELSE RETURN -1;
- END;
- END GenericPos;
- PROCEDURE Replace*(CONST string, by :Texts.UCS32String; text : Texts.Text; VAR nofReplacements : LONGINT);
- VAR pos, stringLen, byLen : LONGINT;
- BEGIN
- ASSERT(text # NIL);
- nofReplacements := 0;
- stringLen := UCS32StrLength(string);
- byLen := UCS32StrLength(by);
- text.AcquireWrite;
- pos := Pos(string, 0, text);
- WHILE (pos > 0) DO
- INC(nofReplacements);
- text.Delete(pos, stringLen);
- text.InsertUCS32(pos, by);
- pos := Pos(string, pos + byLen, text);
- END;
- text.ReleaseWrite;
- END Replace;
- PROCEDURE AddFontFormat*(x : FormatDescriptor);
- BEGIN
- IF x.name # NIL THEN KernelLog.String("name = "); KernelLog.String(x.name^); KernelLog.Ln END;
- IF x.loadProc # NIL THEN KernelLog.String("loadProc = "); KernelLog.String(x.loadProc^); KernelLog.Ln END;
- IF x.storeProc # NIL THEN KernelLog.String("storeProc = "); KernelLog.String(x.storeProc^); KernelLog.Ln END;
- END AddFontFormat;
- PROCEDURE GetConfig;
- VAR sectFM, e : XML.Element;
- p : ANY; enum: XMLObjects.Enumerator;
- f : FormatDescriptor;
- BEGIN
- IF Configuration.config # NIL THEN
- sectFM := Configuration.GetNamedElement(Configuration.config.GetRoot(), "Section", "TextFormats");
- ELSE
- sectFM := NIL;
- END;
- IF sectFM # NIL THEN
- enum := sectFM.GetContents();
- IF enum # NIL THEN
- WHILE enum.HasMoreElements() DO
- p := enum.GetNext();
- IF p IS XML.Element THEN
- NEW(f);
- f.name := p(XML.Element).GetName();
- e := Configuration.GetNamedElement(p(XML.Element), "Setting", "Load");
- IF e # NIL THEN f.loadProc := e.GetAttributeValue("Value") END;
- e := Configuration.GetNamedElement(p(XML.Element), "Setting", "Store");
- IF e # NIL THEN f.storeProc := e.GetAttributeValue("Value") END;
- AddFontFormat(f);
- END
- END
- END;
- END
- END GetConfig;
- (* Oberon File Format *)
- PROCEDURE OberonDecoderFactory*() : Codecs.TextDecoder;
- VAR p : OberonDecoder;
- BEGIN
- NEW(p);
- RETURN p
- END OberonDecoderFactory;
- PROCEDURE OberonEncoderFactory*() : Codecs.TextEncoder;
- VAR p : OberonEncoder;
- BEGIN
- NEW(p);
- RETURN p
- END OberonEncoderFactory;
- (* Bluebottle File Format *)
- PROCEDURE BluebottleDecoderFactory*() : Codecs.TextDecoder;
- VAR p : BluebottleDecoder;
- BEGIN
- NEW(p);
- RETURN p
- END BluebottleDecoderFactory;
- PROCEDURE BluebottleEncoderFactory*() : Codecs.TextEncoder;
- VAR p : BluebottleEncoder;
- BEGIN
- NEW(p);
- RETURN p
- END BluebottleEncoderFactory;
- (* UTF-8 File Format *)
- PROCEDURE UTF8DecoderFactory*() : Codecs.TextDecoder;
- VAR p : UTF8Decoder;
- BEGIN
- NEW(p);
- RETURN p
- END UTF8DecoderFactory;
- PROCEDURE UTF8EncoderFactory*() : Codecs.TextEncoder;
- VAR p : UTF8Encoder;
- BEGIN
- NEW(p);
- RETURN p
- END UTF8EncoderFactory;
- (* ISO8859-1 File Format *)
- PROCEDURE ISO88591DecoderFactory*() : Codecs.TextDecoder;
- VAR p : ISO88591Decoder;
- BEGIN
- NEW(p);
- RETURN p
- END ISO88591DecoderFactory;
- PROCEDURE ISO88591EncoderFactory*() : Codecs.TextEncoder;
- VAR p : ISO88591Encoder;
- BEGIN
- NEW(p);
- RETURN p
- END ISO88591EncoderFactory;
- (* Hex File Format *)
- PROCEDURE HEXDecoderFactory*() : Codecs.TextDecoder;
- VAR p : HEXDecoder;
- BEGIN
- NEW(p);
- RETURN p
- END HEXDecoderFactory;
- PROCEDURE HEXEncoderFactory*() : Codecs.TextEncoder;
- VAR p : HEXEncoder;
- BEGIN
- NEW(p);
- RETURN p
- END HEXEncoderFactory;
- PROCEDURE GetClipboard* (context: Commands.Context);
- VAR r: TextReader;
- BEGIN
- NEW (r, Texts.clipboard);
- Streams.Copy (r, context.out); context.out.Update;
- END GetClipboard;
- PROCEDURE SetClipboard* (context: Commands.Context);
- VAR w: TextWriter;
- BEGIN
- NEW (w, Texts.clipboard);
- Streams.Copy (context.in, w); w.Update;
- END SetClipboard;
- PROCEDURE GetTextReader* (CONST filename: ARRAY OF CHAR): Streams.Reader;
- VAR
- file: Files.File; fileReader: Files.Reader; offset: LONGINT;
- text: Text; format: LONGINT; res: WORD; textReader: TextReader;
- BEGIN
- (* Optimisation: skip header of oberon files and return a file reader instead of default text reader*)
- file := Files.Old (filename);
- IF file = NIL THEN RETURN NIL END;
- NEW (fileReader, file, 0);
- IF (fileReader.Get () = 0F0X) & (fileReader.Get () = 001X) THEN
- offset := ORD (fileReader.Get ());
- INC (offset, LONG (ORD (fileReader.Get ())) * 0100H);
- fileReader.SetPos(offset);
- RETURN fileReader
- ELSE
- NEW (text);
- LoadAuto (text, filename, format, res);
- NEW (textReader, text);
- RETURN textReader
- END
- END GetTextReader;
- PROCEDURE GetDefaultAttributes* () : Texts.Attributes;
- BEGIN
- RETURN Texts.defaultAttributes.Clone();
- END GetDefaultAttributes;
- BEGIN
- oberonFontAllocatable := NIL;
- GetConfig;
- END TextUtilities.
- TextUtilities.ConvertAll~
|