Assembling pages

This is the thirteenth post in the Mostly Oberon series. Mostly Oberon documents my exploration of the Oberon Language, Oberon System and the various rabbit holes I will inevitably fall into.

Pandoc and JSON

I use Pandoc to process Markdown documents. I like to keep my front matter in JSON rather than Pandoc’s YAML. Fortunately Pandoc does support working with JSON as a metadata file include. Normally I would manually split the JSON front matter and the rest of the markup into two separate files, then process with Pandoc and other tooling like LunrJS. AssemblePage automates this process.

Example shell usage:

  1. AssemblePage MyText.txt \
  2. metadata=document.json \
  3. document=document.md
  4. pandoc --from markdown --to html \
  5. --metadata-file document.json \
  6. --standalone \
  7. document.md >MyText.html

Source code for AssemblePage.Mod

  1. MODULE AssemblePage;
  2. IMPORT Out, Strings, Files, Args := extArgs;
  3. VAR
  4. srcName, metaName, docName : ARRAY 1024 OF CHAR;
  5. (* FrontMatter takes a "read" Rider, r, and a "write" Rider "w".
  6. If the first character read by r is an opening curly bracket
  7. (the start of the front matter) it writes it out with w, until
  8. it finds a matching closing curly bracket or the file ends. *)
  9. PROCEDURE FrontMatter*(VAR r : Files.Rider; VAR w : Files.Rider);
  10. VAR c : BYTE; cCnt : INTEGER;
  11. BEGIN
  12. (* Scan for opening JSON front matter *)
  13. cCnt := 0;
  14. REPEAT
  15. Files.Read(r, c);
  16. IF r.eof = FALSE THEN
  17. IF c = ORD("{") THEN
  18. cCnt := cCnt + 1;
  19. ELSIF c = ORD("}") THEN
  20. cCnt := cCnt - 1;
  21. END;
  22. Files.Write(w, c);
  23. END;
  24. UNTIL (r.eof = TRUE) OR (cCnt = 0);
  25. IF cCnt # 0 THEN
  26. Out.String("ERROR: mis matched '{' and '}' in front matter");
  27. ASSERT(FALSE);
  28. END;
  29. END FrontMatter;
  30. (* CopyIO copies the characters from a "read" Rider to a "write" Rider *)
  31. PROCEDURE CopyIO*(VAR r : Files.Rider; VAR w: Files.Rider);
  32. VAR c : BYTE;
  33. BEGIN
  34. REPEAT
  35. Files.Read(r, c);
  36. IF r.eof = FALSE THEN
  37. Files.Write(w, c);
  38. END;
  39. UNTIL r.eof = TRUE;
  40. END CopyIO;
  41. PROCEDURE ProcessParameters(VAR sName, mName, dName : ARRAY OF CHAR);
  42. VAR
  43. arg : ARRAY 1024 OF CHAR;
  44. i, res : INTEGER;
  45. BEGIN
  46. mName := "document.json";
  47. dName := "document.txt";
  48. arg := "";
  49. FOR i := 0 TO (Args.count - 1) DO
  50. Args.Get(i, arg, res);
  51. IF Strings.Pos("metadata=", arg, 0) = 0 THEN
  52. Strings.Extract(arg, 9, Strings.Length(arg), mName);
  53. ELSIF Strings.Pos("document=", arg, 0) = 0 THEN
  54. Strings.Extract(arg, 9, Strings.Length(arg), dName);
  55. ELSE
  56. Strings.Extract(arg, 0, Strings.Length(arg), sName);
  57. END;
  58. END;
  59. END ProcessParameters;
  60. PROCEDURE AssemblePage(srcName, metaName, docName : ARRAY OF CHAR);
  61. VAR
  62. src, meta, doc : Files.File;
  63. reader, writer : Files.Rider;
  64. BEGIN
  65. src := Files.Old(srcName);
  66. IF src # NIL THEN
  67. Files.Set(reader, src, 0);
  68. IF metaName # "" THEN
  69. meta := Files.New(metaName);
  70. Files.Register(meta);
  71. Files.Set(writer, meta, 0);
  72. FrontMatter(reader, writer);
  73. Files.Close(meta);
  74. END;
  75. IF docName # "" THEN
  76. doc := Files.New(docName);
  77. Files.Register(doc);
  78. Files.Set(writer, doc, 0);
  79. CopyIO(reader, writer);
  80. Files.Close(doc);
  81. END;
  82. ELSE
  83. Out.String("ERROR: Could not read ");Out.String(srcName);Out.Ln();
  84. ASSERT(FALSE);
  85. END;
  86. Files.Close(src);
  87. END AssemblePage;
  88. BEGIN
  89. ProcessParameters(srcName, metaName, docName);
  90. AssemblePage(srcName, metaName, docName);
  91. END AssemblePage.

Next, Previous