#!/usr/bin/env js24 // Create a tune index from the abcm2ps PostScript output // (javascript version with js24 - mozjs24) // Copyright (C) 2017 Jean-François Moine // 2017-07-23 // Bad output when index on many pages // Wrong computation of the number of indexes per page // Accept m$windows and MAC files // 2017-04-14 // Creation var before, main, args = scriptArgs function do_index(fn) { var i, j, index, a, page, atitle, title, titlelist, xmid, font, gsave, margin, x, ph, fh, lh, n, first, file = read(fn) if (!file) { printErr('Cannot read "' + fn + '"') quit() } // handle m$windows and MAC files if (file.indexOf('\r\n') >= 0) file = file.replace(/\r\n/g, '\n') if (file.indexOf('\r') >= 0) file = file.replace(/\r/g, '\n') i = file.indexOf('%%EndSetup\n'); if (i < 0) { printErr('"' + fn + '" is not a PostScript file') quit() } i += 11; titlelist = [] // loop on the lines while (1) { j = file.indexOf('\n', i) // end of line if (j < 0) break if (file[i] == '%') { switch (file.slice(i, i + 8)) { case '%%Page: ': i += 8; page = file.slice(i, i + 5).match(/\d+/) if (gsave) break i = ++j; j = file.indexOf('\n', i); gsave = file.slice(i, j); break case '% --- wi': // "% --- width " if (xmid) break xmid = file.slice(i + 12, j - 1) * 0.5 i = ++j; j = file.indexOf('\n', i); margin = file.slice(i, j); break case '% --- ti': // "% --- title " // "% --- titlesub <subtitle>" if (file.slice(i + 11, i + 14) == 'sub') { if (main) break atitle = file.slice(i + 15, j) } else { atitle = file.slice(i + 12, j) } i = ++j; j = file.indexOf('\n', i); title = file.slice(i, j); i = title.indexOf(']arrayshow') if (i > 0) { title = title.match(/\[.*\]/).toString(); title = title.replace(/^\[\(\d+. /, '[('); titlelist.push({ a: atitle, b: title + '(' + page + ')mkidx2\n', p: page }) } else { title = title.match(/\(.*\)/).toString(); title = title.replace(/^\(\d+. /, '('); titlelist.push({ a: atitle, b: title + '(' + page + ')mkidx\n', p: page }) } break case '% --- fo': // "% --- font <size> <name>" if (font) break font = file.slice(i + 11, j) break } } i = ++j } // sort the titles titlelist = titlelist.sort(function (a, b) { if (a.a < b.a) return -1 if (a.a > b.a) return 1 return 0 }) // generate the index functions x = xmid * 2; // page width fh = font.match(/\d+/) * 1.1; file = file.replace('%%EndSetup', "% for tune index\n\ /mklink{\n\ [ /Rect [35 0 300 20] /Page 5 -1 roll /View [ /XYZ 0 830 null ]\n\ /Border [0 0 0] /Subtype /Link /ANN pdfmark}!\n\ /mkidx{ " + (x - 40).toFixed(0) + " 0 M showr\n\ 40 0 M show 20 0 RM\n\ {( . )show currentpoint pop " + (x - 80).toFixed(0) + " ge{exit}if}loop\n\ 0 -" + fh + " T}!\n\ /mkidx2{ " + (x - 40).toFixed(0) + " 0 M showr\n\ 40 0 M arrayshow 20 0 RM\n\ {( . )show currentpoint pop " + (x - 80).toFixed(0) + " ge{exit}if}loop\n\ 0 -" + fh + " T}!\n\ %%EndSetup"); // generate the index index = '% -- Tune index\n'; a = gsave.split(/\s+/); ph = a[a.length - 2]; // page height lh = fh * 1.6; // height of header lines n = (ph / fh - 4) | 0; first = true while (1) { page++; i = n; index += '%%Page: ' + page + ' ' + page + '\n' + gsave + '\n' + margin + '\n' + font + '\n\ 0 -' + lh.toFixed(1) + ' T\n' if (first) { first = false; index += xmid.toFixed(0) + ' 0 M(index)showc\n\ 0 -' + lh.toFixed(1) + ' T\n'; i -= 2 } while (--i >= 0) { a = titlelist.shift() if (!a) break index += a.p + ' mklink' + a.b } index += '%%PageTrailer\n\ grestore\n\ showpage\n\ %%EndPage: ' + page + ' ' + page + '\n' if (!a) break } //should update %%Pages: <n> if (before) print(file.replace('%%EndSetup\n', '%%EndSetup\n' + index)) else print(file.replace('%%Trailer', index + '%%Trailer')) } // main if (args[0] == '-b') { before = true; args.shift() } if (args[0] == '-m') { main = true; args.shift() } if (!args[0]) { printErr('Add a tune index to a abcm2ps output.\n\ Usage: ./abcmaddidx [options] <input abcm2ps file>\n\ -b set the index before the music\n\ -m set an index for main titles only (not for subtitles)\n\ The resulting file goes to stdout') quit() } do_index(args[0])