Canola
0.8.D001
|
00001 // 00002 // canola - canon canola 1614p emulator 00003 // Copyright (C) 2011, 2012 Peter Miller 00004 // 00005 // This program is free software; you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License, version 3, as 00007 // published by the Free Software Foundation. 00008 // 00009 // This program is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License along 00015 // with this program. If not, see <http://www.gnu.org/licenses/>. 00016 // 00017 00018 #include <lib/ac/assert.h> 00019 #include <lib/ac/fcntl.h> 00020 #include <lib/ac/stdio.h> 00021 #include <lib/ac/unistd.h> 00022 #include <libexplain/close.h> 00023 #include <libexplain/creat.h> 00024 #include <libexplain/fclose.h> 00025 #include <libexplain/fflush.h> 00026 #include <libexplain/fopen.h> 00027 #include <libexplain/write.h> 00028 #include <map> 00029 00030 #include <lib/calculator.h> 00031 #include <lib/sizeof.h> 00032 00033 00034 typedef std::map<int, const char *> system_subroutines_t; 00035 static system_subroutines_t system_subroutines; 00036 00037 00038 static void 00039 setup_system_subroutines(void) 00040 { 00041 if (!system_subroutines.empty()) 00042 return; 00043 00044 struct table_t 00045 { 00046 const char *name; 00047 int number; 00048 }; 00049 00050 // Instruction Manual, p. 56 00051 static const table_t table[] = 00052 { 00053 { "sin(x)", 0x21 }, 00054 { "cos(x)", 0x22 }, 00055 { "tan(x)", 0x23 }, 00056 { "asin(x)", 0x24 }, 00057 { "acos(x)", 0x25 }, 00058 { "atan(x)", 0x26 }, 00059 { "a**n", 0x27 }, 00060 { "a**x", 0x28 }, 00061 { "10**n", 0x29 }, 00062 { "log10(x)", 0x2A }, 00063 { "exp(x)", 0x2B }, 00064 { "ln(x)", 0x2C }, 00065 { "sinh(x)", 0x2D }, 00066 { "cosh(x)", 0x2E }, 00067 { "tanh(x)", 0x31 }, 00068 { "asinh(x)", 0x32 }, 00069 { "acosh(x)", 0x33 }, 00070 { "atanh(x)", 0x34 }, 00071 { "polar_to_rectangular", 0x35 }, 00072 { "rectangular_to_polar", 0x36 }, 00073 { "dms_to_degree", 0x37 }, 00074 { "degree_to_dms", 0x38 }, 00075 { "degree_to_radian", 0x39 }, 00076 { "radian_to_degree", 0x3A }, 00077 { "factorial(n)", 0x3B }, 00078 }; 00079 00080 for (const table_t *tp = table; tp < ENDOF(table); ++tp) 00081 system_subroutines[tp->number] = tp->name; 00082 } 00083 00084 00085 void 00086 calculator::save_program_as(const std::string &filename, bool binary) 00087 { 00088 unsigned char *prog_data = programme + 1; 00089 size_t prog_size = 240; 00090 switch (program_selector) 00091 { 00092 case program_selector_i_ii: 00093 default: 00094 break; 00095 00096 case program_selector_i: 00097 prog_size = 120; 00098 break; 00099 00100 case program_selector_ii: 00101 prog_data = programme + 121; 00102 prog_size = 120; 00103 break; 00104 } 00105 assert(prog_data >= programme); 00106 assert(prog_data < programme + sizeof(programme)); 00107 assert(prog_data + prog_size >= programme); 00108 assert(prog_data + prog_size <= programme + sizeof(programme)); 00109 00110 if (binary) 00111 { 00112 const int mode = 0666; 00113 int fd = creat(filename.c_str(), mode); 00114 if (fd < 0) 00115 { 00116 on_error("%s", explain_creat(filename.c_str(), mode)); 00117 return; 00118 } 00119 if (write(fd, prog_data, prog_size) < 0) 00120 { 00121 on_error("%s", explain_write(fd, prog_data, prog_size)); 00122 close(fd); 00123 return; 00124 } 00125 if (close(fd) < 0) 00126 { 00127 on_error("%s", explain_close(fd)); 00128 return; 00129 } 00130 } 00131 else 00132 { 00133 FILE *fp = fopen(filename.c_str(), "w"); 00134 if (!fp) 00135 { 00136 on_error("%s", explain_fopen(filename.c_str(), "w")); 00137 return; 00138 } 00139 00140 // text mode requires a little more work. 00141 const unsigned char *p = prog_data; 00142 const unsigned char *prog_end = prog_data + prog_size; 00143 while (p < prog_end && prog_end[-1] == 0) 00144 --prog_end; 00145 while (p < prog_end) 00146 { 00147 unsigned char op = *p++; 00148 switch (op) 00149 { 00150 case 0: 00151 case 0xFF: 00152 break; 00153 00154 case opcode_dot: 00155 case opcode_n0: 00156 case opcode_n1: 00157 case opcode_n2: 00158 case opcode_n3: 00159 case opcode_n4: 00160 case opcode_n5: 00161 case opcode_n6: 00162 case opcode_n7: 00163 case opcode_n8: 00164 case opcode_n9: 00165 fputs(" ", fp); 00166 for (;;) 00167 { 00168 fprintf(fp, "%s", opcode_name((opcode_t)op).c_str()); 00169 if (p >= prog_end) 00170 break; 00171 op = *p; 00172 switch (op) 00173 { 00174 case opcode_dot: 00175 case opcode_n0: 00176 case opcode_n1: 00177 case opcode_n2: 00178 case opcode_n3: 00179 case opcode_n4: 00180 case opcode_n5: 00181 case opcode_n6: 00182 case opcode_n7: 00183 case opcode_n8: 00184 case opcode_n9: 00185 ++p; 00186 continue; 00187 00188 default: 00189 break; 00190 } 00191 break; 00192 } 00193 fputc('\n', fp); 00194 break; 00195 00196 case opcode_sj: 00197 case opcode_ej: 00198 case opcode_mj: 00199 case opcode_uj: 00200 case opcode_suj: 00201 fputs(" ", fp); 00202 // Fall through... 00203 00204 case opcode_fj: 00205 case opcode_sfj: 00206 fputs(opcode_name((opcode_t)op).c_str(), fp); 00207 if (p < prog_end) 00208 { 00209 fputc(' ', fp); 00210 int op2 = *p++; 00211 if (op2 < 0x70) 00212 fputs(opcode_raw_name((opcode_t)op2).c_str(), fp); 00213 else 00214 fputs(opcode_name((opcode_t)op2).c_str(), fp); 00215 00216 if (op == opcode_suj) 00217 { 00218 // 00219 // Let's assume users don't re-use library 00220 // subroutine labels, and thus include the names of 00221 // library subroutines. 00222 // 00223 setup_system_subroutines(); 00224 system_subroutines_t::const_iterator it = 00225 system_subroutines.find((int)op2); 00226 if (it != system_subroutines.end()) 00227 fprintf(fp, " ; %s", it->second); 00228 } 00229 } 00230 fputc('\n', fp); 00231 break; 00232 00233 case opcode_round_up: 00234 case opcode_round_off: 00235 case opcode_round_down: 00236 fputs(" ", fp); 00237 fputs(opcode_name((opcode_t)op).c_str(), fp); 00238 if (p < prog_end) 00239 { 00240 fputc(' ', fp); 00241 op = *p++; 00242 fputs(opcode_name((opcode_t)op).c_str(), fp); 00243 } 00244 fputc('\n', fp); 00245 break; 00246 00247 default: 00248 fputs(" ", fp); 00249 fputs(opcode_name((opcode_t)op).c_str(), fp); 00250 fputc('\n', fp); 00251 break; 00252 } 00253 } 00254 if (fflush(fp)) 00255 { 00256 on_error("%s", explain_fflush(fp)); 00257 fclose(fp); 00258 return; 00259 } 00260 if (fclose(fp)) 00261 { 00262 on_error("%s", explain_fclose(fp)); 00263 return; 00264 } 00265 } 00266 }