install.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. /*
  2. * Installation code for REDUCE in the Codemist CSL version. This
  3. * code is intended for use with MSDOS, and is compiled with
  4. * Zortech C release 3.0
  5. *
  6. * Compile with:
  7. * ztc -mc -DMS_DOS=1 install.c
  8. */
  9. /*
  10. * Copyright (C) 1992, Codemist Ltd.
  11. * This code has been modelled after suggestions from Jed Marti
  12. */
  13. /* Signature: 351e7887 29-Mar-1994 */
  14. /*
  15. * Here, right at the top of this program, I give a list of the
  16. * files that are to be unpacked.
  17. */
  18. typedef struct arch
  19. {
  20. char *name;
  21. int loaded;
  22. } arch;
  23. static arch archives[] =
  24. {
  25. {"EXE286.CAR", 0}, /* 0 */
  26. {"EXE386.CAR", 0}, /* 1 */
  27. {"OBJS286.CAR", 0}, /* 2 */
  28. {"SMAL286.CAR", 0}, /* 3 */
  29. {"OBJS386.CAR", 0}, /* 4 */
  30. {"SMAL386.CAR", 0}, /* 5 */
  31. {"SOURCE1.CAR", 0}, /* 6 */
  32. {"SOURCE2.CAR", 0}, /* 7 */
  33. {"SOURCE3.CAR", 0}, /* 8 */
  34. {"SOURCE4.CAR", 0}, /* 9 */
  35. {"GNUPLOT1.CAR", 0}, /* 10 */
  36. {"GNUPLOT2.CAR", 0}, /* 11 */
  37. {"IMG1.CAR", 0}, /* 12 */
  38. {"IMG2.CAR", 0}, /* 13 */
  39. {"DOCS1.CAR", 0}, /* 14 */
  40. {"DOCS2.CAR", 0}, /* 15 */
  41. {"XLOG1.CAR", 0}, /* 16 */
  42. {"XLOG2.CAR", 0}, /* 17 */
  43. {"XMPL1.CAR", 0}, /* 18 */
  44. {"XMPL2.CAR", 0}, /* 19 */
  45. {"README.CAR", 0} /* 20 */
  46. };
  47. #define NARCHIVES (sizeof(archives)/sizeof(archives[0]))
  48. #define O_EXE286 0
  49. #define O_EXE386 1
  50. #define O_OBJS286 2
  51. #define O_SMAL286 3
  52. #define O_OBJS386 4
  53. #define O_SMAL386 5
  54. #define O_SOURCE1 6
  55. #define O_SOURCE2 7
  56. #define O_SOURCE3 8
  57. #define O_SOURCE4 9
  58. #define O_GNUPLOT1 10
  59. #define O_GNUPLOT2 11
  60. #define O_IMG1 12
  61. #define O_IMG2 13
  62. #define O_DOCS1 14
  63. #define O_DOCS2 15
  64. #include <stdio.h>
  65. #include <stdlib.h>
  66. #include <ctype.h>
  67. #include <signal.h>
  68. #include <setjmp.h>
  69. #include <errno.h>
  70. #include <string.h>
  71. #include <math.h>
  72. #include <time.h>
  73. #include <disp.h> /* The Zortech C fast screen-output package */
  74. #include <conio.h> /* unbuffered keyboard input etc */
  75. #include <direct.h> /* for mkdir() to create directories */
  76. #include <dos.h> /* so that I can select which drive is current */
  77. #define EXTRACT 1
  78. #define INSTALL 1
  79. static jmp_buf escape_buffer;
  80. static void ctrl_c_handler(int n)
  81. {
  82. longjmp(escape_buffer, 1);
  83. }
  84. static void show_txt(int row, int col, char *msg);
  85. #include "car.c" /* File decompression technology */
  86. #define white_on_blue 0x17
  87. #define white_on_black 0x07
  88. #define black_on_white 0x70
  89. /*
  90. * filep(dr, fn) - returns nonzero if drive dr and file name exists, 0 if not.
  91. */
  92. static FILE *filep(char *dr, char *fn)
  93. {
  94. char fname[256];
  95. FILE *fh;
  96. sprintf(fname, "%s%s\0", dr, fn);
  97. return fopen(fname, "rb");
  98. }
  99. /*
  100. * There is a smallish area in the middle of the screen that I
  101. * actually use here - clear it to the background colour (blue) that
  102. * I am using.
  103. */
  104. static void clear_work_area()
  105. {
  106. disp_fillbox(256*white_on_blue + ' ', 7, 11, 18, 68);
  107. }
  108. static void show_txt(int row, int col, char *msg)
  109. {
  110. int c, l = col;
  111. disp_move(row, col);
  112. while ((c = *msg++) != 0)
  113. { if (c == '\n')
  114. { while (l <= 68)
  115. { disp_putc(' ');
  116. l++;
  117. }
  118. disp_move(++row, col);
  119. l = col;
  120. }
  121. else
  122. { disp_putc(c);
  123. l++;
  124. }
  125. }
  126. }
  127. /*
  128. * This routine asks the use a question. The question is passed as
  129. * MSG and it will ask the user to type in a value. The default
  130. * will be provided in VAL, and that will be what is used if the user
  131. * just hits ENTER. maxlen indicates the size of the VAL buffer, so
  132. * that (with luck) I can avoid overwriting things. The message HELP
  133. * is displayed so that the user understands what the question is
  134. * supposed to be about. Returns non-zero if user wants to give up.
  135. */
  136. static int request_string(int maxlen, char *msg, char *help,
  137. char *val, char *dflt)
  138. {
  139. int i, j, hwm;
  140. clear_work_area();
  141. disp_setattr(white_on_black);
  142. show_txt(8, 11, msg);
  143. show_txt(12, 11, help);
  144. disp_setattr(black_on_white);
  145. strcpy(val, dflt);
  146. show_txt(10, 16, val);
  147. hwm = i = strlen(val);
  148. disp_move(10, 16+i);
  149. disp_flush();
  150. for (;;)
  151. { int c = getch();
  152. if (c == 0) c = 0x100 + getch(); /* Extended character */
  153. switch (c)
  154. {
  155. case 0x03:
  156. case 0x1b: /* ^C and ESC */
  157. return 1;
  158. case 0x08: /* backspace deletes char before the cursor */
  159. if (i == 0) continue;
  160. i--;
  161. case 0xff:
  162. case 0x100+'S': /* DELete deletes char at cursor */
  163. if (i == hwm) continue;
  164. disp_move(10, 16+i);
  165. hwm--;
  166. for (j=i; j<hwm; j++)
  167. { int c = val[j+1];
  168. disp_putc(c);
  169. val[j] = c;
  170. }
  171. disp_setattr(white_on_blue);
  172. disp_putc(' ');
  173. disp_setattr(black_on_white);
  174. disp_move(10, 16+i);
  175. disp_flush();
  176. continue;
  177. case '\r':
  178. case '\n': /* ENTER */
  179. hwm--; /* I truncate off any trailing blanks here */
  180. while (hwm!=0 && val[hwm]==' ') hwm--;
  181. val[hwm+1] = 0;
  182. return 0;
  183. case 0x100+'R': /* Insert */
  184. if (hwm >= maxlen) continue;
  185. hwm++;
  186. for (j=hwm; j>i; j--) val[j] = val[j-1];
  187. val[i] = ' ';
  188. disp_move(10, 16+i);
  189. for (j=i; j<hwm; j++) disp_putc(val[j]);
  190. disp_move(10, 16+i);
  191. continue;
  192. case 0x100+'K': /* Left arrow */
  193. if (i == 0) continue;
  194. i--;
  195. disp_move(10, 16+i);
  196. disp_flush();
  197. continue;
  198. case 0x100+'M': /* Right arrow */
  199. if (i == hwm) continue;
  200. i++;
  201. disp_move(10, 16+i);
  202. disp_flush();
  203. continue;
  204. case 0x100+'G': /* Home - reinstate default text */
  205. disp_move(10, 16);
  206. disp_setattr(white_on_blue);
  207. for (j=0; j<hwm; j++) disp_putc(' ');
  208. disp_setattr(black_on_white);
  209. strcpy(val, dflt);
  210. show_txt(10, 16, val);
  211. hwm = i = strlen(val);
  212. disp_move(10, 16+i);
  213. disp_flush();
  214. continue;
  215. default:
  216. if (c >= 0x100) continue; /* Ignore extended chars */
  217. if (i < maxlen)
  218. { val[i++] = c;
  219. disp_putc(c);
  220. disp_flush();
  221. if (i > hwm) hwm = i;
  222. }
  223. continue;
  224. }
  225. }
  226. }
  227. /*
  228. * request_char is like request_string, except that the input needed from
  229. * the user will be just one character long. The result is dumped into the
  230. * first character of VAL.
  231. */
  232. static int request_char(char *msg, char *help, char *val)
  233. {
  234. clear_work_area();
  235. disp_setattr(white_on_black);
  236. show_txt(8, 11, msg);
  237. show_txt(12, 11, help);
  238. disp_setattr(black_on_white);
  239. show_txt(10, 16, val);
  240. disp_move(10, 16);
  241. disp_flush();
  242. for (;;)
  243. { int c = getch();
  244. switch (c & 0x7f)
  245. {
  246. case 0x03:
  247. case 0x1b: /* ^C and ESC */
  248. return 1;
  249. case '\r':
  250. case '\n': /* ENTER */
  251. return 0;
  252. case 0x08:
  253. case 0x7f: /* backspace and DELete - mapped to blank */
  254. c = ' ';
  255. default:
  256. c = toupper(c);
  257. val[0] = c;
  258. disp_move(10, 16);
  259. disp_putc(c);
  260. disp_move(10, 16);
  261. disp_flush();
  262. continue;
  263. }
  264. break;
  265. }
  266. return 0;
  267. }
  268. /*
  269. * request_ok() displays the given message and just waits for the user
  270. * to press any (printing) key. It is used for diagnostic messages and
  271. * similar reports.
  272. */
  273. static void request_ok(char *help)
  274. {
  275. clear_work_area();
  276. disp_setattr(white_on_black);
  277. show_txt(8, 11, "Press a key (e.g. ENTER) to continue\n");
  278. show_txt(12, 11, help);
  279. disp_move(10, 16);
  280. disp_flush();
  281. (void)getch(); /* All characters behave the same here */
  282. }
  283. /*
  284. * This is an interface to code found in the #included file "car.c"
  285. * that contains the Codemist file compression code and archive
  286. * utility. It sets up various workspace and invokes file decompression.
  287. */
  288. static void decompress_files()
  289. {
  290. int32 i;
  291. for (i=0; i<PREDICTION_SIZE; i++)
  292. { prediction1[i] = ' ';
  293. prediction2[i] = '\n';
  294. }
  295. memcpy(current_frequencies, default_frequencies,
  296. sizeof(default_frequencies));
  297. CRC = 1;
  298. while (extract_files()) continue;
  299. { unsigned32 calculated_CRC = CRC;
  300. unsigned32 stored_CRC = get4(); /* WARNING: get4() changes CRC! */
  301. if (calculated_CRC != stored_CRC)
  302. fprintf(stderr, "Warning: CRC failure - archive may be corrupt\n");
  303. }
  304. fclose(archive_file);
  305. }
  306. static int install(int default_source)
  307. {
  308. int cpu = cputype(); /* Used to select version to install */
  309. char *xdir, sdrive[4], dest[48], yes_no[4];
  310. char msg[1000], fname[256];
  311. int i, l, c, something_found;
  312. int disable_exe = 0, want_exe = 1, want_doc = 1,
  313. want_src = 1, want_gnuplot = 1;
  314. if (cpu < 2)
  315. { request_ok("Unsuitable computer - can not install REDUCE\n"
  316. "REDUCE needs at least an 80286 computer (and if you\n"
  317. "have an 80386 or 80486 a faster version will be\n"
  318. "installed for you). This machine seems to be an 8086\n"
  319. "or 80186. You will not be allowed to install\n"
  320. "executable binaries, but can load sources or docs\n");
  321. disable_exe = 1;
  322. }
  323. if (cpu < 3) archives[O_EXE386].loaded = 1,
  324. archives[O_OBJS386].loaded = 1,
  325. archives[O_SMAL386].loaded = 1,
  326. xdir = "csl286";
  327. else archives[O_EXE286].loaded = 1,
  328. archives[O_OBJS286].loaded = 1,
  329. archives[O_SMAL286].loaded = 1,
  330. xdir = "csl386";
  331. for (;;)
  332. { if (disable_exe) want_exe = 0;
  333. else
  334. { for (;;)
  335. { sprintf(yes_no, "Y");
  336. if (request_char(
  337. "Do you want to install executable binaries?\n",
  338. "If you select Y and type ENTER then executable binaries\n"
  339. "for REDUCE will be installed onto your hard disc. If you\n"
  340. "type N and then ENTER binaries will not be installed.\n"
  341. "The binary files involved will be called r35.exe and\n"
  342. "r35.img\n", yes_no)) goto abandon;
  343. c = toupper(yes_no[0]);
  344. if (c == 'Y' || c == 'N') break;
  345. }
  346. want_exe = (c == 'Y');
  347. }
  348. for (;;)
  349. { sprintf(yes_no, "Y");
  350. if (request_char("Do you want to install documentation?\n",
  351. "If you select Y and type ENTER then machine-readable\n"
  352. "documentation for REDUCE will be installed onto your hard\n"
  353. "disc. If you type N and then ENTER it will not be\n"
  354. "installed. The files involved will be placed in a\n"
  355. "subdirectory called \"DOC\" and most of them are formatted\n"
  356. "using the TeX text layout system\n", yes_no)) goto abandon;
  357. c = toupper(yes_no[0]);
  358. if (c == 'Y' || c == 'N') break;
  359. }
  360. want_doc = (c == 'Y');
  361. for (;;)
  362. { sprintf(yes_no, "Y");
  363. if (request_char("Do you want to install the GNUPLOT package?\n",
  364. "If you select Y and type ENTER then the GNUPLOT package\n"
  365. "will be installed onto your hard disc. GNUPLOT is not\n"
  366. "strictly part of REDUCE, but can be driven by one of the\n"
  367. "REDUCE packages. If you type N and then ENTER it will not\n"
  368. "be installed.\n", yes_no)) goto abandon;
  369. c = toupper(yes_no[0]);
  370. if (c == 'Y' || c == 'N') break;
  371. }
  372. want_gnuplot = (c == 'Y');
  373. #ifdef PERSONAL
  374. want_src = 0;
  375. #else
  376. for (;;)
  377. { sprintf(yes_no, "Y");
  378. if (request_char("Do you want to install source files?\n",
  379. "If you select Y and type ENTER then all source files for\n"
  380. "REDUCE will be installed onto your hard disc. If you type\n"
  381. "N and then ENTER binaries will not be installed. The\n"
  382. "REDUCE source files will be put in a directory \"SRC\", and\n"
  383. "many further files relating to the underlying Lisp (CSL)\n"
  384. "will also appear\n", yes_no)) goto abandon;
  385. c = toupper(yes_no[0]);
  386. if (c == 'Y' || c == 'N') break;
  387. }
  388. want_src = (c == 'Y');
  389. #endif
  390. for (;;)
  391. { sprintf(yes_no, "Y");
  392. if (want_exe || want_doc || want_src || want_gnuplot)
  393. sprintf(msg, "You have chosen to install%s%s%s%s\n",
  394. (want_exe ? "\n Executable binaries" : ""),
  395. (want_doc ? "\n Documentation" : ""),
  396. (want_src ? "\n Source code" : ""),
  397. (want_gnuplot ? "\n Gnuplot" : ""));
  398. else sprintf(msg, "You seem not to want to install anything!\n");
  399. if (request_char("Proceed with installation?\n",
  400. msg, yes_no)) goto abandon;
  401. c = toupper(yes_no[0]);
  402. if (c == 'Y' || c == 'N') break;
  403. else if (c == 'Q') goto abandon;
  404. }
  405. if (c == 'N') continue; /* Give user a chance to try again */
  406. break;
  407. }
  408. if (!want_exe)
  409. archives[O_EXE286].loaded =
  410. archives[O_EXE386].loaded =
  411. archives[O_IMG1].loaded =
  412. archives[O_IMG2].loaded = 1;
  413. if (!want_doc)
  414. archives[O_DOCS1].loaded =
  415. archives[O_DOCS2].loaded = 1;
  416. if (!want_src)
  417. archives[O_SOURCE1].loaded =
  418. archives[O_SOURCE2].loaded =
  419. archives[O_SOURCE3].loaded =
  420. archives[O_SOURCE4].loaded =
  421. archives[O_OBJS286].loaded =
  422. archives[O_SMAL286].loaded =
  423. archives[O_OBJS386].loaded =
  424. archives[O_SMAL386].loaded = 1;
  425. if (!want_gnuplot)
  426. archives[O_GNUPLOT1].loaded =
  427. archives[O_GNUPLOT2].loaded = 1;
  428. for (;;)
  429. { sdrive[0] = default_source;
  430. sdrive[1] = ':';
  431. sdrive[2] = 0;
  432. if (request_char("Floppy Drive Name\n",
  433. "This is the drive identifier where the Codemist Floppy\n"
  434. "disks will be mounted. Common values are A or B. If you\n"
  435. "want the default, just type the ENTER key. To change the\n"
  436. "value, enter a new letter, any of A-Z will be accepted.\n"
  437. "Any other key will cause the installation procedure to\n"
  438. "be aborted.", sdrive)) goto abandon;
  439. sdrive[0] = toupper(sdrive[0]);
  440. if (!('A' <= sdrive[0] && sdrive[0] <= 'Z')) goto abandon;
  441. select_destination:
  442. if (request_string(44, "Hard Disk Drive and Directory\n",
  443. "This is the drive and directory you wish to install\n"
  444. "Codemist REDUCE 3.5 on. If you want the default, just\n"
  445. "type the ENTER key. To change the value, enter a new\n"
  446. "letter. If the directory does not exist, it will be\n"
  447. "created for you.", dest, "C:\\REDUCE")) goto abandon;
  448. for (;;)
  449. { sprintf(yes_no, "Y");
  450. sprintf(msg, "Source Disk Drive %s\n"
  451. "Where to install %s\n"
  452. "Are these values correct (Y or N)\n"
  453. "Type Q or ^C to abandon installation\n", sdrive, dest);
  454. if (request_char("Proceed with installation?\n",
  455. msg, yes_no)) goto abandon;
  456. c = toupper(yes_no[0]);
  457. if (c == 'Y' || c == 'N') break;
  458. else if (c == 'Q') goto abandon;
  459. }
  460. if (c == 'N') continue; /* Give user a chance to try again */
  461. /*
  462. * Now I try to ensure that the directory indicated exists... First
  463. * I select the relevant drive as current, that is always supposing that
  464. * the user's response started off as "X:" for some X.
  465. */
  466. if (dest[0] != 0 && dest[1] == ':')
  467. { unsigned int want, ndrives, found;
  468. want = toupper(dest[0]) - 'A' + 1;
  469. dos_setdrive(want, &ndrives);
  470. /*
  471. * I check that the desired drive was indeed selected by checking which
  472. * drive is current after I (attempt to) make the selection.
  473. */
  474. dos_getdrive(&found);
  475. if (found != want) goto select_failed;
  476. }
  477. l = strlen(dest);
  478. for (i=1; i<=l; i++)
  479. { c = dest[i];
  480. if ((c == '\\' || c == 0) &&
  481. dest[i-1] != ':' && dest[i-1] != '\\')
  482. { int w;
  483. dest[i] = 0;
  484. w = mkdir(dest);
  485. if (w == 0 || /* created OK */
  486. errno == EACCES) /* already present */
  487. { dest[i] = c;
  488. continue;
  489. }
  490. yes_no[0] = 'Y'; yes_no[1] = 0;
  491. sprintf(msg, "The directory\n"
  492. "%s\n"
  493. "could not be created for you. Type Y/ENTER\n"
  494. "to select another destination, anything else to\n"
  495. "quit.\n", dest);
  496. if (request_char("Try again?\n", msg, yes_no)) goto abandon;
  497. if (toupper(yes_no[0]) != 'Y') goto abandon;
  498. else goto select_destination;
  499. }
  500. }
  501. /*
  502. * Now the destination directory ought to exist - select it as
  503. * current.
  504. * I will leave this drive and directory selected when I exit from
  505. * the installation process (even if installation fails)
  506. */
  507. if (chdir(dest) == 0) break;
  508. /*
  509. * If I fail to select the desired drive I give the user a chance to
  510. * select another.
  511. */
  512. select_failed:
  513. yes_no[0] = 'Y'; yes_no[1] = 0;
  514. sprintf(msg, "The directory\n"
  515. "%s\n"
  516. "could not be selected. Type Y/ENTER\n"
  517. "to select another destination, anything else to\n"
  518. "quit.\n", dest);
  519. if (request_char("Try again?\n", msg, yes_no)) goto abandon;
  520. if (toupper(yes_no[0]) != 'Y') goto abandon;
  521. else goto select_destination;
  522. }
  523. /*
  524. * I want two sub-directories created here - SLOW is used to hold
  525. * log files from the slow version of the system, while COUNTS holds
  526. * statistics that can indicate which (bytecoded) functions are being used
  527. * most heavily.
  528. */
  529. if (mkdir(xdir) != 0 && errno != EACCES) goto installation_failed;
  530. if (chdir(xdir) != 0) goto installation_failed;
  531. if (mkdir("slow") != 0 && errno != EACCES) goto installation_failed;
  532. if (mkdir("counts") != 0 && errno != EACCES) goto installation_failed;
  533. /*
  534. * Now I have the guts of the installation process - I have a list of
  535. * archives that I would like to find and will accept discs in any order
  536. * until I have found them all.
  537. */
  538. for (;;)
  539. {
  540. something_found = 0;
  541. look_for_another:
  542. for (i=0; i<NARCHIVES; i++)
  543. { if (archives[i].loaded) continue;
  544. goto another_to_load;
  545. }
  546. break; /* Installation complete */
  547. another_to_load:
  548. for (i=0; i<NARCHIVES; i++)
  549. { if (!archives[i].loaded)
  550. { archive_file = filep(sdrive, archives[i].name);
  551. if (archive_file == NULL) continue;
  552. something_found = 1;
  553. clear_work_area();
  554. sprintf(msg, "File %s to be uncompressed\n", archives[i].name);
  555. show_txt(9, 16, msg);
  556. decompress_files();
  557. archives[i].loaded = 1;
  558. goto look_for_another;
  559. }
  560. }
  561. if (something_found)
  562. request_ok(
  563. "Please load the next disc of the REDUCE distribution\n"
  564. "set in your floppy disc drive and type a character\n"
  565. "(e.g. ENTER). Type ^C to abort installation.\n");
  566. else request_ok(
  567. "*** No relevant files were found on that disc ***\n"
  568. "This may be because you are not loading the whole of\n"
  569. "REDUCE. Please load the next disc of the distribution\n"
  570. "set in your floppy disc drive and type a character\n"
  571. "(e.g. ENTER). Type ^C to abort installation.\n");
  572. }
  573. request_ok(
  574. "Installation complete. The directory with the REDUCE\n"
  575. "files will now be selected as current. Please check\n"
  576. "the file \"READ.ME\" for last-minute notes.\n");
  577. return EXIT_SUCCESS;
  578. installation_failed:
  579. request_ok(
  580. "The installation script was unable to create\n"
  581. "one of the files or directories needed for REDUCE.\n");
  582. return EXIT_FAILURE;
  583. abandon:
  584. request_ok("Installation of REDUCE incomplete.\n");
  585. return EXIT_FAILURE;
  586. }
  587. /*
  588. * The following procedure displays one line of text, centred in the
  589. * box I have drawn on the screen.
  590. */
  591. static void disp(int row, char *s)
  592. {
  593. int len = strlen(s);
  594. disp_move(row, 40-len/2);
  595. disp_puts(s);
  596. }
  597. int main(int argc, char *argv[])
  598. {
  599. int rc, vm = disp_getmode();
  600. int nrows, ncols, crow, ccol;
  601. unsigned short *ssave;
  602. /*
  603. * Firstly I grab the initial contents of the screen so that I can
  604. * restore it at the end.
  605. */
  606. disp_open();
  607. nrows = disp_numrows; ncols = disp_numcols;
  608. crow = disp_cursorrow; ccol = disp_cursorcol;
  609. ssave = (unsigned short *)malloc(nrows*ncols*sizeof(short));
  610. if (ssave == NULL)
  611. { disp_close();
  612. fprintf(stderr, "Insufficient memory for installation of REDUCE\n");
  613. exit(EXIT_FAILURE);
  614. }
  615. disp_peekbox(ssave, 0, 0, nrows-1, ncols-1);
  616. disp_close();
  617. /*
  618. * Now I grab the memory that will be needed for file decompression, so
  619. * that use of malloc() is all done early and thus out-of-memory
  620. * messages can be dealt with before anything else is messed up.
  621. */
  622. prediction1 = (unsigned char *)malloc((size_t)PREDICTION_SIZE);
  623. prediction2 = (unsigned char *)malloc((size_t)PREDICTION_SIZE);
  624. fast_decode_table =
  625. (int32 *)malloc((size_t)(FAST_DECODE_TABLESIZE*sizeof(int32)));
  626. char_being_coded = (int *)malloc((size_t)(2*CODE_SIZE*sizeof(int)));
  627. number_of_occurences = (int32 *)malloc((size_t)(2*CODE_SIZE*sizeof(int32)));
  628. character_index = (int *)malloc((size_t)(2*CODE_SIZE*sizeof(int)));
  629. corresponding_character = (int *)malloc((size_t)(CODE_SIZE*sizeof(int)));
  630. huffman_coded_bits =
  631. (unsigned32 *)malloc((size_t)(CODE_SIZE*sizeof(unsigned32)));
  632. length_of_code = (char *)malloc((size_t)CODE_SIZE);
  633. /*
  634. * I re-use the double-length array character_index[] as one of the
  635. * arrays needed for decoding...
  636. */
  637. sorted_huffman_codes = (unsigned32 *)&character_index[0];
  638. if (prediction1 == NULL ||
  639. prediction2 == NULL ||
  640. fast_decode_table == NULL ||
  641. char_being_coded == NULL ||
  642. number_of_occurences == NULL ||
  643. character_index == NULL ||
  644. corresponding_character == NULL ||
  645. huffman_coded_bits == NULL ||
  646. length_of_code == NULL)
  647. { fprintf(stderr, "Insufficient memory for installation of REDUCE\n");
  648. exit(EXIT_FAILURE);
  649. }
  650. /*
  651. * Now force myself into an 80*25 alphanumeric screen mode
  652. */
  653. if (vm != 3) disp_setmode(3);
  654. disp_open();
  655. /*
  656. * Clear the screen
  657. */
  658. disp_move(0, 0); disp_eeop();
  659. /*
  660. * Draw a box, with a border, for installation messages to live within
  661. */
  662. disp_fillbox(256*white_on_blue + ' ', 4, 9, 21, 70);
  663. disp_box(0, white_on_blue, 4, 9, 21, 70);
  664. disp_setattr(white_on_blue);
  665. #ifdef PERSONAL
  666. disp(6, "Personal R E D U C E 3.5");
  667. #else
  668. disp(6, "R E D U C E 3.5");
  669. #endif
  670. disp(19, "Codemist Ltd, Alta, Horsecombe Vale, Combe Down,");
  671. disp(20, "Bath BA2 5QR, England. Telephone/Fax: +44 225 837430");
  672. switch (setjmp(escape_buffer))
  673. {
  674. case 0:
  675. signal(SIGTERM, ctrl_c_handler);
  676. rc = install(argc > 0 ? toupper(argv[0][0]) : 'A');
  677. break;
  678. default:
  679. signal(SIGTERM, SIG_IGN);
  680. rc = EXIT_FAILURE;
  681. break;
  682. }
  683. /*
  684. * Re-instate the screen-mode that was active when I started
  685. */
  686. disp_close();
  687. if (vm != 3) disp_setmode(vm);
  688. /*
  689. * Restore previous screen contents and cursor position
  690. */
  691. disp_open();
  692. disp_pokebox(ssave, 0, 0, nrows-1, ncols-1);
  693. disp_move(crow, ccol);
  694. disp_flush();
  695. disp_close();
  696. exit(rc);
  697. return 0;
  698. }
  699. /* end of install.c */