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 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
#!/usr/bin/env pike
// Converts CHANGES to an XML form used to port change notes on pike.ida.liu.se
// Usage: tools/changes2html.pike CHANGES | xclip (And then paste into CMS)
constant sub = "---"; //If a line begins with this the line above is a header.
void main(int argc, array argv)
{
string changes = Stdio.read_file(argv[1]);
string state = "INIT";
string out, tmp;
out = "<column charwidth='60'>\n\n";
foreach(changes/"\n", string line)
{
line -= "\r";
// werror("state: %O\nout: %O\ntmp: %O\nline: %O\n-------\n", state, out, tmp, line);
switch(state) {
case "INIT":
if(!text(line))
continue;
if(line[0..sizeof(sub)-1] == sub)
{
out += make_header(1, tmp);
state = "NONE";
continue;
}
if(sizeof(line)>=sizeof(sub))
tmp = line;
continue;
case "NONE":
if(!text(line))
continue;
if(line[0..1] == "o ")
{
tmp = line[2..]+"\n";
out += make_list_start();
state = "BULLET";
continue;
}
tmp = line;
state = "HEADER"; //FIXME: large assumption, really should be TEXT.
continue;
case "TEXT":
exit(1, "FATAL: unhandled state 'TEXT'\n");
case "HEADER":
//We only want the latest batch of changes.
if(has_prefix(tmp, "Changes since Pike"))
{
out += "</column>\n";
//Tweaks
//Remove 2nd empty <p>. Should really be done in make_bullet()
out = replace(out,
({ "\n<p>\n</p><p>\n</p>" }),
({ "\n<p></p>" }));
//Remove ":" at end of header line
out = replace(out,
({ ":</b>" }),
({ "</b>" }));
//Things that still has to be fixed manually:
// o Sub-bullets (could be automated easily)
// o One sentence bullets spread over several lines (trivial a)
// o Run-on descriptions with no clear bullet header (resonable method for some: Let "(Fixed bug .*) ((that|where) .*)" be header: /1, body: /2)
// o Putting emphasis on "You are encouraged to ugrade just for this fix .*" sentences. (trivial a)
write(out);
exit(0);
}
if(line[0..sizeof(sub)-1] == sub)
{
out += make_header(2, tmp);
state = "NONE";
continue;
} else
exit(1, "FATAL: Header state without underline.\n");
continue;
case "BULLET": //broken by header or new bullet (or unindented text?)
if(line[0..1] == "o ")
{
out += make_bullet(tmp);
tmp = line[2..]+"\n";
state = "BULLET";
continue;
}
if(!indented(line))
{
out += make_bullet(tmp);
out += make_list_end();
tmp = line;
state = "HEADER";
continue;
}
//not interrupted? add to tmp.
tmp += line;
}
}
}
string make_bullet(string lines)
{
string outtmp = "";
foreach(lines/"\n"; int nr; string line)
{
if(nr == 0)
outtmp += "<li><b>"+line+"</b>\n<p>\n";
else
{
if(!text(line))
outtmp += "</p><p>\n";
else
outtmp += line+"\n";
}
}
outtmp += "</p></li>\n\n";
return outtmp;
}
string make_list_start()
{
return "<p><ul>\n\n";
}
string make_list_end()
{
return "</ul></p>\n\n";
}
int indented(string line)
{
if(!text(line) || line[0..0] == " ")
return 1;
else
return 0;
}
int text(string line)
{
if(sizeof(line-" "))
return 1;
else
return 0;
}
string make_header(int level, string text)
{
return sprintf("<h%d>%s</h%d>\n\n", level, text, level);
}
|