1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
#!/usr/bin/env rdmd
/+
- read in file .sst .ssi .ssm
- loop twice
- first
- check for and skip code blocks
- use unique code marker for endnote markers in text and give an endnote
number ★1, increment
- extract all endnotes in array
- second
- check that the footnote marker number count matches the number of notes
in the array
- if they match either:
- substitute each endnote marker with the array footnote[number-1]
- substitute each endnote marker with footnote
as inlined footnote markup (footnote number not needed)
- if they do not match exit
- check whether changes have been made
- if so write file with inline footnotes in sub-directory converted_output_/
using the same name as the original file
- else, exit
+/
import std.stdio;
import std.file;
import std.array : split;
import std.exception;
import core.stdc.errno;
import std.regex;
import std.format;
import std.conv;
void main(string[] args) {
static comment = ctRegex!(`^%+ `);
static block_tic_code_open = ctRegex!("^`{3} code(?:[.](?P<syntax>[a-z][0-9a-z#+_]+))?(?:[(](?P<attrib>[ a-zA-Z0-9;:,]*)[)])?");
static block_tic_close = ctRegex!("^(`{3})$","m");
static block_curly_code_open = ctRegex!(`^(?:code(?:[.](?P<syntax>[a-z][0-9a-z_]+))?(?:[(](?P<attrib>[ a-zA-Z0-9;:,]*)[)])?[{][ ]*$)`);
static block_curly_code_close = ctRegex!(`^([}]code)`);
auto rgx_endnote_ref = ctRegex!(`([~]\^)(?P<tail>[)\]]? |$)`, "gm");
auto rgx_endnote = ctRegex!(`^\^~\s+(.+|\n)`, "gm");
foreach(arg; args[1..$]) {
if (
!(arg.match(regex(r"--\w+")))
&& arg.match(regex(r"\w+?\.ss[itm]"))
) {
writeln(arg);
string filename = arg;
try {
string[] contents, endnotes, endnote_refs;
string text = filename.readText;
string[] paragraphs = text.split("\n\n");
int endnote_ref_count = 0;
int code_block_status = 0;
enum codeBlock { off, curly, tic, }
foreach (paragraph; paragraphs) { /+ loop to gather binary endnotes +/
if (code_block_status == codeBlock.off
&& paragraph.match(rgx_endnote)
) {
endnotes ~= replaceAll!(m => m[1])
(paragraph, rgx_endnote);
} else {
if ((code_block_status == codeBlock.curly
&& paragraph.matchFirst(block_curly_code_close))
|| ((code_block_status == codeBlock.tic
&& paragraph.matchFirst(block_tic_close))
) {
code_block_status = codeBlock.off;
} else if ( type["curly_code"] == 1 || type["tic_code"] == 1) {
// skip, prevent search for endnotes
} else if (paragraph.matchFirst(block_curly_code_open)) {
code_block_status = codeBlock.curly;
} else if (paragraph.matchFirst(block_tic_code_open)) {
code_block_status = codeBlock.tic;
} else if (auto m = paragraph.matchAll(rgx_endnote_ref)) {
foreach (n; m) {
endnote_ref_count++; // endnote_refs ~= (n.captures[1]);
}
}
contents ~= paragraph;
}
}
if (endnotes.length == endnote_ref_count) {
import std.outbuffer;
writeln("endnote ref count: ", endnote_ref_count);
writeln("number of binary endnotes: ", endnotes.length);
int endnote_count = -1;
auto buffer = new OutBuffer();
foreach (content; contents) { /+ loop to inline endnotes +/
content = replaceAll!(m => "~{ " ~ endnotes[++endnote_count] ~ " }~" ~ m["tail"] )
(content, rgx_endnote_ref);
buffer.write(content ~ "\n\n");
}
if (buffer) {
try {
string dir_out = "converted_output_";
string path_and_file_out = dir_out ~ "/" ~ filename;
dir_out.mkdirRecurse;
auto f = File(path_and_file_out, "w");
f.write(buffer);
writeln("wrote: ", path_and_file_out);
} catch (FileException ex) {
writeln("did not write file");
// Handle errors
}
}
} else {
writeln("ERROR binary endnote mismatch, check markup,\nmisatch in the number of endnotes & endnote references!");
writeln(" number of endnotes: ", endnotes.length);
writeln(" number of endnote refs: ", endnote_ref_count); // endnote_refs.length,
}
// assert(endnotes.length == endnote_ref_count);
} catch (ErrnoException ex) {
switch(ex.errno) {
case EPERM:
case EACCES: // Permission denied
break;
case ENOENT: // File does not exist
break;
default: // Handle other errors
break;
}
}
}
}
}
|