1* snopea -- a tiny "Plain Old Document" formatter for SNOBOL4 2 sp.version = '$Id: snopea.sno,v 1.34 2020-12-16 22:19:03 phil Exp $' 3 4* NOTE! The directives are only *inspired* by "POD" format 5 6-include 'basename.sno' 7-include 'host.sno' 8 9* snopea.debug = 1 10 11* character entity handling... A mishmash of troff and HTML! 12 snopea.charpats = TABLE() 13 14 snopea.charmaps = TABLE() 15 snopea.charpats['roff'] = "''" | "``" | '\=' | 16+ '&' ANY(&LCASE) SPAN(&LCASE) ';' 17* Turn \- into \[en]? 18 snopea.charmaps['roff'] = snopea.charmap.roff = TABLE() 19 snopea.charmap.roff["``"] = '\*(lq' 20 snopea.charmap.roff["''"] = '\*(rq' 21 snopea.charmap.roff["<"] = '<' 22 snopea.charmap.roff[">"] = '>' 23 snopea.charmap.roff["π"] = '\*(pi' 24 snopea.charmap.roff["&"] = '&' 25 snopea.charmap.roff["\="] = '=' 26 27 snopea.charpats['html'] = "''" | "``" | '\' ANY("e-&|~'`=") 28 snopea.charmaps['html'] = snopea.charmap.html = TABLE() 29 snopea.charmap.html["``"] = '“' 30 snopea.charmap.html["''"] = '”' 31 snopea.charmap.html["\e"] = '\' 32 snopea.charmap.html["\-"] = '–' 33 snopea.charmap.html["\&"] = '' 34 snopea.charmap.html["\|"] = ' ' 35 snopea.charmap.html["\~"] = ' ' 36 snopea.charmap.html["\'"] = "'" 37 snopea.charmap.html["\`"] = '`' 38 snopea.charmap.html["\="] = '=' 39 40 snopea.tab = CHAR(9) 41 snopea.ws = SPAN(' ' snopea.tab) 42 snopea.bws = BREAK(' ' snopea.tab) 43 44 HOST() POS(0) BREAK(':') ':' BREAK(':') ':' REM . snopea.snovers 45 46 DEFINE('snopea(ifile,ofile,page,sect,format)' 47+ 'font,efont,endlist,lsep,pre,chr,ctab,numb,t1,t2,pat,' 48+ 'date,text,snomod,line,inpea,needspace,after,' 49+ 'oline,text,iunit,ounit,lbl,cmd') :(snopea.end) 50snopea 51 iunit = IO_FINDUNIT() 52 INPUT(.in, iunit,, ifile) :S(sp.oo) 53 TERMINAL = 'snopea: could not open ' ifile :(FRETURN) 54 55sp.oo DELETE(ofile) 56 ounit = IO_FINDUNIT() 57 OUTPUT(.out, ounit,, ofile) :S(sp.begin) 58 TERMINAL = 'snopea: could not open ' ofile 59 ENDFILE(iunit) 60 DETACH(.in) :(FRETURN) 61 62sp.begin 63 TERMINAL = IDENT(page) "snopea: need page name" :S(FRETURN) 64 TERMINAL = IDENT(sect) "snopea: need section" :S(FRETURN) 65 format = IDENT(format) 'roff' 66 67 page = REPLACE(page, &LCASE, &UCASE) 68 date = HOST(HOST_VERSION_DATE) 69 cmd = 'head' :(sp.dispatch2) 70 71**************** 72sp.top line = in :F(sp.eof) 73* strip leading stars 74 line POS(0) SPAN('*') = 75* check for =cmd 76 cmd = 'XXX' 77 line POS(0) '=' SPAN(&LCASE) . cmd REM . rest :S(sp.cmd) 78* no command: 79 IDENT(inpea) :S(sp.top) 80* in pea mode, no command: 81 IDENT(line) :S(sp.eop) 82* non-empty line, output paragraph break if needed 83 cmd = DIFFER(needspace) 'para' :S(sp.cmd) 84* handle text, clear output line holder 85sp.text oline = 86* font loop: here back from 'font' dispatch 87sp.floop 88 line POS(0) BREAKX('BICL') . pre 89+ ANY('BICL') . font '<' BREAK('>') . txt '>' = 90+ :f(sp.fdone) 91* here with pre, font & txt: 92 cmd = 'font' :(sp.dispatch) 93 94* done with fonts, perform character substitutions 95sp.fdone 96 line = oline line 97 oline = 98 99* loop for character substitutions 100sp.cloop 101 line POS(0) ARB . pre snopea.charpats[format] . chr = :f(sp.cdone) 102 oline = oline pre snopea.charmaps[format][chr] :(sp.cloop) 103 104* done with character substitutions 105sp.cdone 106 cmd = 'oline' 107 oline = oline line :(sp.dispatch2) 108 109* here after 'oline' command 110sp.out out = vdiffer(lsep) 111 text = 1 112 :(sp.top) 113 114**** 115* saw end of input file 116sp.eof cmd = 'eof' :(sp.dispatch) 117 118**** 119* saw end of paragraph (blank line) 120sp.eop needspace = text 121 text = :(sp.top) 122 123**************** 124* here to dispatch to a command, clears argument 125sp.dispatch 126 rest = 127* here with user command, remove leading spaces on argument 128sp.cmd rest POS(0) snopea.ws = 129 inpea = 1 130 131**** dispatch a command without altering "inpea" 132* NOTE!! commands may return to someplace OTHER than sp.top!!! 133sp.dispatch2 134 lsep = 135 TERMINAL = DIFFER(snopea.debug) '>>> ' cmd 136 lbl = 'sp.' format '.' cmd 137 LABEL(lbl) :S($lbl) 138 TERMINAL = 'Unknown command ' cmd :(sp.top) 139 140**** 141* here from 'eof' command processing 142sp.close 143 ENDFILE(iunit) 144 ENDFILE(ounit) 145 DETACH(.in) 146 DETACH(.out) :(return) 147 148**************** 149* command processing for *roff: 150 151sp.roff.head 152 out = '.\" generated by ' sp.version 153 154* if nroff, give "ragged right" output': 155 out = '.if n .ad l' 156 out = ".ie '\*[.T]'ascii' \{\" 157 out = '. ds lq \&"\"' 158 out = '. ds rq \&"\"' 159 out = ". ds pi \fIpi\fP" 160 out = ".\}" 161 out = ".el \{\" 162 out = ". ds rq ''" 163 out = ". ds lq ``" 164 out = ". ds pi \[*p]" 165 out = ".\}" 166 167* disable hyphenation: 168 out = '.nh' 169 170 out = '.TH ' page ' ' sect ' "' date '" "' snopea.snovers '"' 171+ ' "CSNOBOL4 Manual"' 172 173 indent = 4 174 text = 175 regfont = '\fR' :(sp.top) 176 177sp.roff.pea :(sp.top) 178 179* internal (blank line seen) 180sp.roff.para 181 out = ".PP" 182 needspace = numb = :(sp.text) 183 184sp.roff.cut 185 inpea = :(sp.top) 186 187sp.roff.font 188 oline = IDENT(font, 'L') oline pre txt :s(sp.floop) 189 font = (IDENT(font, 'C') '\f(CW', '\f' font) 190 oline = oline pre font txt '\fP' :(sp.floop) 191 192sp.roff.oline 193 oline = DIFFER(oline ? POS(0) ANY(".'")) '\&' oline 194 out = oline :(sp.out) 195 196sp.roff.sect 197 rest POS(0) snopea.ws = 198 out = '.SH "' rest '"' 199 out = '.nh' 200 needspace = :(sp.top) 201 202sp.roff.subsect 203 rest POS(0) snopea.ws = 204 out = '.SS "' rest '"' 205 out = '.nh' 206 needspace = :(sp.top) 207 208* set indent level for items 209sp.roff.indent 210 indent = rest 211 needspace = :(sp.top) 212 213* unadorned item 214sp.roff.item 215 needspace = 216 rest POS(0) snopea.ws = 217 out = IDENT(rest) '.IP' :s(sp.top) 218 out = '.TP ' indent 219 line = rest :(sp.text) 220 221* bullet item 222sp.roff.bull 223 out = '.IP \(bu' 224 needspace = 225 line = rest :(sp.text) 226 227* numbered item 228sp.roff.nitem 229 numb = (VDIFFER(numb), 1) 230 out = '.IP ' numb 231 numb = numb + 1 232 needspace = 233 line = rest :(sp.text) 234 235sp.roff.code 236* constant width font: 237 out = '.ft CW' 238* fresh line 239 out = '.br' 240* soft page break: need 10 lines 241 out = '.ne 10' 242* indent: 243 out = '.RS ' indent 244* no hyphenation, formatting: 245 out = '.nh' 246 out = '.nf' :(sp.top) 247 248* back to "Roman" typeface: 249sp.roff.ecode 250 out = '.ft R' 251* fill, no hyphenation: 252 out = '.fi' 253 out = '.nh' 254* unindent: 255 out = '.RE' :(sp.top) 256 257sp.roff.break 258 out = '.br' :(sp.top) 259 260sp.roff.table 261 out = '.PP' 262 rest POS(0) snopea.ws = 263 out = DIFFER(rest) '.ta ' rest 264 out = '.nf' :(sp.top) 265 266sp.roff.row 267 rest POS(0) snopea.ws = 268 line = rest :(sp.text) 269 270sp.roff.etable 271 out = '.fi' :(sp.top) 272 273sp.roff.anchor :(sp.top) 274 275sp.roff.link 276 rest = rest ' ' 277 rest POS(0) snopea.ws = 278 rest POS(0) snopea.bws . t1 = 279 rest POS(0) snopea.ws = 280 line = (VDIFFER(rest), t1) :s(sp.text) 281 282* ADD NEW OPS ABOVE THIS LINE 283 284sp.roff.eof :(sp.close) 285 286**************** 287* command processing for html 288 289sp.html.head 290 out = '<!-- generated by ' sp.version ' -->' 291 292 out = '<html>' 293 out = '<head>' 294 htext = page '(' sect ') | ' snopea.snovers ' | ' date 295 out = ' <title>' htext '</title>' 296* _COULD_ output <style> here, but trying to work with lynx! 297 out = '</head>' 298 out = '<body>' 299 out = '<h1>' htext '</h1>' 300 indent = 4 301 text = 302 303sp.html.pea :(sp.top) 304 305* internal (blank line seen) 306sp.html.para 307 out = VDIFFER(endlist) 308 out = '<p>' 309 needspace = endlist = :(sp.text) 310 311sp.html.cut :(sp.roff.cut) 312 313sp.html.font 314 oline = IDENT(font, 'L') oline pre '<a href="' txt '">' txt '</a>' :s(sp.floop) 315 font = ident(font, 'R') :s(sp.html.font2) 316 font = ident(font, 'C') 'TT' 317sp.html.font2 318 efont = ident(font) :s(sp.html.font3) 319 efont = '</' font '>' 320 font = '<' font '>' 321 322sp.html.font3 323 oline = oline pre font txt efont :(sp.floop) 324 325* MASSIVE CROCK!!! detect snobol4 man page refs, and turn into links!! 326sp.html.oline 327+ t1 = 328 pat = POS(0) BREAKX('<') . pre 329+ ('<B>' 330+ (('snobol4' | 'sdb' | 'snolib' | 'snopea') BREAK('<')) . pg 331+ '</B>' 332+ '(' ANY('137') . sec ')' 333+ ) . full 334sp.html.oline1 335+ IDENT(oline) :s(sp.html.oline2) 336 oline pat = :f(sp.html.oline2) 337 t1 = t1 pre '<a href="' pg '.' sec '.html">' full '</a>' 338 :(sp.html.oline1) 339sp.html.oline2 340+ out = t1 oline 341 out = VDIFFER(after) 342 after = :(sp.out) 343 344sp.html.sect 345 out = vdiffer(endlist) 346 endlist = 347 out = '<h2>' rest '</h2>' 348 needspace = :(sp.top) 349 350sp.html.subsect 351 out = vdiffer(endlist) 352 endlist = 353 out = '<h3>' rest '</h3>' 354 needspace = :(sp.top) 355 356* set indent level for items 357sp.html.indent 358 indent = rest 359 needspace = :(sp.top) 360 361* definition list 362sp.html.item 363 differ(endlist) :s(sp.html.item2) 364 out = '<dl>' 365 endlist = '</dl>' 366sp.html.item2 367* don't REALLY want whitespace immediately after a (sub)section header: 368 out = '<p>' 369 out = '<dt>' 370 after = '<dd>' 371 needspace = 372 line = rest :(sp.text) 373 374* bullet item 375sp.html.bull 376 differ(endlist) :s(sp.html.bull2) 377 out = '<p>' 378 out = '<ul>' 379 endlist = '</ul>' 380sp.html.bull2 381 out = '<li>' 382 needspace = 383 line = rest :(sp.text) 384 385* numbered item 386sp.html.nitem 387 differ(endlist) :s(sp.html.bull2) 388 out = '<ol>' 389 endlist = '</ol>' :(sp.html.bull2) 390 391sp.html.code 392 out = '<pre>' :(sp.top) 393 394sp.html.ecode 395 out = '</pre>' :(sp.top) 396 397sp.html.break 398 out = '<br>' :(sp.top) 399 400sp.html.table 401 out = '<p>' 402 out = '<table>' :(sp.top) 403 404sp.html.row 405 rest = '<tr>' snopea.tab rest 406sp.html.rowloop 407 rest snopea.tab = '<td>' :s(sp.html.rowloop) 408 line = rest :(sp.text) 409 410sp.html.etable 411 out = '</table>' :(sp.top) 412 413sp.html.anchor 414 rest POS(0) snopea.ws = 415 out = '<a name="' rest '"></a>' :(sp.top) 416 417sp.html.link 418 rest = rest ' ' 419 rest POS(0) snopea.ws = 420 rest POS(0) snopea.bws . t1 = 421 rest POS(0) snopea.ws = 422 line = '<a href="' t1 '">' (VDIFFER(rest), t1) '</a>' :(sp.text) 423 424* ADD NEW OPS ABOVE THIS LINE 425 426sp.html.eof 427 out = vdiffer(endlist) 428* output footer? link to csnobol4 home page?? 429 out = '</body>' 430 out = '</html>' :(sp.close) 431 432**************** 433 434snopea.end 435