preserve.c 89 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601
  1. /* preserve.c Copyright (c) Codemist Ltd, 1990-2002 */
  2. /*
  3. * This code may be used and modified, and redistributed in binary
  4. * or source form, subject to the "CCL Public License", which should
  5. * accompany it. This license is a variant on the BSD license, and thus
  6. * permits use of code derived from this in either open and commercial
  7. * projects: but it does require that updates to this code be made
  8. * available back to the originators of the package.
  9. * Before merging other code in with this or linking this code
  10. * with other packages or libraries please check that the license terms
  11. * of the other material are compatible with those of this.
  12. */
  13. /* Signature: 1936b719 10-Oct-2002 */
  14. #include <stdarg.h>
  15. #include <string.h>
  16. #include <ctype.h>
  17. #include "machine.h"
  18. #include "version.h"
  19. #include "tags.h"
  20. #include "cslerror.h"
  21. #include "externs.h"
  22. #include "arith.h"
  23. #include "read.h"
  24. #include "stream.h"
  25. #ifdef TIMEOUT
  26. #include "timeout.h"
  27. #endif
  28. /*
  29. * I perform file compression when making checkpoint images.
  30. * This is achieved by having procedure Cfwrite and Cfread which
  31. * are much like fwrite and fread but which are entitled to use a
  32. * squashed format on the external medium. It is fairly important that
  33. * Cfread should be reasonably fast - Cfwrite is just used by (preserve)
  34. * and is not so critical. The overall compression strategy implemented
  35. * here is a variant on LZ - the compressed file is made up of 12-bit
  36. * characters. The first 256 codes stand for bytes present in the original
  37. * data, while the remaining codes get allocated to stand for pairs of
  38. * characters found adjacent in the data. Initial experiments show that
  39. * the simple version of the idea implemented here squashes binary image
  40. * files to about 60% of their original size, while more elaborate
  41. * schemes can not do MUCH better.
  42. */
  43. int32 compression_worth_while = 128;
  44. #ifndef DEMO_MODE
  45. static void Cfwrite(char *a, int32 size)
  46. {
  47. /*
  48. * I keep a table showing how single 12-bit characters in the
  49. * compressed file map onto character-pairs in the original. The
  50. * field "where" in this table is notionally a quite separate
  51. * array, used to give hashed access to compressed codes. The table is
  52. * only needed at startup time and when I am dumping a checkpoint file -
  53. * in each case nothing else is one the stack, so since the table is
  54. * only 16/32 Kbytes or so I allocate it on the stack: this code is only
  55. * used when the stack is otherwise almost empty. Well actually
  56. * with the introduction of the (checkpoint) function that can be
  57. * used to dump images whatever else is going on the stack may not
  58. * be so empty after all. I will nevertheless continue to allocate
  59. * my buffers on it.
  60. */
  61. unsigned char pair_c[CODESIZE]; /* 4 Kbytes */
  62. unsigned short int pair_prev[CODESIZE], pair_where[CODESIZE];
  63. /* 16 Kbytes */
  64. unsigned char *p = (unsigned char *)a;
  65. int32 n = size, i;
  66. unsigned32 prev1;
  67. int hash, step, half;
  68. unsigned int next_code, prev, c;
  69. if (size < compression_worth_while)
  70. { if (size != 0) Iwrite(a, size);
  71. return;
  72. }
  73. /*
  74. * Clear the hash table and indicate that the next code to allocate is 256
  75. */
  76. memset(pair_where, 0, sizeof(pair_where));
  77. next_code = 256;
  78. /*
  79. * I deal with the first two characters by hand since they can not be
  80. * subject to compression. After these first two I can apply uniform
  81. * processing.
  82. */
  83. prev = *p++;
  84. c = *p++;
  85. /*
  86. * The hash function I use is not especially scientific, but a couple of
  87. * exclusive-or operations and a shift will be cheap to compute, and I
  88. * can eventually expect prev to be fairly evenly distributed, while the
  89. * distribution of c depends a lot on what sort of data is in the file.
  90. */
  91. hash = prev ^ c ^ (c << 5);
  92. prev1 = ((unsigned32)hash << 20) | ((unsigned32)prev << 8) | c;
  93. Iputc(prev >> 4);
  94. half = prev & 0xf;
  95. prev = c;
  96. for (i=2; i<n; i++)
  97. { c = *p++;
  98. hash = (prev ^ c ^ (c << 5)) & 0xfff;
  99. step = (prev - (c << 4)) | 1;
  100. /*
  101. * I compute a hash value, and also a secondary hash to be used when
  102. * making repeated probes. Since the table has size that is a power of
  103. * two I will be OK provided by step is an odd number. When I am finished
  104. * the table will have 4096-256 entries in it, i.e. it will be 94% full,
  105. * so access to it will take about 16 probes to discover that some
  106. * item is not present.
  107. */
  108. for (;;)
  109. { int where = pair_where[hash];
  110. if (where == 0) break;
  111. if (pair_prev[where] == prev &&
  112. pair_c[where] == c)
  113. { prev = where; /* squash 2 chars together */
  114. hash = -1; /* set a flag to indicate it was done */
  115. break;
  116. }
  117. hash = (hash + step) & 0xfff;
  118. }
  119. if (hash >= 0)
  120. {
  121. /*
  122. * There is a delicacy here - so that the uncompression process can
  123. * build its decoding tables on the fly I must delay entering items into
  124. * the compression tables by about one character of output. This is
  125. * achieved by keeping details of what is to be inserted stored in the
  126. * variable "prev1", which is activated here.
  127. * When all 4096 codes have been allocated I just flush out the
  128. * table and start afresh. A scheme that started with 9-bit chunks and
  129. * grew up to use longer ones up to (say) 15 or 16 bits could give
  130. * significantly better compression, but at the cost of both more
  131. * workspace here and (what is more to the point) seriously extra
  132. * overhead picking bit-fields of variable length out of the stream of
  133. * bytes in files.
  134. */
  135. if (next_code >= CODESIZE)
  136. { memset(pair_where, 0, sizeof(pair_where));
  137. next_code = 256;
  138. }
  139. else
  140. { pair_where[prev1 >> 20] = (unsigned short int)next_code;
  141. pair_prev[next_code] =
  142. (unsigned short int)(prev1 >> 8) & 0xfff;
  143. pair_c[next_code] = (unsigned char)prev1;
  144. next_code++;
  145. }
  146. /*
  147. * Now the mess of collecting 12 bit items and paching them into sequences
  148. * of 8 bit bytes.
  149. */
  150. if (half < 0)
  151. { Iputc(prev >> 4);
  152. half = prev & 0xf;
  153. }
  154. else
  155. { Iputc((half << 4) | ((prev >> 8) & 0xf));
  156. Iputc(prev);
  157. half = -1;
  158. }
  159. /*
  160. * record the information that the decoder will in due course see.
  161. */
  162. prev1 = ((unsigned32)hash << 20) | ((unsigned32)prev << 8) | c;
  163. prev = c;
  164. }
  165. }
  166. /*
  167. * Now I have to flush out the final buffered character
  168. */
  169. if (half < 0)
  170. { Iputc(prev >> 4);
  171. Iputc(prev << 4);
  172. }
  173. else
  174. { Iputc((half << 4) | ((prev >> 8) & 0xf));
  175. Iputc(prev);
  176. }
  177. }
  178. #endif /* DEMO_MODE */
  179. /*
  180. * These routines pack multiple binary files into one big one. The
  181. * good effect is that I expect fseek to be faster than fopen, and as
  182. * a result accessing fasl files will be faster. The bad news is that
  183. * when I update files I may need to compact them, and doing so will
  184. * be very tedious. In this model I do not permit arbitrary interleaving
  185. * of read and write operations.
  186. */
  187. static void set_dirused(directory_header *h, int v)
  188. {
  189. h->dirused = (unsigned char)(v & 0xff);
  190. h->dirext = (unsigned char)((h->dirext & 0xf0) + ((v>>8) & 0x0f));
  191. }
  192. static directory empty_directory =
  193. {
  194. {'C', MIDDLE_INITIAL, 'L', IMAGE_FORMAT_VERSION,
  195. 0, 0, 0, 0, 0},
  196. NULL,
  197. "EmptyFile",
  198. {"\nEmpty ** *** not dated *** **"}
  199. };
  200. /*
  201. * In a way that may look clumsy I store file offsets and lengths as
  202. * sequences of three or four characters. The object of this
  203. * explicit control over memory layout is so that directories produced by
  204. * this code have a layout that is not sensitive to the byte-order used
  205. * by the computer involved. I also put a few newline characters into
  206. * my directory structure so that if one uses an ordinary text editor to
  207. * inspect an image file the set of modules and their datestamps should
  208. * be easily visible.
  209. */
  210. static int32 bits32(char *v)
  211. {
  212. int32 r = v[3] & 0xff;
  213. r = (r << 8) | (v[2] & 0xff);
  214. r = (r << 8) | (v[1] & 0xff);
  215. return (r << 8) | (v[0] & 0xff);
  216. }
  217. static int32 bits24(char *v)
  218. {
  219. int32 r = v[2] & 0xff;
  220. r = (r << 8) | (v[1] & 0xff);
  221. return (r << 8) | (v[0] & 0xff);
  222. }
  223. static void setbits32(char *v, int32 r)
  224. {
  225. *v++ = (char)r;
  226. *v++ = (char)(r >> 8);
  227. *v++ = (char)(r >> 16);
  228. *v = (char)(r >> 24);
  229. }
  230. static void setbits24(char *v, int32 r)
  231. {
  232. *v++ = (char)r;
  233. *v++ = (char)(r >> 8);
  234. *v = (char)(r >> 16);
  235. }
  236. static directory *current_input_directory;
  237. static directory_entry *current_output_entry;
  238. static directory *current_output_directory = NULL;
  239. static CSLbool any_output_request;
  240. static char would_be_output_directory[DIRNAME_LENGTH];
  241. #define I_INACTIVE 0
  242. #define I_READING 1
  243. #define I_WRITING 2
  244. static int Istatus = I_INACTIVE;
  245. FILE *binary_read_file;
  246. static FILE *binary_write_file;
  247. static unsigned32 subfile_checksum;
  248. static long int read_bytes_remaining, write_bytes_written;
  249. directory *fasl_files[MAX_FASL_PATHS];
  250. static directory *make_empty_directory(char *name)
  251. /*
  252. * The sole purpose of this empty directory is to carry with it the
  253. * name of the file that I had tried to open.
  254. */
  255. {
  256. directory *d;
  257. d = (directory *) malloc(sizeof(directory) - sizeof(directory_entry));
  258. if (d == NULL) return &empty_directory;
  259. d->h.C = 'C'; d->h.S = MIDDLE_INITIAL; d->h.L = 'L';
  260. d->h.version = IMAGE_FORMAT_VERSION;
  261. d->h.dirsize = 0;
  262. d->h.dirused = 0;
  263. d->h.dirext = 0;
  264. d->h.updated = 0; /* NB read-only */
  265. d->f = NULL;
  266. strncpy(d->filename, name, DIRNAME_LENGTH);
  267. d->filename[DIRNAME_LENGTH-1] = 0;
  268. memset(d->h.eof, 0, 4);
  269. return d;
  270. }
  271. static directory *make_pending_directory(char *name)
  272. /*
  273. * The sole purpose of this empty directory is to carry with it the
  274. * name of the file that I had tried to open.
  275. */
  276. {
  277. directory *d;
  278. int n = sizeof(directory) + (DIRECTORY_SIZE-1)*sizeof(directory_entry);
  279. int l = strlen(name) + 1 -
  280. DIRNAME_LENGTH -
  281. DIRECTORY_SIZE*sizeof(directory_entry);
  282. /*
  283. * Here I extend the directory header with enough extra bytes to hold the
  284. * full name of the file... Once the file has been opened the (potential)
  285. * extra data becomes unnecessary. However with room for DIRECTORY_SIZE
  286. * entries already it would seem bizarre if the path-name ever actually
  287. * overflowed here.
  288. */
  289. if (l > 0) n += l;
  290. d = (directory *)malloc(n);
  291. if (d == NULL) return &empty_directory;
  292. d->h.C = 'C'; d->h.S = MIDDLE_INITIAL; d->h.L = 'L';
  293. d->h.version = IMAGE_FORMAT_VERSION;
  294. d->h.dirsize = DIRECTORY_SIZE & 0xff;
  295. d->h.dirused = 0;
  296. d->h.dirext = (DIRECTORY_SIZE >> 4) & 0xf0;
  297. d->h.updated = D_PENDING | D_WRITE_OK;
  298. /* Well I HOPE that writing will be OK */
  299. d->f = NULL;
  300. strcpy(d->filename, name); /* guaranteed enough space here */
  301. memset(d->h.eof, 0, 4);
  302. return d;
  303. }
  304. static void clear_entry(directory_entry *d)
  305. {
  306. d->D_newline = NEWLINE_CHAR;
  307. memset(&d->D_name, ' ', name_size);
  308. memcpy(&d->D_name, "<Unused>", 8);
  309. memset(&d->D_date, ' ', date_size);
  310. (&d->D_date)[0] = '-';
  311. memset(&d->D_position, 0, 4);
  312. memset(&d->D_size, 0, 3);
  313. }
  314. static CSLbool version_moan(int v)
  315. {
  316. #if defined DEMO_MODE || defined DEMO_BUILD
  317. if (v == 'd') return NO;
  318. term_printf("\n");
  319. term_printf("+++++ This image file is either corrupted or was not\n");
  320. term_printf("+++++ built for use with the Demonstration version.\n");
  321. term_printf("+++++ Unable to proceed - sorry.\n");
  322. #else
  323. if (v == IMAGE_FORMAT_VERSION ||
  324. v == IMAGE_FORMAT_VERSION-1) return NO;
  325. term_printf("\n");
  326. if (v == 'd')
  327. { term_printf("+++++ This image file was built for use with the Demonstration\n");
  328. term_printf("+++++ version of this software and can not be used with the\n");
  329. term_printf("+++++ full product.\n");
  330. }
  331. else
  332. { term_printf("+++++ This image file seems to be from an old or incompatible\n");
  333. term_printf("+++++ version of the software. Please check it by re-installing\n");
  334. term_printf("+++++ or re-building.\n");
  335. }
  336. #endif
  337. return YES;
  338. }
  339. directory *open_pds(char *name, CSLbool forinput)
  340. /*
  341. * Given a file-name, open the associated file, make space for
  342. * a directory and return same.
  343. */
  344. {
  345. char expanded[LONGEST_LEGAL_FILENAME];
  346. directory hdr, *d;
  347. CSLbool write_OK = NO;
  348. FILE *f;
  349. int l, i, n;
  350. l = strlen(name);
  351. f = NULL;
  352. /*
  353. * If you are using "-z" for a cold start you may sometimes want to
  354. * delete the image file (by hand) before running CSL
  355. */
  356. if (!forinput)
  357. {
  358. #ifdef DEMO_MODE
  359. f = NULL;
  360. #else
  361. f = open_file(expanded, name, l, "r+b", NULL);
  362. any_output_request = YES;
  363. strncpy(would_be_output_directory, expanded, DIRNAME_LENGTH-1);
  364. if (f != NULL) write_OK = YES;
  365. else
  366. {
  367. /*
  368. * I first try to open in "r+" mode, which leaves data alone if there
  369. * is already some in the file. If that fails, I try "w+" which can
  370. * create a new file for me.
  371. */
  372. f = open_file(expanded, name, l, "w+b", NULL);
  373. if (f != NULL) write_OK = YES;
  374. }
  375. #endif /* DEMO_MODE */
  376. }
  377. /*
  378. * If I wanted the file for input or if I tried it for output and failed
  379. * then I open for input.
  380. */
  381. if (f == NULL) f = open_file(expanded, name, l, "rb", NULL);
  382. /*
  383. * If the file does not exist I will just hand back a directory that shows
  384. * no files in it. This seems as easy a thing to do at this stage as I can
  385. * think of. Maybe I should warn the user?
  386. */
  387. if (f == NULL) return make_empty_directory(expanded);
  388. #ifndef SIXTEEN_BIT
  389. #define BUFFER_SIZE 0x10000 /* Use 64 Kbyte buffers for extra speed? */
  390. { char *buffer = (char *)malloc(BUFFER_SIZE);
  391. if (buffer != NULL) setvbuf(f, buffer, _IOFBF, BUFFER_SIZE);
  392. }
  393. #endif
  394. fseek(f, 0, SEEK_SET); /* Ensure I am at start of the file */
  395. hdr.h.C = hdr.h.S = hdr.h.L = 0;
  396. if (fread(&hdr.h, sizeof(directory_header), 1, f) != 1 ||
  397. hdr.h.C != 'C' ||
  398. hdr.h.S != MIDDLE_INITIAL ||
  399. hdr.h.L != 'L' ||
  400. /*
  401. * Image format versions are somewhat delicate things. I will not change
  402. * this format often or lightly and the tests I make will then be set up to
  403. * cope with updates from the immediately previous version. The testing code
  404. * will need review each time I consider such a change. For the current
  405. * upgrade I will allow opening of files from version N-1, but I will
  406. * specifically lock out reading an initial heap-image from such. The issue
  407. * of people who start with an old file and then write a fresh image back into
  408. * it will be viewed as too messy to worry about in detail, but I hope that
  409. * I have made it so that writing a new base image (via PRESERVE) updates the
  410. * version info.
  411. */
  412. version_moan(hdr.h.version) ||
  413. get_dirused(hdr.h) > get_dirsize(hdr.h) ||
  414. bits32(hdr.h.eof) < sizeof(directory_header))
  415. {
  416. /*
  417. * Here I did not find a satisfactory header to the directory. If I wanted
  418. * to open the file for input I just return an empty directory, otherwise I
  419. * need to create a new one.
  420. */
  421. if (!write_OK) return make_empty_directory(expanded);
  422. fseek(f, 0, SEEK_SET);
  423. n = DIRECTORY_SIZE; /* Size for a directory */
  424. d = (directory *)
  425. malloc(sizeof(directory)+(n-1)*sizeof(directory_entry));
  426. if (d == NULL) return &empty_directory;
  427. d->h.C = 'C'; d->h.S = MIDDLE_INITIAL; d->h.L = 'L';
  428. d->h.version = IMAGE_FORMAT_VERSION;
  429. d->h.dirsize = (unsigned char)(n & 0xff);
  430. d->h.dirused = 0;
  431. d->h.dirext = (unsigned char)((n >> 4) & 0xf0);
  432. d->h.updated = D_WRITE_OK | D_UPDATED;
  433. for (i=0; i<n; i++) clear_entry(&d->d[i]);
  434. if (fwrite(&d->h, sizeof(directory_header), 1, f) != 1)
  435. return make_empty_directory(expanded);
  436. if (fwrite(&d->d[0], sizeof(directory_entry), (size_t)n, f) != (size_t)n)
  437. return make_empty_directory(expanded);
  438. d->f = f;
  439. strncpy(d->filename, expanded, DIRNAME_LENGTH);
  440. d->filename[DIRNAME_LENGTH-1] = 0;
  441. if (fwrite(registration_data, REGISTRATION_SIZE, 1, f) != 1)
  442. return make_empty_directory(expanded);
  443. setbits32(d->h.eof, (int32)ftell(f));
  444. return d;
  445. }
  446. hdr.h.updated = write_OK ? D_WRITE_OK : 0;
  447. n = get_dirsize(hdr.h);
  448. d = (directory *)
  449. malloc(sizeof(directory)+(n-1)*sizeof(directory_entry));
  450. if (d == NULL) return &empty_directory;
  451. memcpy(&d->h, &hdr.h, sizeof(directory_header));
  452. if (fread(&d->d[0], sizeof(directory_entry), (size_t)n, f) != (size_t)n)
  453. return make_empty_directory(expanded);
  454. /*
  455. * Here the directory seemed OK
  456. */
  457. d->f = f;
  458. strncpy(d->filename, expanded, DIRNAME_LENGTH);
  459. d->filename[DIRNAME_LENGTH-1] = 0;
  460. /*
  461. * For binary files ANSI specify that the values used with fseek and ftell
  462. * are simple counts of the number of characters in the file, and hence
  463. * it is proper to save ftell() values from one run to the next.
  464. */
  465. return d;
  466. }
  467. directory *open_default_output_pds(char *name)
  468. /*
  469. * Given a file-name check if the file exists already. If so try to open
  470. * it writable, and if that fails fall back to opening it read-only.
  471. * if it does NOT exist yet then defer creating it until the first
  472. * write operation on it is attempted.
  473. */
  474. {
  475. char expanded[LONGEST_LEGAL_FILENAME];
  476. directory hdr, *d;
  477. CSLbool write_OK = NO;
  478. FILE *f;
  479. int l, i, n;
  480. l = strlen(name);
  481. f = NULL;
  482. #ifndef DEMO_MODE
  483. /*
  484. * See if I can read from the file. If so it must exist, so close it and
  485. * try again for output.
  486. */
  487. f = open_file(expanded, name, l, "r+b", NULL);
  488. any_output_request = YES;
  489. strncpy(would_be_output_directory, expanded, DIRNAME_LENGTH-1);
  490. if (f != NULL) write_OK = YES;
  491. else
  492. {
  493. /*
  494. * I first try to open in "r+" mode, which leaves data alone if there
  495. * is already some in the file. If that fails, I will hand back a special
  496. * variant on an empty directory.
  497. */
  498. f = open_file(expanded, name, l, "rb", NULL);
  499. if (f == NULL) return make_pending_directory(expanded);
  500. }
  501. #endif /* DEMO_MODE */
  502. /*
  503. * If the file exists but I could not open it for output then I will
  504. * use it read-only.
  505. */
  506. if (f == NULL) f = open_file(expanded, name, l, "rb", NULL);
  507. /*
  508. * If the file does not exist I will just hand back a directory that shows
  509. * no files in it. This seems as easy a thing to do at this stage as I can
  510. * think of. Maybe I should warn the user?
  511. */
  512. if (f == NULL) return make_empty_directory(expanded);
  513. #ifndef SIXTEEN_BIT
  514. #define BUFFER_SIZE 0x10000 /* Use 64 Kbyte buffers for extra speed? */
  515. { char *buffer = (char *)malloc(BUFFER_SIZE);
  516. if (buffer != NULL) setvbuf(f, buffer, _IOFBF, BUFFER_SIZE);
  517. }
  518. #endif
  519. fseek(f, 0, SEEK_SET); /* Ensure I am at start of the file */
  520. if (fread(&hdr.h, sizeof(directory_header), 1, f) != 1 ||
  521. hdr.h.C != 'C' ||
  522. hdr.h.S != MIDDLE_INITIAL ||
  523. hdr.h.L != 'L' ||
  524. version_moan(hdr.h.version) ||
  525. get_dirused(hdr.h) > get_dirsize(hdr.h) ||
  526. bits32(hdr.h.eof) < sizeof(directory_header))
  527. {
  528. /*
  529. * Here I did not find a satisfactory header to the directory. If I wanted
  530. * to open the file for input I just return an empty directory, otherwise I
  531. * need to create a new one.
  532. */
  533. if (!write_OK) return make_empty_directory(expanded);
  534. fseek(f, 0, SEEK_SET);
  535. n = DIRECTORY_SIZE; /* Size for a directory */
  536. d = (directory *)
  537. malloc(sizeof(directory)+(n-1)*sizeof(directory_entry));
  538. if (d == NULL) return &empty_directory;
  539. d->h.C = 'C'; d->h.S = MIDDLE_INITIAL; d->h.L = 'L';
  540. d->h.version = IMAGE_FORMAT_VERSION;
  541. d->h.dirsize = (unsigned char)(n & 0xff);
  542. d->h.dirused = 0;
  543. d->h.dirext = (unsigned char)((n >> 4) & 0xf0);
  544. d->h.updated = D_WRITE_OK | D_UPDATED;
  545. for (i=0; i<n; i++) clear_entry(&d->d[i]);
  546. if (fwrite(&d->h, sizeof(directory_header), 1, f) != 1)
  547. return make_empty_directory(expanded);
  548. if (fwrite(&d->d[0], sizeof(directory_entry), (size_t)n, f) != (size_t)n)
  549. return make_empty_directory(expanded);
  550. d->f = f;
  551. strncpy(d->filename, expanded, DIRNAME_LENGTH);
  552. d->filename[DIRNAME_LENGTH-1] = 0;
  553. if (fwrite(registration_data, REGISTRATION_SIZE, 1, f) != 1)
  554. return make_empty_directory(expanded);
  555. setbits32(d->h.eof, (int32)ftell(f));
  556. return d;
  557. }
  558. hdr.h.updated = write_OK ? D_WRITE_OK : 0;
  559. n = get_dirsize(hdr.h);
  560. d = (directory *)
  561. malloc(sizeof(directory)+(n-1)*sizeof(directory_entry));
  562. if (d == NULL) return &empty_directory;
  563. memcpy(&d->h, &hdr.h, sizeof(directory_header));
  564. if (fread(&d->d[0], sizeof(directory_entry), (size_t)n, f) != (size_t)n)
  565. return make_empty_directory(expanded);
  566. /*
  567. * Here the directory seemed OK
  568. */
  569. d->f = f;
  570. strncpy(d->filename, expanded, DIRNAME_LENGTH);
  571. d->filename[DIRNAME_LENGTH-1] = 0;
  572. /*
  573. * For binary files ANSI specify that the values used with fseek and ftell
  574. * are simple counts of the number of characters in the file, and hence
  575. * it is proper to save ftell() values from one run to the next.
  576. */
  577. return d;
  578. }
  579. static int unpending(directory *d)
  580. {
  581. FILE *f = fopen(d->filename, "w+b");
  582. int32 i, n;
  583. if (f == NULL) return YES;
  584. d->f = f;
  585. d->filename[DIRNAME_LENGTH-1] = 0; /* truncate the name now */
  586. n = DIRECTORY_SIZE; /* Size for a directory */
  587. /* (the next bits were done when the pending directory was first created
  588. d->h.C = 'C'; d->h.S = MIDDLE_INITIAL; d->h.L = 'L';
  589. d->h.version = IMAGE_FORMAT_VERSION;
  590. d->h.dirsize = n & 0xff;
  591. d->h.dirused = 0;
  592. d->h.dirext = (n >> 4) & 0xf0;
  593. */
  594. d->h.updated = D_WRITE_OK | D_UPDATED;
  595. for (i=0; i<n; i++) clear_entry(&d->d[i]);
  596. if (fwrite(&d->h, sizeof(directory_header), 1, f) != 1)
  597. return YES;
  598. if (fwrite(&d->d[0], sizeof(directory_entry), (size_t)n, f) != (size_t)n)
  599. return YES;
  600. if (fwrite(registration_data, REGISTRATION_SIZE, 1, f) != 1)
  601. return YES;
  602. setbits32(d->h.eof, (int32)ftell(f));
  603. return NO;
  604. }
  605. void Iinit(void)
  606. {
  607. int i;
  608. Istatus = I_INACTIVE;
  609. current_input_directory = NULL;
  610. current_output_entry = NULL;
  611. current_output_directory = NULL;
  612. binary_read_file = binary_write_file = NULL;
  613. read_bytes_remaining = write_bytes_written = 0;
  614. any_output_request = NO;
  615. strcpy(would_be_output_directory, "<unknown>");
  616. for (i=0; i<number_of_fasl_paths; i++)
  617. { if (0x40000000+i == output_directory)
  618. fasl_files[i] = open_default_output_pds(fasl_paths[i]);
  619. else
  620. fasl_files[i] = open_pds(fasl_paths[i], i != output_directory);
  621. }
  622. MD5_Update((unsigned char *)"Copyright 1997 Codemist Ltd", 24);
  623. }
  624. void Icontext(Ihandle *where)
  625. /*
  626. * This and the next are used so that reading from binary files can be
  627. * nested, as may be needed while loading fasl files. An Ihandle should
  628. * be viewed as an abstract handle on the input stream. Beware however that
  629. * if input is from a regular Lisp stream (indicated by read_bytes_remaining
  630. * being negative) that standard_input is NOT saved here. Therefore in
  631. * some cases it needs to be stacked elsewhere. The reason I do not save
  632. * it here is that it is a Lisp_Object and needs garbage collection
  633. * protection, which is not easily provided here.
  634. */
  635. {
  636. switch (where->status = Istatus)
  637. {
  638. case I_INACTIVE:
  639. break;
  640. case I_READING:
  641. where->f = binary_read_file;
  642. if (read_bytes_remaining >= 0) where->o = ftell(binary_read_file);
  643. where->n = read_bytes_remaining;
  644. where->chk = subfile_checksum;
  645. break;
  646. case I_WRITING:
  647. where->f = binary_write_file;
  648. where->o = ftell(binary_write_file);
  649. where->n = write_bytes_written;
  650. where->chk = subfile_checksum;
  651. break;
  652. }
  653. Istatus = I_INACTIVE;
  654. }
  655. void Irestore_context(Ihandle x)
  656. {
  657. switch (Istatus = x.status)
  658. {
  659. case I_INACTIVE:
  660. return;
  661. case I_READING:
  662. binary_read_file = x.f;
  663. read_bytes_remaining = x.n;
  664. if (read_bytes_remaining >= 0) fseek(binary_read_file, x.o, SEEK_SET);
  665. subfile_checksum = x.chk;
  666. return;
  667. case I_WRITING:
  668. binary_write_file = x.f;
  669. fseek(binary_write_file, x.o, SEEK_SET);
  670. write_bytes_written = x.n;
  671. subfile_checksum = x.chk;
  672. return;
  673. }
  674. }
  675. #define IMAGE_CODE (-1000)
  676. #define HELP_CODE (-1001)
  677. #define BANNER_CODE (-1002)
  678. /*
  679. * The code here was originally written to support module names up to
  680. * 11 characters, but it has now been extended to support long names as
  681. * well.
  682. * The mechanism used is as follows:
  683. * The name field in a directory entry is 12 characters long. For system
  684. * special pseudo-modules all 12 characters are used for a name, and the
  685. * cases used at present are InitialImage and HelpDataFile. For all
  686. * user names the name is padded with blanks, and so user names of up
  687. * to 11 characters live in the field with the 12th character a blank.
  688. * To support long names I use values 0x80 and up in this 12th position.
  689. * (NB position 12 is at offset 11 because of zero-base counting!)
  690. * The first segment of a long name uses 11 characters of the user name
  691. * and puts 0x80 in the 12th. Subsequent directory entries are used
  692. * to hold more characters of the name. These hold 11 characters in the
  693. * name field and 24 in the date, and put values 0x81, 0x82 etc in
  694. * character 12. They will have a zero length field, but their position
  695. * field MUST match that of the first record. This requirement is so that
  696. * when I sort a directory the parts of a long name are kept both
  697. * together and in the correct order. The last part of a long name has
  698. * 0xff in position 12. The result is that I can distinguish the case
  699. * of
  700. * a regular username of up to 11 chars (blank in position 12)
  701. * a system special file (non-bloank, but under 0x80 in posn 12)
  702. * the start of a long name (0x80)
  703. * a middle part of a long name (0x81 ...)
  704. * the final part of a long name (0xff).
  705. * when I match names here I will only allow a long-name match if my
  706. * directory is pointing at the first part of a long name.
  707. * As a further minor usefulness here if I find a match the non-zero value I
  708. * return is the number of entries involved.
  709. */
  710. static int samename(char *n1, directory *d, int j, int len)
  711. /*
  712. * Compare the given names, given that n1 is of length len and n2 is
  713. * blank-padded to exactly name_size characters. The special cases
  714. * with n1 NULL allow len to encode what I am looking for.
  715. */
  716. {
  717. char *n2 = &d->d[j].D_name;
  718. int i, n, recs;
  719. if (len == IMAGE_CODE)
  720. return (memcmp(n2, "InitialImage", 12) == 0);
  721. if (len == HELP_CODE)
  722. return (memcmp(n2, "HelpDataFile", 12) == 0);
  723. if (len == BANNER_CODE)
  724. return (memcmp(n2, "Start-Banner", 12) == 0);
  725. if (len < 0)
  726. { char hard[16];
  727. sprintf(hard, "HardCode<%.2x>", (-len) & 0xff);
  728. return (memcmp(n2, hard, 12) == 0);
  729. }
  730. if ((n2[11] & 0xff) > 0x80) return 0;
  731. n = 0;
  732. #define next_char_of_name (n++ < len ? *n1++ : ' ')
  733. for (i=0; i<11; i++)
  734. if (n2[i] != next_char_of_name) return 0;
  735. if ((n2[11] & 0x80) == 0) return ((n >= len) ? 1 : 0);
  736. recs = 1;
  737. do
  738. { n2 = &d->d[++j].D_name;
  739. for (i=0; i<11; i++)
  740. if (n2[i] != next_char_of_name) return 0;
  741. for (i=12; i<36; i++)
  742. if (n2[i] != next_char_of_name) return 0;
  743. recs++;
  744. } while ((n2[11] & 0xff) != 0xff);
  745. #undef next_char_of_name
  746. if (n < len) return 0;
  747. else return recs;
  748. }
  749. static CSLbool open_input(directory *d, char *name, int len, int32 offset)
  750. /*
  751. * Set up binary_read_file to access the given module, returning YES
  752. * if it was not found in the given directory. I used to pass the
  753. * names "InitialImage" and "HelpDataFile" directly to this function, but
  754. * to allow for long module names I am changing things so that these special
  755. * cases are indicated by passing down a NULL string for the name and giving
  756. * an associated length of -1 or -2 (resp).
  757. */
  758. {
  759. int i;
  760. if (Istatus != I_INACTIVE || d == NULL) return YES;
  761. subfile_checksum = 0;
  762. /*
  763. * I use simple linear search to scan the directory - mainly because I
  764. * expect directories to be fairly small and once I have found a file
  765. * I will take a long while to process it, so any clumsiness here is
  766. * not critical. I will not allow myself to read from whichever file
  767. * is currently open for output.
  768. * Because samename() is careful to ensure it only reports a match when
  769. * pointed at the start of a long name it is OK to search in steps of 1
  770. * here.
  771. */
  772. for (i=0; i<get_dirused(d->h); i++)
  773. { if (samename(name, d, i, len) &&
  774. &d->d[i] != current_output_entry)
  775. { binary_read_file = d->f;
  776. read_bytes_remaining = bits24(&d->d[i].D_size);
  777. i = fseek(binary_read_file,
  778. bits32(&d->d[i].D_position)+offset, SEEK_SET);
  779. if (i == 0) /* If fseek succeeded it returned zero */
  780. { Istatus = I_READING;
  781. return NO;
  782. }
  783. else return YES;
  784. }
  785. }
  786. return YES;
  787. }
  788. void IreInit(void)
  789. {
  790. MD5_Update((unsigned char *)"Copyright 1997 Codemist Ltd", 24);
  791. MD5_Update((unsigned char *)"memory.u", 8);
  792. }
  793. static int MS_CDECL for_qsort(void const *aa, void const *bb)
  794. {
  795. directory_entry *a = (directory_entry *)aa,
  796. *b = (directory_entry *)bb;
  797. long int ap = bits32(&a->D_position), bp = bits32(&b->D_position);
  798. if (ap < bp) return -1;
  799. else if (ap > bp) return 1;
  800. /*
  801. * I make the position of the module in the image my primary sort key.
  802. * Over-long module names are coped with by giving each part of the
  803. * name the same position field, but marking the 12th character of the
  804. * name field (D_space) with 0x80, 0x81 ... in extension records. Note that
  805. * a regular short module name has a blank character there, while the special
  806. * cases of "InitialImage" and "HelpDataFile" each have 'e' there,
  807. * "Start-Banner" has 'r', while hard code has '>'.
  808. * So bytes 0x80 and up are clearly (if hackily!) distinguished.
  809. */
  810. ap = a->D_space & 0xff, bp = b->D_space & 0xff;
  811. if (ap < bp) return -1;
  812. else if (ap > bp) return 1;
  813. else return 0;
  814. }
  815. static void sort_directory(directory *d)
  816. {
  817. qsort((void *)d->d, (size_t)get_dirused(d->h),
  818. sizeof(directory_entry), for_qsort);
  819. }
  820. static directory *enlarge_directory(int current_size)
  821. {
  822. nil_as_base
  823. int n = (3*current_size)/2;
  824. int newsize = sizeof(directory)+(n-1)*sizeof(directory_entry);
  825. int newpos = sizeof(directory_header)+n*sizeof(directory_entry);
  826. /*
  827. * enlarge_directory() is only called when an output library is known
  828. * to exist, so I do not need to check for that here.
  829. */
  830. int dirno = library_number(qvalue(output_library));
  831. directory *d1 = fasl_files[dirno];
  832. if (n > current_size+20) n = current_size+20;
  833. for (;;)
  834. { directory_entry *first;
  835. FILE *f;
  836. char buffer[512]; /* I hope this is not done too often, since this */
  837. /* is not a very big buffer size for the copy. */
  838. int32 firstpos, firstlen, newfirst, eofpos;
  839. sort_directory(d1);
  840. first = &d1->d[0];
  841. firstpos = bits32(&first->D_position);
  842. if (firstpos >= newpos + REGISTRATION_SIZE) break;
  843. /*
  844. * Here I need to copy a module up to the end of the file to make room
  845. * for the enlarged directory
  846. */
  847. firstlen = bits24(&first->D_size);
  848. newfirst = eofpos = bits32(d1->h.eof);
  849. f = d1->f;
  850. firstlen += 4; /* Allow for the checksum */
  851. while (firstlen >= sizeof(buffer))
  852. { fseek(f, firstpos, SEEK_SET);
  853. if (fread(buffer, sizeof(buffer), 1, f) != 1) return NULL;
  854. fseek(f, eofpos, SEEK_SET);
  855. if (fwrite(buffer, sizeof(buffer), 1, f) != 1) return NULL;
  856. firstlen -= sizeof(buffer);
  857. firstpos += sizeof(buffer);
  858. eofpos += sizeof(buffer);
  859. }
  860. if (firstlen != 0)
  861. { fseek(f, firstpos, SEEK_SET);
  862. if (fread(buffer, firstlen, 1, f) != 1) return NULL;
  863. fseek(f, eofpos, SEEK_SET);
  864. if (fwrite(buffer, firstlen, 1, f) != 1) return NULL;
  865. eofpos += firstlen;
  866. }
  867. setbits32(&first->D_position, newfirst);
  868. if ((first->D_space & 0xff) == 0x80)
  869. { do
  870. { first++;
  871. setbits32(&first->D_position, newfirst);
  872. } while ((first->D_space & 0xff) != 0xff);
  873. }
  874. setbits32(d1->h.eof, eofpos);
  875. }
  876. fseek(d1->f, newpos, SEEK_SET);
  877. fwrite(registration_data, REGISTRATION_SIZE, 1, d1->f);
  878. d1 = (directory *)realloc((void *)d1, newsize);
  879. if (d1 == NULL) return NULL;
  880. d1->h.dirsize = (unsigned char)(n & 0xff);
  881. d1->h.dirext = (unsigned char)((d1->h.dirext & 0x0f) + ((n>>4) & 0xf0));
  882. d1->h.updated |= D_COMPACT | D_UPDATED;
  883. while (n>current_size) clear_entry(&d1->d[--n]);
  884. fasl_files[dirno] = d1;
  885. return d1;
  886. }
  887. static CSLbool open_output(char *name, int len)
  888. /*
  889. * Set up binary_write_file to access the given module, returning YES
  890. * if anything went wrong. Remember name==NULL for initial image & help
  891. * data.
  892. */
  893. {
  894. #ifdef DEMO_MODE
  895. return YES;
  896. #else
  897. nil_as_base
  898. int i, j, n;
  899. char *ct;
  900. char hard[16];
  901. directory *d;
  902. time_t t = time(NULL);
  903. Lisp_Object oo = qvalue(output_library);
  904. if (!is_library(oo)) return YES;
  905. d = fasl_files[library_number(oo)];
  906. if (d == NULL) return YES; /* closed handle, I guess */
  907. if ((d->h.updated & D_WRITE_OK) == 0) return YES;
  908. /*
  909. * The main effect of the next line will be to prohibit opening a new
  910. * FASL file while I am in the middle of reading one that already exists.
  911. * Indeed this is a restriction, but at present it seems a very reasonable
  912. * on for me to apply.
  913. */
  914. if (Istatus != I_INACTIVE) return YES;
  915. if (d->h.updated & D_PENDING)
  916. { if (unpending(d)) return YES;
  917. }
  918. subfile_checksum = 0;
  919. current_output_directory = d;
  920. /*
  921. * I use simple linear search to scan the directory - mainly because I
  922. * expect directories to be fairly small and once I have found a file
  923. * I will take a long while to process it, so any clumsiness here is
  924. * not critical. Again note it is OK to scan in steps of 1 despite the
  925. * fact that long-names are stored split across consecutive directory slots.
  926. */
  927. for (i=0; i<get_dirused(d->h); i++)
  928. { if (samename(name, d, i, len))
  929. { current_output_entry = &d->d[i];
  930. d->h.updated |= D_COMPACT | D_UPDATED;
  931. if (t == (time_t)(-1)) ct = "not dated";
  932. else ct = ctime(&t);
  933. /*
  934. * Note that I treat the result handed back by ctime() as delicate, in that
  935. * I do not do any library calls between calling ctime and copying the
  936. * string it returns to somewhere that is under my own control.
  937. */
  938. strncpy(&d->d[i].D_date, ct, date_size);
  939. binary_write_file = d->f;
  940. write_bytes_written = 0;
  941. memcpy(&d->d[i].D_position, d->h.eof, 4);
  942. /* For long names I must put the location in each record */
  943. if (d->d[i].D_space & 0x80)
  944. { j = 0;
  945. do
  946. { j++;
  947. memcpy(&d->d[i+j].D_position, d->h.eof, 4);
  948. } while ((d->d[i+j].D_space & 0xff) != 0xff);
  949. }
  950. i = fseek(binary_write_file, bits32(d->h.eof), SEEK_SET);
  951. if (i == 0) Istatus = I_WRITING;
  952. else current_output_directory = NULL;
  953. if (name == NULL && len == IMAGE_CODE)
  954. d->h.version = IMAGE_FORMAT_VERSION;
  955. return i;
  956. }
  957. }
  958. /*
  959. * Here the name did not already exist, and so I will need to enter it into
  960. * the directory. If I get here the variable i points to the first unused
  961. * directory entry.
  962. */
  963. if (len == IMAGE_CODE)
  964. { name = "InitialImage";
  965. n = 1;
  966. d->h.version = IMAGE_FORMAT_VERSION;
  967. }
  968. else if (len == HELP_CODE) name = "HelpDataFile", len = IMAGE_CODE, n = 1;
  969. else if (len == BANNER_CODE) name = "Start-Banner", len = IMAGE_CODE, n = 1;
  970. else if (len < 0)
  971. { sprintf(hard, "HardCode<%.2x>", (-len) & 0xff);
  972. name = hard, len = IMAGE_CODE, n = 1;
  973. }
  974. else if (len <= 11) n = 1;
  975. else if (len <= 11+11+24) n = 2;
  976. else if (len <= 11+11+11+24+24) n = 3;
  977. else return YES; /* Name longer than 81 chars not supported, sorry */
  978. while (i+n > (int)get_dirsize(d->h))
  979. { d = enlarge_directory(i);
  980. current_output_directory = d;
  981. if (d == NULL) return YES;
  982. }
  983. current_output_entry = &d->d[i];
  984. if (len == IMAGE_CODE)
  985. { d->d[i].D_newline = NEWLINE_CHAR;
  986. memcpy(&d->d[i].D_name, name, 12);
  987. memset(&d->d[i].D_date, ' ', date_size);
  988. memset(&d->d[i].D_size, 0, 3);
  989. memcpy(&d->d[i].D_position, d->h.eof, 4);
  990. }
  991. else
  992. { int np;
  993. char *p;
  994. /*
  995. * First I will clear all the relevant fields to blanks.
  996. */
  997. for (j=0; j<n; j++)
  998. { d->d[i+j].D_newline = '\n';
  999. memset(&d->d[i+j].D_name, ' ', name_size);
  1000. memset(&d->d[i+j].D_date, ' ', date_size);
  1001. memset(&d->d[i+j].D_size, 0, 3);
  1002. memcpy(&d->d[i+j].D_position, d->h.eof, 4);
  1003. }
  1004. #define next_char_of_name (np++ >= len ? ' ' : *p++)
  1005. np = 0;
  1006. p = name;
  1007. for (j=0; j<n; j++)
  1008. { int k;
  1009. for (k=0; k<11; k++) (&d->d[i+j].D_name)[k] = next_char_of_name;
  1010. if (j != 0)
  1011. for (k=0; k<24; k++)
  1012. (&d->d[i+j].D_date)[k] = next_char_of_name;
  1013. if (j == 0 && n == 1) d->d[i+j].D_space = ' ';
  1014. else if (j == n-1) d->d[i+j].D_space = 0xff;
  1015. else d->d[i+j].D_space = (char)(0x80+j);
  1016. #undef next_char_of_name
  1017. }
  1018. }
  1019. if (t == (time_t)(-1)) ct = "** *** not dated *** ** ";
  1020. else ct = ctime(&t);
  1021. strncpy(&d->d[i].D_date, ct, date_size);
  1022. set_dirused(&d->h, get_dirused(d->h)+n);
  1023. binary_write_file = d->f;
  1024. write_bytes_written = 0;
  1025. d->h.updated |= D_UPDATED;
  1026. i = fseek(binary_write_file, bits32(d->h.eof), SEEK_SET);
  1027. if (i == 0)
  1028. { Istatus = I_WRITING;
  1029. return NO;
  1030. }
  1031. else
  1032. { current_output_directory = NULL;
  1033. return YES;
  1034. }
  1035. #endif /* DEMO_MODE */
  1036. }
  1037. static void list_one_library(Lisp_Object oo, CSLbool out_only)
  1038. {
  1039. int j;
  1040. directory *d = fasl_files[library_number(oo)];
  1041. trace_printf("\nFile %s (dirsize %ld length %ld",
  1042. d->filename, (long)get_dirsize(d->h), (long)bits32(d->h.eof));
  1043. j = d->h.updated;
  1044. if (j != 0) trace_printf(",");
  1045. if (j & D_WRITE_OK) trace_printf(" Writable");
  1046. if (j & D_UPDATED) trace_printf(" Updated");
  1047. if (j & D_COMPACT) trace_printf(" NeedsCompaction");
  1048. if (j & D_PENDING) trace_printf(" Pending");
  1049. if (out_only) trace_printf(" OutputOnly");
  1050. trace_printf("):\n");
  1051. /*
  1052. * The format string used here will need adjustment if you ever change the
  1053. * number of characters used to store names or dates.
  1054. */
  1055. for (j=0; j<get_dirused(d->h); j++)
  1056. { int n = 0;
  1057. if (d->d[j].D_space & 0x80)
  1058. { trace_printf(" %.11s", &d->d[j].D_name);
  1059. do
  1060. { n++;
  1061. trace_printf("%.11s%.24s",
  1062. &d->d[j+n].D_name, &d->d[j+n].D_date);
  1063. } while ((d->d[j+n].D_space & 0xff) != 0xff);
  1064. trace_printf(
  1065. "\n %-24.24s position %-7ld size: %ld\n",
  1066. &d->d[j].D_date,
  1067. (long)bits32(&d->d[j].D_position),
  1068. (long)bits24(&d->d[j].D_size));
  1069. j += n;
  1070. }
  1071. else trace_printf(
  1072. " %-12.12s %-24.24s position %-7ld size: %ld\n",
  1073. &d->d[j].D_name, &d->d[j].D_date,
  1074. (long)bits32(&d->d[j].D_position),
  1075. (long)bits24(&d->d[j].D_size));
  1076. }
  1077. }
  1078. void Ilist(void)
  1079. {
  1080. Lisp_Object nil = C_nil;
  1081. Lisp_Object il = qvalue(input_libraries), w;
  1082. Lisp_Object ol = qvalue(output_library);
  1083. while (consp(il))
  1084. { w = qcar(il); il = qcdr(il);
  1085. if (!is_library(w)) continue;
  1086. if (w == ol) ol = nil;
  1087. list_one_library(w, NO);
  1088. }
  1089. if (is_library(ol)) list_one_library(ol, YES);
  1090. }
  1091. Lisp_Object Llibrary_members(Lisp_Object nil, Lisp_Object oo)
  1092. {
  1093. int i, j, k;
  1094. directory *d = fasl_files[library_number(oo)];
  1095. Lisp_Object v, r = C_nil;
  1096. char *p;
  1097. for (j=0; j<get_dirused(d->h); j++)
  1098. { int n = 0;
  1099. p = (char *)&celt(boffo, 0);
  1100. k = 0;
  1101. if (d->d[j].D_space & 0x80)
  1102. { for (i=0; i<11; i++)
  1103. { *p++ = (&d->d[j].D_name)[i];
  1104. k++;
  1105. }
  1106. do
  1107. { n++;
  1108. for (i=0; i<11; i++)
  1109. { *p++ = (&d->d[j+n].D_name)[i];
  1110. k++;
  1111. }
  1112. } while ((d->d[j+n].D_space & 0xff) != 0xff);
  1113. j += n;
  1114. }
  1115. else
  1116. { if (memcmp(&d->d[j].D_name, "InitialImage", 12) == 0 ||
  1117. memcmp(&d->d[j].D_name, "HelpDataFile", 12) == 0 ||
  1118. memcmp(&d->d[j].D_name, "Start-Banner", 12) == 0 ||
  1119. memcmp(&d->d[j].D_name, "HardCode<", 9) == 0 &&
  1120. (&d->d[j].D_name)[11] == '>')
  1121. continue; /* not user modules */
  1122. for (i=0; i<12; i++)
  1123. { *p++ = (&d->d[j].D_name)[i];
  1124. k++;
  1125. }
  1126. }
  1127. while (k>0 && p[-1] == ' ') k--, p--;
  1128. *p = 0;
  1129. push(r);
  1130. v = iintern(boffo, k, lisp_package, 0);
  1131. pop(r);
  1132. errexit();
  1133. r = cons(v, r);
  1134. errexit();
  1135. }
  1136. return onevalue(r);
  1137. }
  1138. Lisp_Object MS_CDECL Llibrary_members0(Lisp_Object nil, int nargs, ...)
  1139. /*
  1140. * This returns a list of the modules in the first library on the current
  1141. * search path.
  1142. */
  1143. {
  1144. Lisp_Object il = qvalue(input_libraries), w;
  1145. Lisp_Object ol = qvalue(output_library);
  1146. argcheck(nargs, 0, "library-members");
  1147. while (consp(il))
  1148. { w = qcar(il); il = qcdr(il);
  1149. if (!is_library(w)) continue;
  1150. return Llibrary_members(nil, w);
  1151. }
  1152. if (is_library(ol)) return Llibrary_members(nil, ol);
  1153. else return onevalue(nil);
  1154. }
  1155. CSLbool Imodulep(char *name, int len, char *datestamp, int32 *size,
  1156. char *expanded_name)
  1157. /*
  1158. * Hands back information about whether the given module exists, and
  1159. * if it does when it was written. Code should be very similar to
  1160. * that in Iopen.
  1161. */
  1162. {
  1163. int i;
  1164. Lisp_Object nil = C_nil;
  1165. Lisp_Object il = qvalue(input_libraries);
  1166. /*
  1167. * nil is conditionally needed for two reasons here:
  1168. * (a) if NILSEG_EXTERNS was not selected it is needed as a base register for
  1169. * access to input_libraries
  1170. * (b) if COMMON was selected it is needed for the expansion of the
  1171. * consp test.
  1172. * If neither of the above apply its is redundant, but not a very greate pain.
  1173. */
  1174. CSL_IGNORE(nil);
  1175. while (consp(il))
  1176. { int j;
  1177. directory *d;
  1178. Lisp_Object oo = qcar(il); il = qcdr(il);
  1179. if (!is_library(oo)) continue;
  1180. i = library_number(oo);
  1181. d = fasl_files[i];
  1182. if (d == NULL) continue;
  1183. for (j=0; j<get_dirused(d->h); j++)
  1184. { if (samename(name, d, j, len))
  1185. { char *n = fasl_files[i]->filename;
  1186. memcpy(datestamp, &d->d[j].D_date, date_size);
  1187. *size = bits24(&d->d[j].D_size);
  1188. if (name == NULL) sprintf(expanded_name, "%s(InitialImage)", n);
  1189. else sprintf(expanded_name, "%s(%.*s)", n, len, name);
  1190. return NO;
  1191. }
  1192. }
  1193. }
  1194. return YES;
  1195. }
  1196. CSLbool IopenRoot(char *expanded_name, int hard)
  1197. /*
  1198. * Opens the "InitialImage" file so that it can be loaded. Note that
  1199. * when I am about to do this I do not have a valid heap image loaded, and
  1200. * so it would NOT be possible to use the regular search-path mechanism for
  1201. * libraries. Therefore I will just use images as specified from the
  1202. * command line (or by default).
  1203. */
  1204. {
  1205. char *n;
  1206. int i;
  1207. if (hard == 0) hard = IMAGE_CODE;
  1208. for (i=0; i<number_of_fasl_paths; i++)
  1209. { CSLbool bad;
  1210. bad = open_input(fasl_files[i], NULL, hard, 0);
  1211. /*
  1212. * The name that I return (for possible display in error messages) will be
  1213. * either that of the file that was opened, or one relating to the last
  1214. * entry in the search path.
  1215. */
  1216. n = fasl_files[i]->filename;
  1217. if (expanded_name != NULL)
  1218. { if (hard == IMAGE_CODE)
  1219. { if (!bad)
  1220. { long int pos = ftell(binary_read_file);
  1221. directory *d = fasl_files[i];
  1222. unsigned char rr[REGISTRATION_SIZE];
  1223. int n = get_dirsize(d->h) * sizeof(directory_entry);
  1224. n += sizeof(directory_header);
  1225. fseek(binary_read_file, n, SEEK_SET);
  1226. fread(rr, REGISTRATION_SIZE,
  1227. 1, binary_read_file);
  1228. if (memcmp(rr, REGISTRATION_VERSION, 4) == 0)
  1229. memcpy(registration_data, rr, REGISTRATION_SIZE);
  1230. fseek(binary_read_file, pos, SEEK_SET);
  1231. }
  1232. sprintf(expanded_name, "%s(InitialImage)", n);
  1233. }
  1234. else if (hard == BANNER_CODE)
  1235. sprintf(expanded_name, "%s(InitialImage)", n);
  1236. else sprintf(expanded_name, "%s(HardCode<%.2x>)",
  1237. n, (-hard) & 0xff);
  1238. }
  1239. if (!bad) return NO;
  1240. }
  1241. return YES;
  1242. }
  1243. CSLbool Iopen(char *name, int len, CSLbool forinput, char *expanded_name)
  1244. /*
  1245. * Make file with the given name available through this package of
  1246. * routines. (name) is a pointer to a string (len characters valid) that
  1247. * names a fasl file. (forinput) specifies the direction of the transfer
  1248. * to set up. Returns YES if something failed.
  1249. * name can be NULL when a module is opened for output, and then output
  1250. * is sent to "InitialImage".
  1251. * The same is done for input, but it would be more sensible to use
  1252. * IopenRoot() to access the root image.
  1253. */
  1254. {
  1255. char *n;
  1256. Lisp_Object nil = C_nil;
  1257. CSL_IGNORE(nil);
  1258. if (name == NULL) len = IMAGE_CODE;
  1259. if (forinput)
  1260. { int i;
  1261. Lisp_Object il = qvalue(input_libraries);
  1262. while (consp(il))
  1263. { CSLbool bad;
  1264. Lisp_Object oo = qcar(il); il = qcdr(il);
  1265. if (!is_library(oo)) continue;
  1266. i = library_number(oo);
  1267. bad = open_input(fasl_files[i], name, len, 0);
  1268. /*
  1269. * The name that I return (for possible display in error messages) will be
  1270. * either that of the file that was opened, or one relating to the last
  1271. * entry in the search path.
  1272. */
  1273. n = fasl_files[i]->filename;
  1274. if (expanded_name != NULL)
  1275. sprintf(expanded_name, "%s(%.*s)", n, len, name);
  1276. if (!bad) return NO;
  1277. }
  1278. return YES;
  1279. }
  1280. #ifndef DEMO_MODE
  1281. if (!any_output_request)
  1282. #endif
  1283. { if (expanded_name != NULL)
  1284. strcpy(expanded_name, "<no output file specified>");
  1285. return YES;
  1286. }
  1287. #ifndef DEMO_MODE
  1288. n = would_be_output_directory;
  1289. if (expanded_name != NULL)
  1290. { if (len == IMAGE_CODE)
  1291. sprintf(expanded_name, "%s(InitialImage)", n);
  1292. else sprintf(expanded_name, "%s(%.*s)", n, len, name);
  1293. }
  1294. return open_output(name, len);
  1295. #endif
  1296. }
  1297. CSLbool Iwriterootp(char *expanded_name)
  1298. /*
  1299. * Test if it will be possible to write out an image file. Used
  1300. * by (preserve) so it can report that this would fail without actually
  1301. * doing anything too drastic.
  1302. */
  1303. {
  1304. #ifdef DEMO_MODE
  1305. strcpy(expanded_name, "<demo-system>");
  1306. return YES;
  1307. #else
  1308. Lisp_Object nil = C_nil;
  1309. directory *d;
  1310. Lisp_Object oo = qvalue(output_library);
  1311. CSL_IGNORE(nil);
  1312. if (!any_output_request)
  1313. { strcpy(expanded_name, "<no output file specified>");
  1314. return YES;
  1315. }
  1316. sprintf(expanded_name, "%s(InitialImage)", would_be_output_directory);
  1317. if (!is_library(oo)) return YES;
  1318. d = fasl_files[library_number(oo)];
  1319. if (d == NULL) return YES; /* closed handle, I guess */
  1320. if ((d->h.updated & D_WRITE_OK) == 0) return YES;
  1321. if (Istatus != I_INACTIVE) return YES;
  1322. return NO;
  1323. #endif /* DEMO_MODE */
  1324. }
  1325. CSLbool Iopen_help(int32 offset)
  1326. /*
  1327. * Get ready to handle the HELP subfile. offset >= 0 will open an
  1328. * existing help module for input and position at the given location.
  1329. * A negative offset indicates that the help module should be opened
  1330. * for writing.
  1331. */
  1332. {
  1333. Lisp_Object nil = C_nil;
  1334. CSL_IGNORE(nil);
  1335. if (offset >= 0)
  1336. { Lisp_Object il = qvalue(input_libraries);
  1337. while (consp(il))
  1338. { CSLbool bad;
  1339. Lisp_Object oo = qcar(il); il = qcdr(il);
  1340. if (!is_library(oo)) continue;
  1341. bad = open_input(fasl_files[library_number(oo)],
  1342. NULL, HELP_CODE, offset);
  1343. if (!bad) return NO;
  1344. }
  1345. return YES;
  1346. }
  1347. #ifdef DEMO_MODE
  1348. return YES;
  1349. #else
  1350. if (!any_output_request) return YES;
  1351. return open_output(NULL, HELP_CODE);
  1352. #endif
  1353. }
  1354. CSLbool Iopen_banner(int code)
  1355. /*
  1356. * Get ready to handle the startup banner.
  1357. * code = 0 open for reading
  1358. * code = -1 open for writing
  1359. * code = -2 delete banner file
  1360. */
  1361. {
  1362. Lisp_Object nil = C_nil;
  1363. CSL_IGNORE(nil);
  1364. if (code == -2) return Idelete(NULL, BANNER_CODE);
  1365. else if (code == 0)
  1366. { Lisp_Object il = qvalue(input_libraries);
  1367. while (consp(il))
  1368. { CSLbool bad;
  1369. Lisp_Object oo = qcar(il); il = qcdr(il);
  1370. if (!is_library(oo)) continue;
  1371. bad = open_input(fasl_files[library_number(oo)],
  1372. NULL, BANNER_CODE, 0);
  1373. if (!bad) return NO;
  1374. }
  1375. return YES;
  1376. }
  1377. #ifdef DEMO_MODE
  1378. return YES;
  1379. #else
  1380. if (!any_output_request) return YES;
  1381. return open_output(NULL, BANNER_CODE);
  1382. #endif
  1383. }
  1384. /*
  1385. * Set up binary_read_file to read from standard input. Return YES if
  1386. * things fail.
  1387. */
  1388. CSLbool Iopen_from_stdin(void)
  1389. {
  1390. if (Istatus != I_INACTIVE) return YES;
  1391. subfile_checksum = 0;
  1392. binary_read_file = NULL;
  1393. read_bytes_remaining = -1;
  1394. Istatus = I_READING;
  1395. return NO;
  1396. }
  1397. CSLbool Iopen_to_stdout(void)
  1398. {
  1399. if (Istatus != I_INACTIVE) return YES;
  1400. subfile_checksum = 0;
  1401. Istatus = I_WRITING;
  1402. return NO;
  1403. }
  1404. CSLbool Idelete(char *name, int len)
  1405. {
  1406. #ifdef DEMO_MODE
  1407. return YES;
  1408. #else
  1409. nil_as_base
  1410. int i, nrec;
  1411. directory *d;
  1412. Lisp_Object oo = qvalue(output_library);
  1413. if (!is_library(oo)) return YES;
  1414. d = fasl_files[library_number(oo)];
  1415. if (d == NULL ||
  1416. (d->h.updated && D_WRITE_OK) == 0 ||
  1417. Istatus != I_INACTIVE) return YES;
  1418. for (i=0; i<get_dirused(d->h); i++)
  1419. { if ((nrec = samename(name, d, i, len)) != 0)
  1420. { int j;
  1421. set_dirused(&d->h, get_dirused(d->h)-nrec);
  1422. for (j=i; j<get_dirused(d->h); j++)
  1423. d->d[j] = d->d[j+nrec];
  1424. /*
  1425. * I tidy up the now-unused entry - in some sense this is a redundant
  1426. * operation, but I think it makes the file seem neater, which may possibly
  1427. * help avoid confusion and ease debugging.
  1428. */
  1429. while (nrec-- != 0)
  1430. { memset(&d->d[j].D_name, ' ', name_size);
  1431. memcpy(&d->d[j].D_name, "<Unused>", 8);
  1432. memset(&d->d[j].D_date, ' ', date_size);
  1433. (&d->d[j].D_date)[0] = '-';
  1434. setbits32(&d->d[j].D_position, 0);
  1435. setbits24(&d->d[j].D_size, 0);
  1436. j++;
  1437. }
  1438. d->h.updated |= D_COMPACT | D_UPDATED;
  1439. return NO;
  1440. }
  1441. }
  1442. return YES;
  1443. #endif /* DEMO_MODE */
  1444. }
  1445. #define update_crc(chk, c) \
  1446. chk_temp = (chk << 7); \
  1447. chk = ((chk >> 25) ^ \
  1448. (chk_temp >> 1) ^ \
  1449. (chk_temp >> 4) ^ \
  1450. (0xff & (unsigned32)c)) & 0x7fffffff;
  1451. static int validate_checksum(FILE *f, unsigned32 chk1)
  1452. {
  1453. int c;
  1454. unsigned32 chk2 = 0;
  1455. if (read_bytes_remaining < 0)
  1456. { if ((c = Igetc()) == EOF) goto failed;
  1457. chk2 = c & 0xff;
  1458. if ((c = Igetc()) == EOF) goto failed;
  1459. chk2 = (chk2 << 8) | (c & 0xff);
  1460. if ((c = Igetc()) == EOF) goto failed;
  1461. chk2 = (chk2 << 8) | (c & 0xff);
  1462. if ((c = Igetc()) == EOF) goto failed;
  1463. chk2 = (chk2 << 8) | (c & 0xff);
  1464. if (chk1 == chk2) return NO; /* All went well */
  1465. }
  1466. else
  1467. { if ((c = getc(f)) == EOF) goto failed;
  1468. chk2 = c & 0xff;
  1469. if ((c = getc(f)) == EOF) goto failed;
  1470. chk2 = (chk2 << 8) | (c & 0xff);
  1471. if ((c = getc(f)) == EOF) goto failed;
  1472. chk2 = (chk2 << 8) | (c & 0xff);
  1473. if ((c = getc(f)) == EOF) goto failed;
  1474. chk2 = (chk2 << 8) | (c & 0xff);
  1475. if (chk1 == chk2) return NO; /* All went well */
  1476. }
  1477. failed:
  1478. err_printf("\n+++ FASL module checksum failure (%.8x instead of %.8x)\n",
  1479. chk2, chk1);
  1480. return YES;
  1481. }
  1482. #ifndef DEMO_MODE
  1483. static int put_checksum(FILE *f, unsigned32 chk)
  1484. {
  1485. Lisp_Object nil = C_nil;
  1486. /*
  1487. * NB that while I am writing out the root section of a checkpoint image
  1488. * I will have unadjusted all Lisp variables, and in particular this will
  1489. * mean that anything that used to have the value NIL will then be
  1490. * SPID_NIL instead. Part of what I should remember here is that
  1491. * in consequence I can not send a main image to a Lisp stream. But I
  1492. * think that is OK, since the only way I have of setting up fasl_stream
  1493. * is via the FASLOUT mechanism.
  1494. */
  1495. if (fasl_stream != nil && fasl_stream != SPID_NIL)
  1496. { putc_stream((int)(chk>>24), fasl_stream);
  1497. putc_stream((int)(chk>>16), fasl_stream);
  1498. putc_stream((int)(chk>>8), fasl_stream);
  1499. putc_stream((int)chk, fasl_stream);
  1500. return NO;
  1501. }
  1502. if (putc((int)(chk>>24), f) == EOF) return YES;
  1503. if (putc((int)(chk>>16), f) == EOF) return YES;
  1504. if (putc((int)(chk>>8), f) == EOF) return YES;
  1505. return (putc((int)chk, f) == EOF);
  1506. }
  1507. #endif /* DEMO_MODE */
  1508. CSLbool Icopy(char *name, int len)
  1509. /*
  1510. * Find the named module in one of the input files, and if the place that
  1511. * it is found is not already the output file copy it to the output.
  1512. */
  1513. {
  1514. #ifdef DEMO_MODE
  1515. return YES;
  1516. #else
  1517. int i, ii, j, n;
  1518. long int k, l, save = read_bytes_remaining;
  1519. unsigned32 chk1;
  1520. char hard[16];
  1521. directory *d, *id;
  1522. Lisp_Object nil = C_nil;
  1523. Lisp_Object il, oo = qvalue(output_library);
  1524. CSL_IGNORE(nil);
  1525. if (!is_library(oo)) return YES;
  1526. d = fasl_files[library_number(oo)];
  1527. /*
  1528. * Only valid if there is an output file and nothing else is going on.
  1529. */
  1530. if (d == NULL ||
  1531. (d->h.updated & D_WRITE_OK) == 0 ||
  1532. Istatus != I_INACTIVE) return YES;
  1533. if (d->h.updated & D_PENDING)
  1534. { if (unpending(d)) return YES;
  1535. }
  1536. /*
  1537. * Search for a suitable input module to copy...
  1538. */
  1539. for (il=qvalue(input_libraries); consp(il); il = qcdr(il))
  1540. { oo = qcar(il);
  1541. if (!is_library(oo)) continue;
  1542. i = library_number(oo);
  1543. id = fasl_files[i];
  1544. for (ii=0; ii<get_dirused(id->h); ii++)
  1545. if (samename(name, id, ii, len)) goto found;
  1546. }
  1547. return YES; /* Module to copy not found */
  1548. found:
  1549. /*
  1550. * If the potential input module found was in the output directory exit now.
  1551. */
  1552. if (id == d) return NO;
  1553. /*
  1554. * Now scan output directory to see where to put result
  1555. */
  1556. for (i=0; i<get_dirused(d->h); i++)
  1557. if (samename(name, d, i, len))
  1558. { d->h.updated |= D_UPDATED | D_COMPACT;
  1559. goto ofound;
  1560. }
  1561. /*
  1562. * The file was not previously present in the output directory, so
  1563. * I need to insert it. The code here is copies from open_output and is
  1564. * now messy enoug that I should really move it to a sub-function.
  1565. */
  1566. if (len == IMAGE_CODE)
  1567. name = "InitialImage", n = 1;
  1568. else if (len == HELP_CODE)
  1569. name = "HelpDataFile", len = IMAGE_CODE, n = 1;
  1570. else if (len == BANNER_CODE)
  1571. name = "Start-Banner", len = IMAGE_CODE, n = 1;
  1572. else if (len < 0)
  1573. { sprintf(hard, "HardCode<%.2x>", (-len) & 0xff);
  1574. name = hard, len = IMAGE_CODE, n = 1;
  1575. }
  1576. else if (len <= 11) n = 1;
  1577. else if (len <= 11+11+24) n = 2;
  1578. else if (len <= 11+11+11+24+24) n = 3;
  1579. else return YES; /* Name longer than 81 chars not supported, sorry */
  1580. while (i+n > (int)get_dirsize(d->h))
  1581. { d = enlarge_directory(i);
  1582. current_output_directory = d;
  1583. if (d == NULL) return YES;
  1584. }
  1585. current_output_entry = &d->d[i];
  1586. if (len == IMAGE_CODE)
  1587. { d->d[i].D_newline = NEWLINE_CHAR;
  1588. memcpy(&d->d[i].D_name, name, 12);
  1589. memset(&d->d[i].D_date, ' ', date_size);
  1590. memset(&d->d[i].D_size, 0, 3);
  1591. memcpy(&d->d[i].D_position, d->h.eof, 4);
  1592. }
  1593. else
  1594. { int np;
  1595. char *p;
  1596. /*
  1597. * First I will clear all the relevant fields to blanks.
  1598. */
  1599. for (j=0; j<n; j++)
  1600. { d->d[i+j].D_newline = '\n';
  1601. memset(&d->d[i+j].D_name, ' ', name_size);
  1602. memset(&d->d[i+j].D_date, ' ', date_size);
  1603. memset(&d->d[i+j].D_size, 0, 3);
  1604. memcpy(&d->d[i+j].D_position, d->h.eof, 4);
  1605. }
  1606. #define next_char_of_name (np++ >= len ? ' ' : *p++)
  1607. np = 0;
  1608. p = name;
  1609. for (j=0; j<n; j++)
  1610. { for (k=0; k<11; k++) (&d->d[i+j].D_name)[k] = next_char_of_name;
  1611. if (j != 0)
  1612. for (k=0; k<24; k++)
  1613. (&d->d[i+j].D_date)[k] = next_char_of_name;
  1614. if (j == 0 && n == 1) d->d[i+j].D_space = ' ';
  1615. else if (j == n-1) d->d[i+j].D_space = 0xff;
  1616. else d->d[i+j].D_space = (char)(0x80+j);
  1617. #undef next_char_of_name
  1618. }
  1619. }
  1620. set_dirused(&d->h, get_dirused(d->h)+n);
  1621. ofound:
  1622. memcpy(&d->d[i].D_date, &id->d[ii].D_date, date_size);
  1623. trace_printf("\nCopy %.*s from %s to %s\n",
  1624. len, name, id->filename, d->filename);
  1625. memcpy(&d->d[i].D_position, d->h.eof, 4);
  1626. if (d->d[i].D_space & 0x80)
  1627. { n = 0;
  1628. do
  1629. { n++;
  1630. memcpy(&d->d[i+n].D_position, d->h.eof, 4);
  1631. } while ((d->d[i+n].D_space & 0xff) != 0xff);
  1632. }
  1633. /*
  1634. * I provisionally set the size to zero so that if something goes wrong
  1635. * I will still have a tolerably sensible image file.
  1636. */
  1637. memset(&d->d[i].D_size, 0, 3);
  1638. d->h.updated |= D_UPDATED;
  1639. if (fseek(d->f, bits32(&d->d[i].D_position), SEEK_SET) != 0 ||
  1640. fseek(id->f, bits32(&id->d[ii].D_position), SEEK_SET) != 0) return YES;
  1641. l = bits24(&id->d[ii].D_size);
  1642. chk1 = 0;
  1643. for (k=0; k<l; k++)
  1644. { int c = getc(id->f);
  1645. unsigned32 chk_temp;
  1646. /*
  1647. * I do not have to do anything special about encryption here...
  1648. */
  1649. update_crc(chk1, c);
  1650. if (c == EOF) return YES;
  1651. putc(c, d->f);
  1652. }
  1653. read_bytes_remaining = 0;
  1654. j = validate_checksum(id->f, chk1);
  1655. read_bytes_remaining = save;
  1656. if (j) return YES;
  1657. if (put_checksum(d->f, chk1)) return YES;
  1658. if (fflush(d->f) != 0) return YES;
  1659. setbits24(&d->d[i].D_size, (int32)l);
  1660. setbits32(d->h.eof, (int32)ftell(d->f));
  1661. return NO;
  1662. #endif /* DEMO_MODE */
  1663. }
  1664. CSLbool IcloseInput(int check_checksum)
  1665. /*
  1666. * Terminate processing one whatever subfile has been being processed.
  1667. * returns nonzero if there was trouble.
  1668. * read and verify checksum if arg is TRUE.
  1669. */
  1670. {
  1671. Istatus = I_INACTIVE;
  1672. if (check_checksum)
  1673. return validate_checksum(binary_read_file, subfile_checksum);
  1674. else return NO;
  1675. }
  1676. CSLbool IcloseOutput(void)
  1677. /*
  1678. * Terminate processing one whatever subfile has been being processed.
  1679. * returns nonzero if there was trouble. Write a checksum to the file.
  1680. * There is a jolly joke here! I MUST NOT try to pick up the identification
  1681. * of the output directory from the lisp-level variable output_directory
  1682. * because (preserve) calls this AFTER it has utterly mangled the heap (to
  1683. * put all pointers into relative form). To alloc for this the variable
  1684. * current_output_directory identifies the directory within which a file
  1685. * was most recently opened.
  1686. */
  1687. {
  1688. #ifdef DEMO_MODE
  1689. return YES;
  1690. #else
  1691. int r;
  1692. Lisp_Object nil = C_nil;
  1693. directory *d = current_output_directory;
  1694. Istatus = I_INACTIVE;
  1695. if (fasl_stream != nil && fasl_stream != SPID_NIL)
  1696. { put_checksum(NULL, subfile_checksum);
  1697. return NO;
  1698. }
  1699. current_output_directory = NULL;
  1700. /* Here I have to write a checksum to the current ouput dir */
  1701. if (d == NULL || (d->h.updated & D_WRITE_OK) == 0) return NO;
  1702. put_checksum(d->f, subfile_checksum);
  1703. setbits24(&current_output_entry->D_size, (int32)write_bytes_written);
  1704. r = fflush(d->f);
  1705. setbits32(d->h.eof, (int32)ftell(d->f));
  1706. /*
  1707. * I bring the directory at the start of the output file up to date at this
  1708. * stage - the effect is that if things crash somehow I have a better
  1709. * chance of resuming from where disaster hit.
  1710. */
  1711. fseek(d->f, 0, SEEK_SET);
  1712. if (fwrite(&d->h, sizeof(directory_header), 1, d->f) != 1) r = YES;
  1713. if (fwrite(&d->d[0], sizeof(directory_entry),
  1714. (size_t)get_dirsize(d->h), d->f) !=
  1715. (size_t)get_dirsize(d->h)) r = YES;
  1716. if (fflush(d->f) != 0) r = YES;
  1717. d->h.updated &= ~D_UPDATED;
  1718. current_output_entry = NULL;
  1719. return r;
  1720. #endif /* DEMO_MODE */
  1721. }
  1722. CSLbool finished_with(int j)
  1723. {
  1724. #ifdef DEMO_MODE
  1725. return YES;
  1726. #else
  1727. directory *d = fasl_files[j];
  1728. fasl_files[j] = NULL;
  1729. /*
  1730. * If the library concerned had been opened using (open-library ...) then
  1731. * the name stored in fasl_paths[] would have been allocated using malloc(),
  1732. * and just discarding it as here will represent a space-leak. Just for now
  1733. * I am going to accept that as an unimportant detail.
  1734. */
  1735. fasl_paths[j] = NULL;
  1736. if (d == NULL) return NO;
  1737. if (d->h.updated & D_COMPACT)
  1738. { int i;
  1739. long int hwm;
  1740. if (d->f == NULL) return YES;
  1741. d->h.updated |= D_UPDATED;
  1742. sort_directory(d);
  1743. hwm = sizeof(directory_header) +
  1744. get_dirsize(d->h)*(long int)sizeof(directory_entry) +
  1745. REGISTRATION_SIZE;
  1746. for (i=0; i<get_dirused(d->h); i++)
  1747. { long int pos = bits32(&d->d[i].D_position);
  1748. if (pos != hwm)
  1749. { char *b = 16 + (char *)stack;
  1750. char small_buffer[64];
  1751. /* I add 4 to the length specified here to allow for checksums */
  1752. long int len = bits24(&d->d[i].D_size) + 4L;
  1753. long int newpos = hwm;
  1754. while (len != 0)
  1755. { size_t n =
  1756. (size_t)((CSL_PAGE_SIZE - 64 -
  1757. ((char *)stack - (char *)stackbase)) &
  1758. (~(int32)0xff));
  1759. /*
  1760. * I only perform compression of the file when I am in the process of stopping,
  1761. * and in that case the Lisp stack is not in use, so I use if as a buffer.
  1762. * WELL the above statement used to be true, but now it is not, since the
  1763. * function CLOSE-LIBRARY does exactly what I have declared is never
  1764. * possible. But all is not lost - I can afford to use that part of
  1765. * the stack that remains unused. In cases where CLOSE-LIBRARY is called
  1766. * just before a stack overflow was due the result will be utterly terrible
  1767. * (on speed) but it should still be correct. So what you will see is that
  1768. * I start my buffer 16 bytes above the active part of the stack, and
  1769. * let it run to within 48 bytes of the top of the stack page, but
  1770. * rounded down so I do transfers in multiples of 256 bytes. If there
  1771. * is really no (Lisp) stack free I use a 64 byte local buffer.
  1772. */
  1773. if (n == 0) b = small_buffer, n = sizeof(small_buffer);
  1774. if (len < (long int)n) n = (size_t)len;
  1775. fseek(d->f, pos, SEEK_SET);
  1776. fread(b, 1, n, d->f);
  1777. pos = ftell(d->f);
  1778. fseek(d->f, newpos, SEEK_SET);
  1779. fwrite(b, 1, n, d->f);
  1780. newpos = ftell(d->f);
  1781. len -= n;
  1782. }
  1783. setbits32(&d->d[i].D_position, (int32)hwm);
  1784. }
  1785. hwm += bits24(&d->d[i].D_size) + 4L;
  1786. }
  1787. fflush(d->f);
  1788. if (hwm != bits32(d->h.eof))
  1789. { truncate_file(d->f, hwm);
  1790. setbits32(d->h.eof, (int32)hwm);
  1791. }
  1792. }
  1793. if (d->h.updated & D_UPDATED)
  1794. {
  1795. if (d->f == NULL || fflush(d->f) != 0) return YES;
  1796. fseek(d->f, 0, SEEK_SET);
  1797. if (fwrite(&d->h, sizeof(directory_header), 1, d->f) != 1) return YES;
  1798. if (fwrite(&d->d[0], sizeof(directory_entry),
  1799. (size_t)get_dirsize(d->h), d->f) !=
  1800. (size_t)get_dirsize(d->h)) return YES;
  1801. if (fflush(d->f) != 0) return YES;
  1802. }
  1803. if (d->h.updated & D_PENDING) return NO;
  1804. else if (d->f != NULL && fclose(d->f) != 0) return YES;
  1805. else return NO;
  1806. #endif /* DEMO_MODE */
  1807. }
  1808. CSLbool Ifinished(void)
  1809. /*
  1810. * Indicates total completion of all work on image files, and so calls
  1811. * for things to be (finally) tidied up. Again returns YES of anything
  1812. * has gone wrong.
  1813. */
  1814. {
  1815. /*
  1816. * Need to close all files here... loads of calls to fflush and fclose.
  1817. * Actually only output files are a real issue here. And then only
  1818. * the ones that are flagged as needing compaction.
  1819. */
  1820. int j;
  1821. CSLbool failed = NO;
  1822. for (j=0; j<number_of_fasl_paths; j++)
  1823. if (finished_with(j)) failed = YES;
  1824. return failed;
  1825. }
  1826. int Igetc(void)
  1827. /*
  1828. * Returns next byte from current image sub-file, or EOF if either
  1829. * real end-of-file or on failure. As a special fudge here (ugh) I
  1830. * use a negative value of read_bytes_remaining to indicate that
  1831. * input should NOT be from the usual image-file mechanism, but from
  1832. * the currently selected standard input. Setting things up that way
  1833. * then supports processing of FASL files from almost arbitrary
  1834. * sources.
  1835. */
  1836. {
  1837. long int nn = read_bytes_remaining;
  1838. int c;
  1839. unsigned32 chk_temp;
  1840. if (nn <= 0)
  1841. { if (nn == 0) return EOF;
  1842. else
  1843. { Lisp_Object nil = C_nil;
  1844. Lisp_Object stream = qvalue(standard_input);
  1845. if (!is_stream(stream)) return EOF;
  1846. c = getc_stream(stream);
  1847. nil = C_nil;
  1848. if (exception_pending()) return EOF;
  1849. }
  1850. }
  1851. else
  1852. { read_bytes_remaining = nn - 1;
  1853. c = getc(binary_read_file);
  1854. }
  1855. if (c == EOF) return c;
  1856. update_crc(subfile_checksum, c);
  1857. if (crypt_active >= 0)
  1858. { if (crypt_count >= CRYPT_BLOCK)
  1859. { crypt_get_block(crypt_buffer);
  1860. crypt_count = 0;
  1861. }
  1862. c ^= crypt_buffer[crypt_count++];
  1863. }
  1864. return (c & 0xff);
  1865. }
  1866. #ifdef SIXTEEN_BIT
  1867. #define FREAD_CHUNK 0x4000
  1868. #endif
  1869. int32 Iread(void *buff, int32 size)
  1870. /*
  1871. * Reads (size) bytes into the indicated buffer. Returns number of
  1872. * bytes read. Decrypts if crypt_active >= 0.
  1873. */
  1874. {
  1875. unsigned char *p = (unsigned char *)buff;
  1876. int32 n = 0;
  1877. unsigned32 chk_temp;
  1878. int i;
  1879. size_t n1;
  1880. long int nn = read_bytes_remaining;
  1881. if (nn < 0)
  1882. { for (i=0; i<size; i++)
  1883. { int c = Igetc();
  1884. if (c == EOF) return i;
  1885. p[i] = (char)c;
  1886. }
  1887. return i;
  1888. }
  1889. if (size > nn) size = (int32)nn; /* Do not go beyond end of file */
  1890. #ifdef FREAD_CHUNK
  1891. /*
  1892. * Iread can read a number of bytes that is specified by an int32, so on
  1893. * 16 bit implementations I will need to issue a sequence of calls to fread(),
  1894. * each transferring < 64Kbytes (in fact I do 16K at a time).
  1895. */
  1896. while (size >= FREAD_CHUNK)
  1897. { n1 = fread(p, 1, FREAD_CHUNK, binary_read_file);
  1898. for (i=0; i<(int)n1; i++)
  1899. { int c = p[i];
  1900. update_crc(subfile_checksum, c);
  1901. if (crypt_active >= 0)
  1902. { if (crypt_count >= CRYPT_BLOCK)
  1903. { crypt_get_block(crypt_buffer);
  1904. crypt_count = 0;
  1905. }
  1906. c ^= crypt_buffer[crypt_count++];
  1907. p[i] = c;
  1908. }
  1909. }
  1910. read_bytes_remaining -= n1;
  1911. if (n1 != FREAD_CHUNK) return n + n1;
  1912. p += n1;
  1913. size -= n1;
  1914. n += n1;
  1915. }
  1916. #endif
  1917. if (size == 0) return n;
  1918. n1 = fread(p, 1, (size_t)size, binary_read_file);
  1919. /*
  1920. * Updating the checksum here is probably a painful extra cost, but I count
  1921. * the security it gives me as worthwhile. I compute the checksum byte at a
  1922. * time so that it is not sensitive to the byte ordering of the machine used.
  1923. */
  1924. for (i=0; i<(int)n1; i++)
  1925. { int c = p[i];
  1926. update_crc(subfile_checksum, c);
  1927. if (crypt_active >= 0)
  1928. { if (crypt_count >= CRYPT_BLOCK)
  1929. { crypt_get_block(crypt_buffer);
  1930. crypt_count = 0;
  1931. }
  1932. c ^= crypt_buffer[crypt_count++];
  1933. p[i] = (char)c;
  1934. }
  1935. }
  1936. read_bytes_remaining -= n1;
  1937. return n + n1;
  1938. }
  1939. long int Ioutsize(void)
  1940. {
  1941. return write_bytes_written;
  1942. }
  1943. CSLbool Iputc(int ch)
  1944. /*
  1945. * Puts one character into image system, returning YES if there
  1946. * was trouble.
  1947. */
  1948. {
  1949. #ifdef DEMO_MODE
  1950. return YES;
  1951. #else
  1952. unsigned32 chk_temp;
  1953. Lisp_Object nil = C_nil;
  1954. write_bytes_written++;
  1955. if (crypt_active >= 0)
  1956. { if (crypt_count >= CRYPT_BLOCK)
  1957. { crypt_get_block(crypt_buffer);
  1958. crypt_count = 0;
  1959. }
  1960. ch ^= crypt_buffer[crypt_count++];
  1961. }
  1962. update_crc(subfile_checksum, ch);
  1963. if (fasl_stream != nil && fasl_stream != SPID_NIL)
  1964. putc_stream(ch, fasl_stream);
  1965. else if (putc(ch, binary_write_file) == EOF) return YES;
  1966. return NO;
  1967. #endif /* DEMO_MODE */
  1968. }
  1969. #define FWRITE_CHUNK 0x4000
  1970. CSLbool Iwrite(void *buff, int32 size)
  1971. /*
  1972. * Writes (size) bytes from the given buffer, returning YES if trouble.
  1973. */
  1974. {
  1975. #ifdef DEMO_MODE
  1976. return YES;
  1977. #else
  1978. unsigned char *p = (unsigned char *)buff;
  1979. int32 i;
  1980. unsigned32 chk_temp;
  1981. Lisp_Object nil = C_nil;
  1982. if (crypt_active >= 0 ||
  1983. (fasl_stream != nil && fasl_stream != SPID_NIL))
  1984. {
  1985. /*
  1986. * Note that in this case the checksum is updated within Iputc() so I do
  1987. * not have to do anything special about it here.
  1988. */
  1989. for (i=0; i<size; i++)
  1990. if (Iputc(p[i])) return YES;
  1991. return NO;
  1992. }
  1993. /*
  1994. * If encrypted writing is active I will have gone through Iputc for
  1995. * every individual character and so will not get down to here. Thus the
  1996. * optimised calls to fwrite() can remain intact.
  1997. */
  1998. for (i=0; i<size; i++)
  1999. { /* Beware - update_crc is a macro and the {} block here is essential */
  2000. update_crc(subfile_checksum, p[i]);
  2001. }
  2002. write_bytes_written += size;
  2003. while (size >= FWRITE_CHUNK)
  2004. { if (fwrite(p, 1, FWRITE_CHUNK, binary_write_file) != FWRITE_CHUNK)
  2005. return YES;
  2006. p += FWRITE_CHUNK;
  2007. size -= FWRITE_CHUNK;
  2008. }
  2009. if (size == 0) return NO;
  2010. else return
  2011. (fwrite(p, 1, (size_t)size, binary_write_file) != (size_t)size);
  2012. #endif /* DEMO_MODE */
  2013. }
  2014. /*
  2015. * Now code that maps real pointers into references relative
  2016. * to page numbers. Here I will also go to the trouble of putting zero
  2017. * bytes in unused bits of memory - that will make checkpoint files
  2018. * compress better and will also make them independent of all actual
  2019. * addresses used on the host machine. Observe that the representation
  2020. * created has to depend a bit on the current page size.
  2021. */
  2022. #define PACK_PAGE_OFFSET(pg, of) ((pg << PAGE_BITS) + of)
  2023. static void unadjust(Lisp_Object *cp)
  2024. /*
  2025. * If p is a pointer to an object that has moved, unadjust it.
  2026. */
  2027. {
  2028. #ifndef DEMO_MODE
  2029. Lisp_Object nil = C_nil, p = (*cp); /* Beware "=*" anachronism! */
  2030. if (p == nil)
  2031. { *cp = SPID_NIL; /* Marks NIL in preserve files */
  2032. return;
  2033. }
  2034. else if (is_cons(p))
  2035. { int32 i;
  2036. for (i=0; i<heap_pages_count; i++)
  2037. { void *page = heap_pages[i];
  2038. char *base = (char *)quadword_align_up((intxx)page);
  2039. /*
  2040. * The next line is pretty dodgy - I want to decide which segment a
  2041. * pointer references, but pointer comparisons are only valid within
  2042. * single segments. I cast to int and cross my fingers! Actually no
  2043. * REASONABLE C system would fail on this - it is just that ANSI specifies
  2044. * that you can only do any address arithmetic WITHIN the area returned
  2045. * by a single malloc() (etc).
  2046. */
  2047. if ((intxx)base <= (intxx)p &&
  2048. (intxx)p <= (intxx)(base+CSL_PAGE_SIZE))
  2049. { unsigned int offset = (unsigned int)((char *)p - base);
  2050. *cp = PACK_PAGE_OFFSET(i, offset);
  2051. return;
  2052. }
  2053. }
  2054. term_printf("\n[%lx] Cons address %lx not found in heap\n",
  2055. (long)cp, (long)p);
  2056. abort();
  2057. }
  2058. else if (!is_immed_or_cons(p))
  2059. { int32 i; /* vectors get relocated here */
  2060. for (i=0; i<vheap_pages_count; i++)
  2061. { void *page = vheap_pages[i];
  2062. char *base = (char *)doubleword_align_up((intxx)page);
  2063. /* see comments above re the next line */
  2064. if ((intxx)base <= (intxx)p &&
  2065. (intxx)p <= (intxx)(base+CSL_PAGE_SIZE))
  2066. { unsigned int offset = (unsigned int)((char *)p - base);
  2067. *cp = PACK_PAGE_OFFSET(i, offset);
  2068. return;
  2069. }
  2070. }
  2071. term_printf("\n[%.8lx] Vector address %.8lx not found in heap\n",
  2072. (long)cp, (long)p);
  2073. abort();
  2074. }
  2075. #endif /* DEMO_MODE */
  2076. }
  2077. static void unadjust_consheap(void)
  2078. {
  2079. #ifndef DEMO_MODE
  2080. int32 page_number;
  2081. for (page_number = 0; page_number < heap_pages_count; page_number++)
  2082. { void *page = heap_pages[page_number];
  2083. char *low = (char *)quadword_align_up((intxx)page);
  2084. char *start = low + CSL_PAGE_SIZE;
  2085. char *fr = low + car32(low);
  2086. /* The next line sets unused space in the page to be zero */
  2087. while ((fr -= sizeof(Lisp_Object)) != low) qcar(fr) = 0;
  2088. fr = low + car32(low);
  2089. while (fr < start)
  2090. { unadjust((Lisp_Object *)fr);
  2091. fr += sizeof(Lisp_Object);
  2092. }
  2093. }
  2094. #endif /* DEMO_MODE */
  2095. }
  2096. static void convert_word_order(void *p)
  2097. {
  2098. /*
  2099. * This bit seems a bit strange to me. I cope with all other
  2100. * byte order issues by having the exporting machine dump data
  2101. * in its own native format and then fixing things up again when
  2102. * I re-load. Why not do that here? However what I *do* do is to keep
  2103. * image files in a single WORD order in image files but let the bytes
  2104. * within words fall how they do. But during the transition to support
  2105. * of full 64-bit machines I will disable all attempts at byte correction
  2106. * when in 64-bit mode...
  2107. */
  2108. #ifndef ADDRESS_64
  2109. if ((current_fp_rep & FP_WORD_ORDER) != 0)
  2110. { unsigned32 *f = (unsigned32 *)p;
  2111. unsigned32 w = f[0];
  2112. f[0] = f[1];
  2113. f[1] = w;
  2114. }
  2115. #endif
  2116. }
  2117. static struct entry_lookup
  2118. { int32 code;
  2119. intxx entry;
  2120. char *s;
  2121. } entry_lookup[entry_table_size];
  2122. static int MS_CDECL order_lookup_entries(void const *aa, void const *bb)
  2123. {
  2124. struct entry_lookup *a = (struct entry_lookup *)aa,
  2125. *b = (struct entry_lookup *)bb;
  2126. intxx ap = a->entry, bp = b->entry;
  2127. if (ap < bp) return -1;
  2128. else if (ap > bp) return 1;
  2129. else return 0;
  2130. }
  2131. static void set_up_entry_lookup(void)
  2132. /*
  2133. * This makes a sorted version of entries_table. Since the table is
  2134. * only a few dozen words long it hardly seems worth being too clever,
  2135. * but the C library provides qsort() for me so I use it.
  2136. */
  2137. {
  2138. int i;
  2139. for (i=0; i<entry_table_size; i++)
  2140. { entry_lookup[i].code = i;
  2141. entry_lookup[i].entry = (intxx)entries_table[i].p;
  2142. entry_lookup[i].s = entries_table[i].s;
  2143. }
  2144. qsort((void *)entry_lookup,
  2145. entry_table_size, sizeof(struct entry_lookup),
  2146. order_lookup_entries);
  2147. }
  2148. static int32 code_up_fn(intxx e)
  2149. {
  2150. int low = 0, high = entry_table_size-1;
  2151. while (low < high)
  2152. { int mid = (high + low)/2;
  2153. intxx s = entry_lookup[mid].entry;
  2154. if (s == e) return entry_lookup[mid].code;
  2155. if (s < e) low = mid + 1;
  2156. else high = mid - 1;
  2157. }
  2158. if (low == high &&
  2159. entry_lookup[low].entry == e) return entry_lookup[low].code;
  2160. else return 0;
  2161. }
  2162. static void unadjust_vecheap(void)
  2163. {
  2164. #ifndef DEMO_MODE
  2165. int32 page_number, i;
  2166. for (page_number = 0; page_number < vheap_pages_count; page_number++)
  2167. { void *page = vheap_pages[page_number];
  2168. char *low = (char *)doubleword_align_up((intxx)page);
  2169. char *high = low + (CSL_PAGE_SIZE - 8);
  2170. char *fr = low + car32(low);
  2171. low += 8;
  2172. while (low < fr)
  2173. { Header h = *(Header *)low;
  2174. if (is_symbol_header(h))
  2175. { Lisp_Object s = (Lisp_Object)(low+TAG_SYMBOL);
  2176. ifn1(s) = code_up_fn(ifn1(s));
  2177. ifn2(s) = code_up_fn(ifn2(s));
  2178. ifnn(s) = code_up_fn(ifnn(s));
  2179. unadjust(&qvalue(s));
  2180. unadjust(&qenv(s));
  2181. unadjust(&qpname(s));
  2182. unadjust(&qplist(s));
  2183. unadjust(&qfastgets(s));
  2184. #ifdef COMMON
  2185. unadjust(&qpackage(s));
  2186. #endif
  2187. low += symhdr_length;
  2188. continue;
  2189. }
  2190. else switch (type_of_header(h))
  2191. {
  2192. #ifdef COMMON
  2193. case TYPE_RATNUM:
  2194. case TYPE_COMPLEX_NUM:
  2195. unadjust((Lisp_Object *)(low+CELL));
  2196. unadjust((Lisp_Object *)(low+2*CELL));
  2197. break;
  2198. #endif
  2199. case TYPE_HASH:
  2200. case TYPE_SIMPLE_VEC:
  2201. case TYPE_ARRAY:
  2202. case TYPE_STRUCTURE:
  2203. for (i=CELL;
  2204. i<doubleword_align_up(length_of_header(h));
  2205. i+=CELL)
  2206. unadjust((Lisp_Object *)(low+i));
  2207. break;
  2208. case TYPE_STREAM:
  2209. { Lisp_Object ss = (Lisp_Object)(low+TAG_VECTOR);
  2210. /*
  2211. * It might make rather good sense to close any file or pipe streams
  2212. * that I come across at this stage...
  2213. */
  2214. if (elt(ss, 4) == (intxx)char_to_file &&
  2215. elt(ss, 3) != 0)
  2216. { fclose(stream_file(ss));
  2217. set_stream_write_fn(ss, char_to_illegal);
  2218. set_stream_write_other(ss, write_action_illegal);
  2219. set_stream_file(ss, NULL);
  2220. }
  2221. #ifdef PIPES
  2222. if (elt(ss, 4) == (intxx)char_to_pipeout &&
  2223. elt(ss, 3) != 0)
  2224. { my_pclose(stream_file(ss));
  2225. set_stream_write_fn(ss, char_to_illegal);
  2226. set_stream_write_other(ss, write_action_illegal);
  2227. set_stream_file(ss, NULL);
  2228. }
  2229. #endif
  2230. if (elt(ss, 8) == (intxx)char_from_file &&
  2231. elt(ss, 3) != 0)
  2232. { fclose(stream_file(ss));
  2233. set_stream_read_fn(ss, char_from_illegal);
  2234. set_stream_read_other(ss, read_action_illegal);
  2235. set_stream_file(ss, NULL);
  2236. }
  2237. elt(ss, 4) = code_up_fn(elt(ss, 4));
  2238. elt(ss, 5) = code_up_fn(elt(ss, 5));
  2239. elt(ss, 8) = code_up_fn(elt(ss, 8));
  2240. elt(ss, 9) = code_up_fn(elt(ss, 9));
  2241. }
  2242. case TYPE_MIXED1:
  2243. case TYPE_MIXED2:
  2244. case TYPE_MIXED3:
  2245. for (i=CELL; i<4*CELL; i+=CELL)
  2246. unadjust((Lisp_Object *)(low+i));
  2247. break;
  2248. case TYPE_DOUBLE_FLOAT:
  2249. convert_word_order((void *)(low + 8));
  2250. break;
  2251. #ifdef COMMON
  2252. case TYPE_SINGLE_FLOAT:
  2253. break;
  2254. case TYPE_LONG_FLOAT:
  2255. /* If long floats were 3 words long I might need to adjust this code... */
  2256. convert_word_order((void *)(low + 8));
  2257. break;
  2258. #endif
  2259. default:
  2260. break;
  2261. }
  2262. low += doubleword_align_up(length_of_header(h));
  2263. }
  2264. /*
  2265. * Now clean up the unused space in the page...
  2266. */
  2267. while (low <= high)
  2268. { qcar(low) = 0;
  2269. qcdr(low) = 0;
  2270. low += 2*sizeof(Lisp_Object);
  2271. }
  2272. }
  2273. #endif /* DEMO_MODE */
  2274. }
  2275. static void unadjust_bpsheap(void)
  2276. {
  2277. #ifndef DEMO_MODE
  2278. int32 page_number;
  2279. for (page_number = 0; page_number < bps_pages_count; page_number++)
  2280. { void *page = bps_pages[page_number];
  2281. char *low = (char *)doubleword_align_up((intxx)page);
  2282. char *fr = low + car32(low);
  2283. /* Clean up unused space */
  2284. while ((fr -= sizeof(Lisp_Object)) != low) qcar(fr) = 0;
  2285. fr = low + qcar(low);
  2286. while (fr < low + CSL_PAGE_SIZE)
  2287. { Header h = *(Header *)fr;
  2288. #ifdef ENVIRONMENT_VECTORS_IN_BPS_HEAP
  2289. switch (type_of_header(h))
  2290. {
  2291. /* This option is not actually used at present... */
  2292. case TYPE_SIMPLE_VEC:
  2293. for (i=CELL;
  2294. i<doubleword_align_up(length_of_header(h));
  2295. i+=CELL)
  2296. unadjust((Lisp_Object *)(fr+i));
  2297. break;
  2298. default:
  2299. break;
  2300. }
  2301. #endif
  2302. fr += doubleword_align_up(length_of_header(h));
  2303. }
  2304. }
  2305. #endif /* DEMO_MODE */
  2306. }
  2307. static void unadjust_all(void)
  2308. {
  2309. #ifndef DEMO_MODE
  2310. int32 i;
  2311. Lisp_Object nil = C_nil;
  2312. set_up_entry_lookup();
  2313. qheader(nil) = TAG_ODDS+TYPE_SYMBOL+SYM_SPECIAL_VAR;
  2314. qvalue(nil) = 0;
  2315. qenv(nil) = 0;
  2316. ifn1(nil) = 0;
  2317. ifn2(nil) = 0;
  2318. ifnn(nil) = 0;
  2319. unadjust(&(qpname(nil))); /* not a gensym */
  2320. unadjust(&(qplist(nil)));
  2321. unadjust(&(qfastgets(nil)));
  2322. #ifdef COMMON
  2323. unadjust(&(qpackage(nil)));
  2324. #endif
  2325. copy_into_nilseg(YES);
  2326. eq_hash_table_list = eq_hash_tables;
  2327. equal_hash_table_list = equal_hash_tables;
  2328. for (i = first_nil_offset; i<last_nil_offset; i++)
  2329. unadjust(&BASE[i]);
  2330. copy_out_of_nilseg(YES);
  2331. unadjust_consheap();
  2332. unadjust_vecheap();
  2333. unadjust_bpsheap();
  2334. #endif /* DEMO_MODE */
  2335. }
  2336. void preserve_native_code(void)
  2337. {
  2338. #ifndef DEMO_MODE
  2339. /*
  2340. * I should maybe worry a little more here about IO errors...
  2341. */
  2342. int i;
  2343. if (!native_pages_changed) return;
  2344. if (open_output(NULL, -native_code_tag))
  2345. { term_printf("Failed to open module for native code storage\n");
  2346. return;
  2347. }
  2348. Iputc(native_pages_count & 0xff);
  2349. Iputc((native_pages_count>>8) & 0xff);
  2350. /*
  2351. * The FINAL native page will in general not be full, so I put a count of
  2352. * the number of bytes in it that are in use in its first word, and
  2353. * zero out the parts of it beyond there. Then the file compression that
  2354. * routinely use when writing into image files.
  2355. */
  2356. if (native_pages_count != 0)
  2357. { intxx p = (intxx)native_pages[native_pages_count-1];
  2358. p = doubleword_align_up(p);
  2359. car32(p) = native_fringe;
  2360. memset((char *)p+native_fringe, 0, CSL_PAGE_SIZE-native_fringe);
  2361. }
  2362. for (i=0; i<native_pages_count; i++)
  2363. { intxx p = (intxx)native_pages[i];
  2364. p = doubleword_align_up(p);
  2365. Cfwrite((char *)p, CSL_PAGE_SIZE);
  2366. }
  2367. IcloseOutput();
  2368. #endif /* DEMO_MODE */
  2369. }
  2370. void preserve(char *banner)
  2371. {
  2372. #ifdef DEMO_MODE
  2373. err_printf("\nThe demo systen can not save a checkpoint file\n");
  2374. give_up();
  2375. return;
  2376. #else
  2377. int32 i;
  2378. CSLbool int_flag = NO;
  2379. Lisp_Object nil = C_nil;
  2380. /*
  2381. * I dump out any altered chunk of native code before I mangle the heap
  2382. * up.
  2383. */
  2384. preserve_native_code();
  2385. if (Iopen(NULL, 0, NO, NULL))
  2386. { err_printf("+++ PRESERVE failed to open image file\n");
  2387. return;
  2388. }
  2389. /*
  2390. * I set a whole bunch of things to NIL here. If spurious data is left over
  2391. * in global list-bases from a previous calculation it could clog up the
  2392. * heap and waste a lot of space...
  2393. */
  2394. #ifdef NILSEG_EXTERNS
  2395. for (i=0; i<=50; i++) workbase[i] = nil;
  2396. #else
  2397. for (i=work_0_offset; i<last_nil_offset; i++)
  2398. BASE[i] = nil;
  2399. #endif
  2400. exit_tag = exit_value = catch_tags =
  2401. codevec = litvec = B_reg = faslvec = faslgensyms = nil;
  2402. reclaim(nil, "preserve", GC_PRESERVE, 0); /* FULL garbage collection */
  2403. nil = C_nil;
  2404. /*
  2405. * if the user generated a SIGINT this is where it gets noticed...
  2406. */
  2407. if (exception_pending())
  2408. { flip_exception();
  2409. int_flag = YES;
  2410. }
  2411. { char msg[128];
  2412. time_t t0 = time(0);
  2413. for (i=0; i<128; i++) msg[i] = ' ';
  2414. if (banner[0] == 0) msg[0] = 0;
  2415. else sprintf(msg, "%.60s", banner);
  2416. /* 26 bytes starting from byte 64 shows the time of the dump */
  2417. sprintf(msg+64, "%.25s\n", ctime(&t0));
  2418. /* 16 bytes starting at byte 90 are for a checksum of the u01.c etc checks */
  2419. get_user_files_checksum((unsigned char *)&msg[90]);
  2420. /* 106 to 109 free at present but available if checksum goes to 160 bits */
  2421. /* 1 byte at 110 marks an encrypted image (work in progress!) */
  2422. msg[110] = 0;
  2423. /* The final byte at 111 indicates whether compression is to be used */
  2424. { int32 cc = compression_worth_while;
  2425. int fg = 0;
  2426. while (cc > 128) fg++, cc >>= 1;
  2427. msg[111] = (char)fg;
  2428. }
  2429. Cfwrite(msg, 112); /* Exactly 112 bytes in the header records */
  2430. }
  2431. unadjust_all(); /* Turn all pointers into base-offset form */
  2432. Cfwrite("\nNilseg:", 8);
  2433. copy_into_nilseg(YES);
  2434. { Lisp_Object saver[9];
  2435. for (i=0; i<9; i++)
  2436. saver[i] = BASE[i+13],
  2437. BASE[i+13] = 0;
  2438. /* codefringe */
  2439. /* codelimit */
  2440. /* stacklimit */
  2441. /* ... ditto */
  2442. /* ... ditto */
  2443. /* fringe */
  2444. /* heaplimit */
  2445. /* vheaplimit */
  2446. /* vfringe */
  2447. Cfwrite((char *)BASE, sizeof(Lisp_Object)*last_nil_offset);
  2448. for (i=0; i<9; i++)
  2449. BASE[i+13] = saver[i];
  2450. }
  2451. Cfwrite((char *)&heap_pages_count, sizeof(heap_pages_count));
  2452. Cfwrite((char *)&vheap_pages_count, sizeof(vheap_pages_count));
  2453. Cfwrite((char *)&bps_pages_count, sizeof(bps_pages_count));
  2454. Cfwrite("\nVecseg:", 8);
  2455. for (i=0; i<vheap_pages_count; i++)
  2456. { intxx p = (intxx)vheap_pages[i];
  2457. Cfwrite((char *)doubleword_align_up(p), CSL_PAGE_SIZE);
  2458. }
  2459. Cfwrite("\nConsseg", 8);
  2460. for (i=0; i<heap_pages_count; i++)
  2461. { intxx p = (intxx)heap_pages[i];
  2462. Cfwrite((char *)quadword_align_up(p), CSL_PAGE_SIZE);
  2463. }
  2464. Cfwrite("\nCodeseg", 8);
  2465. for (i=0; i<bps_pages_count; i++)
  2466. { intxx p = (intxx)bps_pages[i];
  2467. Cfwrite((char *)doubleword_align_up(p), CSL_PAGE_SIZE);
  2468. }
  2469. #ifndef COMMON
  2470. Cfwrite("\n\nEnd of CSL dump file\n\n", 24);
  2471. #else
  2472. Cfwrite("\n\nEnd of CCL dump file\n\n", 24);
  2473. #endif
  2474. /*
  2475. * Here I pad the image file to be a multiple of 4 bytes long. Since it is a
  2476. * binary file the '\n' characters I put in will always be just 1 byte each
  2477. * (for text files that might have expanded). See comments in fasl.c for
  2478. * a diatribe about why I do this, or at least why rather a long while ago
  2479. * this was necessary on at least one sort of computer.
  2480. */
  2481. { int k = (int)((-write_bytes_written) & 3);
  2482. while (k != 0) k--, Iputc(NEWLINE_CHAR);
  2483. }
  2484. /*
  2485. flip_needed = NO; Since I stop after (preserve) these lines are unnecessary?
  2486. old_fp_rep = current_fp_rep;
  2487. */
  2488. /*
  2489. * I need to check for write errors here and moan if there were any...
  2490. */
  2491. if (IcloseOutput()) error(0, err_write_err);
  2492. if (int_flag) term_printf("\nInterrupt during (preserve) was ignored\n");
  2493. return;
  2494. #endif /* DEMO_MODE */
  2495. }
  2496. /* end of file preserve.c */