Repositories.Mod 64 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203
  1. MODULE Repositories; (** AUTHOR "staubesv"; PURPOSE "Component repositories"; *)
  2. IMPORT
  3. Streams, Modules, KernelLog, Commands, Strings, Files, Archives, Localization,
  4. UTF8Strings, XML, XMLObjects, XMLScanner, XMLParser, WMEvents;
  5. CONST
  6. Ok* = 0;
  7. NotFound* = 10;
  8. RepositoryNotFound* = 11;
  9. ComponentNotFound* = 12;
  10. RepositoryNotLoaded* = 13;
  11. DuplicateName* = 20;
  12. DuplicateID* = 21;
  13. DuplicateRepository* = 22;
  14. IndexError* = 50;
  15. CannotCreateArchive* = 100;
  16. ArchivesError* = 101;
  17. WrongVersion* = 200;
  18. FormatError* = 201;
  19. ParseError* = 300;
  20. DictionaryNotFound* = 400;
  21. LanguageNotAvailable* = 410;
  22. LanguageFileNotFound* = 420;
  23. InternalError* = 999;
  24. (* Component.flags *)
  25. Generated = 0; (* this component composite was generated by a generator procedure *)
  26. Locked = 1; (* this component composite is part of a loaded component *)
  27. IndexFile = "index.xml";
  28. DefaultFileExtension* = "rep";
  29. Delimiter* = ":";
  30. PrototypeID = 0;
  31. (* Header information *)
  32. Version = 1;
  33. Quote = '"';
  34. EscapeCharacter = "&";
  35. EscapeQuote = """;
  36. (* IndexEntry.type *)
  37. Type_Component = 1;
  38. Type_Generator = 2;
  39. CommandPrefix* = "cmd:";
  40. (* Strings used in XML index file *)
  41. XmlRepository = "Repository";
  42. XmlComponents = "Components";
  43. XmlComponent = "Component";
  44. XmlDictionaries = "Dictionaries";
  45. XmlDictionary = "Dictionary";
  46. XmlLanguage = "Language";
  47. XmlApplications = "Applications";
  48. XmlApplication = "Application";
  49. XmlAttributeName = "name";
  50. XmlAttributeDefault = "default";
  51. XmlAttributeID = "id";
  52. XmlAttributeSource = "source";
  53. TraceLoading = 0;
  54. TraceInstantiate = 1;
  55. TraceCreation = 2;
  56. Trace = {};
  57. TYPE
  58. Context* = OBJECT(Commands.Context)
  59. VAR
  60. object* : ANY;
  61. PROCEDURE &Init*(in, arg : Streams.Reader; out, error : Streams.Writer; caller: OBJECT);
  62. BEGIN
  63. Init^(in, arg, out, error, caller);
  64. object := NIL;
  65. END Init;
  66. END Context;
  67. StoreContext*= OBJECT
  68. VAR repository-: Repository;
  69. PROCEDURE &InitStoreContext(r: Repository);
  70. BEGIN
  71. repository := r;
  72. END InitStoreContext;
  73. END StoreContext;
  74. Command* = PROCEDURE {DELEGATE} (context : Context);
  75. TYPE
  76. (** Base class of all components *)
  77. Component* = OBJECT(XML.Element)
  78. VAR
  79. repository : Repository; name : Strings.String; refNum : LONGINT;
  80. flags : SET;
  81. timestamp- : LONGINT;
  82. onChanged* : WMEvents.EventSource; (* for update mechanisms, basically every component needs a feature to inform about updates *)
  83. PROCEDURE &Init*;
  84. BEGIN
  85. Init^;
  86. repository := NIL; name := NIL; refNum := 0;
  87. flags := {};
  88. timestamp := 0;
  89. NEW(onChanged, NIL, NIL, NIL, NIL);
  90. END Init;
  91. PROCEDURE SetGenerator*(CONST gen: ARRAY OF CHAR);
  92. BEGIN SetAttributeValue("generator", gen);
  93. END SetGenerator;
  94. PROCEDURE SetRepository*(repository : Repository; CONST name : Name; refNum : LONGINT);
  95. BEGIN {EXCLUSIVE}
  96. SELF.repository := repository; SELF.refNum := refNum;
  97. IF (repository # NIL) THEN
  98. SELF.name := Strings.NewString(name);
  99. SetNameAsString(SELF.name);
  100. (*
  101. SetNameAsString(NewJoinName(repository.name, name, refNum));
  102. *)
  103. ELSE
  104. IF (SELF.name # NIL) THEN
  105. SetNameAsString(SELF.name);
  106. SELF.name := NIL;
  107. ELSE
  108. SetName("Unbound");
  109. END;
  110. END;
  111. INC(timestamp);
  112. END SetRepository;
  113. PROCEDURE GetRepository*(VAR repository : Repository; VAR name : Name; VAR refNum : LONGINT);
  114. BEGIN {EXCLUSIVE}
  115. repository := SELF.repository; refNum := SELF.refNum;
  116. IF (SELF.name # NIL) THEN COPY(SELF.name^, name); ELSE name := ""; END;
  117. END GetRepository;
  118. PROCEDURE IsLocked*() : BOOLEAN;
  119. BEGIN
  120. RETURN Locked IN flags;
  121. END IsLocked;
  122. PROCEDURE FromXML*(xml: XML.Element);
  123. VAR component: Component; enum: XMLObjects.Enumerator; c: ANY;
  124. BEGIN
  125. enum := xml.GetContents();
  126. WHILE enum.HasMoreElements() DO
  127. c := enum.GetNext();
  128. IF c IS XML.Element THEN
  129. component := ComponentFromXML(c(XML.Element));
  130. IF component # NIL THEN
  131. AddContent(component)
  132. END;
  133. END;
  134. END;
  135. END FromXML;
  136. END Component;
  137. TYPE
  138. Name* = ARRAY 32 OF CHAR;
  139. ApplicationInfo = OBJECT(XML.Element)
  140. END ApplicationInfo;
  141. ComponentInfo = OBJECT(XML.Element)
  142. VAR
  143. name, source : Strings.String; (* { (name # NIL) & (source # NIL) } *)
  144. type, id : LONGINT;
  145. instance : ANY;
  146. next : ComponentInfo;
  147. PROCEDURE &Init*;
  148. BEGIN
  149. Init^;
  150. SetNameAsString(StrComponent);
  151. name := StrNoName;
  152. source := StrNoName;
  153. type := Type_Generator; id := 0;
  154. instance := NIL;
  155. next := NIL;
  156. END Init;
  157. PROCEDURE AddAttribute*(attribute : XML.Attribute);
  158. VAR name, temp : Strings.String;
  159. BEGIN
  160. name := attribute.GetName();
  161. IF (name # NIL) THEN
  162. IF (name^ = XmlAttributeName) THEN
  163. SELF.name := attribute.GetValue();
  164. IF (SELF.name = NIL) THEN SELF.name := StrNoName; END;
  165. ELSIF (name^ = XmlAttributeID) THEN
  166. temp := attribute.GetValue();
  167. IF (temp # NIL) THEN
  168. Strings.StrToInt(temp^, SELF.id);
  169. END;
  170. ELSIF (name^ = XmlAttributeSource) THEN
  171. temp := attribute.GetValue();
  172. IF (temp # NIL) THEN
  173. source := temp;
  174. IF IsXmlFilename(source^) THEN
  175. type := Type_Component;
  176. ELSE
  177. type := Type_Generator;
  178. END;
  179. ELSE
  180. source := StrNoName;
  181. END;
  182. END;
  183. END;
  184. AddAttribute^(attribute);
  185. END AddAttribute;
  186. END ComponentInfo;
  187. TYPE
  188. IndexRegistry* = OBJECT(XML.ElementRegistry)
  189. PROCEDURE InstantiateElement*(CONST name: ARRAY OF CHAR): XML.Element;
  190. VAR element : XML.Element; appInfo : ApplicationInfo; comInfo : ComponentInfo; repository : Repository; dictionary : Dictionary;
  191. BEGIN
  192. element := NIL;
  193. IF (name = XmlApplication) THEN
  194. NEW(appInfo); element := appInfo;
  195. ELSIF (name = XmlComponent) THEN
  196. NEW(comInfo); element := comInfo;
  197. ELSIF (name = XmlRepository) THEN
  198. NEW(repository); element := repository;
  199. ELSIF (name = XmlDictionary) THEN
  200. NEW(dictionary); element := dictionary;
  201. END;
  202. RETURN element;
  203. END InstantiateElement;
  204. END IndexRegistry;
  205. TYPE
  206. Entry = OBJECT
  207. VAR
  208. word, translation : Strings.String;
  209. next : Entry;
  210. PROCEDURE &Init(word, translation : Strings.String);
  211. BEGIN
  212. ASSERT((word # NIL) & (translation # NIL));
  213. SELF.word := word;
  214. SELF.translation := translation;
  215. next := NIL;
  216. END Init;
  217. END Entry;
  218. TYPE
  219. Translator = OBJECT
  220. VAR
  221. entries : Entry;
  222. PROCEDURE &Init;
  223. BEGIN
  224. entries := NIL;
  225. END Init;
  226. PROCEDURE Add(word, translation : Strings.String);
  227. VAR e, newEntry : Entry;
  228. BEGIN
  229. ASSERT((word # NIL) & (translation # NIL));
  230. e := Find(word^);
  231. IF (e = NIL) THEN
  232. NEW(newEntry, word, translation);
  233. IF (entries = NIL) THEN
  234. entries := newEntry;
  235. ELSIF (UTF8Strings.Compare(word^, entries.word^) # UTF8Strings.CmpLess) THEN
  236. newEntry.next := entries;
  237. entries := newEntry;
  238. ELSE
  239. e := entries;
  240. WHILE (e.next # NIL) & (UTF8Strings.Compare(word^, e.next.word^) = UTF8Strings.CmpLess) DO e := e.next; END;
  241. newEntry.next := e.next;
  242. e.next := newEntry;
  243. END;
  244. ELSE
  245. KernelLog.String("Repositories.Translator: Warning: Ignoring duplicate dictionary entry (");
  246. KernelLog.String(word^); KernelLog.String(", "); KernelLog.String(translation^); KernelLog.String(")");
  247. KernelLog.Ln;
  248. END;
  249. END Add;
  250. PROCEDURE Parse(reader : Streams.Reader; VAR res : WORD);
  251. VAR buffer : Strings.Buffer; entry : Entry; ch : CHAR;
  252. PROCEDURE ReportError(CONST msg : ARRAY OF CHAR; position : LONGINT);
  253. BEGIN
  254. KernelLog.String("Repositories.Dictionary.Parse: Error: "); KernelLog.String(msg);
  255. KernelLog.String(" at position "); KernelLog.Int(position, 0); KernelLog.Ln;
  256. END ReportError;
  257. (* Read all characters until '"' OR 0X (excl) *)
  258. PROCEDURE GetString(reader : Streams.Reader) : Strings.String;
  259. VAR temp : Strings.String; writer : Streams.Writer; escaping : BOOLEAN; escape : ARRAY 8 OF CHAR; i : LONGINT;
  260. BEGIN
  261. ASSERT(reader # NIL);
  262. buffer.Clear;
  263. writer := buffer.GetWriter();
  264. escaping := FALSE;
  265. ch := reader.Peek();
  266. WHILE (ch # Quote) & (ch # 0X) DO
  267. ch := reader.Get();
  268. IF (ch = EscapeCharacter) THEN
  269. IF (escaping) THEN writer.String(escape); ELSE escaping := TRUE; END;
  270. escape[0] := EscapeCharacter;
  271. escape[1] := 0X;
  272. i := 1;
  273. ELSIF escaping THEN
  274. escape[i] := ch;
  275. escape[i + 1] := 0X;
  276. INC(i);
  277. IF Strings.Length(escape) = Strings.Length(EscapeQuote) THEN
  278. escaping := FALSE;
  279. IF (escape = EscapeQuote) THEN
  280. writer.Char(Quote);
  281. ELSE
  282. writer.String(escape);
  283. END;
  284. END;
  285. ELSE
  286. writer.Char(ch);
  287. END;
  288. ch := reader.Peek();
  289. END;
  290. IF escaping THEN writer.String(escape); END;
  291. temp := buffer.GetString();
  292. RETURN Strings.NewString(temp^);
  293. END GetString;
  294. (** Parse and generate one entry of the form "word"="translation" *)
  295. PROCEDURE ParseEntry(reader : Streams.Reader) : BOOLEAN;
  296. VAR ch : CHAR; word, translation : Strings.String;
  297. BEGIN
  298. ASSERT(reader # NIL);
  299. entry := NIL;
  300. reader.SkipWhitespace;
  301. ch := reader.Get();
  302. IF (ch = Quote) THEN
  303. word := GetString(reader);
  304. ch := reader.Get();
  305. IF (ch = Quote) THEN
  306. reader.SkipWhitespace;
  307. ch := reader.Get();
  308. IF (ch = "=") THEN
  309. reader.SkipWhitespace;
  310. ch := reader.Get();
  311. IF (ch = Quote) THEN
  312. translation := GetString(reader);
  313. ch := reader.Get();
  314. IF (ch = Quote) THEN
  315. Add(word, translation);
  316. RETURN TRUE;
  317. ELSE
  318. ReportError("Expected closing quote", reader.Pos() - 1);
  319. END;
  320. ELSE
  321. ReportError("Expected opening quote", reader.Pos() - 1);
  322. END;
  323. ELSE
  324. ReportError("Expected equal sign", reader.Pos() - 1);
  325. END;
  326. ELSE
  327. ReportError("Expected closing quote", reader.Pos() - 1);
  328. END;
  329. ELSE
  330. ReportError("Expected opening quote", reader.Pos() - 1);
  331. END;
  332. RETURN FALSE;
  333. END ParseEntry;
  334. BEGIN
  335. ASSERT(reader # NIL);
  336. NEW(buffer, 512);
  337. reader.SkipWhitespace;
  338. ch := reader.Peek();
  339. WHILE (ch # 0X) & ParseEntry(reader) DO
  340. reader.SkipWhitespace;
  341. ch := reader.Peek();
  342. END;
  343. IF (ch = 0X) THEN
  344. res := Ok;
  345. ELSE
  346. res := ParseError;
  347. END;
  348. END Parse;
  349. PROCEDURE Find(CONST word : ARRAY OF CHAR) : Entry;
  350. VAR e : Entry; result : LONGINT;
  351. BEGIN
  352. result := UTF8Strings.CmpLess;
  353. e := entries;
  354. LOOP
  355. IF (e = NIL) THEN EXIT; END;
  356. result := UTF8Strings.Compare(word, e.word^);
  357. IF (result # UTF8Strings.CmpLess) THEN
  358. EXIT;
  359. ELSE
  360. e := e.next;
  361. END;
  362. END;
  363. IF (result = UTF8Strings.CmpEqual) THEN
  364. ASSERT(e # NIL);
  365. RETURN e;
  366. ELSE
  367. RETURN NIL;
  368. END;
  369. END Find;
  370. PROCEDURE ComplexTranslation(CONST word : ARRAY OF CHAR) : Strings.String;
  371. VAR buf : ARRAY 1024 OF CHAR; i, j : LONGINT; translation : Strings.String; w : Name;
  372. PROCEDURE BoundsCheck() : BOOLEAN;
  373. BEGIN
  374. RETURN (i < LEN(word)) & (j < LEN(buf) - 1);
  375. END BoundsCheck;
  376. PROCEDURE Append;
  377. BEGIN
  378. WHILE BoundsCheck() & (word[i] # 0X) & (word[i] # ":") DO
  379. buf[j] := word[i];
  380. INC(j); INC(i);
  381. END;
  382. END Append;
  383. PROCEDURE AppendTranslation(CONST translation : ARRAY OF CHAR);
  384. VAR idx : LONGINT;
  385. BEGIN
  386. idx := 0;
  387. WHILE (j < LEN(buf) - 1) & (idx < LEN(translation)) & (translation[idx] # 0X) DO
  388. buf[j] := translation[idx];
  389. INC(j); INC(idx);
  390. END;
  391. buf[j] := 0X;
  392. END AppendTranslation;
  393. PROCEDURE GetName(VAR w : ARRAY OF CHAR) : BOOLEAN;
  394. VAR getName : BOOLEAN; idx : LONGINT;
  395. BEGIN
  396. getName := TRUE;
  397. w := "";
  398. WHILE BoundsCheck() & (word[i] = ":") DO (** unescape :: to : *)
  399. IF getName THEN buf[j] := ":"; getName := FALSE; ELSE getName := TRUE; END;
  400. INC(i);
  401. END;
  402. IF getName THEN
  403. idx := 0;
  404. WHILE (i < LEN(word)) & (word[i] # 0X) & (word[i] # ":") DO
  405. IF (idx < LEN(w) - 1) THEN
  406. w[idx] := word[i];
  407. INC(idx);
  408. END;
  409. INC(i);
  410. END;
  411. w[idx] := 0X;
  412. IF (i < LEN(word)) & (word[i] = ":") THEN INC(i); END;
  413. END;
  414. RETURN getName & (w # "");
  415. END GetName;
  416. BEGIN
  417. i := 0; j := 0;
  418. WHILE BoundsCheck() & (word[i] # 0X) DO
  419. Append;
  420. IF BoundsCheck() & (word[i] = ":") THEN
  421. INC(i); (* skip ":" *)
  422. IF GetName(w) THEN
  423. ASSERT(Strings.Count(w, ":") = 0);
  424. translation := TranslateAOC(w);
  425. ASSERT(translation # NIL);
  426. AppendTranslation(translation^);
  427. END;
  428. END;
  429. END;
  430. buf[j] := 0X;
  431. RETURN Strings.NewString(buf);
  432. END ComplexTranslation;
  433. PROCEDURE TranslateAOC(CONST word : ARRAY OF CHAR) : Strings.String;
  434. VAR result : Strings.String; entry : Entry;
  435. BEGIN
  436. IF Strings.Count(word, ":") = 0 THEN
  437. entry := Find(word);
  438. IF (entry # NIL) THEN
  439. result := entry.translation;
  440. ELSE
  441. result := Strings.NewString(word);
  442. END;
  443. ELSE
  444. result := ComplexTranslation(word);
  445. END;
  446. ASSERT(result # NIL);
  447. RETURN result;
  448. END TranslateAOC;
  449. PROCEDURE Translate(word : Strings.String) : Strings.String;
  450. VAR result : Strings.String; entry : Entry;
  451. BEGIN
  452. ASSERT(word # NIL);
  453. IF Strings.Count(word^, ":") = 0 THEN (* simple translation *)
  454. entry := Find(word^);
  455. IF (entry # NIL) THEN
  456. result := entry.translation;
  457. ELSE
  458. result := word;
  459. END;
  460. ELSE
  461. result := ComplexTranslation(word^);
  462. END;
  463. ASSERT(result # NIL);
  464. RETURN result;
  465. END Translate;
  466. END Translator;
  467. TYPE
  468. Language = RECORD
  469. code : ARRAY 3 OF CHAR;
  470. source : Files.FileName;
  471. translator : Translator;
  472. error, default : BOOLEAN;
  473. END;
  474. TYPE
  475. Dictionary* = OBJECT(XML.Element)
  476. VAR
  477. fullname- : Strings.String; (* {fullname # NIL} *)
  478. name : Strings.String;
  479. languages : POINTER TO ARRAY OF Language;
  480. repository : Repository;
  481. next : Dictionary;
  482. PROCEDURE &Init*;
  483. BEGIN
  484. Init^;
  485. fullname := StrNoName;
  486. name := StrNoName;
  487. languages := NIL;
  488. repository := NIL;
  489. next := NIL;
  490. END Init;
  491. PROCEDURE Initialize;
  492. VAR temp : ARRAY 256 OF CHAR;
  493. BEGIN
  494. ASSERT(repository # NIL);
  495. COPY(repository.name, temp); Strings.Append(temp, ":"); Strings.Append(temp, name^);
  496. fullname := Strings.NewString(temp);
  497. InitializeLanguages;
  498. END Initialize;
  499. PROCEDURE InitializeLanguages;
  500. VAR
  501. enum : XMLObjects.Enumerator; string : Strings.String; ptr : ANY;
  502. nofLanguages, i : LONGINT;
  503. BEGIN
  504. nofLanguages := 0;
  505. enum := GetContents();
  506. WHILE enum.HasMoreElements() DO
  507. ptr := enum.GetNext();
  508. IF (ptr IS XML.Element) THEN
  509. string := ptr(XML.Element).GetName();
  510. IF (string # NIL) & (string^ = XmlLanguage) & (ptr(XML.Element).GetAttributeValue(XmlAttributeName) # NIL) THEN
  511. INC(nofLanguages);
  512. END;
  513. END;
  514. END;
  515. IF (nofLanguages > 0) THEN
  516. NEW(languages, nofLanguages);
  517. i := 0;
  518. enum.Reset;
  519. WHILE enum.HasMoreElements() DO
  520. ptr := enum.GetNext();
  521. IF (ptr IS XML.Element) THEN
  522. string := ptr(XML.Element).GetName();
  523. IF (string # NIL) & (string^ = XmlLanguage) THEN
  524. string := ptr(XML.Element).GetAttributeValue(XmlAttributeName);
  525. IF (string # NIL) THEN
  526. COPY(string^, languages[i].code);
  527. string := ptr(XML.Element).GetAttributeValue(XmlAttributeSource);
  528. IF (string # NIL) THEN
  529. COPY(string^, languages[i].source);
  530. END;
  531. string := ptr(XML.Element).GetAttributeValue(XmlAttributeDefault);
  532. languages[i].default := (string # NIL) & (string^ = "true");
  533. languages[i].translator := NIL;
  534. languages[i].error := FALSE;
  535. INC(i);
  536. END;
  537. END;
  538. END;
  539. END;
  540. END;
  541. END InitializeLanguages;
  542. PROCEDURE Find(CONST language : Localization.Language) : Translator;
  543. VAR t : Translator; res: WORD; i : LONGINT;
  544. BEGIN
  545. t := NIL;
  546. IF (languages # NIL) THEN
  547. i := 0;
  548. WHILE (i < LEN(languages)) & (languages[i].code # language.code) DO INC(i); END;
  549. IF (i < LEN(languages)) THEN
  550. t := languages[i].translator;
  551. IF (t = NIL) & ~languages[i].error THEN
  552. LoadLanguage(languages[i], res);
  553. IF (res = Ok) THEN
  554. t := languages[i].translator;
  555. ELSE
  556. KernelLog.String("Repositories.Dictionary ");
  557. IF (name # NIL) THEN KernelLog.String(name^); ELSE KernelLog.String("UNKNOWN"); END;
  558. KernelLog.String(": ERROR: Could not load language file "); KernelLog.String(languages[i].source);
  559. KernelLog.String(", res = "); KernelLog.Int(res, 0); KernelLog.Ln;
  560. END;
  561. END;
  562. END;
  563. END;
  564. RETURN t;
  565. END Find;
  566. PROCEDURE GetDefaultTranslator() : Translator;
  567. VAR t : Translator; i: LONGINT; res : WORD;
  568. BEGIN
  569. t := NIL;
  570. IF (languages # NIL) THEN
  571. i := 0;
  572. WHILE (i < LEN(languages)) & ~languages[i].default DO INC(i); END;
  573. IF (i < LEN(languages)) THEN
  574. t := languages[i].translator;
  575. IF (t = NIL) & ~languages[i].error THEN
  576. LoadLanguage(languages[i], res);
  577. IF (res = Ok) THEN
  578. t := languages[i].translator;
  579. END;
  580. END;
  581. END;
  582. END;
  583. RETURN t;
  584. END GetDefaultTranslator;
  585. PROCEDURE FindBestMatch(languages : Localization.Languages) : Translator;
  586. VAR translator : Translator; i : LONGINT;
  587. BEGIN
  588. ASSERT(languages # NIL);
  589. translator := NIL;
  590. i := 0;
  591. WHILE (translator = NIL) & (i < LEN(languages)) DO
  592. translator := Find(languages[i]);
  593. INC(i);
  594. END;
  595. IF (translator = NIL) THEN
  596. translator := GetDefaultTranslator();
  597. END;
  598. RETURN translator;
  599. END FindBestMatch;
  600. PROCEDURE AddAttribute*(attribute : XML.Attribute);
  601. VAR name : Strings.String;
  602. BEGIN
  603. name := attribute.GetName();
  604. IF (name # NIL) THEN
  605. IF (name^ = XmlAttributeName) THEN
  606. SELF.name := attribute.GetValue();
  607. IF (SELF.name = NIL) THEN SELF.name := StrNoName; END;
  608. END;
  609. END;
  610. AddAttribute^(attribute);
  611. END AddAttribute;
  612. PROCEDURE LoadLanguage(VAR language :Language; VAR res : WORD);
  613. VAR translator : Translator; reader : Streams.Reader;
  614. BEGIN {EXCLUSIVE}
  615. ASSERT(repository # NIL);
  616. reader := repository.GetFile(language.source);
  617. IF (reader # NIL) THEN
  618. NEW(translator);
  619. translator.Parse(reader, res);
  620. IF (res = Ok) THEN
  621. language.translator := translator;
  622. ELSE
  623. language.error := TRUE;
  624. res := ParseError;
  625. END;
  626. ELSE
  627. language.error := TRUE;
  628. res := LanguageFileNotFound;
  629. END;
  630. END LoadLanguage;
  631. (** Translate UTF8 string 'word' to UTF8 string translation. The resulting string has to be considered immutable! *)
  632. PROCEDURE TranslateAOC*(CONST word : ARRAY OF CHAR; languages : Localization.Languages) : Strings.String;
  633. VAR translator : Translator; translation : Strings.String;
  634. BEGIN
  635. ASSERT(languages # NIL);
  636. translator := FindBestMatch(languages);
  637. IF (translator # NIL) THEN
  638. translation := translator.TranslateAOC(word);
  639. ELSE
  640. translation := Strings.NewString(word);
  641. END;
  642. RETURN translation;
  643. END TranslateAOC;
  644. (** Translate UTF8 string 'word' to UTF8 string translation. The resulting string has to be considered immutable! *)
  645. PROCEDURE Translate*(word : Strings.String; languages : Localization.Languages) : Strings.String;
  646. VAR translator : Translator; translation : Strings.String;
  647. BEGIN
  648. ASSERT(languages # NIL);
  649. IF (word # NIL) THEN
  650. translator := FindBestMatch(languages);
  651. IF (translator # NIL) THEN
  652. translation := translator.Translate(word);
  653. ELSE
  654. translation := word;
  655. END;
  656. ELSE
  657. translation := NIL;
  658. END;
  659. ASSERT(((word = NIL) & (translation = NIL)) OR ((word # NIL) & (translation # NIL)));
  660. RETURN translation;
  661. END Translate;
  662. PROCEDURE GetLanguages*() : Localization.Languages;
  663. VAR languages : Localization.Languages; i : LONGINT;
  664. BEGIN
  665. IF (SELF.languages # NIL) THEN
  666. NEW(languages, LEN(SELF.languages));
  667. FOR i := 0 TO LEN(languages)-1 DO
  668. COPY(SELF.languages[i].code, languages[i].code);
  669. END;
  670. ELSE
  671. languages := NIL;
  672. END;
  673. RETURN languages;
  674. END GetLanguages;
  675. END Dictionary;
  676. TYPE
  677. Repository* = OBJECT(XML.Element)
  678. VAR
  679. name- : Name;
  680. filename- : Files.FileName;
  681. archive : Archives.Archive;
  682. timestamp- : LONGINT;
  683. modified : BOOLEAN;
  684. nextID : LONGINT;
  685. components : ComponentInfo;
  686. dictionaries : Dictionary;
  687. errors : ErrorReporter;
  688. registry-: Registry;
  689. next : Repository;
  690. PROCEDURE &Init*;
  691. BEGIN
  692. Init^;
  693. SetNameAsString(StrRepository);
  694. name := "";
  695. archive := NIL;
  696. timestamp := 0;
  697. modified := FALSE;
  698. nextID := 0;
  699. components := NIL;
  700. dictionaries := NIL;
  701. NEW(errors);
  702. NEW(registry, SELF);
  703. next := NIL;
  704. END Init;
  705. (* Post-instantiation initialization *)
  706. PROCEDURE Initialize() : WORD;
  707. VAR enum : XMLObjects.Enumerator; ptr : ANY; element : XML.Element; res : WORD;
  708. BEGIN
  709. nextID := 0;
  710. element := FindChild(SELF, "Components");
  711. IF (element # NIL) THEN
  712. enum := element.GetContents();
  713. WHILE enum.HasMoreElements() DO
  714. ptr := enum.GetNext();
  715. IF (ptr # NIL) & (ptr IS ComponentInfo) THEN
  716. ptr(ComponentInfo).next := components;
  717. components := ptr(ComponentInfo);
  718. nextID := Strings.Max(nextID, components(ComponentInfo).id);
  719. END;
  720. END;
  721. ELSE
  722. res := 9934;
  723. END;
  724. element := FindChild(SELF, XmlDictionaries);
  725. IF (element # NIL) THEN
  726. enum := element.GetContents();
  727. WHILE enum.HasMoreElements() DO
  728. ptr := enum.GetNext();
  729. IF (ptr # NIL) & (ptr IS Dictionary) THEN
  730. ptr(Dictionary).next := dictionaries;
  731. dictionaries := ptr(Dictionary);
  732. dictionaries.repository := SELF;
  733. dictionaries.Initialize;
  734. END;
  735. END;
  736. END;
  737. RETURN res;
  738. END Initialize;
  739. PROCEDURE FindComponentInfo(CONST name : ARRAY OF CHAR; id : LONGINT) : ComponentInfo;
  740. VAR ci : ComponentInfo;
  741. BEGIN
  742. ci := components;
  743. WHILE (ci # NIL) & ((ci.name^ # name) OR (ci.id # id)) DO ci := ci.next; END;
  744. RETURN ci;
  745. END FindComponentInfo;
  746. PROCEDURE GetDictionary*(CONST name : ARRAY OF CHAR) : Dictionary;
  747. VAR d : Dictionary;
  748. BEGIN
  749. d := dictionaries;
  750. WHILE (d # NIL) & (d.name^ # name) DO d := d.next; END;
  751. RETURN d;
  752. END GetDictionary;
  753. PROCEDURE AddComponentInfo(ci : ComponentInfo);
  754. VAR element : XML.Element;
  755. BEGIN
  756. ASSERT(ci # NIL);
  757. element := FindChild(SELF, XmlComponents);
  758. ASSERT(element # NIL);
  759. element.AddContent(ci);
  760. ci.next := components;
  761. components := ci;
  762. END AddComponentInfo;
  763. PROCEDURE RemoveComponentInfo(ci : ComponentInfo);
  764. VAR c : ComponentInfo; element : XML.Element;
  765. BEGIN
  766. ASSERT(ci # NIL);
  767. element := FindChild(SELF, XmlComponents);
  768. ASSERT(element # NIL);
  769. element.RemoveContent(ci);
  770. IF (components # NIL) THEN
  771. IF (components = ci) THEN
  772. components := components.next;
  773. ELSE
  774. c := components;
  775. WHILE (c.next # NIL) & (c.next # ci) DO c := c.next; END;
  776. IF (c.next # NIL) THEN c.next := c.next.next; END;
  777. END;
  778. END;
  779. END RemoveComponentInfo;
  780. PROCEDURE GetComponentEnumerator*() : XMLObjects.Enumerator;
  781. VAR element : XML.Element;
  782. BEGIN
  783. element := FindChild(SELF, XmlComponents);
  784. ASSERT(element # NIL);
  785. RETURN element.GetContents();
  786. END GetComponentEnumerator;
  787. PROCEDURE GetApplicationEnumerator*() : XMLObjects.Enumerator;
  788. VAR element : XML.Element;
  789. BEGIN
  790. element := FindChild(SELF, XmlApplications);
  791. ASSERT(element # NIL);
  792. RETURN element.GetContents();
  793. END GetApplicationEnumerator;
  794. PROCEDURE GetFile(CONST name : ARRAY OF CHAR) : Streams.Reader;
  795. VAR receiver : Streams.Receiver; reader : Streams.Reader;
  796. BEGIN {EXCLUSIVE}
  797. reader := NIL;
  798. archive.Acquire;
  799. receiver := archive.OpenReceiver(name);
  800. archive.Release;
  801. IF (receiver # NIL) THEN
  802. NEW(reader, receiver, 1024);
  803. END;
  804. RETURN reader;
  805. END GetFile;
  806. PROCEDURE Check() : BOOLEAN;
  807. VAR archiveIndex : Archives.Index; error : BOOLEAN; i : LONGINT;
  808. BEGIN {EXCLUSIVE}
  809. error := TRUE;
  810. archive.Acquire;
  811. archiveIndex := archive.GetIndex();
  812. IF (archiveIndex # NIL) THEN
  813. FOR i := 0 TO LEN(archiveIndex)-1 DO
  814. END;
  815. END;
  816. archive.Release;
  817. RETURN error;
  818. END Check;
  819. PROCEDURE GetComponent*(CONST name : ARRAY OF CHAR; id : LONGINT) : Component;
  820. VAR ci : ComponentInfo; component : Component; cname : Name;
  821. BEGIN
  822. IF TraceInstantiate IN Trace THEN
  823. KernelLog.String("GetComponent: ");
  824. KernelLog.String(SELF.name); KernelLog.String(":"); KernelLog.String(name); KernelLog.String(":"); KernelLog.Int(id, 0);
  825. KernelLog.Ln;
  826. END;
  827. ci := FindComponentInfo(name, id);
  828. IF (ci # NIL) & (ci.source # StrNoName) THEN
  829. IF TraceInstantiate IN Trace THEN
  830. KernelLog.String("Entry found for "); KernelLog.String(ci.name^);
  831. KernelLog.String(" (ID="); KernelLog.Int(ci.id, 0); KernelLog.String(", instance: ");
  832. KernelLog.Boolean(ci.instance # NIL); KernelLog.String(")");
  833. KernelLog.Ln;
  834. END;
  835. IF (ci.instance # NIL) THEN
  836. ASSERT(ci.id # PrototypeID);
  837. component := ci.instance(Component);
  838. IF TraceInstantiate IN Trace THEN KernelLog.String("GetComponent: Reuse!!!"); KernelLog.Ln; END;
  839. ELSE
  840. IF (ci.type = Type_Generator) THEN
  841. component := GenerateComponent(ci.source^);
  842. ELSIF (ci.type = Type_Component) THEN
  843. component := LoadComponent(ci.source^);
  844. END;
  845. IF (component # NIL) THEN
  846. IF (ci.type = Type_Generator) THEN
  847. INCL(component.flags, Generated);
  848. ELSIF (ci.type = Type_Component) THEN
  849. (*! what is this for? temporary commented to check persistency implementation.. *)
  850. (*
  851. LockChildren(component);
  852. *)
  853. END;
  854. COPY(ci.name^, cname);
  855. component(Component).SetRepository(SELF, cname, ci.id);
  856. IF (ci.id # PrototypeID) THEN
  857. ci.instance := component; (*TBD: Replaced by weak reference *)
  858. IncrementTimestamp(timestamp);
  859. END;
  860. END;
  861. END;
  862. ELSIF TraceInstantiate IN Trace THEN
  863. KernelLog.String("Repositories.GetComponent: Component '"); KernelLog.String(SELF.name); KernelLog.String(":");
  864. KernelLog.String(name); KernelLog.String(":"); KernelLog.Int(id, 0); KernelLog.String("' not found"); KernelLog.Ln;
  865. END;
  866. RETURN component;
  867. END GetComponent;
  868. PROCEDURE PutComponent*(component : Component; CONST name : ARRAY OF CHAR; VAR id : LONGINT; VAR res : WORD);
  869. VAR ci : ComponentInfo; filename : Files.FileName; nbrStr : ARRAY 16 OF CHAR; cname : Name;
  870. BEGIN
  871. ASSERT(component # NIL); (* TBD: Locking *)
  872. ci := components;
  873. WHILE (ci # NIL) & (ci.instance # component) DO ci := ci.next; END;
  874. IF (ci # NIL) THEN
  875. id := ci.id;
  876. res := Ok;
  877. RETURN
  878. END;
  879. NEW(ci);
  880. IF (id # 0) THEN id := GetID(); END;
  881. Strings.IntToStr(id, nbrStr);
  882. COPY(name, filename); Strings.Append(filename, nbrStr); Strings.Append(filename, ".xml");
  883. ci.SetAttributeValue(XmlAttributeName, name);
  884. ci.SetAttributeValue(XmlAttributeID, nbrStr);
  885. ci.SetAttributeValue(XmlAttributeSource, filename);
  886. ASSERT(ci.type = Type_Component);
  887. ci.instance := component;
  888. StoreComponent(filename, component, res);
  889. IF (res = Ok) THEN
  890. AddComponentInfo(ci);
  891. IF (res = Ok) THEN
  892. COPY(ci.name^, cname);
  893. component.SetRepository(SELF, cname, ci.id);
  894. END;
  895. ELSE HALT(100);
  896. END;
  897. Store(res);
  898. IncrementTimestamp(timestamp);
  899. END PutComponent;
  900. PROCEDURE UnbindComponent*(CONST name : ARRAY OF CHAR; id : LONGINT; VAR res : WORD);
  901. VAR ci : ComponentInfo;
  902. BEGIN
  903. ci := FindComponentInfo(name, id);
  904. IF (ci # NIL) THEN
  905. ci.instance := NIL;
  906. res := Ok;
  907. ELSE
  908. res := NotFound;
  909. END;
  910. IncrementTimestamp(timestamp);
  911. END UnbindComponent;
  912. PROCEDURE Unbind*(component : Component);
  913. VAR c : ComponentInfo;
  914. BEGIN
  915. ASSERT(component # NIL);
  916. c := components;
  917. WHILE (c # NIL) & (c.instance # component) DO c := c.next; END;
  918. IF (c # NIL) THEN
  919. c.instance := NIL;
  920. END;
  921. IncrementTimestamp(timestamp);
  922. END Unbind;
  923. PROCEDURE RemoveComponent*(CONST name : ARRAY OF CHAR; refNum : LONGINT; VAR res : WORD);
  924. VAR ci : ComponentInfo;
  925. BEGIN
  926. archive.Acquire;
  927. ci := FindComponentInfo(name, refNum);
  928. IF (ci # NIL) THEN
  929. RemoveComponentInfo(ci);
  930. IF (ci.type = Type_Component) THEN
  931. archive.RemoveEntry(ci.source^);
  932. END;
  933. res := Ok;
  934. ELSE
  935. res := NotFound;
  936. END;
  937. archive.Release;
  938. IncrementTimestamp(timestamp);
  939. END RemoveComponent;
  940. PROCEDURE Remove*(component : Component; VAR res : WORD);
  941. VAR ci : ComponentInfo;
  942. BEGIN
  943. ci := components;
  944. WHILE (ci # NIL) & (ci.instance # component) DO ci := ci.next; END;
  945. IF (ci # NIL) THEN
  946. archive.Acquire;
  947. RemoveComponentInfo(ci);
  948. IF (ci.type = Type_Component) THEN
  949. archive.RemoveEntry(ci.source^);
  950. END;
  951. archive.Release;
  952. END;
  953. IncrementTimestamp(timestamp);
  954. END Remove;
  955. PROCEDURE LoadComponent(CONST filename : ARRAY OF CHAR) : Component;
  956. VAR element : XML.Element; reader : Streams.Reader;
  957. BEGIN
  958. IF TraceInstantiate IN Trace THEN
  959. KernelLog.String("Repositories.Registry.Create: "); KernelLog.String(filename); KernelLog.Ln;
  960. END;
  961. element := NIL;
  962. reader := GetFile(filename);
  963. IF (reader # NIL) THEN
  964. IF TraceInstantiate IN Trace THEN KernelLog.String("Repositories.Registry.Create: File found"); KernelLog.Ln; END;
  965. element := Parse(reader, registry, errors);
  966. END;
  967. IF (element # NIL) & (element IS Component) THEN
  968. RETURN element (Component);
  969. ELSE
  970. RETURN NIL;
  971. END;
  972. END LoadComponent;
  973. (* Return an ID that is unique withhin this repository *)
  974. PROCEDURE GetID*() : LONGINT;
  975. BEGIN {EXCLUSIVE}
  976. INC(nextID);
  977. RETURN nextID;
  978. END GetID;
  979. PROCEDURE Store*(VAR res : WORD);
  980. VAR writer : Streams.Writer;context: StoreContext;
  981. BEGIN
  982. archive.Acquire;
  983. writer := GetWriter(archive, IndexFile);
  984. IF (writer # NIL) THEN
  985. NEW(context, SELF);
  986. Write(writer, context, 0);
  987. writer.Update;
  988. ELSE
  989. res := 99;
  990. END;
  991. archive.Release;
  992. END Store;
  993. PROCEDURE StoreComponent(CONST filename : ARRAY OF CHAR; component : Component; VAR res : WORD);
  994. VAR writer : Streams.Writer; context: StoreContext;
  995. BEGIN
  996. ASSERT(component # NIL);
  997. archive.Acquire;
  998. writer := GetWriter(archive, filename);
  999. IF (writer # NIL) THEN
  1000. NEW(context, SELF);
  1001. component.Write(writer, context, 0);
  1002. writer.Update;
  1003. res := Ok;
  1004. ELSE
  1005. res := 9912;
  1006. END;
  1007. archive.Release;
  1008. END StoreComponent;
  1009. PROCEDURE Dump*(writer : Streams.Writer);
  1010. BEGIN
  1011. IF (writer = NIL) THEN NEW(writer, KernelLog.Send, 1024); END;
  1012. writer.String("Dump repository "); writer.String(name); writer.String(": "); writer.Ln; writer.Update;
  1013. SELF.Write(writer, NIL, 0); writer.Ln;
  1014. writer.Update;
  1015. END Dump;
  1016. END Repository;
  1017. Repositories* = POINTER TO ARRAY OF Repository;
  1018. Properties* = OBJECT(XML.Element)
  1019. VAR repository-: Repository; (* to pass repository during creation *)
  1020. PROCEDURE &New(r: Repository);
  1021. BEGIN repository := r
  1022. END New;
  1023. END Properties;
  1024. TYPE
  1025. Registry* = OBJECT(XML.ElementRegistry)
  1026. VAR repository: Repository;
  1027. PROCEDURE & InitRegistry(r: Repository);
  1028. BEGIN
  1029. repository := r
  1030. END InitRegistry;
  1031. PROCEDURE InstantiateElement*(CONST name: ARRAY OF CHAR): XML.Element;
  1032. VAR
  1033. repositoryName, componentName : ARRAY 128 OF CHAR; id : LONGINT;
  1034. repository : Repository;
  1035. element : XML.Element;
  1036. properties : Properties;
  1037. BEGIN
  1038. IF TraceInstantiate IN Trace THEN KernelLog.String("Repositories.Registry.InstantiateElement: "); KernelLog.String(name); KernelLog.Ln; END;
  1039. element := NIL;
  1040. IF SplitName(name, repositoryName, componentName, id) THEN
  1041. IF (repositoryName # "") THEN
  1042. repository := ThisRepository(repositoryName);
  1043. IF (repository # NIL) THEN
  1044. element := repository.GetComponent(componentName, id);
  1045. IF TraceInstantiate IN Trace THEN
  1046. KernelLog.String("Repositories.Registry.InstantiateElement: Instantiate component: "); KernelLog.String(componentName); KernelLog.Ln;
  1047. KernelLog.Boolean(element # NIL); KernelLog.Ln;
  1048. END;
  1049. ELSE
  1050. KernelLog.String("Repository not found:"); KernelLog.String(repositoryName); KernelLog.Ln;
  1051. END;
  1052. ELSIF (componentName = "Properties") THEN
  1053. NEW(properties,SELF.repository);
  1054. RETURN properties;
  1055. ELSIF SELF.repository # NIL THEN
  1056. repository := SELF.repository;
  1057. element := repository.GetComponent(componentName, id);
  1058. IF TraceInstantiate IN Trace THEN
  1059. KernelLog.String("Repositories.Registry.InstantiateElement: Instantiate component: "); KernelLog.String(componentName); KernelLog.Ln;
  1060. KernelLog.Boolean(element # NIL); KernelLog.Ln;
  1061. END;
  1062. END;
  1063. ELSE
  1064. KernelLog.String("Wrong name: "); KernelLog.String(name); KernelLog.Ln;
  1065. END;
  1066. RETURN element;
  1067. END InstantiateElement;
  1068. PROCEDURE InstantiateLate*(e: XML.Element): XML.Element;
  1069. VAR generator: XML.String; element: XML.Element;
  1070. moduleName, procedureName : Modules.Name; msg : ARRAY 128 OF CHAR; res : WORD;
  1071. generate : XML.GeneratorProcedure;
  1072. a: XML.Attribute;
  1073. enumerator: XMLObjects.Enumerator;
  1074. ptr: ANY;
  1075. BEGIN
  1076. element := NIL;
  1077. generator := e.GetAttributeValue("generator");
  1078. IF generator # NIL THEN
  1079. IF TraceInstantiate IN Trace THEN KernelLog.String("Repositories.Registry.InstantiateElementLate:"); KernelLog.String(generator^); KernelLog.Ln; END;
  1080. Commands.Split(generator^, moduleName, procedureName, res, msg);
  1081. IF (res = Commands.Ok) THEN
  1082. GETPROCEDURE(moduleName, procedureName, generate);
  1083. IF (generate # NIL) THEN
  1084. element := generate();
  1085. ELSE
  1086. KernelLog.String("Generator procedure not found: ");
  1087. KernelLog.String(moduleName); KernelLog.Char("."); KernelLog.String(procedureName); KernelLog.Ln;
  1088. END;
  1089. ELSE
  1090. KernelLog.String("Invalid generator name"); KernelLog.Ln;
  1091. END;
  1092. END;
  1093. IF (element # NIL) THEN
  1094. enumerator := e.GetAttributes();
  1095. WHILE enumerator.HasMoreElements() DO
  1096. ptr := enumerator.GetNext();
  1097. IF (ptr IS XML.Attribute) THEN
  1098. (*! element must be copied ..., how to avoid this ? *)
  1099. element.SetAttributeValue(ptr(XML.Attribute).GetName()^, ptr(XML.Attribute).GetValue()^);
  1100. (* element.AddAttribute(ptr(XML.Attribute)); *)
  1101. END;
  1102. END;
  1103. RETURN element;
  1104. ELSE
  1105. RETURN e;
  1106. END;
  1107. END InstantiateLate;
  1108. END Registry;
  1109. TYPE
  1110. ErrorReporter = OBJECT
  1111. VAR
  1112. nofErrors : LONGINT;
  1113. PROCEDURE &Reset;
  1114. BEGIN
  1115. nofErrors := 0;
  1116. END Reset;
  1117. PROCEDURE Report(pos, line, col: LONGINT; CONST msg: ARRAY OF CHAR);
  1118. BEGIN
  1119. INC(nofErrors);
  1120. KernelLog.Enter; KernelLog.Char(CHR(9H)); KernelLog.Char(CHR(9H)); KernelLog.String("pos "); KernelLog.Int(pos, 6);
  1121. KernelLog.String(", line "); KernelLog.Int(line, 0); KernelLog.String(", column "); KernelLog.Int(col, 0);
  1122. KernelLog.String(" "); KernelLog.String(msg); KernelLog.Exit;
  1123. END Report;
  1124. END ErrorReporter;
  1125. VAR
  1126. registry- : Registry;
  1127. indexRegistry : IndexRegistry;
  1128. repositories : Repository;
  1129. globalTimestamp : LONGINT;
  1130. StrNoName,
  1131. StrRepository, StrComponent, StrApplication, StrDictionary : Strings.String;
  1132. (* Set Locked flag for <component> and all its children *)
  1133. PROCEDURE SetLockedFlag(component : Component; locked : BOOLEAN);
  1134. VAR c : XML.Content;
  1135. BEGIN
  1136. ASSERT(component # NIL);
  1137. IF locked THEN INCL(component.flags, Locked); ELSE EXCL(component.flags, Locked); END;
  1138. c := component.GetFirst();
  1139. WHILE (c # NIL) DO
  1140. IF (c IS Component) THEN SetLockedFlag(c(Component), locked); END;
  1141. c := component.GetNext(c);
  1142. END;
  1143. END SetLockedFlag;
  1144. PROCEDURE LockChildren(component : Component);
  1145. VAR c : XML.Content;
  1146. BEGIN
  1147. ASSERT(component # NIL);
  1148. c := component.GetFirst();
  1149. WHILE (c # NIL) DO
  1150. IF (c IS Component) THEN SetLockedFlag(c(Component), TRUE); END;
  1151. c := component.GetNext(c);
  1152. END;
  1153. END LockChildren;
  1154. PROCEDURE GenerateComponent*(CONST generator : ARRAY OF CHAR) : Component;
  1155. VAR
  1156. moduleName, procedureName : Modules.Name; msg : ARRAY 128 OF CHAR; res : WORD;
  1157. generate : XML.GeneratorProcedure;
  1158. element : XML.Element;
  1159. BEGIN
  1160. element := NIL;
  1161. Commands.Split(generator, moduleName, procedureName, res, msg);
  1162. IF (res = Commands.Ok) THEN
  1163. GETPROCEDURE(moduleName, procedureName, generate);
  1164. IF (generate # NIL) THEN
  1165. element := generate();
  1166. ELSE
  1167. KernelLog.String("Generator procedure not found: ");
  1168. KernelLog.String(moduleName); KernelLog.Char("."); KernelLog.String(procedureName); KernelLog.Ln;
  1169. END;
  1170. ELSE
  1171. KernelLog.String("Invalid generator name"); KernelLog.Ln;
  1172. END;
  1173. IF (element # NIL) THEN
  1174. RETURN element (Component);
  1175. ELSE
  1176. RETURN NIL;
  1177. END;
  1178. END GenerateComponent;
  1179. PROCEDURE FindChild(parent : XML.Element; CONST elementName : ARRAY OF CHAR) : XML.Element;
  1180. VAR enum : XMLObjects.Enumerator; ptr : ANY; name : Strings.String;
  1181. BEGIN
  1182. ASSERT(parent # NIL);
  1183. enum := parent.GetContents();
  1184. WHILE enum.HasMoreElements() DO
  1185. ptr := enum.GetNext();
  1186. IF (ptr # NIL) & (ptr IS XML.Element) THEN
  1187. name := ptr(XML.Element).GetName();
  1188. IF (name # NIL) & (name^ = elementName) THEN
  1189. RETURN ptr (XML.Element);
  1190. END;
  1191. END;
  1192. END;
  1193. RETURN NIL;
  1194. END FindChild;
  1195. PROCEDURE IncrementTimestamp*(VAR timestamp : LONGINT);
  1196. BEGIN {EXCLUSIVE}
  1197. INC(timestamp);
  1198. INC(globalTimestamp);
  1199. END IncrementTimestamp;
  1200. PROCEDURE GetTimestamp*() : LONGINT;
  1201. BEGIN
  1202. RETURN globalTimestamp;
  1203. END GetTimestamp;
  1204. PROCEDURE AwaitChange*(VAR curTimestamp : LONGINT);
  1205. BEGIN {EXCLUSIVE}
  1206. AWAIT(curTimestamp # globalTimestamp);
  1207. curTimestamp := globalTimestamp;
  1208. END AwaitChange;
  1209. PROCEDURE IsXmlFilename(string : ARRAY OF CHAR) : BOOLEAN;
  1210. BEGIN
  1211. Strings.LowerCase(string);
  1212. RETURN Strings.Match("*.xml", string);
  1213. END IsXmlFilename;
  1214. PROCEDURE Parse(reader : Streams.Reader; elemReg : XML.ElementRegistry; errors : ErrorReporter) : XML.Element;
  1215. VAR scanner : XMLScanner.Scanner; parser : XMLParser.Parser; document : XML.Document;
  1216. BEGIN
  1217. ASSERT((reader # NIL) & (errors # NIL));
  1218. NEW(scanner, reader);
  1219. (* scanner.SetStringPooling({0..31}); *)
  1220. NEW(parser, scanner);
  1221. parser.elemReg := elemReg;
  1222. parser.reportError := errors.Report;
  1223. document := parser.Parse();
  1224. IF (document # NIL) THEN
  1225. RETURN document.GetRoot();
  1226. ELSE
  1227. RETURN NIL;
  1228. END;
  1229. END Parse;
  1230. PROCEDURE GetWriter(archive : Archives.Archive; CONST filename : ARRAY OF CHAR) : Streams.Writer;
  1231. VAR writer : Streams.Writer; sender : Streams.Sender;
  1232. BEGIN (* must hold archive lock!! *)
  1233. sender := archive.OpenSender(filename);
  1234. IF (sender # NIL) THEN
  1235. NEW(writer, sender, 4096);
  1236. ELSE
  1237. writer := NIL;
  1238. END;
  1239. RETURN writer;
  1240. END GetWriter;
  1241. PROCEDURE SplitName*(CONST name : ARRAY OF CHAR; VAR repositoryName, componentName : ARRAY OF CHAR; VAR id : LONGINT) : BOOLEAN;
  1242. VAR count, pos, next : LONGINT; succeeded : BOOLEAN;
  1243. BEGIN
  1244. succeeded := TRUE;
  1245. count := Strings.Count (name, Delimiter);
  1246. IF (count = 0) THEN
  1247. repositoryName := ""; COPY(name, componentName); id := 0;
  1248. ELSIF (count = 1) THEN
  1249. next := Strings.Find(name, 0, Delimiter);
  1250. Strings.Copy(name, 0, next, repositoryName);
  1251. Strings.Copy(name, next + 1, Strings.Length(name) - next, componentName);
  1252. id := 0;
  1253. succeeded := ((repositoryName = "" ) OR IsValidName(repositoryName)) & IsValidName(componentName);
  1254. (* no, this is ambiguous, rather use ":ComponenName:Number" for such cases
  1255. IF ~succeeded & IsValidName(repositoryName) & IsNumber(componentName) THEN
  1256. succeeded := TRUE;
  1257. Strings.StrToInt(componentName, id);
  1258. D.String("split name with index"); D.String(repositoryName); D.String(" : "); D.Int(id,1); D.Ln;
  1259. COPY(repositoryName, componentName);
  1260. repositoryName := "";
  1261. END;
  1262. *)
  1263. ELSIF (count = 2) THEN
  1264. next := Strings.Find(name, 0, Delimiter);
  1265. Strings.Copy(name, 0, next, repositoryName);
  1266. pos := next + 1;
  1267. next := Strings.Find(name, pos, Delimiter);
  1268. Strings.Copy(name, pos, next - pos, componentName);
  1269. pos := next + 1;
  1270. Strings.StrToIntPos(name, id, pos);
  1271. succeeded := ((repositoryName = "") OR IsValidName(repositoryName)) & IsValidName(componentName);
  1272. ELSE
  1273. succeeded := FALSE;
  1274. END;
  1275. RETURN succeeded;
  1276. END SplitName;
  1277. PROCEDURE JoinName*(CONST repositoryName, componentName : ARRAY OF CHAR; id : LONGINT; VAR name : ARRAY OF CHAR);
  1278. VAR nbrStr : ARRAY 16 OF CHAR;
  1279. BEGIN
  1280. COPY(repositoryName, name);
  1281. Strings.Append(name, Delimiter);
  1282. Strings.Append(name, componentName);
  1283. IF (id # 0) THEN
  1284. Strings.Append(name, Delimiter);
  1285. Strings.IntToStr(id, nbrStr);
  1286. Strings.Append(name, nbrStr);
  1287. END;
  1288. END JoinName;
  1289. (** valid name: Starts with latin letter, contains only latin letter and arabic number *)
  1290. PROCEDURE IsValidName*(CONST name : ARRAY OF CHAR) : BOOLEAN;
  1291. VAR valid : BOOLEAN; i : LONGINT;
  1292. BEGIN
  1293. valid := (("A" <= CAP(name[0])) & (CAP(name[0]) <= "Z"));
  1294. IF valid THEN
  1295. i := 0;
  1296. WHILE valid & (i < LEN(name)) & (name[i] # 0X) DO
  1297. valid := (("A" <= CAP(name[i])) & (CAP(name[i]) <= "Z")) OR (("0" <= name[i]) & (name[i] <= "9"));
  1298. INC(i);
  1299. END;
  1300. valid := (i < LEN(name)) & (name[i] = 0X);
  1301. END;
  1302. RETURN valid;
  1303. END IsValidName;
  1304. PROCEDURE IsNumber*(CONST name: ARRAY OF CHAR): BOOLEAN;
  1305. VAR i: LONGINT;
  1306. BEGIN
  1307. i := 0;
  1308. WHILE (i<LEN(name)) & (name[i] # 0X) & ('0' <= name[i]) & (name[i] <= '9') DO
  1309. INC(i);
  1310. END;
  1311. RETURN (i<LEN(name)) & (name[i] = 0X)
  1312. END IsNumber;
  1313. PROCEDURE NewJoinName*(CONST repositoryName, componentName : ARRAY OF CHAR; id : LONGINT) : Strings.String;
  1314. VAR name : ARRAY 256 OF CHAR;
  1315. BEGIN
  1316. JoinName(repositoryName, componentName, id, name);
  1317. RETURN Strings.NewString(name);
  1318. END NewJoinName;
  1319. PROCEDURE SplitFilename(CONST fullname : ARRAY OF CHAR; VAR repositoryName, extension : ARRAY OF CHAR);
  1320. VAR name, path : Files.FileName;
  1321. BEGIN
  1322. Files.SplitPath(fullname, path, name);
  1323. Files.SplitExtension(name, repositoryName, extension);
  1324. END SplitFilename;
  1325. PROCEDURE GetCommand*(CONST command : ARRAY OF CHAR; VAR res : WORD) : Command;
  1326. VAR proc : Command; moduleName, procedureName : Modules.Name; msg : ARRAY 128 OF CHAR;
  1327. BEGIN
  1328. proc := NIL;
  1329. Commands.Split(command, moduleName, procedureName, res, msg);
  1330. IF (res = Commands.Ok) THEN
  1331. GETPROCEDURE(moduleName, procedureName, proc);
  1332. IF (proc # NIL) THEN
  1333. res := Ok;
  1334. ELSE
  1335. res := NotFound;
  1336. KernelLog.String("Repositories.GetCommand: "); KernelLog.String(command);
  1337. KernelLog.String(" not found"); KernelLog.Ln;
  1338. END;
  1339. ELSE
  1340. KernelLog.String("Repositories.GetCommand: "); KernelLog.String(command);
  1341. KernelLog.String(" is not a valid command string, res: "); KernelLog.Int(res, 0); KernelLog.Ln;
  1342. END;
  1343. RETURN proc;
  1344. END GetCommand;
  1345. PROCEDURE IsCommandString*(CONST string : ARRAY OF CHAR) : BOOLEAN;
  1346. BEGIN
  1347. RETURN Strings.StartsWith2(CommandPrefix, string);
  1348. END IsCommandString;
  1349. PROCEDURE ExtractCommand*(CONST string : ARRAY OF CHAR; VAR command : ARRAY OF CHAR);
  1350. BEGIN
  1351. IF IsCommandString(string) THEN
  1352. COPY(string, command);
  1353. Strings.Delete(command, 0, Strings.Length(CommandPrefix));
  1354. ELSE
  1355. command := "";
  1356. END;
  1357. END ExtractCommand;
  1358. PROCEDURE CallCommand*(CONST command : ARRAY OF CHAR; VAR context : Context; VAR res : WORD);
  1359. VAR
  1360. cmd : ARRAY 64 OF CHAR; param : POINTER TO ARRAY OF CHAR; reader : Streams.StringReader;
  1361. proc : Command; i, j : LONGINT; object: ANY;
  1362. BEGIN
  1363. IF Strings.StartsWith2(CommandPrefix, command) THEN
  1364. i := Strings.Length(CommandPrefix);
  1365. ELSE
  1366. i := 0;
  1367. END;
  1368. WHILE (i < LEN(command)) & (command[i] # 0X) & (command[i] <= " ") DO INC(i); END;
  1369. j := 0;
  1370. WHILE (j < LEN(cmd)) & (i < LEN(command)) & (command[i] > " ") DO
  1371. cmd[j] := command[i];
  1372. INC(i); INC(j);
  1373. END;
  1374. IF (j < LEN(cmd)) & (i < LEN(command)) & (j >= 2) (* M.P *) THEN
  1375. cmd[j] := 0X;
  1376. proc := GetCommand(cmd, res);
  1377. IF (res = Ok) THEN
  1378. WHILE (i < LEN(command)) & (command[i] # 0X) & (command[i] <= " ") DO INC(i); END;
  1379. IF (i < Strings.Length(command)) THEN
  1380. NEW(param, Strings.Length(command) - i + 1);
  1381. j := 0;
  1382. WHILE (i < LEN(command)) & (command[i] # 0X) DO param[j] := command[i]; INC(i); INC(j); END;
  1383. param[j] := 0X;
  1384. NEW(reader, Strings.Length(command));
  1385. reader.Set(param^);
  1386. ELSE
  1387. reader := NIL;
  1388. END;
  1389. IF (context = NIL) THEN NEW(context, NIL, reader, NIL, NIL, NIL);
  1390. ELSE
  1391. context.Init(context.in, reader, context.out, context.error, context.caller);
  1392. END;
  1393. proc(context);
  1394. ELSE
  1395. object := GenerateComponent(cmd);
  1396. IF object # NIL THEN
  1397. IF (context = NIL) THEN NEW(context, NIL, reader, NIL, NIL, NIL);
  1398. ELSE
  1399. context.Init(context.in, reader, context.out, context.error, context.caller);
  1400. END;
  1401. context.object := object
  1402. END;
  1403. END;
  1404. ELSE
  1405. res := NotFound;
  1406. END;
  1407. END CallCommand;
  1408. PROCEDURE GetTranslationInfo*(CONST string : ARRAY OF CHAR; VAR dictionary : Dictionary; VAR word : Strings.String; VAR res : WORD);
  1409. VAR repositoryName, dictionaryName, temp : ARRAY 512 OF CHAR; i, j : LONGINT;
  1410. BEGIN
  1411. res := Ok;
  1412. dictionary := NIL; word := NIL;
  1413. IF (LEN(string) > 7) THEN
  1414. (** "::" + LibraryName + ":" + DictionaryName + ":" + DictionaryWord *)
  1415. IF (string[0] = ":") & (string[1] = ":") THEN
  1416. i := 2; j := 0;
  1417. WHILE (i < LEN(string)) & (j < LEN(repositoryName) - 1) & (string[i] # 0X) & (string[i] # ":") DO
  1418. repositoryName[j] := string[i];
  1419. INC(i); INC(j);
  1420. END;
  1421. repositoryName[j] := 0X;
  1422. IF (i < LEN(string)) & (string[i] = ":") THEN
  1423. INC(i); j := 0;
  1424. WHILE (i < LEN(string)) & (j < LEN(dictionaryName) - 1) & (string[i] # 0X) & (string[i] # ":") DO
  1425. dictionaryName[j] := string[i];
  1426. INC(i); INC(j);
  1427. END;
  1428. dictionaryName[j] := 0X;
  1429. IF (i < LEN(string)) & (string[i] = ":") THEN
  1430. INC(i); j := 0;
  1431. WHILE(i < LEN(string)) & (j < LEN(temp) - 1) & (string[i] # 0X) DO
  1432. temp[j] := string[i];
  1433. INC(i); INC(j);
  1434. END;
  1435. temp[j] := 0X;
  1436. IF (i < LEN(string)) & (string[i] = 0X) THEN
  1437. word := Strings.NewString(temp);
  1438. GetDictionary(repositoryName, dictionaryName, dictionary, res);
  1439. IF (res # Ok) THEN
  1440. KernelLog.String("Repositories.GetTranlationInfo: Warning: Dictionary ");
  1441. KernelLog.String(repositoryName); KernelLog.String(":"); KernelLog.String(dictionaryName);
  1442. KernelLog.String(" not found, res: "); KernelLog.Int(res, 0); KernelLog.Ln;
  1443. END;
  1444. END;
  1445. END;
  1446. END;
  1447. END;
  1448. END;
  1449. END GetTranslationInfo;
  1450. PROCEDURE Translate*(CONST string : ARRAY OF CHAR; languages : Localization.Languages) : Strings.String;
  1451. VAR dictionary : Dictionary; word, translation : Strings.String; res : WORD;
  1452. BEGIN
  1453. ASSERT(languages # NIL);
  1454. GetTranslationInfo(string, dictionary, word, res);
  1455. IF (res = Ok) & (dictionary # NIL) & (word # NIL) THEN
  1456. translation := dictionary.Translate(word, languages);
  1457. ELSE
  1458. translation := Strings.NewString(string);
  1459. END;
  1460. ASSERT(translation # NIL);
  1461. RETURN translation;
  1462. END Translate;
  1463. PROCEDURE GetDictionary*(CONST repositoryName, dictionaryName : ARRAY OF CHAR; VAR dictionary : Dictionary; VAR res : WORD);
  1464. VAR repository : Repository;
  1465. BEGIN
  1466. dictionary := NIL;
  1467. repository := ThisRepository(repositoryName);
  1468. IF (repository # NIL) THEN
  1469. dictionary := repository.GetDictionary(dictionaryName);
  1470. IF (dictionary # NIL) THEN
  1471. res := Ok;
  1472. ELSE
  1473. res := DictionaryNotFound;
  1474. END;
  1475. ELSE
  1476. res := RepositoryNotFound;
  1477. END;
  1478. END GetDictionary;
  1479. PROCEDURE GetDictionaryByString*(CONST string : ARRAY OF CHAR; VAR dictionary : Dictionary; VAR res : WORD);
  1480. VAR repositoryName : Files.FileName; dictionaryName : ARRAY 128 OF CHAR; ignoreID : LONGINT;
  1481. BEGIN
  1482. IF SplitName(string, repositoryName, dictionaryName, ignoreID) THEN
  1483. GetDictionary(repositoryName, dictionaryName, dictionary, res);
  1484. ELSE
  1485. res := FormatError;
  1486. END;
  1487. END GetDictionaryByString;
  1488. PROCEDURE GetComponent*(CONST repositoryName, componentName : ARRAY OF CHAR; refNum : LONGINT; VAR component : Component; VAR res : WORD);
  1489. VAR repository : Repository;
  1490. BEGIN
  1491. component := NIL;
  1492. repository := ThisRepository(repositoryName);
  1493. IF (repository # NIL) THEN
  1494. component := repository.GetComponent(componentName, refNum);
  1495. IF (component # NIL) THEN
  1496. res := Ok;
  1497. ELSE
  1498. res := ComponentNotFound;
  1499. END;
  1500. ELSE
  1501. res := RepositoryNotFound;
  1502. END;
  1503. END GetComponent;
  1504. PROCEDURE GetComponentByString*(CONST string : ARRAY OF CHAR; VAR component : Component; VAR res : WORD);
  1505. VAR repositoryName : Files.FileName; componentName : ARRAY 128 OF CHAR; componentID : LONGINT;
  1506. BEGIN
  1507. IF SplitName(string, repositoryName, componentName, componentID) THEN
  1508. GetComponent(repositoryName, componentName, componentID, component, res);
  1509. ELSE
  1510. res := FormatError;
  1511. END;
  1512. END GetComponentByString;
  1513. PROCEDURE PutComponent*(component : Component; CONST repositoryName, componentName : ARRAY OF CHAR; VAR id : LONGINT; VAR res : WORD);
  1514. VAR repository : Repository;
  1515. BEGIN
  1516. ASSERT(component # NIL);
  1517. repository := ThisRepository(repositoryName);
  1518. IF (repository # NIL) THEN
  1519. repository.PutComponent(component, componentName, id, res);
  1520. ELSE
  1521. res := RepositoryNotFound;
  1522. END;
  1523. END PutComponent;
  1524. PROCEDURE UnbindComponent*(CONST repositoryName, componentName : ARRAY OF CHAR; refNum : LONGINT; VAR res : WORD);
  1525. VAR repository : Repository;
  1526. BEGIN
  1527. repository := ThisRepository(repositoryName);
  1528. IF (repository # NIL) THEN
  1529. repository.UnbindComponent(componentName, refNum, res);
  1530. ELSE
  1531. res := RepositoryNotFound;
  1532. END;
  1533. END UnbindComponent;
  1534. PROCEDURE RemoveComponent*(CONST repositoryName, componentName : ARRAY OF CHAR; refNum : LONGINT; VAR res : WORD);
  1535. VAR repository : Repository;
  1536. BEGIN
  1537. repository := ThisRepository(repositoryName);
  1538. IF (repository # NIL) THEN
  1539. repository.RemoveComponent(componentName, refNum, res);
  1540. ELSE
  1541. res := RepositoryNotFound;
  1542. END;
  1543. END RemoveComponent;
  1544. (* Append repository to global list of repositories *)
  1545. PROCEDURE Add(repository : Repository; VAR res : WORD);
  1546. VAR r : Repository;
  1547. BEGIN (* {EXCLUSIVE} *)
  1548. ASSERT(repository # NIL);
  1549. r := FindRepository(repository.name);
  1550. IF (r = NIL) THEN
  1551. IF (repositories = NIL) THEN
  1552. repositories := repository;
  1553. ELSE
  1554. r := repositories;
  1555. WHILE (r.next # NIL) DO r := r.next; END;
  1556. r.next := repository;
  1557. END;
  1558. INC(globalTimestamp);
  1559. res := Ok;
  1560. ELSE
  1561. res := DuplicateRepository;
  1562. END;
  1563. END Add;
  1564. (* Remove repository from global list of repositories *)
  1565. PROCEDURE Remove(repository : Repository; VAR res : WORD);
  1566. VAR r : Repository;
  1567. BEGIN (* {EXCLUSIVE} *)
  1568. ASSERT(repository # NIL);
  1569. IF (repositories = repository) THEN
  1570. repositories := repository.next;
  1571. res := Ok;
  1572. ELSE
  1573. r := repositories;
  1574. WHILE (r # NIL) & (r.next # repository) DO r := r.next; END;
  1575. IF (r # NIL) THEN
  1576. r.next := r.next.next;
  1577. res := Ok;
  1578. ELSE
  1579. res := RepositoryNotFound;
  1580. END;
  1581. END;
  1582. IF (res = Ok) THEN INC(globalTimestamp); END;
  1583. END Remove;
  1584. (* Find a loaded repository by name *)
  1585. PROCEDURE FindRepository(CONST name : ARRAY OF CHAR) : Repository;
  1586. VAR r : Repository;
  1587. BEGIN
  1588. r := repositories;
  1589. WHILE (r # NIL) & (r.name # name) DO r := r.next; END;
  1590. RETURN r;
  1591. END FindRepository;
  1592. (** Retrieve a repository be name *)
  1593. PROCEDURE ThisRepository*(CONST name : ARRAY OF CHAR) : Repository;
  1594. VAR r : Repository; res : WORD;
  1595. BEGIN {EXCLUSIVE}
  1596. r := FindRepository(name);
  1597. IF (r = NIL) THEN
  1598. r := LoadRepository(name, res);
  1599. END;
  1600. RETURN r;
  1601. END ThisRepository;
  1602. (** Retrieve all currently loaded repositories *)
  1603. PROCEDURE GetAll*(VAR reps : Repositories);
  1604. VAR
  1605. r : Repository;
  1606. nofRepositories, i : LONGINT;
  1607. PROCEDURE GetNofRepositories() : LONGINT;
  1608. VAR r : Repository; nofRepositories : LONGINT;
  1609. BEGIN
  1610. nofRepositories := 0;
  1611. r := repositories;
  1612. WHILE (r # NIL) DO INC(nofRepositories); r := r.next; END;
  1613. RETURN nofRepositories;
  1614. END GetNofRepositories;
  1615. BEGIN {EXCLUSIVE}
  1616. nofRepositories := GetNofRepositories();
  1617. IF (nofRepositories > 0) THEN
  1618. IF (reps = NIL) OR (LEN(reps) < nofRepositories) THEN NEW(reps, nofRepositories); END;
  1619. r := repositories; i := 0;
  1620. WHILE (i < LEN(reps)) DO
  1621. reps[i] := r;
  1622. IF (r # NIL) THEN r := r.next; END;
  1623. INC(i);
  1624. END;
  1625. ELSE
  1626. IF (reps # NIL) THEN
  1627. FOR i := 0 TO LEN(reps)-1 DO reps[i] := NIL; END;
  1628. END;
  1629. END;
  1630. END GetAll;
  1631. (* Load a repository *)
  1632. PROCEDURE LoadRepository(CONST name : ARRAY OF CHAR; VAR res : WORD) : Repository;
  1633. VAR
  1634. filename : Files.FileName;
  1635. repository : Repository;
  1636. archive : Archives.Archive;
  1637. receiver : Streams.Receiver; reader : Streams.Reader;
  1638. element : XML.Element;
  1639. ignore : WORD;
  1640. errors : ErrorReporter;
  1641. file: Files.File; writer: Files.Writer; freader: Files.Reader; ch: CHAR; buf: ARRAY 512 OF CHAR; len: LONGINT;
  1642. BEGIN (* {EXCLUSIVE} *)
  1643. ASSERT(FindRepository(name) = NIL);
  1644. COPY(name, filename);
  1645. Strings.Append(filename, "."); Strings.Append(filename, DefaultFileExtension);
  1646. IF TraceLoading IN Trace THEN KernelLog.String("Repositories.LoadRepository: "); KernelLog.String(filename); KernelLog.String(" ... "); END;
  1647. repository := NIL;
  1648. archive := Archives.Old(filename, "tar");
  1649. IF (archive # NIL) THEN
  1650. IF TraceLoading IN Trace THEN KernelLog.String("archive found ... "); END;
  1651. archive.Acquire;
  1652. receiver := archive.OpenReceiver(IndexFile);
  1653. archive.Release;
  1654. IF (receiver # NIL) THEN
  1655. NEW(reader, receiver, 4096);
  1656. (*
  1657. file := Files.New("");
  1658. Files.OpenWriter(writer, file, 0);
  1659. REPEAT
  1660. reader.Bytes(buf, 0, LEN(buf), len); writer.Bytes(buf, 0, len);
  1661. UNTIL reader.res # 0;
  1662. writer.Update;
  1663. Files.OpenReader(freader, file,0);
  1664. reader := freader;
  1665. *)
  1666. IF TraceLoading IN Trace THEN KernelLog.String("index file found ... "); END;
  1667. (*NEW(reader, receiver, 4096);*)
  1668. NEW(errors);
  1669. element := Parse(reader, indexRegistry, errors);
  1670. IF (element # NIL) & (element IS Repository) THEN
  1671. repository := element (Repository);
  1672. repository.archive := archive;
  1673. COPY(name, repository.name);
  1674. COPY(filename, repository.filename);
  1675. ignore := repository.Initialize();
  1676. END;
  1677. IF (repository # NIL) THEN
  1678. IF TraceLoading IN Trace THEN KernelLog.String("index file parsed... "); END;
  1679. Add(repository, res);
  1680. END;
  1681. ELSE
  1682. res := FormatError;
  1683. END;
  1684. ELSE
  1685. res := RepositoryNotFound;
  1686. END;
  1687. IF TraceLoading IN Trace THEN KernelLog.Int(res, 0); KernelLog.Ln; END;
  1688. RETURN repository;
  1689. END LoadRepository;
  1690. (** Unload a currently loaded repository *)
  1691. PROCEDURE UnloadRepository*(CONST name : ARRAY OF CHAR; VAR res : WORD);
  1692. VAR repository : Repository;
  1693. BEGIN {EXCLUSIVE}
  1694. repository := FindRepository(name);
  1695. IF (repository # NIL) THEN
  1696. Remove(repository, res);
  1697. ELSE
  1698. res := RepositoryNotLoaded;
  1699. END;
  1700. END UnloadRepository;
  1701. (** Store the current state of a currenlty loaded repository *)
  1702. PROCEDURE StoreRepository*(CONST name : ARRAY OF CHAR; VAR res : WORD);
  1703. VAR repository : Repository;
  1704. BEGIN {EXCLUSIVE}
  1705. repository := FindRepository(name);
  1706. IF (repository # NIL) THEN
  1707. repository.Store(res);
  1708. INC(globalTimestamp);
  1709. ELSE
  1710. res := RepositoryNotLoaded;
  1711. END;
  1712. END StoreRepository;
  1713. (** Create an empty new repository.
  1714. The repository name is derived from the filename (repository name = filename without extension)
  1715. The repository is not loaded upon creation *)
  1716. PROCEDURE CreateRepository*(CONST filename : ARRAY OF CHAR; VAR res : WORD);
  1717. VAR
  1718. repository : Repository;
  1719. archive : Archives.Archive;
  1720. sender : Streams.Sender; writer : Streams.Writer;
  1721. extension : ARRAY 16 OF CHAR;
  1722. PROCEDURE AddHeader(parent : XML.Element);
  1723. VAR header, element : XML.Element; charArray : XML.ArrayChars;
  1724. BEGIN
  1725. ASSERT(parent # NIL);
  1726. NEW(header); header.SetName("Header");
  1727. parent.AddContent(header);
  1728. NEW(element); element.SetName("Version");
  1729. header.AddContent(element);
  1730. NEW(charArray); charArray.SetStr("1");
  1731. element.AddContent(charArray);
  1732. NEW(element); element.SetName("Public");
  1733. header.AddContent(element);
  1734. NEW(charArray); charArray.SetStr("FALSE");
  1735. element.AddContent(charArray);
  1736. END AddHeader;
  1737. PROCEDURE AddStructure(parent : XML.Element);
  1738. VAR element : XML.Element;
  1739. BEGIN
  1740. ASSERT(parent # NIL);
  1741. NEW(element); element.SetName("Applications"); parent.AddContent(element);
  1742. NEW(element); element.SetName("Components"); parent.AddContent(element);
  1743. NEW(element); element.SetName("Dictionaries"); parent.AddContent(element);
  1744. END AddStructure;
  1745. BEGIN
  1746. IF TraceCreation IN Trace THEN KernelLog.String("Repositories.CreateRepository "); KernelLog.String(filename); KernelLog.String(" ... "); END;
  1747. archive := Archives.New(filename, "tar");
  1748. IF (archive # NIL) THEN
  1749. archive.Acquire;
  1750. sender := archive.OpenSender(IndexFile);
  1751. archive.Release;
  1752. IF (sender # NIL) THEN
  1753. NEW(writer, sender, 4096);
  1754. NEW(repository);
  1755. SplitFilename(filename, repository.name, extension);
  1756. COPY(filename, repository.filename);
  1757. repository.archive := archive;
  1758. AddHeader(repository);
  1759. AddStructure(repository);
  1760. writer.String('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'); writer.Ln;
  1761. repository.Write(writer, NIL, 0);
  1762. writer.Update;
  1763. res := Ok;
  1764. ELSE
  1765. res := ArchivesError;
  1766. END;
  1767. ELSE
  1768. res := CannotCreateArchive;
  1769. END;
  1770. IF TraceCreation IN Trace THEN KernelLog.String("res = "); KernelLog.Int(res, 0); KernelLog.Ln; END;
  1771. END CreateRepository;
  1772. (*
  1773. PROCEDURE FromXMLInRepository*(xml: XML.Element; repository: Repository);
  1774. VAR generator: PROCEDURE(): XML.Element;
  1775. VAR
  1776. l,name: Strings.String;
  1777. moduleName, procedureName: Modules.Name;
  1778. res: WORD; msg: ARRAY 32 OF CHAR;
  1779. component: Component;
  1780. element: XML.Element;
  1781. BEGIN
  1782. component := NIL;
  1783. IF xml # NIL THEN
  1784. name := xml.GetName();
  1785. l := xml.GetAttributeValue("generator");
  1786. IF l # NIL THEN
  1787. Commands.Split(l^, moduleName, procedureName, res, msg);
  1788. IF (res = Commands.Ok) THEN
  1789. GETPROCEDURE(moduleName, procedureName, generator);
  1790. IF (generator # NIL) THEN
  1791. element := generator();
  1792. IF (element # NIL) & (element IS Component) THEN
  1793. component := element(Component);
  1794. component.SetName(name^);
  1795. component.FromXMLInRepository(xml,repository);
  1796. END;
  1797. ELSE KernelLog.String("WMComponents error: invalid generator "); KernelLog.String(l^); KernelLog.Ln;
  1798. END;
  1799. ELSE KernelLog.String("WMComponents error: could not generate component "); KernelLog.String(l^); KernelLog.Ln;
  1800. END;
  1801. ELSE
  1802. l := xml.GetAttributeValue("reference");
  1803. IF l # NIL THEN
  1804. repository.GetComponent(l^);
  1805. END;
  1806. END;
  1807. RETURN component
  1808. END FromXMLInRepository;
  1809. *)
  1810. PROCEDURE ComponentFromXML*(xml: XML.Element): Component;
  1811. VAR generator: PROCEDURE(): XML.Element;
  1812. VAR
  1813. l,name: Strings.String;
  1814. moduleName, procedureName: Modules.Name;
  1815. res: WORD; msg: ARRAY 32 OF CHAR;
  1816. component: Component;
  1817. element: XML.Element;
  1818. BEGIN
  1819. component := NIL;
  1820. IF xml # NIL THEN
  1821. name := xml.GetName();
  1822. l := xml.GetAttributeValue("generator");
  1823. IF l # NIL THEN
  1824. Commands.Split(l^, moduleName, procedureName, res, msg);
  1825. IF (res = Commands.Ok) THEN
  1826. GETPROCEDURE(moduleName, procedureName, generator);
  1827. IF (generator # NIL) THEN
  1828. element := generator();
  1829. IF (element # NIL) & (element IS Component) THEN
  1830. component := element(Component);
  1831. component.SetName(name^);
  1832. component.FromXML(xml);
  1833. END;
  1834. ELSE KernelLog.String("WMComponents error: invalid generator "); KernelLog.String(l^); KernelLog.Ln;
  1835. END;
  1836. ELSE KernelLog.String("WMComponents error: could not generate component "); KernelLog.String(l^); KernelLog.Ln;
  1837. END;
  1838. END;
  1839. END;
  1840. RETURN component
  1841. END ComponentFromXML;
  1842. PROCEDURE ShowRes*(res : WORD; out : Streams.Writer);
  1843. BEGIN
  1844. ASSERT(out # NIL);
  1845. out.String("res: "); out.Int(res, 0);
  1846. out.String(" (");
  1847. CASE res OF
  1848. |Ok: out.String("Ok");
  1849. |NotFound: out.String("Not found");
  1850. |RepositoryNotFound: out.String("Repository not found");
  1851. |ComponentNotFound: out.String("Component not found");
  1852. |RepositoryNotLoaded: out.String("Repository not loaded");
  1853. |DuplicateName: out.String("Duplicate name");
  1854. |DuplicateID: out.String("Duplicate ID");
  1855. |DuplicateRepository: out.String("Duplicate repository");
  1856. |IndexError: out.String("Index error");
  1857. |CannotCreateArchive: out.String("Cannot create archive");
  1858. |ArchivesError: out.String("Archive error");
  1859. |WrongVersion: out.String("Wrong version");
  1860. |FormatError: out.String("Format error");
  1861. ELSE
  1862. out.String("Unknown");
  1863. END;
  1864. out.String(")");
  1865. END ShowRes;
  1866. (** Create an empty repository *)
  1867. PROCEDURE Create*(context : Commands.Context); (** repositoryName ~ *)
  1868. VAR repositoryName : Files.FileName; res : WORD;
  1869. BEGIN
  1870. context.arg.SkipWhitespace; context.arg.String(repositoryName);
  1871. context.out.String("Creating repository '"); context.out.String(repositoryName); context.out.String("' ... ");
  1872. context.out.Update;
  1873. CreateRepository(repositoryName, res);
  1874. IF (res = Ok) THEN
  1875. context.out.String("done.");
  1876. ELSE
  1877. context.out.String("not done, "); ShowRes(res, context.out);
  1878. END;
  1879. context.out.Ln;
  1880. END Create;
  1881. PROCEDURE Store*(context : Commands.Context); (** repositoryName ~ *)
  1882. VAR repositoryName : Files.FileName; res : WORD;
  1883. BEGIN
  1884. context.arg.SkipWhitespace; context.arg.String(repositoryName);
  1885. context.out.String("Storing repository '"); context.out.String(repositoryName); context.out.String("' ... "); context.out.Update;
  1886. StoreRepository(repositoryName, res);
  1887. IF (res = Ok) THEN
  1888. context.out.String("done.");
  1889. ELSE
  1890. context.out.String("not done, "); ShowRes(res, context.out);
  1891. END;
  1892. context.out.Ln;
  1893. END Store;
  1894. PROCEDURE Load*(context : Commands.Context); (** filename ~ *)
  1895. VAR repository : Repository; filename : Files.FileName;
  1896. BEGIN
  1897. context.arg.SkipWhitespace; context.arg.String(filename);
  1898. context.out.String("Loading repository '"); context.out.String(filename); context.out.String("' ... ");
  1899. repository := ThisRepository(filename);
  1900. IF (repository # NIL) THEN
  1901. context.out.String("done.");
  1902. ELSE
  1903. context.out.String("repository not found.");
  1904. END;
  1905. context.out.Ln;
  1906. END Load;
  1907. PROCEDURE Unload*(context : Commands.Context); (** repositoryName ~ *)
  1908. VAR repositoryName : Files.FileName; res : WORD;
  1909. BEGIN
  1910. context.arg.SkipWhitespace; context.arg.String(repositoryName);
  1911. context.out.String("Unloaded repository '"); context.out.String(repositoryName); context.out.String("' ... "); context.out.Update;
  1912. UnloadRepository(repositoryName, res);
  1913. IF (res = Ok) THEN
  1914. context.out.String("done.");
  1915. ELSE
  1916. context.out.String("not done, "); ShowRes(res, context.out);
  1917. END;
  1918. context.out.Ln;
  1919. END Unload;
  1920. (** Put component into repository *)
  1921. PROCEDURE Put*(context : Commands.Context); (** componentName repositoryName asName [zeroID] ~ *)
  1922. VAR
  1923. componentName, repositoryName, asName : ARRAY 256 OF CHAR;
  1924. nbr : ARRAY 3 OF CHAR;
  1925. component : Component; id : LONGINT; res: WORD;
  1926. BEGIN
  1927. context.arg.SkipWhitespace; context.arg.String(componentName);
  1928. context.arg.SkipWhitespace; context.arg.String(repositoryName);
  1929. context.arg.SkipWhitespace; context.arg.String(asName);
  1930. context.arg.SkipWhitespace; context.arg.String(nbr);
  1931. IF (nbr = "0") THEN id := 0; ELSE id := -1; END;
  1932. context.out.String("Put component '"); context.out.String(componentName);
  1933. context.out.String("' to repository '"); context.out.String(repositoryName); context.out.String("' as '");
  1934. context.out.String(asName); context.out.String("' ... ");
  1935. context.out.Update;
  1936. GetComponentByString(componentName, component, res);
  1937. IF (res = Ok) & (component # NIL) THEN
  1938. PutComponent(component, repositoryName, asName, id, res);
  1939. IF (res = Ok) THEN
  1940. context.out.String("done.");
  1941. ELSE
  1942. context.out.String("not done, "); ShowRes(res, context.out);
  1943. END;
  1944. ELSE
  1945. context.out.String("component loading error, "); ShowRes(res, context.out);
  1946. END;
  1947. context.out.Ln;
  1948. END Put;
  1949. PROCEDURE Dump*(context : Commands.Context); (** filename ~ *)
  1950. VAR repository : Repository; filename : Files.FileName;
  1951. BEGIN
  1952. context.arg.SkipWhitespace; context.arg.String(filename);
  1953. context.out.String("Dump of repository '"); context.out.String(filename); context.out.String("': ");
  1954. context.out.Ln; context.out.Update;
  1955. repository := ThisRepository(filename);
  1956. IF (repository # NIL) THEN
  1957. repository.Dump(context.out);
  1958. ELSE
  1959. context.out.String("Repository not found.");
  1960. END;
  1961. context.out.Ln;
  1962. END Dump;
  1963. PROCEDURE DumpAll*(context : Commands.Context); (** ~ *)
  1964. VAR repositories : Repositories; count, i : LONGINT;
  1965. BEGIN
  1966. context.out.String("Currently loaded repositories: "); context.out.Ln;
  1967. GetAll(repositories);
  1968. IF (repositories # NIL) THEN
  1969. count := 0;
  1970. FOR i := 0 TO LEN(repositories) - 1 DO
  1971. IF (repositories[i] # NIL) THEN
  1972. INC(count);
  1973. repositories[i].Dump(context.out);
  1974. END;
  1975. END;
  1976. context.out.Int(count, 0); context.out.String(" repositories loaded.");
  1977. ELSE
  1978. context.out.String("none");
  1979. END;
  1980. context.out.Ln;
  1981. END DumpAll;
  1982. PROCEDURE Call*(context : Commands.Context); (** moduleName.procedureName [params] ~ *)
  1983. VAR c : Context; cmdString : POINTER TO ARRAY OF CHAR; res : WORD; ignore: LONGINT;
  1984. BEGIN
  1985. NEW(c, NIL, NIL, context.out, context.error, context.caller);
  1986. IF (context.arg.Available() > 0) THEN
  1987. NEW(cmdString, context.arg.Available());
  1988. context.arg.Bytes(cmdString^, 0, LEN(cmdString), ignore);
  1989. CallCommand(cmdString^, c, res);
  1990. context.out.String("res: "); context.out.Int(res, 0); context.out.Ln;
  1991. context.out.String("c.res: "); context.out.Int(c.result, 0); context.out.Ln;
  1992. context.out.String("c.object: ");
  1993. IF (c.object = NIL) THEN context.out.String("NIL"); ELSE context.out.String("Present"); END;
  1994. context.out.Ln;
  1995. ELSE
  1996. context.error.String("Missing arguments"); context.error.Ln;
  1997. END;
  1998. END Call;
  1999. PROCEDURE InitStrings;
  2000. BEGIN
  2001. StrNoName := Strings.NewString("NoName");
  2002. StrRepository := Strings.NewString(XmlRepository);
  2003. StrComponent := Strings.NewString(XmlComponent);
  2004. StrApplication := Strings.NewString(XmlApplication);
  2005. StrDictionary := Strings.NewString(XmlDictionary);
  2006. END InitStrings;
  2007. BEGIN
  2008. globalTimestamp := 0;
  2009. repositories := NIL;
  2010. InitStrings;
  2011. NEW(registry,NIL); NEW(indexRegistry);
  2012. END Repositories.