#!/usr/bin/env perl ## Copyright (C) 2008, 2009 by Daniel Friesel ## ## Permission to use, copy, modify, and/or distribute this software for any ## purpose with or without fee is hereby granted, provided that the above ## copyright notice and this permission notice appear in all copies. ## ## THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ## WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ## MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ## ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ## WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ## ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ## OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. use strict; use warnings; use utf8; use 5.010; use Getopt::Std; use constant { HEADERLENGTH => 0x4a, FOOTERLENGTH => 0x02, }; binmode(STDOUT, ':utf8'); my ($header, $footer); my ($char, $char2); my $out; my $cache; my $file; my ($indent, $rindent) = (0,0); my %opts; my ($program, $length, $offset); my %header; my %all = ( 0x01 => '►DMS', 0x02 => '►Dec', 0x03 => '►Frac', 0x04 => '→', 0x05 => 'Boxplot', 0x06 => '[', 0x07 => ']', 0x08 => '{', 0x09 => '}', 0x0a => 'r', 0x0b => '°', 0x0c => '⁻¹', 0x0d => '²', 0x0e => 'Ṭ', 0x0f => '³', 0x10 => '(', 0x11 => ')', 0x12 => 'round(', 0x13 => 'pxl-Test(', 0x14 => 'augment(', 0x15 => 'rowSwap(', 0x16 => 'row+(', 0x17 => '*row(', 0x18 => '*row+(', 0x19 => 'max(', 0x1a => 'min(', 0x1b => 'R►Pr(', 0x1c => 'R►Pθ(', 0x1d => 'P►Rx(', 0x1e => 'P►Ry', 0x1f => 'median(', 0x20 => 'randM(', 0x21 => 'mean(', 0x22 => 'solve(', 0x23 => 'seq(', 0x24 => 'fnInt(', 0x25 => 'nDeriv(', 0x27 => 'fMin(', 0x28 => 'fMax(', 0x29 => ' ', 0x2a => '"', 0x2b => ',', 0x2c => 'i', 0x2d => '!', 0x2e => 'CubicReg', 0x2f => 'QuartReg', 0x30 => 0, 0x31 => 1, 0x32 => 2, 0x33 => 3, 0x34 => 4, 0x35 => 5, 0x36 => 6, 0x37 => 7, 0x38 => 8, 0x39 => 9, 0x3a => '.', 0x3b => 'E', 0x3c => ' or ', 0x3d => ' xor ', 0x3e => ':', 0x3f => "\n", 0x40 => ' and ', 0x41 => 'A', 0x42 => 'B', 0x43 => 'C', 0x44 => 'D', 0x45 => 'E', 0x46 => 'F', 0x47 => 'G', 0x48 => 'H', 0x49 => 'I', 0x4a => 'J', 0x4b => 'K', 0x4c => 'L', 0x4d => 'M', 0x4e => 'N', 0x4f => 'O', 0x50 => 'P', 0x51 => 'O', 0x52 => 'R', 0x53 => 'S', 0x54 => 'T', 0x55 => 'U', 0x56 => 'V', 0x57 => 'W', 0x58 => 'X', 0x59 => 'Y', 0x5a => 'Z', 0x5b => 'θ', 0x5f => 'prgm', 0x64 => 'Radian', 0x65 => 'Degree', 0x66 => 'Normal', 0x67 => 'Sci', 0x68 => 'Eng', 0x69 => 'Float', 0x6a => '=', 0x6b => '<', 0x6c => '>', 0x6d => '≤', 0x6e => '≥', 0x6f => '≠', 0x70 => '+', 0x71 => '-', 0x72 => 'Ans', 0x73 => 'Fix', 0x74 => 'Horiz', 0x75 => 'Full', 0x76 => 'Func', 0x77 => 'Param', 0x78 => 'Polar', 0x79 => 'Seq', 0x7a => 'IndpntAuto', 0x7b => 'IndpntAsk', 0x7c => 'DependAuto', 0x7d => 'DependAsk', 0x7f => '☐', 0x80 => '+', 0x81 => '·', 0x82 => '*', 0x83 => '/', 0x84 => 'Trace', 0x85 => 'ClrDraw', 0x86 => 'ZStandard', 0x87 => 'ZTrig', 0x88 => 'ZBox', 0x89 => 'Zoom In', 0x8a => 'Zoom Out', 0x8b => 'ZSquare', 0x8c => 'ZInteger', 0x8d => 'ZPrevious', 0x8e => 'ZDecimal', 0x8f => 'ZoomStat', 0x90 => 'ZoomRcl', 0x91 => 'PrintScreen', 0x92 => 'ZoomSto', 0x93 => 'Text(', 0x94 => 'nPr', 0x95 => 'nCr', 0x96 => 'FnOn', 0x97 => 'FnOff', 0x98 => 'StorePic', 0x99 => 'RecallPic', 0x9a => 'StoreGDB', 0x9b => 'RecallGDB', 0x9c => 'Line(', 0x9d => 'Vertical', 0x9e => 'Pt-On(', 0x9f => 'Pt-Off(', 0xa0 => 'Pt-Change(', 0xa1 => 'Pxl-On(', 0xa2 => 'Pxl-Off(', 0xa3 => 'Pxl-Change(', 0xa4 => 'Shade(', 0xa5 => 'Circle(', 0xa6 => 'Horizontal', 0xa7 => 'Tangent(', 0xa8 => 'DrawInv', 0xa9 => 'DrawF', 0xab => 'rand', 0xac => 'π', 0xad => 'getKey', 0xae => '\'', 0xaf => '?', 0xb0 => '-', 0xb1 => 'int(', 0xb2 => 'abs(', 0xb3 => 'det(', 0xb4 => 'identity(', 0xb5 => 'dim(', 0xb6 => 'sum(', 0xb7 => 'prod(', 0xb8 => 'not(', 0xb9 => 'iPart(', 0xba => 'fPart(', 0xbc => '√(', 0xbd => '³√(', 0xbe => 'ln(', 0xbf => 'e^(', 0xc0 => 'log(', 0xc1 => '10^(', 0xc2 => 'sin(', 0xc3 => 'sinֿ¹(', 0xc4 => 'cos(', 0xc5 => 'cosֿ¹(', 0xc6 => 'tan(', 0xc7 => 'tanֿ¹(', 0xc8 => 'sinh(', 0xc9 => 'sinhֿ¹(', 0xca => 'cosh(', 0xcb => 'coshֿ¹(', 0xcc => 'tanh(', 0xcd => 'tanhֿ¹(', 0xce => 'If ', 0xcf => 'Then', 0xd0 => 'Else', 0xd1 => 'While ', 0xd2 => 'Repeat ', 0xd3 => 'For(', 0xd4 => 'End', 0xd5 => 'Return', 0xd6 => 'Lbl ', 0xd7 => 'Goto ', 0xd8 => 'Pause', 0xd9 => 'Stop', 0xda => 'IS>(', 0xdb => 'DS<(', 0xdc => 'Input ', 0xdd => 'Prompt ', 0xde => 'Disp ', 0xdf => 'DispGraph', 0xe0 => 'Output(', 0xe1 => 'ClrHome', 0xe2 => 'Fill(', 0xe3 => 'SortA(', 0xe4 => 'SortD(', 0xe5 => 'DispTable', 0xe6 => 'Menu(', 0xe7 => 'Send(', 0xe8 => 'Get(', 0xe9 => 'PlotsOn', 0xea => 'PlotsOff', 0xeb => '∟', 0xec => 'Plot1(', 0xed => 'Plot2(', 0xee => 'Plot3(', 0xf0 => '^', 0xf1 => '×√', 0xf2 => '1-Var Stats', 0xf3 => '2-Var Stats', 0xf4 => 'Linreg(a+bx)', 0xf5 => 'ExpReg', 0xf6 => 'LnReg', 0xf7 => 'PwrReg', 0xf8 => 'Med-Med', 0xf9 => 'QuadReg', 0xfa => 'ClrList', 0xfb => 'ClrTable', 0xfc => 'Histogram', 0xfd => 'xyLine', 0xfe => 'Scatter', 0xff => 'LinReg(ax+b)', ); my $special = { 0x5c => { 0x00 => '[A]', 0x01 => '[B]', 0x02 => '[C]', 0x03 => '[D]', 0x04 => '[E]', 0x05 => '[F]', 0x06 => '[G]', 0x07 => '[H]', 0x08 => '[I]', 0x09 => '[J]', }, 0x5d => { 0x00 => 'L₁', 0x01 => 'L₂', 0x02 => 'L₃', 0x03 => 'L₄', 0x04 => 'L₅', 0x05 => 'L₆', }, 0x5e => { 0x10 => 'Y₁', 0x11 => 'Y₂', 0x12 => 'Y₃', 0x13 => 'Y₄', 0x14 => 'Y₅', 0x15 => 'Y₆', 0x16 => 'Y₇', 0x17 => 'Y₈', 0x18 => 'Y₉', 0x19 => 'Y₀', 0x20 => 'X₁T', 0x21 => 'Y₁T', 0x22 => 'X₂T', 0x23 => 'Y₂T', 0x24 => 'X₃T', 0x25 => 'Y₃T', 0x26 => 'X₄T', 0x27 => 'Y₄T', 0x28 => 'X₅T', 0x29 => 'Y₅T', 0x2A => 'X₆T', 0x2B => 'Y₆T', 0x40 => 'r₁', 0x41 => 'r₂', 0x42 => 'r₃', 0x43 => 'r₄', 0x44 => 'r₅', 0x45 => 'r₆', 0x80 => 'u', 0x81 => 'v', 0x82 => 'w', }, 0x60 => { 0x00 => 'Pic1', 0x01 => 'Pic2', 0x02 => 'Pic3', 0x03 => 'Pic4', 0x04 => 'Pic5', 0x05 => 'Pic6', 0x06 => 'Pic7', 0x07 => 'Pic8', 0x08 => 'Pic9', 0x09 => 'Pic0', }, 0x61 => { 0x00 => 'GDB1', 0x01 => 'GDB2', 0x02 => 'GDB3', 0x03 => 'GDB4', 0x04 => 'GDB5', 0x05 => 'GDB6', 0x06 => 'GDB7', 0x07 => 'GDB8', 0x08 => 'GDB9', 0x09 => 'GDB0', }, 0x62 => { 0x01 => 'RegEq', 0x02 => 'n', 0x03 => 'x̅', 0x04 => 'Σx', 0x05 => 'Σx²', 0x06 => 'Sx', 0x07 => 'σx', 0x08 => 'minX', 0x09 => 'maxX', 0x0a => 'minY', 0x0b => 'maxY', 0x0c => 'y̅', 0x0d => 'Σy', 0x0e => 'Σy²', 0x0f => 'Sy', 0x10 => 'σy', 0x11 => 'Σxy', 0x12 => 'r', 0x13 => 'Med', 0x14 => 'Q1', 0x15 => 'Q3', 0x16 => 'a', 0x17 => 'b', 0x18 => 'c', 0x19 => 'd', 0x1a => 'e', 0x1b => 'x₁', 0x1c => 'x₂', 0x1d => 'x₃', 0x1e => 'y₁', 0x1f => 'y₂', 0x20 => 'y₃', 0x21 => 'n', 0x22 => 'p', 0x23 => 'z', 0x24 => 't', 0x25 => 'χ²', 0x26 => 'F', 0x27 => 'df', 0x28 => 'p̂', 0x29 => 'p̂₁', 0x2a => 'p̂₂', 0x2b => 'x̅₁', 0x2c => 'Sx₁', 0x2d => 'n₁', 0x2e => 'x̅₂', 0x2f => 'Sx₂', 0x30 => 'n₂', 0x31 => 'Sxp', 0x32 => 'lower', 0x33 => 'upper', 0x34 => 's', 0x35 => 'r²', 0x36 => 'R²', 0x37 => 'Factor df', 0x38 => 'Factor SS', 0x39 => 'Factor MS', 0x3a => 'Error df', 0x3b => 'Error SS', 0x3c => 'Error MS', }, 0x63 => { 0x00 => 'ZXscl', 0x01 => 'ZYscl', 0x02 => 'Xscl', 0x03 => 'Yscl', 0x04 => 'u(nMin)', 0x05 => 'v(nMin)', 0x06 => 'u(n-1)', 0x07 => 'v(n-1)', 0x08 => 'Zu(nMin)', 0x09 => 'Zv(nMin)', 0x0a => 'Xmin', 0x0b => 'Xmax', 0x0c => 'Ymin', 0x0d => 'Ymax', 0x0e => 'Tmin', 0x0f => 'Tmax', 0x10 => 'θmin', 0x11 => 'θmax', 0x12 => 'ZXmin', 0x13 => 'ZXmax', 0x14 => 'ZYmin', 0x15 => 'ZYmax', 0x16 => 'Zθmin', 0x17 => 'Zθmax', 0x18 => 'ZTmin', 0x19 => 'ZTmax', 0x1a => 'TblStart', 0x1b => 'PlotStart', 0x1c => 'ZPlotStart', 0x1d => 'nMax', 0x1e => 'ZnMax', 0x1f => 'nMin', 0x20 => 'ZnMin', 0x21 => 'ΔTbl', 0x22 => 'Tstep', 0x23 => 'θstep', 0x24 => 'ZTstep', 0x25 => 'Zθstep', 0x26 => 'ΔX', 0x27 => 'ΔY', 0x28 => 'XFact', 0x29 => 'YFact', 0x2a => 'TblInput', 0x2b => 'N', 0x2c => 'I%', 0x2d => 'PV', 0x2e => 'PMT', 0x2f => 'FV', 0x30 => 'P/Y', 0x31 => 'C/Y', 0x32 => 'w(nMin)', 0x33 => 'Zw(nMin)', 0x34 => 'PlotStep', 0x35 => 'ZPlotStep', 0x36 => 'Xres', 0x37 => 'ZXres', }, 0x7e => { 0x00 => 'Sequential', 0x01 => 'Simul', 0x02 => 'PolarGC', 0x03 => 'RectGC', 0x04 => 'CoordOn', 0x05 => 'CoordOff', 0x06 => 'Connected', 0x07 => 'Dot', 0x08 => 'AxesOn', 0x09 => 'AxesOff', 0x0a => 'GridOn', 0x0b => 'Gridoff', 0x0c => 'LabelOn', 0x0d => 'LabelOff', 0x0e => 'Web', 0x0f => 'Time', 0x10 => 'uvAxes', 0x11 => 'vwAxes', 0x12 => 'uwAxes', }, 0xaa => { 0x00 => 'Str1', 0x01 => 'Str2', 0x02 => 'Str3', 0x03 => 'Str4', 0x04 => 'Str5', 0x05 => 'Str6', 0x06 => 'Str7', 0x07 => 'Str8', 0x08 => 'Str9', 0x09 => 'Str0', }, 0xbb => { 0x00 => 'npv(', 0x01 => 'irr(,', 0x02 => 'bal(', 0x03 => 'Σprn(', 0x04 => 'ΣInt(', 0x05 => '►Nom(', 0x06 => '►Eff(', 0x07 => 'dbd(', 0x08 => 'lcm(', 0x09 => 'gcd(', 0x0A => 'randInt(', 0x0B => 'randBin(', 0x0C => 'sub(', 0x0D => 'stdDev(', 0x0E => 'variance(', 0x0F => 'inString(', 0x10 => 'normalcdf(', 0x11 => 'invNorm(', 0x12 => 'tcdf(', 0x13 => 'χ²cdf(', 0x14 => 'Fcdf(', 0x15 => 'binompdf(', 0x16 => 'binomcdf(', 0x17 => 'poissonpdf(', 0x18 => 'poissoncdf(', 0x19 => 'geometpdf(', 0x1A => 'geometcdf(', 0x1B => 'normalpdf(', 0x1C => 'tpdf(', 0x1D => 'χ²pdf(', 0x1E => 'Fpdf(', 0x1F => 'randNorm(', 0x20 => 'tmv_Pmt', 0x21 => 'tmv_I%', 0x22 => 'tmv_PV', 0x23 => 'tmv_N', 0x24 => 'tmv_FV', 0x25 => 'conj(', 0x26 => 'real(', 0x27 => 'imag(', 0x28 => 'angle(', 0x29 => 'cumSum(', 0x2A => 'expr(', 0x2B => 'length(', 0x2C => 'ΔList(', 0x2D => 'ref(', 0x2E => 'rref(', 0x2F => '►Rect', 0x30 => '►Polar', 0x31 => 'e', 0x32 => 'SinReg', 0x33 => 'Logistic', 0x34 => 'LinRegTTest', 0x35 => 'ShadeNorm(', 0x36 => 'Shade_t(', 0x37 => 'Shadeχ²', 0x38 => 'ShadeF(', 0x39 => 'Matr►list(', 0x3A => 'List►matr(', 0x3B => 'Z-Test(', 0x3C => 'T-Test', 0x3D => '2-SampZTest(', 0x3E => '1-PropZTest(', 0x3F => '2-PropZTest(', 0x40 => 'χ²-Test(', 0x41 => 'ZInterval', 0x42 => '2-SampZInt(', 0x43 => '1-PropZInt(', 0x44 => '2-PropZInt(', 0x45 => 'GraphStyle(', 0x46 => '2-SampTTest', 0x47 => '2-SampFTest', 0x48 => 'TInterval', 0x49 => '2-SampTInt', 0x4A => 'SetUpEditor', 0x4B => 'Pmt_End', 0x4C => 'Pmt_Bgn', 0x4D => 'Real', 0x4E => 're^θi', 0x4F => 'a+bi', 0x50 => 'ExprOn', 0x51 => 'ExprOff', 0x52 => 'ClrAllLists', 0x53 => 'GetCalc(', 0x54 => 'DelVar ', 0x55 => 'Equ►String(', 0x56 => 'String►Equ(', 0x57 => 'Clear Entries', 0x58 => 'Select(', 0x59 => 'ANOVA(', 0x5A => 'ModBoxplot', 0x5B => 'NormProbPlot', 0x64 => 'G-T', 0x65 => 'ZoomFit', 0x66 => 'DiagnosticOn', 0x67 => 'DiagnosticOff', 0x68 => 'Archive', 0x69 => 'UnArchive', 0x6A => 'Asm(', 0x6B => 'AsmComp(', 0x6C => 'AsmPrgm', 0x6D => 'compiled asm', 0x6E => 'Á', 0x6F => 'À', 0x70 => 'Â', 0x71 => 'Ä', 0x72 => 'á', 0x73 => 'à', 0x74 => 'â', 0x75 => 'ä', 0x76 => 'É', 0x77 => 'È', 0x78 => 'Ê', 0x79 => 'Ë', 0x7A => 'é', 0x7B => 'è', 0x7C => 'ê', 0x7D => 'ë', 0x7F => 'Ì', 0x80 => 'Î', 0x81 => 'Ï', 0x82 => 'í', 0x83 => 'ì', 0x84 => 'î', 0x85 => 'ï', 0x86 => 'Ó', 0x87 => 'Ò', 0x88 => 'Ô', 0x89 => 'Ö', 0x8A => 'ó', 0x8B => 'ò', 0x8C => 'ô', 0x8D => 'ö', 0x8E => 'Ú', 0x8F => 'Ù', 0x90 => 'Û', 0x91 => 'Ü', 0x92 => 'ú', 0x93 => 'ù', 0x94 => 'û', 0x95 => 'ü', 0x96 => 'Ç', 0x97 => 'ç', 0x98 => 'Ñ', 0x99 => 'ñ', 0x9A => '´', 0x9B => '`', 0x9C => '¨', 0x9D => '¿', 0x9E => '¡', 0x9F => 'α', 0xA0 => 'β', 0xA1 => 'γ', 0xA2 => 'Δ', 0xA3 => 'δ', 0xA4 => 'ε', 0xA5 => 'λ', 0xA6 => 'μ', 0xA7 => 'π', 0xA8 => 'ρ', 0xA9 => 'Σ', 0xAB => 'φ', 0xAC => 'Ω', 0xAD => '^p', 0xAE => 'χ', 0xAF => 'F', 0xB0 => 'a', 0xB1 => 'b', 0xB2 => 'c', 0xB3 => 'd', 0xB4 => 'e', 0xB5 => 'f', 0xB6 => 'g', 0xB7 => 'h', 0xB8 => 'i', 0xB9 => 'j', 0xBA => 'k', 0xBC => 'l', 0xBD => 'm', 0xBE => 'n', 0xBF => 'o', 0xC0 => 'p', 0xC1 => 'q', 0xC2 => 'r', 0xC3 => 's', 0xC4 => 't', 0xC5 => 'u', 0xC6 => 'v', 0xC7 => 'w', 0xC8 => 'x', 0xC9 => 'y', 0xCA => 'z', 0xCB => 'σ', 0xCC => 'τ', 0xCD => 'Í', 0xCE => 'GarbageCollect', 0xCF => '~', 0xD1 => '@', 0xD2 => '#', 0xD3 => '$', 0xD4 => '&', 0xD5 => '`', 0xD6 => ';', 0xD7 => '\\', 0xD8 => '|', 0xD9 => '_', 0xDA => '%', 0xDB => '…', 0xDC => '∠', 0xDD => 'ß', 0xDE => 'x', 0xDF => 'T', 0xE0 => '0', 0xE1 => '1', 0xE2 => '2', 0xE3 => '3', 0xE4 => '4', 0xE5 => '5', 0xE6 => '6', 0xE7 => '7', 0xE8 => '8', 0xE9 => '9', 0xEA => '10', 0xEB => '←', 0xEC => '→', 0xED => '↑', 0xEE => '↓', 0xF0 => 'x', 0xF1 => '∫', 0xF4 => '√', }, 0xef => { 0x00 => 'setDate(', 0x01 => 'setTime(', 0x02 => 'checkTmr(', 0x03 => 'setDtFmt(', 0x04 => 'setTmFmt(', 0x05 => 'timeCnv(', 0x06 => 'dayOfWk(', 0x07 => 'getDtStr(', 0x08 => 'getTmStr(', 0x09 => 'getDate', 0x0a => 'getTime', 0x0b => 'startTmr', 0x0c => 'getDtFmt', 0x0e => 'getTmFmt', 0x0f => 'isClockOn', 0x10 => 'ClockOn', 0x11 => 'ClockOff', 0x12 => 'OpenLib(', 0x13 => 'ExecLib', 0x14 => 'invT(', 0x15 => 'χ²GOF-Test(', 0x16 => 'LinRegTInt', 0x17 => 'Manual-Fit', }, }; local $/ = undef; sub print_header { my ($header, $content) = @_; printf( "# %-20s: %s\n", $header, $content, ); return; } sub header_type { my $header = shift; given (ord(substr($header, 0x3b, 1))) { when(0x00) { return('var') } when(0x01) { return('list') } when(0x02) { return('matrix') } when(0x03) { return('equation') } when(0x04) { return('string') } when(0x05) { return('program') } when(0x10) { return('zoom') } when(0x0f) { return('window') } default { return(sprintf('0x%02x', $_)) } } return; } sub header_name { my $header = shift; my $name; given (header_type($header)) { when('var') { $name = substr($header, 0x3c, 1) } when('matrix') { $name = substr($header, 0x3d, 1) } when('string') { $name = (ord(substr($header, 0x3d, 1)) + 1) % 10 } when('program') { $name = substr($header, 0x3c, 10); $name =~ s/\x00/ /g; } when('list') { $name = ord(substr($header, 0x3e, 1)); $name &= 0x0f; } } return($name); } sub header_size { my $header = shift; my $size; $size->{full} = ord(substr($header, 0x46, 1)) + 255 * ord(substr($header, 0x47, 1)); given(header_type($header)) { when('list') { $size->{items} = ord(substr($header, 0x48, 1)); } when('matrix') { $size->{cols} = ord(substr($header, 0x48, 1)); $size->{rows} = ord(substr($header, 0x49, 1)); } when(['program', 'string', 'equation']) { $size->{source} = ord(substr($header, 0x48, 1)) + 255 * ord(substr($header, 0x49, 1)); } } return($size); } sub header_compat { return(substr(shift, 0x02, 4)); } sub header_datestr { return(substr(shift, 0x1d, 19)); } getopts('ih', \%opts); $file = shift; open(my $input, '<', $file) or die("Cannot open $file: $!"); binmode($input); read($input, $header, HEADERLENGTH); $program = <$input>; close($input); # The last two bytes don't contain program code $footer = substr($program, -(FOOTERLENGTH), FOOTERLENGTH, ''); $length = length($program); $offset = 0; # Parse the header %header = ( compat => header_compat($header), datestr => header_datestr($header), type => header_type($header), name => header_name($header), size => header_size($header), ); if ($opts{h}) { print_header('Compatibility', $header{compat} ); print_header('Extracted at' , $header{datestr}); print_header('Type' , $header{type} ); print_header('Name' , $header{name} ); print_header('Length w/o header', $header{size}->{full}); given ($header{type}) { when ('matrix') { print_header('Matrix dimensions', join('x', @{$header{size}}{'rows', 'cols'})); } when ('list') { print_header('List length', $header{size}->{items}); } when ('string') { print_header('String length', $header{size}->{source}); } when ('program') { print_header('Program size', $header{size}->{source}); } when ('equation') { print_header('Payload length', $header{size}->{source}); } } } # And now, the actual file content if ($header{type} ~~ ['program', 'equation']) { while($offset < $length) { $char = ord(substr($program, $offset++, 1)); if (exists($all{$char})) { $out = $all{$char}; } elsif (exists($special->{$char})) { $char2 = ord(substr($program, $offset++, 1)); $out = $special->{$char}->{$char2}; } else { printf STDERR ( "Unknown byte 0x%02x at %04x\n", $char, HEADERLENGTH + $offset - 1, ); $out = chr($char); } if ($opts{i}) { if ($out =~ /Then | While | Repeat | For/x) { $indent++; } elsif ($out =~ /Else/) { $rindent--; } elsif ($out =~ /End/) { $indent--; $rindent--; } } $cache .= $out; if ($out eq "\n") { print "\t" x $rindent; $rindent = $indent; print $cache; $cache = ''; } } print "$cache\n"; } elsif ($header{type} ~~ ['matrix', 'list', 'var', 'zoom', 'window']) { my ($exp, $digit); my $i = 0; my @values; # Variables have a shorter header if ($header{type} eq 'var') { substr($program, 0, 0, substr($header, -2, 2)); $length = length($program); } while ($offset+9 <= $length) { $i++; $digit = ''; if (ord(substr($program, $offset++, 1)) >= 0x80) { $digit .= '-'; } $exp = ord(substr($program, $offset++, 1)) - 0x80; for(1 .. 7) { $char = ord(substr($program, $offset++, 1)); $digit .= $char >> 4; $digit .= $char & 0x0f; } substr($digit, 1 + ($digit <= 0), 0, '.'); $digit *= 10 ** $exp; if ($header{type} eq 'zoom') { push(@values, $digit); } else { printf('%-8s', $digit); } if ($header{type} eq 'matrix' and $i == $header{size}->{cols} or $header{type} eq 'var') { print "\n"; $i = 0; } elsif ($header{type} eq 'matrix') { print ' | '; } elsif ($header{type} ne 'zoom') { print ' '; } } if ($header{type} eq 'zoom') { print "Xmin = $values[0]\n"; print "Xmax = $values[1]\n"; print "Xscl = $values[2]\n"; print "Ymin = $values[3]\n"; print "Ymax = $values[4]\n"; print "Yscl = $values[5]\n"; } } elsif ($header{type} eq 'string') { while($offset < $length) { print substr($program, $offset++, 1); } print "\n"; } else { print STDERR "file type $header{type} not supported\n"; exit 1; } __END__ =head1 NAME tibtoa - Texas Instruments TI8x Binary to ASCII converter =head1 SYNOPSIS B [ B<-hi> ] I =head1 DESCRIPTION B converts the binary files dumped from a calculator (for example by tilp(1)) into human-readable text. The name is not quite right, though - for programs, it also uses various unicode chars, not plain ASCII. B reads in the file specified on the commandline and prints the result to STDOUT. Errors, such as unknown bytes in the source, go to STDERR. Currently, the following file types are supported: B<.8Xv> (variable), B<.8Xl> (list), B<.8Xm> (matrix), B<.8Xe> (equation), B<.8Xs> (string), B<.8Xp> (program). =head1 OPTIONS =over =item B<-i> Indent the content of for, while, if, etc. statements =item B<-h> Print the content of the file header before the file content, prefixed by '//' =back