fasl.c 110 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537
  1. /* fasl.c Copyright (C) 1990-99 Codemist Ltd */
  2. /*
  3. * Binary file support for faster loading of precompiled code etc.
  4. */
  5. /* Signature: 6d967a4d 07-Mar-2000 */
  6. #include <stdarg.h>
  7. #include <string.h>
  8. #include <ctype.h>
  9. #include "machine.h"
  10. #include "tags.h"
  11. #include "cslerror.h"
  12. #include "externs.h"
  13. #include "read.h"
  14. #include "stream.h"
  15. #include "arith.h"
  16. #include "entries.h"
  17. #ifdef TIMEOUT
  18. #include "timeout.h"
  19. #endif
  20. #ifdef SOCKETS
  21. #include "sockhdr.h"
  22. #endif
  23. CSLbool fasl_output_file = NO; /* An output file is open? */
  24. static int skipping_input = 0, skipping_output = 0;
  25. static int32 recent_pointer = 0, hits = 0 , misses = 0, fasl_byte_count = 0;
  26. static CSLbool fp_rep_set = NO;
  27. /*
  28. * FASL files are binary, and are treated as containing sequences of
  29. * unsigned bytes, where the bytes are names as in the following set
  30. * of definitions, which MUST be kept in step with the code that
  31. * creates FASL files. I expect FASL files to be portable between
  32. * computers that use the same character set, but names of symbols
  33. * will get totally scrambled between ASCII and EBCDIC hosts.
  34. */
  35. #define F_END 0 /* end of FASL file */
  36. #define F_NIL 1 /* the symbol NIL */
  37. #define F_TRU 2 /* the symbol T */
  38. #define F_EXT 3 /* used to get operands > 8 bits into other codes */
  39. #define F_INT 4 /* positive fixnum */
  40. #define F_NEG 5 /* negative fixnum */
  41. #define F_BIG 6 /* bignum */
  42. #define F_RAT 7 /* ratio */
  43. #define F_CPX 8 /* complex number */
  44. #define F_FPS 9 /* short float */
  45. #define F_FPF 10 /* single float */
  46. #define F_FPD 11 /* double float */
  47. #define F_FPL 12 /* long float */
  48. #define F_SYM 13 /* symbol, general length */
  49. #define F_ID1 14 /* symbol with 1-character name */
  50. #define F_ID2 15 /* symbol with 2-character name */
  51. #define F_ID3 16 /* etc */
  52. #define F_ID4 17
  53. #define F_ID5 18
  54. #define F_ID6 19
  55. #define F_ID7 20
  56. #define F_ID8 21
  57. #define F_ID9 22
  58. #define F_IDA 23
  59. #define F_IDB 24
  60. #define F_IDC 25
  61. #define F_IDD 26
  62. #define F_IDE 27
  63. #define F_IDF 28 /* symbol with 15 character name */
  64. #define F_STR 29 /* string */
  65. #define F_BP0 30 /* bytecode string for binary code (0 - 255 bytes) */
  66. #define F_BP1 31 /* 256 - 511 bytes of BPS */
  67. #define F_BP2 32 /* 512 - 767 bytes of BPS */
  68. #define F_BP3 33 /* 768 - 1023 bytes of BPS */
  69. #define F_HASH 34 /* hash table */
  70. #define F_VEC 35 /* simple Lisp vector */
  71. #define F_LST 36 /* list, general length */
  72. #define F_LS1 37 /* list of length 1 */
  73. #define F_LS2 38 /* list of length 2 */
  74. #define F_LS3 39 /* list of length 3 */
  75. #define F_LS4 40 /* list of length 4 */
  76. #define F_DOT 41 /* list ending with dotted item */
  77. #define F_QUT 42 /* (QUOTE xx) */
  78. #define F_DEF0 43 /* function definition, 0 args */
  79. #define F_DEF1 44 /* function definition, 1 arg */
  80. #define F_DEF2 45 /* function definition, 2 args */
  81. #define F_DEF3 46 /* function definition, 3 args */
  82. #define F_DEFN 47 /* function definition, 4 or more args */
  83. #define F_REP 48 /* followed by 2 bytes giving FP rep */
  84. #define F_CHAR 49 /* bits, font, code */
  85. #define F_SDEF 50 /* associated with fn definition - Lisp coded version */
  86. #define F_STRUCT 51 /* Structure or e-vector */
  87. #define F_DEFOPT 52 /* function definition, &optional args */
  88. #define F_DEFHOPT 53 /* function definition, &optional args + initform */
  89. #define F_DEFREST 54 /* function definition, &optional/&rest args */
  90. #define F_DEFHREST 55 /* function definition, &optional/&rest + initform */
  91. #define F_ARRAY 56 /* Common Lisp style general array */
  92. #define F_BITVEC 57 /* Bit-vector */
  93. #ifdef COMMON
  94. #define F_PKGINT 58 /* abc::def (coded as m, n, c1..cm, c1..cn) */
  95. /* m=0 can be used for gensyms, as in #:xxx */
  96. #else
  97. #define F_GENSYM 58 /* coded as n, c1..cn */
  98. #endif
  99. #define F_PKGEXT 59 /* abc:def (m=0 => keyword) */
  100. #define F_OLD 60 /* all remaining codes denote recently seen symbols */
  101. #define KEEP_RECENT (256 - F_OLD)
  102. #define MAX_OBJECT 256 /* limit on symbol & number length */
  103. #ifdef DEBUG_FASL
  104. static char *fasl_code_names[] =
  105. {
  106. "END", "NIL", "TRU", "EXT",
  107. "INT", "NEG", "BIG", "RAT",
  108. "CPX", "FPS", "FPF", "FPD",
  109. "FPL", "SYM", "ID1", "ID2",
  110. "ID3", "ID4", "ID5", "ID6",
  111. "ID7", "ID8", "ID9", "IDA",
  112. "IDB", "IDC", "IDD", "IDE",
  113. "IDF", "STR", "BP0", "BP1",
  114. "BP2", "BP3", "HASH", "VEC",
  115. "LST", "LS1", "LS2", "LS3",
  116. "LS4", "DOT", "QUT", "DEF0",
  117. "DEF1", "DEF2", "DEF3", "DEFN",
  118. "REP", "CHAR", "SDEF", "STRUCT",
  119. "DEFOPT", "DEFHOPT", "DEFREST", "DEFHREST",
  120. #ifdef COMMON
  121. "ARRAY", "BITVEC", "PKGINT", "PKGEXT"
  122. #else
  123. "ARRAY", "BITVEC", "GENSYM", "PKGEXT"
  124. #endif
  125. };
  126. static char old_name[8];
  127. static char *fasl_code(int n)
  128. {
  129. if (n >= F_OLD)
  130. { sprintf(old_name, "OLD%d", n - F_OLD);
  131. return old_name;
  132. }
  133. else return fasl_code_names[n];
  134. }
  135. #endif
  136. #define boffo_char(i) celt(boffo, i)
  137. static int fp_rep = 0; /* representation used when FASL file was written */
  138. static Lisp_Object fastread(void);
  139. #ifdef COMMON
  140. static char package_name[256];
  141. #endif
  142. #ifdef DEBUG_FASL
  143. static int IgetcDebug()
  144. {
  145. int k = Igetc();
  146. trace_printf("Igetc = %d/%.2x/%s\n", k, k, fasl_code(k));
  147. return k;
  148. }
  149. #define Igetc() IgetcDebug()
  150. static int IreadDebug(char *x, int n)
  151. {
  152. int i;
  153. int k = Iread(x, n);
  154. trace_printf("Iread(%d) = %d:", n, k);
  155. for (i=0; i<k; i++)
  156. { trace_printf(" %d/%x", x[i], x[i]);
  157. if (32 <= x[i] && x[i] < 0x7f) trace_printf("/'%c'", x[i]);
  158. }
  159. trace_printf("\n");
  160. return k;
  161. }
  162. #define Iread(a, n) IreadDebug(a, n)
  163. #endif
  164. static Lisp_Object fastread1(int32 ch, int32 operand)
  165. {
  166. Lisp_Object nil = C_nil;
  167. Lisp_Object r = nil, w;
  168. #ifdef COMMON
  169. int operand0;
  170. #endif
  171. int32 p;
  172. switch (ch)
  173. {
  174. default: /* a recently-mentioned item */
  175. if (ch < F_OLD)
  176. { err_printf("\nError at byte %ld : %#.2x/%d\n",
  177. (long)fasl_byte_count, ch & 0xff, ch & 0xff);
  178. return aerror("bad byte in FASL file");
  179. }
  180. if (operand != 0)
  181. { operand = ((operand-1) << 7) + (ch - F_OLD);
  182. r = faslgensyms;
  183. while (operand != 0)
  184. { r = qcdr(r);
  185. operand--;
  186. }
  187. return qcar(r);
  188. }
  189. operand = recent_pointer - (ch - F_OLD);
  190. if (operand < 0) operand += KEEP_RECENT;
  191. r = elt(faslvec, operand);
  192. return r;
  193. #ifdef COMMON
  194. case F_PKGINT:
  195. case F_PKGEXT:
  196. { int ch1 = Igetc();
  197. fasl_byte_count++;
  198. if (ch1 == EOF) return aerror("premature EOF in FASL file");
  199. operand0 = ch1 & 0xff;
  200. ch1 = Igetc();
  201. if (ch1 == EOF) return aerror("premature EOF in FASL file");
  202. operand = (operand << 8) + ((int32)ch1 & 0xff);
  203. if (operand0 != 0)
  204. { if (Iread(package_name, operand0) != operand0)
  205. return aerror("FASL file corrupted");
  206. fasl_byte_count += operand0;
  207. r = find_package(package_name, operand0);
  208. if (r == nil)
  209. { err_printf(
  210. "+++ Package %s not found, using current package\n",
  211. package_name);
  212. r = CP;
  213. }
  214. }
  215. else r = qvalue(keyword_package);
  216. if (Iread(&boffo_char(0), operand) != operand)
  217. return aerror("FASL file corrupted");
  218. fasl_byte_count += operand;
  219. if (skipping_input == 2) r = nil;
  220. else if (ch == F_PKGINT)
  221. { if (operand0 == 0)
  222. { r = iintern(boffo, (int32)operand, CP, 0);
  223. errexit();
  224. r = Lgensym2(nil, r);
  225. }
  226. else r = iintern(boffo, (int32)operand, r, 0);
  227. }
  228. else if (r == qvalue(keyword_package))
  229. r = iintern(boffo, (int32)operand, r, 0);
  230. else
  231. { push(r);
  232. w = iintern(boffo, (int32)operand, r, 4);
  233. pop(r);
  234. errexit();
  235. if (mv_2 == nil)
  236. { err_printf("+++ Symbol %.*s not external in %s\n",
  237. (int)operand, &celt(boffo, 0), package_name);
  238. err_printf("+++ Treating as an internal symbol...\n");
  239. w = iintern(boffo, (int32)operand, r, 0);
  240. }
  241. r = w;
  242. }
  243. errexit();
  244. /*
  245. * The KEEP_RECENT most recently used symbols are stored in a cyclic buffer
  246. * so that if re-used they will be rapidly available. See comment under
  247. * F_GENSYM for a delicacy here.
  248. */
  249. if (skipping_input == 0 ||
  250. (ch == F_PKGINT && operand0 == 0)) /* NB keep gensyms! */
  251. { recent_pointer++;
  252. if (recent_pointer == KEEP_RECENT) recent_pointer = 0;
  253. w = elt(faslvec, recent_pointer);
  254. #ifdef COMMON
  255. if (qpackage(w) == nil)
  256. #else
  257. if (qheader(w) & SYM_ANY_GENSYM)
  258. #endif
  259. { push(r);
  260. #ifdef DEBUG_FASL
  261. trace_printf("recording gensym ");
  262. prin_to_trace(w);
  263. trace_printf("\n");
  264. #endif
  265. w = cons(w, faslgensyms);
  266. pop(r);
  267. errexit();
  268. faslgensyms = w;
  269. }
  270. elt(faslvec, recent_pointer) = r;
  271. #ifdef DEBUG_FASL
  272. trace_printf("recording ");
  273. prin_to_trace(r);
  274. trace_printf("\n");
  275. #endif
  276. }
  277. return r;
  278. }
  279. #else
  280. case F_GENSYM:
  281. { int ch1 = Igetc();
  282. if (ch1 == EOF) return aerror("premature EOF in FASL file");
  283. operand = (operand << 8) + ((int32)ch1 & 0xff);
  284. if (Iread(&boffo_char(0), operand) != operand)
  285. return aerror("FASL file corrupted");
  286. fasl_byte_count += operand;
  287. if (skipping_input == 2) r = nil;
  288. r = iintern(boffo, (int32)operand, CP, 0);
  289. errexit();
  290. r = Lgensym2(nil, r);
  291. errexit();
  292. /*
  293. * The KEEP_RECENT most recently used symbols are stored in a cyclic buffer
  294. * so that if re-used they will be rapidly available. Note as a real curiosity
  295. * then gensyms will be stored in this even if skipping_input is non-zero.
  296. * this is essential so that gensyms within saved-definitions are
  297. * can get processed properly. Specifically so that repeated use of a gensym
  298. * within a saved definition leads to two references to the same thing
  299. * rather than to the creation of two new gensyms. The same issue should
  300. * arise for un-interned Common Lisp symbols.
  301. */
  302. recent_pointer++;
  303. if (recent_pointer == KEEP_RECENT) recent_pointer = 0;
  304. w = elt(faslvec, recent_pointer);
  305. if (qheader(w) & SYM_ANY_GENSYM)
  306. { push(r);
  307. #ifdef DEBUG_FASL
  308. trace_printf("recording gensym ");
  309. prin_to_trace(w);
  310. trace_printf("\n");
  311. #endif
  312. w = cons(w, faslgensyms);
  313. pop(r);
  314. errexit();
  315. faslgensyms = w;
  316. }
  317. elt(faslvec, recent_pointer) = r;
  318. #ifdef DEBUG_FASL
  319. trace_printf("recording ");
  320. prin_to_trace(r);
  321. trace_printf("\n");
  322. #endif
  323. return r;
  324. }
  325. #endif
  326. /* these all have a 1-byte arg to follow */
  327. case F_INT:
  328. case F_NEG:
  329. case F_BIG:
  330. case F_SYM:
  331. case F_STR:
  332. case F_BP0:
  333. case F_BP1:
  334. case F_BP2:
  335. case F_BP3:
  336. case F_HASH:
  337. case F_VEC:
  338. case F_STRUCT:
  339. case F_LST:
  340. case F_DOT:
  341. { int ch1 = Igetc();
  342. fasl_byte_count++;
  343. if (ch1 == EOF) return aerror("premature EOF in FASL file");
  344. operand = (operand << 8) + ((int32)ch1 & 0xff);
  345. }
  346. switch (ch)
  347. {
  348. default: /* can never occur */
  349. case F_INT: /* positive fixnum */
  350. return fixnum_of_int(operand);
  351. case F_NEG: /* negative fixnum */
  352. return fixnum_of_int(-operand);
  353. case F_BIG:
  354. r = getvector(TAG_NUMBERS, TYPE_BIGNUM, 4+operand);
  355. /* I tidy up the padding word if needbe */
  356. if ((operand & 4) == 0)
  357. *(int32 *)((char *)r + 8L - TAG_NUMBERS + operand) = 0;
  358. /*
  359. * I accumulate the numeric components of the bignum here by steam - one
  360. * byte at a time - so that fasl files made on a machine with one byte-order
  361. * can be used on machines with the other. I do not expect that there
  362. * will be many bignums in fasl files, and thus this is not a performance
  363. * critical area.
  364. */
  365. { int32 i;
  366. for (i = 0; i<operand; i+=4)
  367. { unsigned32 v = (int32)Igetc() & 0xff;
  368. v = (v << 8) | ((int32)Igetc() & 0xff);
  369. v = (v << 8) | ((int32)Igetc() & 0xff);
  370. v = (v << 8) | ((int32)Igetc() & 0xff);
  371. *(unsigned32 *)((char *)r + 4L - TAG_NUMBERS + i) = v;
  372. fasl_byte_count += 4;
  373. }
  374. }
  375. return r;
  376. case F_SYM: /* n characters making a symbol */
  377. if (Iread(&boffo_char(0), operand) != operand)
  378. return aerror("FASL file corrupted");
  379. fasl_byte_count += operand;
  380. /*
  381. * skipping_input is usually zero. If it is 1 then I read in expressions
  382. * as normal save that I do not update the recently-mentioned-symbol cache.
  383. * skipping_input==2 causes me to parse the input FASL file but not
  384. * return a useful result. Well actually everything will be read in
  385. * as normal save that symbols will all be mapped onto NIL.
  386. */
  387. if (skipping_input == 2) r = nil;
  388. else r = iintern(boffo, operand, CP, 0);
  389. errexit();
  390. /*
  391. * The KEEP_RECENT most recently used symbols are stored in a cyclic buffer
  392. * so that if re-used they will be rapidly available.
  393. */
  394. if (skipping_input == 0)
  395. { recent_pointer++;
  396. if (recent_pointer == KEEP_RECENT) recent_pointer = 0;
  397. w = elt(faslvec, recent_pointer);
  398. #ifdef COMMON
  399. if (qpackage(w) == nil)
  400. #else
  401. if (qheader(w) & SYM_ANY_GENSYM)
  402. #endif
  403. { push(r);
  404. #ifdef DEBUG_FASL
  405. trace_printf("recording gensym ");
  406. prin_to_trace(w);
  407. trace_printf("\n");
  408. #endif
  409. w = cons(w, faslgensyms);
  410. pop(r);
  411. errexit();
  412. faslgensyms = w;
  413. }
  414. elt(faslvec, recent_pointer) = r;
  415. #ifdef DEBUG_FASL
  416. trace_printf("recording ");
  417. prin_to_trace(r);
  418. trace_printf("\n");
  419. #endif
  420. }
  421. return r;
  422. case F_STR: /* n characters making a string */
  423. r = getvector(TAG_VECTOR, TYPE_STRING, 4+operand);
  424. errexit();
  425. { int32 l = (operand + 3) & ~(int32)7;
  426. char *s = (char *)r - TAG_VECTOR;
  427. /* I go to some trouble here to zero out the end 2 words of the string */
  428. *(int32 *)(s + l + 4) = 0;
  429. if (l != 0) *(int32 *)(s + l) = 0;
  430. if (Iread(s + 4, operand) != operand)
  431. return aerror("FASL file corrupted");
  432. fasl_byte_count += operand;
  433. }
  434. return r;
  435. case F_BP3: /* n + 768 bytes of BPS */
  436. operand += 256;
  437. /* drop through */
  438. case F_BP2: /* n + 512 bytes of BPS */
  439. operand += 256;
  440. /* drop through */
  441. case F_BP1: /* n + 256 bytes of BPS */
  442. operand += 256;
  443. /* drop through */
  444. case F_BP0: /* n bytes making BPS */
  445. /* See the other place where qvalue(savedef) == savedef is tested. */
  446. if (qvalue(savedef) == savedef)
  447. { int32 i;
  448. for (i=0; i<operand; i++) Igetc();
  449. fasl_byte_count += operand;
  450. return nil;
  451. }
  452. else
  453. { r = getcodevector(TYPE_BPS, operand+4);
  454. errexit();
  455. if (Iread(data_of_bps(r), operand) != operand)
  456. return aerror("FASL file corrupted");
  457. fasl_byte_count += operand;
  458. return r;
  459. }
  460. case F_HASH:
  461. case F_STRUCT:
  462. case F_VEC: /* normal vector with n entries */
  463. r = getvector_init(4*(operand+1), nil);
  464. errexit();
  465. if (ch == F_STRUCT)
  466. vechdr(r) ^= (TYPE_STRUCTURE ^ TYPE_SIMPLE_VEC);
  467. else if (ch == F_HASH)
  468. vechdr(r) ^= (TYPE_HASH ^ TYPE_SIMPLE_VEC);
  469. for (p=0; p<operand; p++)
  470. { push(r);
  471. w = fastread();
  472. pop(r);
  473. errexit();
  474. elt(r, p) = w;
  475. }
  476. if (ch == F_HASH)
  477. {
  478. /*
  479. * If I have just read in a hash table that was built on EQ or EQL I will
  480. * need to rehash it now.
  481. */
  482. if (elt(r, 0) == fixnum_of_int(0) ||
  483. elt(r, 0) == fixnum_of_int(1) ||
  484. !is_fixnum(elt(r, 0)))
  485. { Lisp_Object v;
  486. rehash_this_table(v = elt(r, 4));
  487. push(r);
  488. v = ncons(v);
  489. pop(r);
  490. errexit();
  491. qcdr(v) = eq_hash_tables;
  492. eq_hash_tables = v;
  493. }
  494. }
  495. return r;
  496. case F_LST: /* build list of length n */
  497. case F_DOT: /* dotted list with n values */
  498. if (ch == F_LST) r = nil;
  499. else
  500. { r = fastread();
  501. errexit();
  502. }
  503. for (p = 0; p<operand; p++)
  504. { push(r);
  505. w = fastread();
  506. pop(r);
  507. errexit();
  508. r = cons(w, r);
  509. errexit();
  510. }
  511. return r;
  512. }
  513. }
  514. }
  515. static CSLbool just_reading_source = NO;
  516. static Lisp_Object fastread(void)
  517. {
  518. int32 operand = 0, ch = Igetc();
  519. Lisp_Object nil = C_nil;
  520. Lisp_Object r = nil, w;
  521. fasl_byte_count++;
  522. if (ch == EOF) return aerror("premature EOF in FASL file");
  523. ch &= 0xff;
  524. for (;;)
  525. {
  526. switch (ch)
  527. {
  528. case F_END: /* marks end of file */
  529. return CHAR_EOF;
  530. case F_NIL: /* represents the value NIL */
  531. return nil;
  532. case F_TRU: /* represents the value T */
  533. return lisp_true;
  534. case F_QUT: /* (QUOTE <next thing>) */
  535. r = fastread();
  536. errexit();
  537. return list2(quote_symbol, r);
  538. case F_SDEF:
  539. /*
  540. * I am THINKING about an option that avoids reading in definitions here
  541. * when *SAVEDEF is nil, and just skips the bytes in the FASL file. The
  542. * problem with doing so is that of the table of recently referred to
  543. * symbols - which must be kept in step between FASL writing and reading
  544. * whether or not *SAVEDEF is active.
  545. */
  546. if (qvalue(savedef) == nil) skipping_input = 2;
  547. else skipping_input = 1;
  548. #ifdef __alpha
  549. /*
  550. * This is a fairly shameless hack to try to work around a bug that
  551. * appears to exist when CSL is compiled using some releases of the
  552. * C compiler that comes with DECs OSF on Alpha-based computers. I found
  553. * experimentally that adding a function call here seemed to mend things.
  554. * Originally this was a debug-print statement, but here I have just a
  555. * dummy function call. The observed problem was the variable
  556. * skipping_input not getting set properly, leading to shambles later on.
  557. * ACN: August 1996
  558. */
  559. dummy_function_call("ALPHA", skipping_input);
  560. #endif
  561. r = fastread();
  562. skipping_input = 0;
  563. errexit();
  564. ch = Igetc();
  565. fasl_byte_count++;
  566. if (ch == EOF) return aerror("premature EOF in FASL file");
  567. ch &= 0xff;
  568. /* And drop through */
  569. case F_DEF0: /* introduces defn of compiled code */
  570. case F_DEF1:
  571. case F_DEF2:
  572. case F_DEF3:
  573. case F_DEFN:
  574. case F_DEFOPT:
  575. case F_DEFHOPT:
  576. case F_DEFREST:
  577. case F_DEFHREST:
  578. { Lisp_Object name, bps, env;
  579. push(r);
  580. name = fastread();
  581. pop(r);
  582. errexit();
  583. push(name);
  584. if (qvalue(savedef) != nil)
  585. {
  586. if (just_reading_source)
  587. { Lisp_Object w;
  588. #ifdef COMMON
  589. w = get(name, loadsource_symbol, nil);
  590. #else
  591. w = get(name, loadsource_symbol);
  592. #endif
  593. if (w == nil &&
  594. qvalue(loadsource_symbol) != nil) w = lisp_true;
  595. if (w != nil)
  596. { Lisp_Object w1, chk = w;
  597. CSLbool include = YES;
  598. push3(chk, name, r);
  599. if (consp(w))
  600. { if (integerp(qcar(w)))
  601. { chk = qcar(w);
  602. w = list2star(qcar(w),
  603. current_module, qcdr(w));
  604. }
  605. else w = cons(current_module, w);
  606. }
  607. else
  608. { if (integerp(w)) w = list2(w, current_module);
  609. else w = ncons(current_module);
  610. }
  611. pop3(r, name, chk);
  612. errexit();
  613. /*
  614. * If the load-source property is an integer then the source is only
  615. * loaded if the definition concerned matched that as an MD5 checksum.
  616. * (well actually I compute MD5 then truncate the digest to 60 bits).
  617. * (I allow a property (integer ...) too).
  618. * If load-source started off as just T then the last definition loaded
  619. * will be the one that survives, but the load-source property will
  620. * be replaced by a list of the modules that provided definitions (which
  621. * may or may not be conflicting ones).
  622. */
  623. if (integerp(chk) != nil && consp(r))
  624. { push4(name, r, chk, w);
  625. w1 = Lmd60(nil, qcdr(r));
  626. pop4(w, chk, r, name);
  627. errexit();
  628. push4(name, r, chk, w);
  629. include = numeq2(w1, chk);
  630. #ifdef DEBUG_FASL
  631. prin_to_trace(name); trace_printf("\n");
  632. prin_to_trace(r); trace_printf("\n");
  633. prin_to_trace(w1); trace_printf("\n");
  634. prin_to_trace(w); trace_printf("\n");
  635. prin_to_trace(chk); trace_printf("\n");
  636. trace_printf(" MD5 equality = %d\n", include);
  637. #endif
  638. pop4(w, chk, r, name);
  639. errexit();
  640. }
  641. #ifdef DEBUG_FASL
  642. else trace_printf("simple case\n");
  643. #endif
  644. if (include)
  645. { push2(name, r);
  646. putprop(name, loadsource_symbol, w);
  647. #ifdef DEBUG_FASL
  648. trace_printf("record sourceloc\n");
  649. #endif
  650. pop2(r, name);
  651. errexit();
  652. #ifdef DEBUG_FASL
  653. trace_printf("record savedef\n");
  654. #endif
  655. push2(name, r);
  656. /* here I build up a list of the functions whose definitions were loaded */
  657. w1 = cons(name, qvalue(work_symbol));
  658. pop2(r, name);
  659. errexit();
  660. qvalue(work_symbol) = w1;
  661. putprop(name, savedef, r);
  662. }
  663. }
  664. }
  665. else putprop(name, savedef, r);
  666. errexit();
  667. }
  668. bps = fastread();
  669. errexitn(1);
  670. push(bps);
  671. env = fastread();
  672. errexitn(2);
  673. pop(bps);
  674. if (is_fixnum(bps))
  675. { int nn = int_of_fixnum(bps);
  676. pop(name);
  677. if (qvalue(savedef) != savedef)
  678. { switch (ch)
  679. {
  680. case F_DEF0: switch (nn)
  681. {
  682. case 0: set_fns(name, wrong_no_na, wrong_no_nb, f0_as_0);
  683. break;
  684. default:goto bad_tail;
  685. }
  686. break;
  687. case F_DEF1: switch (nn)
  688. {
  689. case 0: set_fns(name, f1_as_0, too_many_1, wrong_no_1);
  690. break;
  691. case 1: set_fns(name, f1_as_1, too_many_1, wrong_no_1);
  692. break;
  693. default:goto bad_tail;
  694. }
  695. break;
  696. case F_DEF2: switch (nn)
  697. {
  698. case 0: set_fns(name, too_few_2, f2_as_0, wrong_no_2);
  699. break;
  700. case 1: set_fns(name, too_few_2, f2_as_1, wrong_no_2);
  701. break;
  702. case 2: set_fns(name, too_few_2, f2_as_2, wrong_no_2);
  703. break;
  704. default:goto bad_tail;
  705. }
  706. break;
  707. case F_DEF3: switch (nn)
  708. {
  709. case 0: set_fns(name, wrong_no_na, wrong_no_nb, f3_as_0);
  710. break;
  711. case 1: set_fns(name, wrong_no_na, wrong_no_nb, f3_as_1);
  712. break;
  713. case 2: set_fns(name, wrong_no_na, wrong_no_nb, f3_as_2);
  714. break;
  715. case 3: set_fns(name, wrong_no_na, wrong_no_nb, f3_as_3);
  716. break;
  717. default:goto bad_tail;
  718. }
  719. break;
  720. case F_DEFN: switch (nn)
  721. {
  722. default:goto bad_tail;
  723. }
  724. break;
  725. case F_DEFOPT:
  726. switch (nn)
  727. {
  728. default:goto bad_tail;
  729. }
  730. break;
  731. case F_DEFHOPT:
  732. switch (nn)
  733. {
  734. default:goto bad_tail;
  735. }
  736. break;
  737. case F_DEFREST:
  738. switch (nn)
  739. {
  740. default:goto bad_tail;
  741. }
  742. break;
  743. case F_DEFHREST:
  744. switch (nn)
  745. {
  746. default:goto bad_tail;
  747. }
  748. break;
  749. }
  750. if ((qheader(name) & (SYM_C_DEF | SYM_CODEPTR)) ==
  751. (SYM_C_DEF | SYM_CODEPTR))
  752. {
  753. #ifdef NOISY_RE_PROTECTED_FNS
  754. if (verbos_flag & 2)
  755. { freshline_trace();
  756. trace_printf("+++ Protected function ");
  757. prin_to_trace(name);
  758. trace_printf("\n");
  759. }
  760. #endif
  761. }
  762. else
  763. { qenv(name) = env;
  764. if ((qheader(name) & SYM_C_DEF) != 0)
  765. lose_C_def(name);
  766. }
  767. }
  768. return nil;
  769. bad_tail:
  770. err_printf("+++++ Bad tailcall combination %d %d\n",
  771. ch, nn);
  772. return nil;
  773. }
  774. env = cons(bps, env);
  775. pop(name);
  776. errexit();
  777. /*
  778. * If the variable !*savedef has !*savedef as its value I will not instate
  779. * function definitions here at all. This is a very odd thing to do, but
  780. * turns out to help me save memory when I want to load FASL files in order
  781. * to retrieve the Lisp form of definitions but I do not really want the
  782. * code present instated.
  783. */
  784. if (qvalue(savedef) != savedef)
  785. { switch (ch)
  786. {
  787. case F_DEF0: set_fns(name, wrong_no_0a, wrong_no_0b,
  788. bytecoded0);
  789. break;
  790. case F_DEF1: set_fns(name, bytecoded1, too_many_1, wrong_no_1);
  791. break;
  792. case F_DEF2: set_fns(name, too_few_2, bytecoded2, wrong_no_2);
  793. break;
  794. case F_DEF3: set_fns(name, wrong_no_3a, wrong_no_3b,
  795. bytecoded3);
  796. break;
  797. case F_DEFN: set_fns(name, wrong_no_na, wrong_no_nb, bytecodedn);
  798. break;
  799. case F_DEFOPT:
  800. set_fns(name, byteopt1, byteopt2, byteoptn);
  801. break;
  802. case F_DEFHOPT:
  803. set_fns(name, hardopt1, hardopt2, hardoptn);
  804. break;
  805. case F_DEFREST:
  806. set_fns(name, byteoptrest1, byteoptrest2, byteoptrestn);
  807. break;
  808. case F_DEFHREST:
  809. set_fns(name, hardoptrest1, hardoptrest2, hardoptrestn);
  810. break;
  811. }
  812. if ((qheader(name) & (SYM_C_DEF | SYM_CODEPTR)) ==
  813. (SYM_C_DEF | SYM_CODEPTR))
  814. {
  815. #ifdef NOISY_RE_PROTECTED_FNS
  816. if (verbos_flag & 2)
  817. { freshline_trace();
  818. trace_printf("+++ Protected function ");
  819. prin_to_trace(name);
  820. trace_printf("\n");
  821. }
  822. #endif
  823. }
  824. else
  825. { qenv(name) = env;
  826. if ((qheader(name) & SYM_C_DEF) != 0) lose_C_def(name);
  827. }
  828. if (qvalue(comp_symbol) != nil &&
  829. qfn1(native_symbol) != undefined1)
  830. { name = ncons(name);
  831. nil = C_nil;
  832. if (!exception_pending())
  833. (qfn1(native_symbol))(qenv(native_symbol), name);
  834. }
  835. }
  836. return nil;
  837. }
  838. case F_LS4:
  839. push(r);
  840. w = fastread();
  841. pop(r);
  842. errexit();
  843. r = cons(w, r);
  844. errexit();
  845. /* DROP THROUGH */
  846. case F_LS3:
  847. push(r);
  848. w = fastread();
  849. pop(r);
  850. errexit();
  851. r = cons(w, r);
  852. errexit();
  853. /* DROP THROUGH */
  854. case F_LS2:
  855. push(r);
  856. w = fastread();
  857. pop(r);
  858. errexit();
  859. r = cons(w, r);
  860. errexit();
  861. /* DROP THROUGH */
  862. case F_LS1:
  863. push(r);
  864. w = fastread();
  865. pop(r);
  866. errexit();
  867. r = cons(w, r);
  868. errexit();
  869. return r;
  870. case F_CHAR:
  871. /*
  872. * Note that in Kanji mode the interpretation here should be that the 16 bit
  873. * character code is specified by bits/code. I ensure that when FASL files
  874. * are written this arrangement holds.
  875. */
  876. { int32 bits, font, code;
  877. bits = Igetc();
  878. fasl_byte_count++;
  879. if (bits == EOF) return aerror("premature EOF in FASL file");
  880. font = Igetc();
  881. fasl_byte_count++;
  882. if (font == EOF) return aerror("premature EOF in FASL file");
  883. code = Igetc();
  884. fasl_byte_count++;
  885. if (code == EOF) return aerror("premature EOF in FASL file");
  886. return pack_char(bits, font & 0xff, code & 0xff);
  887. }
  888. case F_REP:
  889. { int c1, c2;
  890. c1 = Igetc();
  891. fasl_byte_count++;
  892. if (c1 == EOF) return aerror("premature EOF in FASL file");
  893. c2 = Igetc();
  894. fasl_byte_count++;
  895. if (c2 == EOF) return aerror("premature EOF in FASL file");
  896. fp_rep = (c1 & 0xff) + ((c2 & 0xff) << 8);
  897. ch = Igetc();
  898. fasl_byte_count++;
  899. if (ch == EOF) return aerror("premature EOF in FASL file");
  900. ch &= 0xff;
  901. continue;
  902. }
  903. #ifdef COMMON
  904. case F_RAT:
  905. w = fastread();
  906. errexit();
  907. push(w);
  908. r = fastread();
  909. pop(w);
  910. errexit();
  911. return make_ratio(w, r);
  912. case F_CPX:
  913. w = fastread();
  914. errexit();
  915. push(w);
  916. r = fastread();
  917. pop(w);
  918. errexit();
  919. return make_complex(w, r);
  920. case F_FPS:
  921. { Lisp_Object w1;
  922. if (Iread((char *)&w1, 4) != 4)
  923. return aerror("FASL file corrupted");
  924. fasl_byte_count += 4;
  925. convert_fp_rep(&w1, fp_rep, current_fp_rep, 0);
  926. return w1;
  927. }
  928. case F_FPF:
  929. r = getvector(TAG_BOXFLOAT, TYPE_SINGLE_FLOAT,
  930. sizeof(Single_Float));
  931. errexit();
  932. if (Iread((char *)r + 4L - TAG_BOXFLOAT, 4) != 4)
  933. return aerror("FASL file corrupted");
  934. fasl_byte_count += 4;
  935. convert_fp_rep((char *)r + 4L - TAG_BOXFLOAT,
  936. fp_rep, current_fp_rep, 1);
  937. return r;
  938. #endif
  939. case F_FPD:
  940. r = getvector(TAG_BOXFLOAT, TYPE_DOUBLE_FLOAT,
  941. sizeof(Double_Float));
  942. errexit();
  943. *(int32 *)((char *)r + 4L - TAG_BOXFLOAT) = 0;
  944. if (Iread((char *)r + 8L - TAG_BOXFLOAT, 8) != 8)
  945. return aerror("FASL file corrupted");
  946. fasl_byte_count += 8;
  947. convert_fp_rep((char *)r + 8L - TAG_BOXFLOAT,
  948. fp_rep, current_fp_rep, 2);
  949. return r;
  950. #ifdef COMMON
  951. case F_FPL:
  952. r = getvector(TAG_BOXFLOAT, TYPE_LONG_FLOAT, sizeof(Long_Float));
  953. errexit();
  954. if (Iread((char *)r + 4L - TAG_BOXFLOAT, 12) != 12)
  955. return aerror("FASL file corrupted");
  956. fasl_byte_count += 12;
  957. /* Beware offset of 8 here if long floats -> 3 words */
  958. convert_fp_rep((char *)r + 8L - TAG_BOXFLOAT,
  959. fp_rep, current_fp_rep, 3);
  960. return r;
  961. #endif
  962. case F_ID1:
  963. case F_ID2:
  964. case F_ID3:
  965. case F_ID4:
  966. case F_ID5:
  967. case F_ID6:
  968. case F_ID7:
  969. case F_ID8:
  970. case F_ID9:
  971. case F_IDA:
  972. case F_IDB:
  973. case F_IDC:
  974. case F_IDD:
  975. case F_IDE:
  976. case F_IDF:
  977. operand = ch - F_ID1 + 1;
  978. if (Iread(&boffo_char(0), operand) != operand)
  979. return aerror("FASL file corrupted");
  980. fasl_byte_count += operand;
  981. if (skipping_input == 2) r = nil;
  982. else r = iintern(boffo, operand, CP, 0);
  983. errexit();
  984. /*
  985. * The KEEP_RECENT most recently used symbols are stored in a cyclic buffer
  986. * so that if re-used they will be rapidly available.
  987. */
  988. if (skipping_input == 0)
  989. { recent_pointer++;
  990. if (recent_pointer == KEEP_RECENT) recent_pointer = 0;
  991. w = elt(faslvec, recent_pointer);
  992. #ifdef COMMON
  993. if (qpackage(w) == nil)
  994. #else
  995. if (qheader(w) & SYM_ANY_GENSYM)
  996. #endif
  997. { push(r);
  998. #ifdef DEBUG_FASL
  999. trace_printf("recording gensym ");
  1000. prin_to_trace(w);
  1001. trace_printf("\n");
  1002. #endif
  1003. w = cons(w, faslgensyms);
  1004. pop(r);
  1005. errexit();
  1006. faslgensyms = w;
  1007. }
  1008. elt(faslvec, recent_pointer) = r;
  1009. #ifdef DEBUG_FASL
  1010. trace_printf("recording ");
  1011. prin_to_trace(r);
  1012. trace_printf("\n");
  1013. #endif
  1014. }
  1015. return r;
  1016. case F_EXT: /* extend effective range of operand */
  1017. { int ch1 = Igetc();
  1018. fasl_byte_count++;
  1019. if (ch1 == EOF) return aerror("premature EOF in FASL file");
  1020. operand = (operand << 8) + ((int32)ch1 & 0xff);
  1021. }
  1022. ch = (int32)Igetc();
  1023. fasl_byte_count++;
  1024. if (ch == EOF) return aerror("premature EOF in FASL file");
  1025. ch &= 0xff;
  1026. continue; /* dispatch again on next byte */
  1027. default:
  1028. return fastread1(ch, operand);
  1029. }
  1030. }
  1031. }
  1032. static char *trim_module_name(char *name, int32 *lenp)
  1033. {
  1034. int len = *lenp, len1;
  1035. len1 = len - 1;
  1036. /*
  1037. * Firstly I will decrease the length of the string if there is a "."
  1038. * towards the end.
  1039. */
  1040. while (len1 > 0 && name[len1] != '.')
  1041. { if (name[len1] == '/' || name[len1] == '\\')
  1042. { len1 = len;
  1043. break;
  1044. }
  1045. len1--;
  1046. }
  1047. if (len1 > 0) len = len1;
  1048. /*
  1049. * Now I will try to remove any prefix that ends in "/" or "\".
  1050. * Through all this I will attempt to leave SOMETHING over from "silly"
  1051. * inputs such as ".....", but exactly what happens in such cases does not
  1052. * bother me much!
  1053. */
  1054. len1 = len - 1;
  1055. while (len1 > 0 && name[len1] != '/' &&
  1056. name[len1] != '\\' && name[len1] != '.') len1--;
  1057. if (len1 > 0 && len1 < len-2)
  1058. { len1++;
  1059. name += len1;
  1060. len -= len1;
  1061. }
  1062. *lenp = len;
  1063. return name;
  1064. }
  1065. Lisp_Object Lcopy_module(Lisp_Object nil, Lisp_Object file)
  1066. /*
  1067. * copy-module will ensure that the output PDS contains a copy of
  1068. * the module that is named. As a special case (copy-module nil) will
  1069. * copy the help data "module". There is no provision for copying
  1070. * startup banner data - that must be set up by hand.
  1071. */
  1072. {
  1073. #ifdef DEMO_MODE
  1074. return onevalue(nil);
  1075. #else
  1076. Header h;
  1077. int32 len;
  1078. char *modname;
  1079. #ifdef SOCKETS
  1080. /*
  1081. * Security measure - remote client can not do "copy-module"
  1082. */
  1083. if (socket_server != 0) return onevalue(nil);
  1084. #endif
  1085. if (file == nil) Icopy(NULL, 0);
  1086. else
  1087. { if (symbolp(file))
  1088. { file = get_pname(file);
  1089. errexit();
  1090. h = vechdr(file);
  1091. }
  1092. else if (!is_vector(file) ||
  1093. type_of_header(h = vechdr(file)) != TYPE_STRING)
  1094. return aerror("copy-module");
  1095. len = length_of_header(h) - 4;
  1096. modname = (char *)file + 4 - TAG_VECTOR;
  1097. modname = trim_module_name(modname, &len);
  1098. Icopy(modname, (int)len);
  1099. }
  1100. return onevalue(nil);
  1101. #endif
  1102. }
  1103. Lisp_Object Ldelete_module(Lisp_Object nil, Lisp_Object file)
  1104. /*
  1105. * delete-module deletes the named module from the output PDS, supposing it
  1106. * was there to begin with. (delete-module nil) deletes any help data.
  1107. */
  1108. {
  1109. #ifdef DEMO_MODE
  1110. return onevalue(nil);
  1111. #else
  1112. Header h;
  1113. int32 len;
  1114. char *modname;
  1115. #ifdef SOCKETS
  1116. /*
  1117. * Security measure - remote client can not do "delete-module"
  1118. */
  1119. if (socket_server != 0) return onevalue(nil);
  1120. #endif
  1121. if (file == nil) Idelete(NULL, 0);
  1122. else
  1123. { if (symbolp(file))
  1124. { file = get_pname(file);
  1125. errexit();
  1126. h = vechdr(file);
  1127. }
  1128. else if (!is_vector(file) ||
  1129. type_of_header(h = vechdr(file)) != TYPE_STRING)
  1130. return aerror("delete-module");
  1131. len = length_of_header(h) - 4;
  1132. modname = (char *)file + 4 - TAG_VECTOR;
  1133. modname = trim_module_name(modname, &len);
  1134. Idelete(modname, (int)len);
  1135. }
  1136. return onevalue(nil);
  1137. #endif /* DEMO_MODE */
  1138. }
  1139. Lisp_Object Lbanner(Lisp_Object nil, Lisp_Object info)
  1140. /*
  1141. * (banner nil) returns the current banner info (nil if none)
  1142. * (banner "string") sets new info
  1143. * (banner "") deletes any that there is.
  1144. */
  1145. {
  1146. Header h;
  1147. int i;
  1148. int32 len;
  1149. char *name;
  1150. Ihandle save;
  1151. if (info == nil)
  1152. { char b[64];
  1153. Icontext(&save);
  1154. if (Iopen_banner(0))
  1155. { Irestore_context(save);
  1156. return onevalue(nil);
  1157. }
  1158. for (i=0; i<64; i++)
  1159. b[i] = Igetc();
  1160. IcloseInput(NO);
  1161. Irestore_context(save);
  1162. info = make_string(b);
  1163. errexit();
  1164. return onevalue(info);
  1165. }
  1166. #ifdef DEMO_MODE
  1167. return onevalue(nil);
  1168. #else
  1169. #ifdef SOCKETS
  1170. /*
  1171. * Security measure - remote client can not change banner info
  1172. */
  1173. if (socket_server != 0) return onevalue(nil);
  1174. #endif
  1175. if (symbolp(info))
  1176. { info = get_pname(info);
  1177. errexit();
  1178. h = vechdr(info);
  1179. }
  1180. else if (!is_vector(info) ||
  1181. type_of_header(h = vechdr(info)) != TYPE_STRING)
  1182. return aerror("banner");
  1183. len = length_of_header(h) - 4;
  1184. name = (char *)info + 4 - TAG_VECTOR;
  1185. if (len == 0) Iopen_banner(-2); /* delete banner info */
  1186. else
  1187. { Icontext(&save);
  1188. if (Iopen_banner(-1))
  1189. { Irestore_context(save);
  1190. return onevalue(nil);
  1191. }
  1192. if (len > 63) len = 63;
  1193. for (i=0; i<64; i++) Iputc(i >= len ? 0 : name[i]);
  1194. IcloseOutput();
  1195. Irestore_context(save);
  1196. }
  1197. return onevalue(lisp_true);
  1198. #endif /* DEMO_MODE */
  1199. }
  1200. Lisp_Object MS_CDECL Llist_modules(Lisp_Object nil, int nargs, ...)
  1201. /*
  1202. * display information about available modules
  1203. */
  1204. {
  1205. argcheck(nargs, 0, "list-modules");
  1206. Ilist();
  1207. return onevalue(nil);
  1208. }
  1209. Lisp_Object Lwritable_libraryp(Lisp_Object nil, Lisp_Object file)
  1210. /*
  1211. * This tests if a library handle refers to a writable file.
  1212. */
  1213. {
  1214. #ifdef DEMO_MODE
  1215. return onevalue(nil);
  1216. #else
  1217. int i;
  1218. directory *d;
  1219. if ((file & 0xffff) != SPID_LIBRARY) return onevalue(nil);
  1220. i = (file >> 20) & 0xfff;
  1221. d = fasl_files[i];
  1222. i = d->h.updated;
  1223. return onevalue(Lispify_predicate(i & D_WRITE_OK));
  1224. #endif
  1225. }
  1226. static Lisp_Object load_module(Lisp_Object nil, Lisp_Object file,
  1227. int sourceonly)
  1228. /*
  1229. * load_module() rebinds *package* in COMMON mode, but also note that
  1230. * it DOES rebind a whole load of variables so that loading one module
  1231. * can be done while in the process of loading another.
  1232. * also rebinds *echo to nil in case we are reading from a stream.
  1233. */
  1234. {
  1235. char filename[LONGEST_LEGAL_FILENAME];
  1236. Header h;
  1237. int32 len;
  1238. Ihandle save;
  1239. Lisp_Object v;
  1240. CSLbool from_stream = NO;
  1241. int close_mode;
  1242. char *modname;
  1243. int32 save_recent = recent_pointer,
  1244. save_byte_count = fasl_byte_count;
  1245. if (is_stream(file)) from_stream = YES;
  1246. else if (symbolp(file))
  1247. { file = get_pname(file);
  1248. errexit();
  1249. h = vechdr(file);
  1250. }
  1251. else if (!is_vector(file) ||
  1252. type_of_header(h = vechdr(file)) != TYPE_STRING)
  1253. return aerror("load-module");
  1254. current_module = file;
  1255. if (from_stream)
  1256. { Icontext(&save);
  1257. if (Iopen_from_stdin())
  1258. { err_printf("Failed to load module from stream\n");
  1259. Irestore_context(save);
  1260. return error(1, err_no_fasl, file);
  1261. }
  1262. push(qvalue(standard_input));
  1263. qvalue(standard_input) = file;
  1264. push(qvalue(echo_symbol));
  1265. qvalue(echo_symbol) = nil;
  1266. }
  1267. else
  1268. { len = length_of_header(h) - 4;
  1269. modname = (char *)file + 4 - TAG_VECTOR;
  1270. modname = trim_module_name(modname, &len);
  1271. Icontext(&save);
  1272. if (Iopen(modname, (int)len, YES, filename))
  1273. { err_printf("Failed to find \"%s\"\n", filename);
  1274. Irestore_context(save);
  1275. return error(1, err_no_fasl, file);
  1276. }
  1277. }
  1278. v = getvector_init((KEEP_RECENT+1)<<2, nil);
  1279. nil = C_nil;
  1280. if (exception_pending())
  1281. { IcloseInput(NO);
  1282. Irestore_context(save);
  1283. if (from_stream)
  1284. { flip_exception();
  1285. pop(qvalue(echo_symbol));
  1286. pop(qvalue(standard_input));
  1287. flip_exception();
  1288. }
  1289. return nil;
  1290. }
  1291. push(qvalue(work_symbol));
  1292. qvalue(work_symbol) = nil; /* list of functions loaded in source form */
  1293. /*
  1294. * I will account time spent fast-loading things as "storage management"
  1295. * overhead to be counted as "garbage collector time" rather than
  1296. * regular "cpu time"
  1297. */
  1298. push_clock();
  1299. if (verbos_flag & 2)
  1300. { freshline_trace();
  1301. if (sourceonly)
  1302. { if (from_stream) trace_printf("Loading source from a stream\n");
  1303. else trace_printf("Loading source for \"%s\"\n", filename);
  1304. }
  1305. else
  1306. { if (from_stream) trace_printf("Fast-loading from a stream\n");
  1307. else trace_printf("Fast-loading \"%s\"\n", filename);
  1308. }
  1309. }
  1310. push(CP);
  1311. push(faslvec);
  1312. faslvec = v;
  1313. push(faslgensyms);
  1314. faslgensyms = nil;
  1315. push(qvalue(savedef));
  1316. if (sourceonly) qvalue(savedef) = savedef;
  1317. just_reading_source = sourceonly;
  1318. recent_pointer = 0;
  1319. fasl_byte_count = 0;
  1320. skipping_input = 0;
  1321. for (;;)
  1322. { Lisp_Object r = fastread();
  1323. nil = C_nil;
  1324. if (exception_pending() || r == CHAR_EOF) break;
  1325. if (!sourceonly) voideval(r, nil);
  1326. nil = C_nil;
  1327. if (exception_pending()) break;
  1328. }
  1329. close_mode = YES;
  1330. if (exception_pending()) flip_exception(), close_mode = NO;
  1331. pop(qvalue(savedef));
  1332. pop(faslgensyms);
  1333. pop(faslvec);
  1334. pop(CP);
  1335. if (sourceonly) file = qvalue(work_symbol);
  1336. else file = nil;
  1337. pop(qvalue(work_symbol));
  1338. /* If something already smashed there is no joy in checking the checksum */
  1339. push(file);
  1340. IcloseInput(close_mode);
  1341. Irestore_context(save);
  1342. pop(file);
  1343. if (from_stream)
  1344. { pop(qvalue(echo_symbol));
  1345. pop(qvalue(standard_input));
  1346. }
  1347. recent_pointer = save_recent;
  1348. fasl_byte_count = save_byte_count;
  1349. gc_time += pop_clock();
  1350. if (!close_mode)
  1351. { flip_exception();
  1352. return nil;
  1353. }
  1354. return onevalue(file);
  1355. }
  1356. Lisp_Object Lload_source(Lisp_Object nil, Lisp_Object file)
  1357. {
  1358. return load_module(nil, file, 1);
  1359. }
  1360. Lisp_Object Lload_module(Lisp_Object nil, Lisp_Object file)
  1361. {
  1362. return load_module(nil, file, 0);
  1363. }
  1364. #ifdef DEBUG_FASL
  1365. static void IputcDebug(int c, int line)
  1366. {
  1367. Iputc(c);
  1368. trace_printf("Iputc(%d/%x/%s: %d %.8x %.8x)\n", c, c, fasl_code(c),
  1369. line, C_stack, C_nil);
  1370. }
  1371. #define Iputc(c) IputcDebug(c, __LINE__)
  1372. #endif
  1373. #ifndef DEMO_MODE
  1374. static void out_fasl_prefix(int32 n)
  1375. /*
  1376. * Used to generate any prefixes to cope with large operands in
  1377. * FASL streams
  1378. */
  1379. {
  1380. if (n != 0)
  1381. { out_fasl_prefix(n >> 8);
  1382. Iputc(F_EXT);
  1383. Iputc((int)(n & 0xff));
  1384. }
  1385. }
  1386. #endif
  1387. Lisp_Object Lmodule_exists(Lisp_Object nil, Lisp_Object file)
  1388. {
  1389. char filename[LONGEST_LEGAL_FILENAME], tt[32];
  1390. Header h;
  1391. int32 len;
  1392. int32 size;
  1393. char *modname;
  1394. if (symbolp(file))
  1395. { file = get_pname(file);
  1396. errexit();
  1397. h = vechdr(file);
  1398. }
  1399. else if (!is_vector(file) ||
  1400. type_of_header(h = vechdr(file)) != TYPE_STRING)
  1401. return aerror("modulep");
  1402. len = length_of_header(h) - 4;
  1403. modname = (char *)file + 4 - TAG_VECTOR;
  1404. modname = trim_module_name(modname, &len);
  1405. if (Imodulep(modname, (int)len, tt, &size, filename))
  1406. return onevalue(nil);
  1407. tt[24] = 0;
  1408. file = make_string(tt);
  1409. errexit();
  1410. return onevalue(file);
  1411. }
  1412. Lisp_Object Lstart_module(Lisp_Object nil, Lisp_Object name)
  1413. /*
  1414. * This must be called before write-module - it resets the table of recently-
  1415. * mentioned identifiers to be empty. Calling with a nil argument
  1416. * closes the current fasl file, otherwise the arg is the name of
  1417. * a file to open. It is not intended that ordinary programmers call
  1418. * this function - it is for use from within the compiler.
  1419. * As a special bit of magic the name passed can be a Lisp stream, in
  1420. * which case the module data will be written to it.
  1421. */
  1422. {
  1423. #ifdef DEMO_MODE
  1424. return onevalue(nil);
  1425. #else
  1426. Lisp_Object w;
  1427. #ifdef SOCKETS
  1428. /*
  1429. * Security measure - remote client can not do "FASLOUT" & start-module
  1430. */
  1431. if (socket_server != 0) return onevalue(nil);
  1432. #endif
  1433. recent_pointer = 0;
  1434. skipping_output = 0;
  1435. fp_rep_set = NO;
  1436. if (name == nil)
  1437. { if (fasl_output_file)
  1438. { int k = (int)Ioutsize() & 0x3;
  1439. /*
  1440. * Here I arrange that all FASL modules will end up being a multiple of
  1441. * 4 bytes long. "WHY?" Well I once suffered from a machine that was not
  1442. * very good at supporting odd-length data transfers (the suggestion I
  1443. * collected is that it MAY be because I had an early version of an 80386 CPU
  1444. * chip installed). The padding up here is not very painful and may avoid
  1445. * some painful trouble on my machine (and hence maybe on some other ones).
  1446. * The machine concerned is a PC and the chip and 80386, just in case you
  1447. * wondered. Zortech technical support were very helpful trying to
  1448. * track down the crashes I was having - even had they provided a software
  1449. * work-around in their code at some time I should leave this code and comment
  1450. * in CSL.
  1451. * Note (June 1992) I now have a computer with a newer CPU chip in it and
  1452. * the problem mentioned above does not arise - but it still seems reasonable
  1453. * to keep modules a multiple of 4 bytes long.
  1454. * Note (October 1995) Well, now I have a Pentium rather than a 386, and
  1455. * my previous 80486 system has gone down the feeding chain to replace the
  1456. * old and dodgy 80386. So sometime within the next year or so I will
  1457. * remove this comment, but still leave modules padded to multiples of
  1458. * 4 bytes since maybe I would introduce more bugs removing that than I would
  1459. * save.
  1460. * (January 1999) This little essay continues to entertain me. The 386 system
  1461. * happens to be around Cambridge again as a "relic" having been discarded as
  1462. * too old-fashioned and slow by pretty well everybody! Gosh how machines
  1463. * change during the life-time of a piece of software!
  1464. */
  1465. while (k != 3) k++, Iputc(F_NIL);
  1466. Iputc(F_END);
  1467. IcloseOutput();
  1468. faslvec = nil;
  1469. faslgensyms = nil;
  1470. fasl_output_file = NO;
  1471. fasl_stream = nil;
  1472. if (verbos_flag & 2)
  1473. { freshline_trace();
  1474. #ifdef COMMON
  1475. trace_printf(";; FASLEND: hits = %ld, misses = %ld\n",
  1476. (long)hits, (long)misses);
  1477. #else
  1478. trace_printf("+++ FASLEND: hits = %ld, misses = %ld\n",
  1479. (long)hits, (long)misses);
  1480. #endif
  1481. }
  1482. return onevalue(lisp_true);
  1483. }
  1484. else return onevalue(nil);
  1485. }
  1486. else if (is_stream(name))
  1487. { push(name);
  1488. w = getvector_init((KEEP_RECENT+1)<<2, nil);
  1489. pop(name);
  1490. errexit();
  1491. faslvec = w;
  1492. hits = misses = 0;
  1493. faslgensyms = nil;
  1494. fasl_stream = name;
  1495. fasl_output_file = YES;
  1496. return onevalue(lisp_true);
  1497. }
  1498. else
  1499. { char filename[LONGEST_LEGAL_FILENAME];
  1500. char *modname;
  1501. int32 len;
  1502. Header h;
  1503. push(name);
  1504. w = getvector_init((KEEP_RECENT+1)<<2, nil);
  1505. pop(name);
  1506. errexit();
  1507. faslvec = w;
  1508. hits = misses = 0;
  1509. faslgensyms = nil;
  1510. #ifdef COMMON
  1511. if (complex_stringp(name))
  1512. { name = simplify_string(name);
  1513. errexit();
  1514. h = vechdr(name);
  1515. }
  1516. else
  1517. #endif
  1518. if (symbolp(name))
  1519. { name = get_pname(name);
  1520. errexit();
  1521. h = vechdr(name);
  1522. }
  1523. else if (!(is_vector(name))) return aerror("start-module");
  1524. else if (type_of_header(h = vechdr(name)) != TYPE_STRING)
  1525. return aerror("start-module");
  1526. len = length_of_header(h) - 4;
  1527. modname = (char *)name + 4 - TAG_VECTOR;
  1528. /*
  1529. * Here I will play jolly games! The name as passed in to start-module will
  1530. * be allowed to be a fairly general file-name. If there is a suffix of the
  1531. * form ".xxx" on the end I will strip that off. If there is a directory-
  1532. * style component before that (as signalled by having a "/" or a "\" or
  1533. * another "." within the name) I will trim that off too. So the input
  1534. * string "/home/xxx/something.fsl" (say) would be treated exactly as if
  1535. * it had been just "something".
  1536. */
  1537. modname = trim_module_name(modname, &len);
  1538. if (len >= sizeof(filename)) len = sizeof(filename);
  1539. if (Iopen(modname, (int)len, NO, filename))
  1540. { err_printf("Failed to open \"%s\"\n", filename);
  1541. return onevalue(nil);
  1542. }
  1543. fasl_output_file = YES;
  1544. return onevalue(lisp_true);
  1545. }
  1546. #endif /* DEMO_MODE */
  1547. }
  1548. Lisp_Object Ldefine_in_module(Lisp_Object nil, Lisp_Object a)
  1549. {
  1550. #ifdef DEMO_MODE
  1551. return onevalue(nil);
  1552. #else
  1553. int32 args, opts, ntail;
  1554. #ifdef SOCKETS
  1555. /*
  1556. * Security measure - remote client can not do "define-in-module"
  1557. */
  1558. if (socket_server != 0) return onevalue(nil);
  1559. #endif
  1560. if (!is_fixnum(a)) return aerror("define-in-module");
  1561. if (a == fixnum_of_int(-1))
  1562. { Iputc(F_SDEF);
  1563. /*
  1564. * An expression preceeded with F_SDEF will be loaded again only if
  1565. * the variable "*savedef" is true at the time of loading, or if
  1566. * the load-source function is called and the function whose definition
  1567. * is involved has a load-source property.
  1568. */
  1569. skipping_output = 1;
  1570. return onevalue(nil);
  1571. }
  1572. skipping_output = 0;
  1573. args = int_of_fixnum(a);
  1574. opts = args >> 8;
  1575. ntail = opts >> 10;
  1576. if (ntail != 0)
  1577. return aerror("tailcall magic not supported in FASL files yet");
  1578. opts &= 0x3ff;
  1579. if (opts == 0) switch (args & 0xff)
  1580. {
  1581. case 0: Iputc(F_DEF0);
  1582. break;
  1583. case 1: Iputc(F_DEF1);
  1584. break;
  1585. case 2: Iputc(F_DEF2);
  1586. break;
  1587. case 3: Iputc(F_DEF3);
  1588. break;
  1589. default:Iputc(F_DEFN);
  1590. break;
  1591. }
  1592. else switch (opts >> 8)
  1593. {
  1594. default:
  1595. case 0: Iputc(F_DEFOPT);
  1596. break;
  1597. case 1: Iputc(F_DEFHOPT);
  1598. break;
  1599. case 2: Iputc(F_DEFREST);
  1600. break;
  1601. case 3: Iputc(F_DEFHREST);
  1602. break;
  1603. }
  1604. return onevalue(nil);
  1605. #endif /* DEMO_MODE */
  1606. }
  1607. #ifdef DEBUG_FASL
  1608. static void IwriteDebug(char *x, int n, int line)
  1609. {
  1610. int i;
  1611. Iwrite(x, n);
  1612. trace_printf("Iwrite %d %.8x %.8x", line, C_nil, C_stack);
  1613. for (i=0; i<n ;i++)
  1614. { trace_printf(" %d/%x", x[i], x[i]);
  1615. if (32 <= x[i] && x[i] < 0x7f) trace_printf("/'%c'", x[i]);
  1616. }
  1617. trace_printf("\n");
  1618. }
  1619. #define Iwrite(x, n) IwriteDebug(x, n, __LINE__)
  1620. #endif
  1621. #ifndef DEMO_MODE
  1622. static Lisp_Object write_module1(Lisp_Object a)
  1623. {
  1624. Lisp_Object nil = C_nil;
  1625. if (is_bfloat(a))
  1626. { Header h = flthdr(a);
  1627. if (!fp_rep_set)
  1628. { fp_rep_set = YES;
  1629. Iputc(F_REP);
  1630. Iputc(current_fp_rep & 0xff);
  1631. Iputc((current_fp_rep >> 8) & 0xff);
  1632. }
  1633. switch (type_of_header(h))
  1634. {
  1635. default:
  1636. return aerror("unrecognized FP number type");
  1637. #ifdef COMMON
  1638. case TYPE_SINGLE_FLOAT:
  1639. Iputc(F_FPF);
  1640. Iwrite((char *)a + 4L - TAG_BOXFLOAT, 4);
  1641. break;
  1642. #endif
  1643. case TYPE_DOUBLE_FLOAT:
  1644. Iputc(F_FPD);
  1645. Iwrite((char *)a + 8L - TAG_BOXFLOAT, 8);
  1646. break;
  1647. #ifdef COMMON
  1648. case TYPE_LONG_FLOAT:
  1649. Iputc(F_FPL);
  1650. Iwrite((char *)a + 4L - TAG_BOXFLOAT, 12);
  1651. break;
  1652. #endif
  1653. }
  1654. }
  1655. else if (is_char(a))
  1656. { Iputc(F_CHAR);
  1657. /*
  1658. * Note that for somewhat dubious reasons I have separated out the
  1659. * end of file character earlier on and treated it oddly.
  1660. */
  1661. Iputc((int)bits_of_char(a));
  1662. Iputc((int)font_of_char(a));
  1663. Iputc((int)code_of_char(a));
  1664. }
  1665. else if (is_bps(a))
  1666. { char *d = data_of_bps(a);
  1667. int32 len = length_of_header(*(Header *)(d - 4)) - 4;
  1668. switch (len >> 8)
  1669. {
  1670. case 3: Iputc(F_BP3);
  1671. break;
  1672. case 2: Iputc(F_BP2);
  1673. break;
  1674. case 1: Iputc(F_BP1);
  1675. break;
  1676. default:
  1677. out_fasl_prefix(len >> 8);
  1678. Iputc(F_BP0);
  1679. break;
  1680. }
  1681. Iputc((int)(len & 0xff));
  1682. Iwrite(d, len);
  1683. }
  1684. else if (is_vector(a))
  1685. { Header h = vechdr(a);
  1686. int32 len = length_of_header(h) - 4, i;
  1687. switch (type_of_header(h))
  1688. {
  1689. case TYPE_STRING:
  1690. out_fasl_prefix(len >> 8);
  1691. Iputc(F_STR);
  1692. Iputc((int)(len & 0xff));
  1693. Iwrite((char *)a + 4 - TAG_VECTOR, len);
  1694. break;
  1695. case TYPE_HASH: /* Writing these may be easy... */
  1696. case TYPE_SIMPLE_VEC:
  1697. case TYPE_STRUCTURE:
  1698. len /= 4;
  1699. out_fasl_prefix(len >> 8);
  1700. Iputc(type_of_header(h) == TYPE_HASH ? F_HASH :
  1701. type_of_header(h) == TYPE_STRUCTURE ? F_STRUCT : F_VEC);
  1702. Iputc((int)(len & 0xff));
  1703. for (i=0; i<len; i++)
  1704. { push(a);
  1705. Lwrite_module(nil, elt(a, i));
  1706. pop(a);
  1707. errexit();
  1708. }
  1709. break;
  1710. default:
  1711. /*
  1712. * The explicit enumeration of left-over cases is here ready for when
  1713. * (or if!) I ever decide to extend the FASL format to support these
  1714. * extra types. Until I do please note that Common Lisp arrays and
  1715. * bit-vectors can not be coped with here.
  1716. */
  1717. #ifdef COMMON
  1718. case TYPE_ARRAY:
  1719. case TYPE_BITVEC1:
  1720. case TYPE_BITVEC2:
  1721. case TYPE_BITVEC3:
  1722. case TYPE_BITVEC4:
  1723. case TYPE_BITVEC5:
  1724. case TYPE_BITVEC6:
  1725. case TYPE_BITVEC7:
  1726. case TYPE_BITVEC8:
  1727. #endif
  1728. case TYPE_MIXED1:
  1729. case TYPE_MIXED2:
  1730. return aerror("vector type unsupported by write-module");
  1731. }
  1732. }
  1733. else return aerror("write-module");
  1734. return nil;
  1735. }
  1736. #endif /* DEMO_MODE */
  1737. Lisp_Object Lwrite_module(Lisp_Object nil, Lisp_Object a)
  1738. /*
  1739. * write one expression to the currently selected output stream.
  1740. * That stream ought to have been opened using start-module, and is
  1741. * binary (i.e. no record separators or concern about record length
  1742. * must intrude).
  1743. */
  1744. {
  1745. #ifdef DEMO_MODE
  1746. return onevalue(nil);
  1747. #else
  1748. #ifdef SOCKETS
  1749. /*
  1750. * Security measure - remote client can not do "write-module"
  1751. */
  1752. if (socket_server != 0) return onevalue(nil);
  1753. #endif
  1754. if (a == nil) Iputc(F_NIL);
  1755. else if (a == lisp_true) Iputc(F_TRU);
  1756. else if (a == CHAR_EOF) Iputc(F_END);
  1757. /*
  1758. * In Common Lisp mode there will be a certain amount of horrible fun with
  1759. * symbols and the package system. But a symbol that is EQ to one recently
  1760. * processed can be handled that way regardless.
  1761. */
  1762. else if (is_symbol(a))
  1763. { int32 i, len;
  1764. Lisp_Object w, w1;
  1765. int pkgid = 0;
  1766. int32 k;
  1767. #ifdef COMMON
  1768. int32 lenp;
  1769. #endif
  1770. for (i=0; i<KEEP_RECENT; i++)
  1771. { int32 w = recent_pointer - i;
  1772. if (w < 0) w += KEEP_RECENT;
  1773. if (a == elt(faslvec, w))
  1774. { Iputc((int)(F_OLD+i));
  1775. hits++;
  1776. return onevalue(nil);
  1777. }
  1778. }
  1779. push(a);
  1780. w = get_pname(a);
  1781. pop(a);
  1782. errexit();
  1783. /*
  1784. * The FASL mechanism does not in general preserve EQness. In particular
  1785. * cyclic structures will upset it, and multiple references to the same
  1786. * string or float (etc) will read back as distinct entities. However
  1787. * within one S-expression I will arrange that uninterned symbols are
  1788. * handled tolerably cleanly... The first time such a symbol is written
  1789. * its name is dumped in the file. When this is read back a new uninterned
  1790. * symbol with that name is created. Usually the next few uses will use
  1791. * the "recently referenced symbol" mechanism, and so will refer back to
  1792. * this value. For gensyms I extend the usual cyclic buffer that holds the
  1793. * recently mentioned symbols with a fall-back list of mentioned gensyms,
  1794. * and refer into that using F_EXT followed by a "recent" reference. This
  1795. * mechanism gets activated especially if the FASL file contains a
  1796. * macro-expanded but not compiled form where the expansion introduces
  1797. * gensyms as labels etc.
  1798. */
  1799. #ifdef COMMON
  1800. /*
  1801. * The code here is expected to match that in print.c. It sets pkgid to
  1802. * indicate how the symbol involved needs to be put into the FASL file.
  1803. * My byte format there is optimised for the case where no package marker
  1804. * is needed. The values of pkgid are:
  1805. * 0 no package marker needed
  1806. * 1 display as #:xxx (ie as a gensym)
  1807. * 2 display as :xxx (ie in keyword package)
  1808. * 3 display as ppp:xxx (external in its home package)
  1809. * 4 display as ppp::xxx (internal in its home package)
  1810. */
  1811. if (qpackage(a) == nil)
  1812. { for (w1 = faslgensyms, k=0; w1!=nil; w1=qcdr(w1), k++)
  1813. { if (qcar(w1) == a)
  1814. { out_fasl_prefix(1 + (k>>7));
  1815. Iputc((int)(F_OLD+(k & 0x7f)));
  1816. #ifdef DEBUG_FASL
  1817. trace_printf("++ Ancient FASL gensym ref %d\n", k);
  1818. #endif
  1819. hits++;
  1820. return onevalue(nil);
  1821. }
  1822. }
  1823. pkgid = 1; /* gensym */
  1824. }
  1825. else if (qpackage(a) == qvalue(keyword_package)) pkgid = 2;
  1826. else if (qpackage(a) == CP) pkgid = 0; /* home is current */
  1827. else
  1828. { pkgid = 3;
  1829. k = packflags_(CP);
  1830. if (k != 0 && k <= 10)
  1831. { k = ((int32)1) << (k+SYM_IN_PKG_SHIFT-1);
  1832. if (k & qheader(a)) pkgid = 0;
  1833. }
  1834. else k = 0;
  1835. if (pkgid != 0)
  1836. { push2(a, w);
  1837. w1 = Lfind_symbol_1(nil, w);
  1838. pop2(w, a);
  1839. errexit();
  1840. if (mv_2 != nil && w1 == a)
  1841. { pkgid = 0;
  1842. qheader(a) |= k;
  1843. }
  1844. else if (qheader(a) & SYM_EXTERN_IN_HOME) pkgid = 3;
  1845. else pkgid = 4;
  1846. }
  1847. }
  1848. misses++;
  1849. if (skipping_output == 0 && pkgid == 1)
  1850. { recent_pointer++;
  1851. if (recent_pointer == KEEP_RECENT) recent_pointer = 0;
  1852. w1 = elt(faslvec, recent_pointer);
  1853. if (qpackage(w1) == nil)
  1854. { push(a);
  1855. #ifdef DEBUG_FASL
  1856. trace_printf("recording gensym ");
  1857. prin_to_trace(w1);
  1858. trace_printf("\n");
  1859. #endif
  1860. w1 = cons(w1, faslgensyms);
  1861. pop(a);
  1862. errexit();
  1863. faslgensyms = w1;
  1864. }
  1865. elt(faslvec, recent_pointer) = a;
  1866. #ifdef DEBUG_FASL
  1867. trace_printf("recording ");
  1868. prin_to_trace(a);
  1869. trace_printf("\n");
  1870. #endif
  1871. }
  1872. len = length_of_header(vechdr(w)) - 4;
  1873. switch (pkgid)
  1874. {
  1875. case 0: if (1 <= len && len <= 15) Iputc(F_ID1 + (int)len - 1);
  1876. else
  1877. { out_fasl_prefix(len >> 8);
  1878. Iputc(F_SYM);
  1879. Iputc((int)(len & 0xff));
  1880. }
  1881. lenp = -1;
  1882. break;
  1883. case 1: out_fasl_prefix(len >> 8);
  1884. Iputc(F_PKGINT);
  1885. Iputc(0);
  1886. lenp = 0;
  1887. break;
  1888. case 2: out_fasl_prefix(len >> 8);
  1889. Iputc(F_PKGEXT);
  1890. Iputc(0);
  1891. lenp = 0;
  1892. break;
  1893. case 3: out_fasl_prefix(len >> 8);
  1894. Iputc(F_PKGEXT);
  1895. lenp = 1;
  1896. break;
  1897. case 4: out_fasl_prefix(len >> 8);
  1898. Iputc(F_PKGINT);
  1899. lenp = 1;
  1900. break;
  1901. }
  1902. if (lenp > 0)
  1903. { push(w);
  1904. a = packname_(qpackage(a));
  1905. pop(w);
  1906. errexit();
  1907. lenp = length_of_header(vechdr(a)) - 4;
  1908. /*
  1909. * Another ugliness rears its head here... I allow for symbols that have
  1910. * very long names, but I will only support packages where the name of the
  1911. * package is less then 256 characters. This is so I can use a one-byte
  1912. * counter to indicate its length. If I REALLY have to I can put in
  1913. * support for ultra-long names for packages, but the mess involved
  1914. * seems offensive at the moment. I truncate any over-long package name
  1915. * at 255 here. Silently.
  1916. */
  1917. if (lenp > 255) lenp = 255;
  1918. Iputc(lenp);
  1919. Iputc((int)(len & 255));
  1920. Iwrite((char *)a + 4 - TAG_VECTOR, lenp);
  1921. }
  1922. else if (lenp == 0) Iputc((int)(len & 0xff));
  1923. Iwrite((char *)w + 4 - TAG_VECTOR, len);
  1924. #else
  1925. /*
  1926. * In Standard Lisp mode things that were gensyms in the original
  1927. * will probably get read back in as ordinary symbols. This at least
  1928. * ensures that multiple references to the same gensym end up matching, and
  1929. * it is less effort than the Common Lisp solution...
  1930. * Actually I am now finding this to be UNSATISFACTORY and am going to
  1931. * change it to be much more like the behaviour I have in the COMMON case.
  1932. */
  1933. if ((qheader(a) & SYM_ANY_GENSYM) != 0)
  1934. { for (w1 = faslgensyms, k=0; w1!=nil; w1=qcdr(w1), k++)
  1935. { if (qcar(w1) == a)
  1936. { out_fasl_prefix(1 + (k>>7));
  1937. Iputc((int)(F_OLD+(k & 0x7f)));
  1938. #ifdef DEBUG_FASL
  1939. trace_printf("++ Ancient FASL gensym ref %d\n", k);
  1940. #endif
  1941. hits++;
  1942. return onevalue(nil);
  1943. }
  1944. }
  1945. pkgid = 1; /* gensym */
  1946. }
  1947. misses++;
  1948. /*
  1949. * See commoent where F_GENSYM is read to understand why gensyms must be
  1950. * recorded even when skipping...
  1951. */
  1952. if (skipping_output == 0 || pkgid == 1)
  1953. { recent_pointer++;
  1954. if (recent_pointer == KEEP_RECENT) recent_pointer = 0;
  1955. w1 = elt(faslvec, recent_pointer);
  1956. if ((qheader(w1) & SYM_ANY_GENSYM) != 0)
  1957. { push(a);
  1958. #ifdef DEBUG_FASL
  1959. trace_printf("recording gensym ");
  1960. prin_to_trace(w1);
  1961. trace_printf("\n");
  1962. #endif
  1963. w1 = cons(w1, faslgensyms);
  1964. pop(a);
  1965. errexit();
  1966. faslgensyms = w1;
  1967. }
  1968. elt(faslvec, recent_pointer) = a;
  1969. #ifdef DEBUG_FASL
  1970. trace_printf("recording ");
  1971. prin_to_trace(a);
  1972. trace_printf("\n");
  1973. #endif
  1974. }
  1975. len = length_of_header(vechdr(w)) - 4;
  1976. if (pkgid == 0)
  1977. { if (1 <= len && len <= 15) Iputc(F_ID1 + (int)len - 1);
  1978. else
  1979. { out_fasl_prefix(len >> 8);
  1980. Iputc(F_SYM);
  1981. Iputc((int)(len & 0xff));
  1982. }
  1983. }
  1984. else
  1985. { out_fasl_prefix(len >> 8); /* here it is a gensym */
  1986. Iputc(F_GENSYM);
  1987. Iputc((int)(len & 0xff));
  1988. }
  1989. Iwrite((char *)w + 4 - TAG_VECTOR, len);
  1990. #endif
  1991. }
  1992. else if (is_cons(a))
  1993. { int32 len, i;
  1994. Lisp_Object cara = qcar(a), cdra = qcdr(a);
  1995. if (cara == quote_symbol && consp(cdra) && qcdr(cdra) == nil)
  1996. { Iputc(F_QUT);
  1997. return Lwrite_module(nil, qcar(cdra));
  1998. }
  1999. len = 1;
  2000. while (consp(cdra)) len++, cdra = qcdr(cdra);
  2001. out_fasl_prefix(len >> 8);
  2002. if (cdra == nil)
  2003. { switch (len)
  2004. {
  2005. case 1:
  2006. Iputc(F_LS1);
  2007. break;
  2008. case 2:
  2009. Iputc(F_LS2);
  2010. break;
  2011. case 3:
  2012. Iputc(F_LS3);
  2013. break;
  2014. case 4:
  2015. Iputc(F_LS4);
  2016. break;
  2017. default:
  2018. Iputc(F_LST);
  2019. Iputc((int)(len & 0xff));
  2020. break;
  2021. }
  2022. }
  2023. else
  2024. { Iputc(F_DOT);
  2025. Iputc((int)(len & 0xff));
  2026. push(a);
  2027. stackcheck1(1, cdra);
  2028. Lwrite_module(nil, cdra);
  2029. pop(a);
  2030. errexit();
  2031. }
  2032. cdra = nil;
  2033. for (i=0; i<len; i++)
  2034. { push(a);
  2035. cdra = cons(qcar(a), cdra);
  2036. pop(a);
  2037. errexit();
  2038. a = qcdr(a);
  2039. }
  2040. for (i=0; i<len; i++)
  2041. { push(cdra);
  2042. Lwrite_module(nil, qcar(cdra));
  2043. pop(cdra);
  2044. errexit();
  2045. cdra = qcdr(cdra);
  2046. }
  2047. }
  2048. else if (is_fixnum(a))
  2049. { int32 n = int_of_fixnum(a);
  2050. CSLbool sign;
  2051. /*
  2052. * The fixnum range is 0xf8000000 to 0x07ffffff
  2053. */
  2054. if (n < 0) n = -n, sign = YES;
  2055. else sign = NO;
  2056. out_fasl_prefix(n >> 8);
  2057. Iputc(sign ? F_NEG : F_INT);
  2058. Iputc((int)(n & 0xff));
  2059. }
  2060. else if (is_numbers(a))
  2061. { Header h = numhdr(a);
  2062. int32 len, i;
  2063. switch (type_of_header(h))
  2064. {
  2065. default:
  2066. return aerror("unrecognized number type");
  2067. #ifdef COMMON
  2068. case TYPE_RATNUM:
  2069. Iputc(F_RAT);
  2070. break;
  2071. case TYPE_COMPLEX_NUM:
  2072. Iputc(F_CPX);
  2073. break;
  2074. #endif
  2075. case TYPE_BIGNUM:
  2076. len = length_of_header(h) - 4;
  2077. out_fasl_prefix(len >> 8);
  2078. Iputc(F_BIG);
  2079. Iputc((int)(len & 0xff));
  2080. /*
  2081. * I write out the value byte by byte so that the binary in the file
  2082. * does not depend on the byte-ordering used by the host computer.
  2083. */
  2084. for (i=0; i<len; i+=4)
  2085. { unsigned32 v =
  2086. *(unsigned32 *)((char *)a + 4L - TAG_NUMBERS + i);
  2087. Iputc((int)(v >> 24) & 0xff);
  2088. Iputc((int)(v >> 16) & 0xff);
  2089. Iputc((int)(v >> 8) & 0xff);
  2090. Iputc((int)v & 0xff);
  2091. }
  2092. return onevalue(nil);
  2093. }
  2094. #ifdef COMMON
  2095. Lwrite_module(nil, *(Lisp_Object *)((char *)a + 4L - TAG_NUMBERS));
  2096. errexit();
  2097. return Lwrite_module(nil,
  2098. *(Lisp_Object *)((char *)a + 8L - TAG_NUMBERS));
  2099. #endif
  2100. }
  2101. #ifdef COMMON
  2102. else if (is_sfloat(a))
  2103. { Lisp_Object w = a;
  2104. /*
  2105. * I write out floating point values in whatever the natural host
  2106. * representation is - but prefix the first FP value with a marker that
  2107. * identifies what that representation is so that when the file is re-loaded
  2108. * a conversion can be applied as necessary.
  2109. */
  2110. if (!fp_rep_set)
  2111. { fp_rep_set = YES;
  2112. Iputc(F_REP);
  2113. Iputc(current_fp_rep & 0xff);
  2114. Iputc((current_fp_rep >> 8) & 0xff);
  2115. }
  2116. Iputc(F_FPS);
  2117. Iwrite((char *)&w, 4);
  2118. }
  2119. #endif
  2120. else write_module1(a);
  2121. return onevalue(nil);
  2122. #endif /* DEMO_MODE */
  2123. }
  2124. /*
  2125. * (set-help-file "key" "path") puts an extra help file on the cwin
  2126. * HELP menu. If "path" is NIL then the item specified by "key" is
  2127. * removed. If "key" is NIL then all user-inserted items are removed.
  2128. */
  2129. Lisp_Object Lset_help_file(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
  2130. {
  2131. #ifdef CWIN
  2132. char *w, *aa, *bb = NULL;
  2133. int32 lena, lenb;
  2134. if (a != nil)
  2135. { w = get_string_data(a, "set-help-file", &lena);
  2136. errexit();
  2137. aa = (char *)malloc(lena+1);
  2138. if (aa == NULL) return aerror("set-help-file");
  2139. memcpy(aa, w, lena);
  2140. aa[lena] = 0;
  2141. }
  2142. else
  2143. { aa = NULL;
  2144. b = nil;
  2145. }
  2146. if (b != nil)
  2147. { w = get_string_data(b, "set-help-file", &lenb);
  2148. errexit();
  2149. bb = (char *)malloc(lenb+1);
  2150. if (bb == NULL) return aerror("set-help-file");
  2151. memcpy(bb, w, lenb);
  2152. bb[lenb] = 0;
  2153. }
  2154. cwin_set_help_file(aa, bb);
  2155. #endif
  2156. return onevalue(nil);
  2157. }
  2158. #ifdef NO_HELP_SYSTEM
  2159. #undef HELP_SYSTEM
  2160. #else
  2161. #ifndef HELP_SYSTEM
  2162. # define HELP_SYSTEM 1 /* Always enabled, now */
  2163. #endif
  2164. #endif
  2165. #ifdef HELP_SYSTEM
  2166. /*
  2167. * write-help-module (now) takes as argument a file-name. It expects the
  2168. * file to be in INFO format. It copies the text from the file into
  2169. * a section of the image file and builds an index (which will remain in
  2170. * memory).
  2171. */
  2172. /*
  2173. * write-help-module has two arguments here because the previous version did
  2174. * and changing that would cause short-term confusion...
  2175. */
  2176. #ifndef DEMO_MODE
  2177. static void merge_sort(char *a, char *b, int left, int right)
  2178. {
  2179. int next = left+8, mid, i, j;
  2180. if (left==right) return; /* Empty vector to sort */
  2181. while (next < right && a[next] != 0) next += 8;
  2182. if (next >= right) return; /* Only one item there */
  2183. mid = ((left+right)/2) & ~7;
  2184. if (mid <= next) mid = next;
  2185. else while (a[mid] != 0) mid -= 8;
  2186. /*
  2187. * Now (left..mid) is non-empty because mid >= next, and (mid..right) is not
  2188. * empty because mid rounded downwards and the vector has at least two
  2189. * items in it.
  2190. */
  2191. merge_sort(a, b, left, mid);
  2192. merge_sort(a, b, mid, right);
  2193. for (i=left; i<=right; i++) b[i] = a[i];
  2194. i = left; j = mid; next = left;
  2195. /* Now merge back from b to a */
  2196. while (i < mid && j < right)
  2197. { int i1 = i+4, j1=j+4, k;
  2198. for (k=0; k<28; k++)
  2199. { if (b[i1] != b[j1]) break;
  2200. i1++;
  2201. j1++;
  2202. }
  2203. if (b[i1] <= b[j1])
  2204. { do
  2205. { *(int32 *)(&a[next]) = *(int32 *)(&b[i]);
  2206. *(int32 *)(&a[next+4]) = *(int32 *)(&b[i+4]);
  2207. next += 8;
  2208. i += 8;
  2209. } while (b[i] != 0);
  2210. }
  2211. else
  2212. { do
  2213. { *(int32 *)(&a[next]) = *(int32 *)(&b[j]);
  2214. *(int32 *)(&a[next+4]) = *(int32 *)(&b[j+4]);
  2215. next += 8;
  2216. j += 8;
  2217. } while (b[j] != 0);
  2218. }
  2219. }
  2220. while (i < mid) a[next++] = b[i++];
  2221. while (j < right) a[next++] = b[j++];
  2222. }
  2223. /*
  2224. * To get some sort of compression on the help text I will collect
  2225. * statistics about which pairs of characters occur adjacent to one
  2226. * another. I will first use an array of 256*256 unsigned characters. When
  2227. * a particular pair records 255 in this count field I will enter it in
  2228. * an overflow hash table. The space for each of these tables will be
  2229. * grabbed using malloc(), so if you try to build a help database on
  2230. * a machine where grabbing an extra 100K of memory is awkward then you
  2231. * may be out of luck.
  2232. */
  2233. typedef struct char_pair_hash
  2234. {
  2235. char c1, c2;
  2236. int32 count;
  2237. } char_pair_hash;
  2238. /*
  2239. * I observe (having done the experiment) that the REDUCE help database
  2240. * causes overflow for somewhat under 400 character-pairs. Thus a hash
  2241. * table with room for twice that number should suffice for now. Note that
  2242. * an utterly worst-case file would have to be over 256Kbytes long for
  2243. * more than 1000 character pairs each to occur over 256 times, and all
  2244. * realistic text files will be a very long way from that case. If, by
  2245. * mistake, one fed this code a file that was already compressed it would
  2246. * collapse with an overfull hash table. Tough luck - in such cases I will
  2247. * just deliver slightly silly results.
  2248. */
  2249. #define OVERFLOW_SIZE 1000
  2250. #define PASS_COUNT 12
  2251. static int MS_CDECL compare_char_counts(void const *aa, void const *bb)
  2252. {
  2253. return ((char_pair_hash *)bb)->count -
  2254. ((char_pair_hash *)aa)->count;
  2255. }
  2256. #define INFO_CHAR ('_' & 0x1f)
  2257. #endif /* DEMO_MODE */
  2258. Lisp_Object Lwrite_help_module(Lisp_Object nil,
  2259. Lisp_Object name, Lisp_Object ignore)
  2260. {
  2261. #ifdef DEMO_MODE
  2262. return onevalue(nil);
  2263. #else
  2264. int i, c1, c2, c3, pass, linep;
  2265. int32 info_seen;
  2266. unsigned char cx1[256], cx2[256];
  2267. char buff[16], line[256];
  2268. /*
  2269. * There can be no more than 256 items put in the coded[] hash table, and
  2270. * in general I expect it to be considerably less than that. So having the
  2271. * table of size 409 (a prime) guarantees it will never get too full so
  2272. * performance ought to be pretty good.
  2273. */
  2274. #define CODED_SIZE 409
  2275. char_pair_hash coded[CODED_SIZE];
  2276. int32 buffp;
  2277. Ihandle save;
  2278. Lisp_Object v = nil, v1;
  2279. int32 indexlength, saving;
  2280. int32 helpsize = 0, len;
  2281. char filename[LONGEST_LEGAL_FILENAME];
  2282. Header h;
  2283. FILE *file;
  2284. unsigned char *frequencies;
  2285. char_pair_hash *overflow;
  2286. CSL_IGNORE(ignore);
  2287. #ifdef SOCKETS
  2288. /*
  2289. * Security measure - remote client can not do write-help-module"
  2290. */
  2291. if (socket_server != 0) return onevalue(nil);
  2292. #endif
  2293. #ifdef COMMON
  2294. if (complex_stringp(name))
  2295. { name = simplify_string(name);
  2296. errexit();
  2297. h = vechdr(name);
  2298. }
  2299. else
  2300. #endif
  2301. if (symbolp(name))
  2302. { name = get_pname(name);
  2303. errexit();
  2304. h = vechdr(name);
  2305. }
  2306. else if (!(is_vector(name))) return aerror("write-help-module");
  2307. else if (type_of_header(h = vechdr(name)) != TYPE_STRING)
  2308. return aerror("write-help-module");
  2309. len = length_of_header(h) - 4;
  2310. if (len > sizeof(filename)) len = sizeof(filename);
  2311. file = open_file(filename, (char *)name + (4-TAG_VECTOR),
  2312. (size_t)len, "r", NULL);
  2313. if (file == NULL) return aerror("write-help-module");
  2314. Icontext(&save);
  2315. if (Iopen_help(-1)) /* Open help sub-file for writing */
  2316. { Irestore_context(save);
  2317. fclose(file);
  2318. return aerror("Unable to open help file");
  2319. }
  2320. for (i=0; i<CODED_SIZE; i++)
  2321. { coded[i].c1 = coded[i].c2 = 0;
  2322. coded[i].count = 0;
  2323. }
  2324. frequencies = (unsigned char *)malloc(0x10000);
  2325. overflow = (char_pair_hash *)malloc(OVERFLOW_SIZE*sizeof(char_pair_hash));
  2326. if (frequencies == NULL || overflow == NULL)
  2327. { Irestore_context(save);
  2328. fclose(file);
  2329. free((void *)frequencies);
  2330. free((void *)overflow);
  2331. return aerror("Not enough memory to build help database");
  2332. }
  2333. for (i=0; i<256; i++) cx1[i] = cx2[i] = 0;
  2334. for (pass=1; pass<=PASS_COUNT; pass++)
  2335. { term_printf("Start of pass %d\n", pass);
  2336. if (pass == PASS_COUNT)
  2337. { v = getvector(TAG_VECTOR, TYPE_STRING, 8+indexlength);
  2338. nil = C_nil;
  2339. /*
  2340. * I will get another vectors the same size so that I have plenty of
  2341. * space for a simple-minded implementation of merge-sort.
  2342. */
  2343. if (!exception_pending())
  2344. { push(v);
  2345. v1 = getvector(TAG_VECTOR, TYPE_STRING, 8+indexlength);
  2346. pop(v);
  2347. }
  2348. nil = C_nil;
  2349. if (exception_pending())
  2350. { flip_exception();
  2351. IcloseOutput();
  2352. Irestore_context(save);
  2353. fclose(file);
  2354. free((void *)frequencies);
  2355. free((void *)overflow);
  2356. flip_exception();
  2357. return nil;
  2358. }
  2359. }
  2360. indexlength = 512;
  2361. fseek(file, SEEK_SET, 0L);
  2362. for (i=0; i<0x10000; i++) frequencies[i] = 0;
  2363. for (i=0; i<OVERFLOW_SIZE; i++)
  2364. { overflow[i].c1 = overflow[i].c2 = 0;
  2365. overflow[i].count = 0;
  2366. }
  2367. for (i=0; i<16; i++) buff[i] = 0;
  2368. buffp = 0;
  2369. i = 100;
  2370. saving = 0;
  2371. /* An "info" file has a little header at the top - skip that */
  2372. while ((c2 = getc(file)) != EOF &&
  2373. c2 != INFO_CHAR) /* do nothing */;
  2374. c2 = getc(file); /* newline following the ^_ */
  2375. linep = 0;
  2376. info_seen = 0;
  2377. while ((c2 = getc(file)) != EOF)
  2378. { unsigned32 x;
  2379. int n;
  2380. if (c2 == '\n')
  2381. { line[linep] = 0;
  2382. if (linep == 1 && line[0] == INFO_CHAR)
  2383. { int32 bp = buffp;
  2384. /*
  2385. * I flush the compression look-ahead buffer when I find a "^_" record
  2386. * so that the break between help topics is on a real byte boundary and so
  2387. * that I can tell where in the help file this boundary will fall.
  2388. */
  2389. for (;;)
  2390. { bp++;
  2391. c1 = buff[bp & 15];
  2392. buff[bp & 15] = 0;
  2393. if (c1 == 0) break;
  2394. if (pass == PASS_COUNT)
  2395. { if (c1 == INFO_CHAR) Iputc(0);
  2396. else Iputc(c1);
  2397. helpsize++;
  2398. }
  2399. }
  2400. info_seen = helpsize;
  2401. linep = 0;
  2402. continue; /* Throws away the '\n' after '^_' */
  2403. }
  2404. else if (info_seen >= 0)
  2405. { if (strcmp(line, "Tag Table:") == 0) break;
  2406. /*
  2407. * Here I must spot "File:" lines and count the size of the node name and/or
  2408. * insert it in the index vector.
  2409. */
  2410. if (strncmp(line, "File: ", 6) == 0)
  2411. { linep = linep-6;
  2412. while (linep>0 &&
  2413. strncmp(&line[linep], "Node: ", 6) != 0)
  2414. linep--;
  2415. if (linep != 0)
  2416. { char *node = &line[linep+6];
  2417. int nodelen = 0;
  2418. /*
  2419. * I will force node labels into upper case here. I use upper rather than
  2420. * lower case mainly because it turns out to make it easier for me to compare
  2421. * the sorted order of my key-table with the order imposed by a (DOS) sort
  2422. * utility I have. In particular it makes the collating order of '_' with
  2423. * letters compatible with the independent external utility.
  2424. */
  2425. while (node[nodelen] != ',' &&
  2426. node[nodelen] != 0)
  2427. { node[nodelen] = toupper(node[nodelen]);
  2428. nodelen++;
  2429. }
  2430. if (nodelen > 28) nodelen = 28;
  2431. if (pass == PASS_COUNT)
  2432. { ucelt(v, indexlength++) = 0;
  2433. ucelt(v, indexlength++) = info_seen & 0xff;
  2434. ucelt(v, indexlength++) = (info_seen >> 8) & 0xff;
  2435. ucelt(v, indexlength++) = (info_seen >> 16) & 0xff;
  2436. #ifdef DEBUG_HELP_SYSTEM
  2437. term_printf("Node(%.*s) position %d\n",
  2438. nodelen, node, info_seen);
  2439. #endif
  2440. while (nodelen-- != 0)
  2441. celt(v, indexlength++) = *node++;
  2442. while (indexlength & 7)
  2443. celt(v, indexlength++) = 0;
  2444. }
  2445. else indexlength = indexlength +
  2446. ((nodelen + 11) & ~7);
  2447. }
  2448. }
  2449. info_seen = -1;
  2450. }
  2451. else info_seen = -1;
  2452. linep = 0;
  2453. }
  2454. else if (linep < 255) line[linep++] = c2;
  2455. /*
  2456. * I truncate lines at 255 characters. This is not so comfortable as all that!
  2457. * The Reduce Help Database ends up with lines of up to 195 characters long,
  2458. * in cases where the names of several adjacent sections are all ridiculously
  2459. * long.
  2460. */
  2461. cx1[c2] = c2;
  2462. for (;;)
  2463. { c3 = buff[(buffp-1) & 15];
  2464. if (c3 != 0)
  2465. { int c4 = 0;
  2466. int32 hash = ((((c3 & 0xff)<<8)+
  2467. (c2 & 0xff))*32359) % CODED_SIZE;
  2468. for (;;)
  2469. { if (coded[hash].count == 0) break;
  2470. else if (coded[hash].c1 == c3 &&
  2471. coded[hash].c2 == c2)
  2472. { c4 = coded[hash].count;
  2473. buffp--;
  2474. buff[buffp & 15] = 0;
  2475. saving++;
  2476. break;
  2477. }
  2478. hash++;
  2479. if (hash == CODED_SIZE) hash = 0;
  2480. }
  2481. if (c4 != 0)
  2482. { c2 = c4;
  2483. continue;
  2484. }
  2485. }
  2486. break;
  2487. }
  2488. c1 = buff[(buffp+1) & 15];
  2489. c3 = buff[(buffp+2) & 15];
  2490. buff[buffp & 15] = c2;
  2491. buffp++;
  2492. buff[buffp & 15] = 0;
  2493. c2 = c3;
  2494. if (c1 == 0 || c2 == 0 || c1 == INFO_CHAR ||
  2495. c2 == INFO_CHAR) continue;
  2496. if (pass == PASS_COUNT)
  2497. { if (c1 == INFO_CHAR) Iputc(0); /* terminate a section */
  2498. else Iputc(c1);
  2499. helpsize++;
  2500. }
  2501. x = ((c1 & 0xff) << 8) | (c2 & 0xff);
  2502. n = frequencies[x];
  2503. if (--i == 0)
  2504. { stackcheck0(0);
  2505. i = 100;
  2506. }
  2507. if (n == 255)
  2508. { x = (x*32359) % OVERFLOW_SIZE;
  2509. /*
  2510. * In general I expect inserting chgaracter-pairs in this table will only
  2511. * take a few probes. But any scan that takes over 3*OVERFLOW_SIZE/4 is
  2512. * abandoned. The effect is that worst-case behaviour could eventually
  2513. * fill the table up totally, so this long-stop would be the only thing
  2514. * preventing the code from looping for ever. So then it would run around
  2515. * 200 times slower than usual, but it would eventually finish! Such bad cases
  2516. * can not happen with reasonable input data.
  2517. */
  2518. for (n=0;n<(3*OVERFLOW_SIZE)/4;n++)
  2519. { if (overflow[x].count == 0)
  2520. { overflow[x].c1 = c1;
  2521. overflow[x].c2 = c2;
  2522. overflow[x].count = 256;
  2523. break;
  2524. }
  2525. else if (c1 == overflow[x].c1 &&
  2526. c2 == overflow[x].c2)
  2527. { overflow[x].count++;
  2528. break;
  2529. }
  2530. x = x + 1;
  2531. if (x == OVERFLOW_SIZE) x = 0;
  2532. }
  2533. }
  2534. else frequencies[x] = n+1;
  2535. }
  2536. /*
  2537. * It is possible (probable!) that at the end of processing there are a few
  2538. * characters left buffered up. Flush them out now.
  2539. */
  2540. if (pass == PASS_COUNT)
  2541. { for (;;)
  2542. { buffp++;
  2543. c1 = buff[buffp & 15];
  2544. buff[buffp & 15] = 0;
  2545. if (c1 == INFO_CHAR) Iputc(0);
  2546. else Iputc(c1);
  2547. helpsize++;
  2548. if (c1 == 0) break; /* NB I write a zero to terminate */
  2549. }
  2550. }
  2551. term_printf("Saving this pass was %d\n", saving);
  2552. qsort(overflow, (size_t)OVERFLOW_SIZE, sizeof(char_pair_hash),
  2553. compare_char_counts);
  2554. if (pass < PASS_COUNT)
  2555. { for (i=0; i<(pass==PASS_COUNT-1 ? OVERFLOW_SIZE : 10); i++)
  2556. { int rep;
  2557. int32 hash;
  2558. if (overflow[i].c1 == 0 || overflow[i].c2 == 0) continue;
  2559. for (rep=1; rep<256; rep++)
  2560. if (cx1[rep]==0) break;
  2561. if (rep == 256) break;
  2562. c1 = overflow[i].c1;
  2563. c2 = overflow[i].c2;
  2564. cx1[rep] = c1;
  2565. cx2[rep] = c2;
  2566. hash = ((((c1 & 0xff)<<8)+(c2 & 0xff))*32359) % CODED_SIZE;
  2567. for (;;)
  2568. { if (coded[hash].count == 0)
  2569. { coded[hash].c1 = c1;
  2570. coded[hash].c2 = c2;
  2571. coded[hash].count = rep;
  2572. break;
  2573. }
  2574. else if (coded[hash].c1 == c1 &&
  2575. coded[hash].c2 == c2) break;
  2576. hash++;
  2577. if (hash == CODED_SIZE) hash = 0;
  2578. }
  2579. term_printf("%.2x %.2x => %.2x (%d)\n",
  2580. c1 & 0xff, c2 & 0xff, rep & 0xff, overflow[i].count);
  2581. }
  2582. }
  2583. }
  2584. celt(v, indexlength) = 0; /* needed as a terminator */
  2585. for (i=0; i<256; i++)
  2586. { celt(v, 2*i) = cx1[i];
  2587. celt(v, 2*i+1) = cx2[i];
  2588. }
  2589. i = Ioutsize() & 3;
  2590. while ((i & 3) != 0) Iputc(0), i++; /* Pad to multiple of 4 bytes */
  2591. IcloseOutput();
  2592. fclose(file);
  2593. free((void *)frequencies);
  2594. free((void *)overflow);
  2595. trace_printf("%ld bytes of help data\n", (long)helpsize);
  2596. Irestore_context(save);
  2597. /*
  2598. * Now I have made a help module and an associated index vector, however
  2599. * the index information is at present unordered. I want to sort it but
  2600. * the situation is a little curious - the items in the vector are of
  2601. * variable length and so most of the sorting methods I can think of
  2602. * are not easily applied. I guess that merge-sort is the solution...
  2603. */
  2604. merge_sort(&celt(v, 0), &celt(v1, 0), 512, indexlength);
  2605. #ifdef DEBUG_HELP_SYSTEM
  2606. /* Now, mainly as a debugging measure, I display the sorted index */
  2607. term_printf("\nSorted index\n");
  2608. i = 512;
  2609. while (i < indexlength)
  2610. { for (len=4; len<32; len++)
  2611. { c1 = celt(v, i+len);
  2612. if (c1 == 0) break;
  2613. term_printf("%c", c1);
  2614. }
  2615. for (;(len&7)!=0; len++) term_printf(" ");
  2616. buffp = ucelt(v, i+3) & 0xff;
  2617. buffp = (buffp << 8) + (ucelt(v, i+2) & 0xff);
  2618. buffp = (buffp << 8) + (ucelt(v, i+1) & 0xff);
  2619. i += len;
  2620. for (;len<36; len++) term_printf(" ");
  2621. term_printf("%7d\n", buffp);
  2622. }
  2623. #endif
  2624. help_index = v; /* Only set up the index vector if all seemed OK */
  2625. return onevalue(nil);
  2626. #endif /* DEMO_MODE */
  2627. }
  2628. /*
  2629. * Here I will have a simulation of some modest part of the "curses"
  2630. * interface that Unix tends to support. I will certainly not support
  2631. * everything - just a minimum that I think I need for my help browser.
  2632. * I support the following environments
  2633. * (a) Watcom C for DOS, using the Watcom graphics library
  2634. * (b) Unix using real "curses", but adding two new functions initkb()
  2635. * and resetkb() to switch to unbuffered un-echoed input from getch()
  2636. * (c) Watcom C and Windows (win32) using a separate 25 by 80 window
  2637. * for all the text output here. This case will be flagged by having
  2638. * the pre-processor symbol WINDOWS_NT defined.
  2639. */
  2640. #include <ctype.h>
  2641. #ifdef WINDOWS_NT
  2642. /*
  2643. * Under win32 I will have the implementation of all this stuff as
  2644. * part of my window manager code, and hence elsewhere. So I just provide
  2645. * a collection of declarations to show what will be available.
  2646. */
  2647. /*
  2648. * For Windows I will only support an 80 by 25 window. I guess it
  2649. * would be easy enough to permit other sizes, except that I do not have
  2650. * an easy answer to what should happen if the user re-sizes the window
  2651. * while other things are going on. Hence my conservative caution - at
  2652. * least for now!
  2653. */
  2654. extern int LINES, COLS;
  2655. /* initscr() must be called once at the start of a run */
  2656. extern void initscr();
  2657. /*
  2658. * initkb() and resetkb() delimit regions in the code where keyboard
  2659. * input is treated as requests to the curses window but is accepted
  2660. * with no delay and no echo. Also mouse events can be posted during
  2661. * this time.
  2662. */
  2663. extern void initkb();
  2664. extern void resetkb();
  2665. extern int mouse_button; /* set non-zero when user presses a button */
  2666. extern int mouse_cx; /* 0 <= mouse_cx < COLS */
  2667. extern int mouse_cy; /* 0 <= mouse_cy < LINES */
  2668. /* refresh() is called to force the screen to be up to date */
  2669. extern void refresh();
  2670. /* endwin() hides the curses window, restoring simple text handling */
  2671. extern void endwin();
  2672. /* Move text insertion point. Origin (0,0) is top left of screen */
  2673. extern void move(int y, int x);
  2674. /* standout() and standend() delimit inverse video (or whatever) text */
  2675. extern void standout();
  2676. extern void standend();
  2677. /* erase() clears the whole screen */
  2678. extern void erase();
  2679. /*
  2680. * addch() and addstr() add text to the screen, advancing the cursor. I
  2681. * view it as illegal to write beyond either right or bottom margin of the
  2682. * screen.
  2683. */
  2684. extern void addch(int ch);
  2685. extern void addstr(char *s);
  2686. /*
  2687. * getch() reads a character from the keyboard. It does not wait for
  2688. * a newline, and does not echo anything. Because the name getch() may be
  2689. * in use in some C libraries in a way that could conflict I use some
  2690. * re-naming here. If there has been a mouse-click recently then getch()
  2691. * should return a value (0x100 + bits) where the odd bits may indicate which
  2692. * button was pressed. In that case (mouse_cx,mouse_cy) will be the
  2693. * character-position coordinates at which the hit was taken. Systems
  2694. * that can not support a mouse do not have to worry about this and can always
  2695. * return a value in the range 0..255, or EOF. On some systems getch() will
  2696. * return 0 with no delay if there is no character available (so that
  2697. * the application will busy-wait). On others it is entitled to wait until
  2698. * the user presses a key. But (once again) it should not do line editing or
  2699. * wait for an ENTER.
  2700. */
  2701. extern int my_getch();
  2702. #undef getch
  2703. #define getch() my_getch()
  2704. #else /* WINDOWS_NT */
  2705. #ifdef __WATCOMC__
  2706. /*
  2707. * Here I view __WATCOMC__ as flagging an implementation using MSDOS,
  2708. * and in this context I will take that to mean DOS/4GW
  2709. */
  2710. #include <dos.h>
  2711. #include <i86.h>
  2712. #include <graph.h>
  2713. int LINES=0, COLS=0;
  2714. int XPIXELS=0, YPIXELS=0;
  2715. static int in_curses_mode = 0;
  2716. /*
  2717. * I seem to observe that when I run this in a DOS box under Windows
  2718. * (Windows 95 at least) in a DOS window then the first time I try my
  2719. * DOS window is expanded to full screen. If I shrink it back with
  2720. * ALT-ENTER then subsequent runs of a program that uses initsrc() do not
  2721. * seem to mazimize the window. This seems a little odd!
  2722. */
  2723. void initscr()
  2724. {
  2725. struct videoconfig vinfo;
  2726. _getvideoconfig(&vinfo);
  2727. COLS = vinfo.numtextcols;
  2728. LINES = vinfo.numtextrows;
  2729. XPIXELS = vinfo.numxpixels;
  2730. /* In text screen-modes I expect all characters to be 8x8 */
  2731. if (XPIXELS == 0) XPIXELS = 8*COLS;
  2732. YPIXELS = vinfo.numypixels;
  2733. if (YPIXELS == 0) YPIXELS = 8*LINES;
  2734. _settextposition(1, 1);
  2735. in_curses_mode = 1;
  2736. }
  2737. int mouse_cx = 0;
  2738. int mouse_cy = 0;
  2739. static int mouse_button = 0;
  2740. #pragma off (check_stack)
  2741. void _loadds far mouse_click_handler (int max, int mcx, int mdx)
  2742. {
  2743. #pragma aux mouse_click_handler parm [EAX] [ECX] [EDX]
  2744. mouse_cx = (COLS*mcx)/XPIXELS;
  2745. mouse_cy = (LINES*mdx)/YPIXELS;
  2746. mouse_button = max & 0xe;
  2747. }
  2748. #pragma on (check_stack)
  2749. void initkb()
  2750. {
  2751. struct SREGS sregs;
  2752. union REGS inregs, outregs;
  2753. int far *ptr;
  2754. int (far *function_ptr)();
  2755. segread(&sregs);
  2756. /* check for mouse driver */
  2757. inregs.w.ax = 0;
  2758. int386(0x33, &inregs, &outregs);
  2759. if (outregs.w.ax == -1)
  2760. { /* show mouse cursor */
  2761. inregs.w.ax = 0x1;
  2762. int386(0x33, &inregs, &outregs);
  2763. /* install click watcher */
  2764. inregs.w.ax = 0xC;
  2765. inregs.w.cx = 0x0002 + 0x0008;
  2766. function_ptr = mouse_click_handler;
  2767. inregs.x.edx = FP_OFF(function_ptr);
  2768. sregs.es = FP_SEG(function_ptr);
  2769. int386x(0x33, &inregs, &outregs, &sregs);
  2770. mouse_button = 0;
  2771. }
  2772. }
  2773. void resetkb()
  2774. {
  2775. /* check installation again (to clear watcher) */
  2776. union REGS inregs, outregs;
  2777. inregs.w.ax = 0;
  2778. int386(0x33, &inregs, &outregs);
  2779. mouse_button = 0;
  2780. }
  2781. /*
  2782. * In this implementation I will reflect changes to the display
  2783. * instantly, so refresh() [which curses needs] will be a no-op,
  2784. * except that if I had left curses mode re-entering it should clear
  2785. * the screen.
  2786. */
  2787. void refresh()
  2788. {
  2789. if (!in_curses_mode)
  2790. { _clearscreen(_GWINDOW);
  2791. _settextposition(1, 1);
  2792. in_curses_mode |= 1;
  2793. }
  2794. }
  2795. void endwin()
  2796. {
  2797. _settextposition(LINES, 1);
  2798. in_curses_mode = 0;
  2799. }
  2800. void move(int y, int x)
  2801. {
  2802. _settextposition(y+1, x+1);
  2803. }
  2804. void standout()
  2805. {
  2806. _settextcolor(0);
  2807. _setbkcolor(7);
  2808. }
  2809. void standend()
  2810. {
  2811. _settextcolor(7);
  2812. _setbkcolor(0);
  2813. }
  2814. void erase()
  2815. {
  2816. _clearscreen(_GWINDOW);
  2817. _settextposition(1, 1);
  2818. in_curses_mode = 1;
  2819. }
  2820. void addch(int ch)
  2821. {
  2822. char b[4];
  2823. b[0] = ch;
  2824. b[1] = 0;
  2825. _outtext(b);
  2826. }
  2827. void addstr(char *s)
  2828. {
  2829. _outtext(s);
  2830. }
  2831. int my_getch()
  2832. {
  2833. if (mouse_button != 0)
  2834. { int w = mouse_button;
  2835. mouse_button = 0;
  2836. return 0x100 + w;
  2837. }
  2838. if (!kbhit()) return 0;
  2839. return getch();
  2840. }
  2841. #undef getch
  2842. #define getch() my_getch()
  2843. #else /* __WATCOMC__ */
  2844. /* Assume Unix here - or some system providing Unix compatibility */
  2845. #include <curses.h>
  2846. /*
  2847. * In fact for the curses-Unix style interface I do not support a mouse,
  2848. * but that is no great problem - I just let mouse_button remain zero
  2849. * always.
  2850. */
  2851. int mouse_button = 0; /* set non-zero when user presses a button */
  2852. int mouse_cx = 0; /* 0 <= mouse_cx < COLS */
  2853. int mouse_cy = 0; /* 0 <= mouse_cy < LINES */
  2854. void initkb()
  2855. {
  2856. cbreak();
  2857. noecho();
  2858. }
  2859. void resetkb()
  2860. {
  2861. nocbreak();
  2862. echo();
  2863. }
  2864. #endif /* __WATCOMC__ */
  2865. #endif /* WINDOWS_NT */
  2866. /*
  2867. * End of curses compatibility code
  2868. */
  2869. char file[256], node[256], next[256], prev[256], up[256];
  2870. long int topic_start = 0, topic_header_size = 0;
  2871. void find_word(char *buffer, char *tag, char *value)
  2872. {
  2873. int len = strlen(tag), ch;
  2874. *value = 0;
  2875. while (*buffer != 0)
  2876. { if (strncmp(buffer, tag, len) != 0)
  2877. { buffer++;
  2878. continue;
  2879. }
  2880. buffer += len;
  2881. while ((ch = *buffer) == ' ' && ch != 0) buffer++;
  2882. if (ch == 0) return;
  2883. while ((ch = *buffer++) != ',' && ch != 0) *value++ = ch;
  2884. *value = 0;
  2885. return;
  2886. }
  2887. }
  2888. static int shown_lines = 0;
  2889. static unsigned char cstack[28];
  2890. static int cstackp;
  2891. /*
  2892. * I have here some fairly simple compression on the help text. Characters
  2893. * can either stand for themselves or for pairs of characters. The table in
  2894. * the first 512 bytes of the index table indicates which. If at location
  2895. * (2*i, 2*i+1) this table contains (p,q) then q=0 means that the character
  2896. * i stands for itself (and p=i). Otherwise i expands to p followed by q where
  2897. * each of these are subject to the same potential expansion. Code 0 is
  2898. * reserved as a section or file terminator.
  2899. */
  2900. static int getc_help()
  2901. {
  2902. Lisp_Object nil = C_nil;
  2903. Lisp_Object v = help_index;
  2904. unsigned char *p;
  2905. int k, c2;
  2906. CSL_IGNORE(nil);
  2907. p = &ucelt(v, 0);
  2908. if (cstackp == 0) k = Igetc();
  2909. else k = cstack[--cstackp];
  2910. for (;;)
  2911. { if (k == EOF || k == 0) return 0;
  2912. c2 = p[2*k+1];
  2913. if (c2 == 0) return k;
  2914. cstack[cstackp++] = c2;
  2915. k = p[2*k];
  2916. }
  2917. }
  2918. #define MAX_MENUS 32
  2919. static int at_end_of_topic = 0;
  2920. static int menu_line[MAX_MENUS], menu_col[MAX_MENUS], max_menu, active_menu;
  2921. static char menu_text[MAX_MENUS][40];
  2922. void display_next_page()
  2923. {
  2924. int ch, line = 0, col, llen = 80, i, j;
  2925. char buffer[256];
  2926. if (COLS < 80) llen = COLS;
  2927. erase();
  2928. at_end_of_topic = 0;
  2929. max_menu = active_menu = -1;
  2930. /*
  2931. * There is an "ugly" here. The sprintf that formats the header line
  2932. * does not protect against over-long topic-names that could lead to over-full
  2933. * buffers. I make the buffer 256 characters long and hope! I force a '\0'
  2934. * in at column 80 (or whatever) later on to effect truncation.
  2935. */
  2936. sprintf(buffer, "Node: %s, Next: %s, Prev: %s, Up:%s",
  2937. node, next, prev, up);
  2938. buffer[llen] = 0;
  2939. move(0, 0);
  2940. addstr(buffer);
  2941. while (++line < LINES)
  2942. { col = 0;
  2943. while ((ch = getc_help()) != '\n')
  2944. { if (ch == 0 || ch == EOF)
  2945. { at_end_of_topic = 1;
  2946. break;
  2947. }
  2948. if (col < llen) buffer[col++] = ch;
  2949. }
  2950. if (at_end_of_topic) break;
  2951. buffer[col] = 0;
  2952. for (i=0; i<col &&
  2953. !(buffer[i]=='*' &&
  2954. buffer[i+1]==' '); i++);
  2955. for (j=i+1; j<col &&
  2956. !(buffer[j]==':' &&
  2957. buffer[j+1]==':'); j++);
  2958. if (j < col && max_menu < MAX_MENUS-2)
  2959. { max_menu++;
  2960. menu_line[max_menu] = line;
  2961. menu_col[max_menu] = i + 2;
  2962. memset(menu_text[max_menu], 0, 39);
  2963. strncpy(menu_text[max_menu], &buffer[i+2], j-i-2);
  2964. menu_text[max_menu][39] = 0;
  2965. }
  2966. move(line, 0);
  2967. addstr(buffer);
  2968. shown_lines++;
  2969. }
  2970. refresh();
  2971. }
  2972. void skip_some_lines(int n)
  2973. {
  2974. int ch, line = 0, col;
  2975. char buffer[16];
  2976. at_end_of_topic = 0;
  2977. while (++line <= n)
  2978. { col = 0;
  2979. while ((ch = getc_help()) != '\n')
  2980. { if (ch == 0 || ch == EOF)
  2981. { at_end_of_topic = 1;
  2982. break;
  2983. }
  2984. if (col < 8) buffer[col++] = ch;
  2985. }
  2986. if (at_end_of_topic) break;
  2987. shown_lines++;
  2988. }
  2989. }
  2990. static int topic_in_index(char *key)
  2991. {
  2992. int len = strlen(key);
  2993. Lisp_Object nil = C_nil;
  2994. Lisp_Object v = help_index;
  2995. int32 size, i, low, high, offset;
  2996. int k, l;
  2997. char *p;
  2998. CSL_IGNORE(nil);
  2999. if (len > 28) len = 28;
  3000. if (!is_vector(v)) return 0;
  3001. size = length_of_header(vechdr(v)) - 4;
  3002. p = &celt(v, 0);
  3003. /*
  3004. * The first 512 bytes of the help index contain data for the decompression
  3005. * process, and so are not used in the following search.
  3006. * I stop at size-4 on the next line because I added an extra 4 bytes
  3007. * of padding on the end of the help index to terminate the last entry.
  3008. */
  3009. low = 512;
  3010. high = size-4;
  3011. /*
  3012. * Do a binary search a bit, but when I am down to a fairly narrow
  3013. * range drop down to linear scan. Note that binary search is somewhat
  3014. * curious given that the items in my index are variable length!
  3015. */
  3016. while (high > low + 64) /* largest item in table is 28 bytes */
  3017. { int32 mid = (high + low)/2;
  3018. mid &= ~7; /* Align it properly */
  3019. /*
  3020. * At this stage mid might point part way through an index entry. Move it
  3021. * up until it points at something that has a zero first byte. Because
  3022. * I started off with low and high well separated this is guaranteed to
  3023. * terminate with mid strictly between low and high. I slide up rather
  3024. * than down to (slightly) balance the rounding down that happened in
  3025. * the original calculation of the mid-point.
  3026. */
  3027. while (p[mid] != 0) mid += 8;
  3028. #ifdef DEBUG_HELP_SYSTEM
  3029. term_printf("Compare %.*s with %s\n", len, key, &p[mid+4]);
  3030. #endif
  3031. for (k=0; k<len && toupper(key[k]) == p[mid+k+4]; k++) {};
  3032. if (k < len)
  3033. { if (toupper(key[k]) < p[mid+k+4]) high = mid;
  3034. else low = mid;
  3035. continue;
  3036. }
  3037. else if (p[mid+k+4] != 0)
  3038. { high = mid;
  3039. continue;
  3040. }
  3041. low = high = mid; /* Found it exactly */
  3042. break;
  3043. }
  3044. l = 0;
  3045. for (i=low; i<high; i=i+l+4)
  3046. { l = 4;
  3047. while (p[i+l+4] != 0) l += 8;
  3048. if (len > l) continue;
  3049. for (k=0; k<len && toupper(key[k]) == p[i+k+4]; k++) {};
  3050. if (k < len) continue;
  3051. if (p[i+len+4] != 0) continue;
  3052. l = 0; /* Match found: mark the fact with l=0 */
  3053. break;
  3054. }
  3055. if (l != 0) return 0; /* Failed to find the key */
  3056. offset = p[i+3] & 0xff;
  3057. offset = (offset << 8) + (p[i+2] & 0xff);
  3058. offset = (offset << 8) + (p[i+1] & 0xff);
  3059. IcloseInput(NO);
  3060. if (Iopen_help(offset)) return 0;
  3061. topic_start = offset;
  3062. cstackp = 0;
  3063. return 1;
  3064. }
  3065. int find_topic(char *s)
  3066. {
  3067. char buffer[256];
  3068. int i, c1;
  3069. #ifdef DEBUG_HELP_SYSTEM
  3070. term_printf("Find-topic \"%s\"\n", s);
  3071. #endif
  3072. if (!topic_in_index(s)) return 0;
  3073. #ifdef DEBUG_HELP_SYSTEM
  3074. term_printf("Found in index at %d\n", topic_start);
  3075. #endif
  3076. shown_lines = 0;
  3077. cstackp = 0;
  3078. for (i=0, c1=getc_help();c1!='\n';c1=getc_help())
  3079. if (i < 250) buffer[i++] = c1;
  3080. buffer[i] = 0;
  3081. topic_header_size = i;
  3082. find_word(buffer, "Node:", node);
  3083. find_word(buffer, "File:", file);
  3084. find_word(buffer, "Next:", next);
  3085. find_word(buffer, "Prev:", prev);
  3086. find_word(buffer, "Up:", up);
  3087. #ifdef DEBUG_HELP_SYSTEM
  3088. term_printf("%s:%s:%s:%s:%s\n", node, file, next, prev, up);
  3089. #endif
  3090. display_next_page();
  3091. return 1;
  3092. }
  3093. void restart_topic()
  3094. {
  3095. IcloseInput(NO);
  3096. if (!Iopen_help(topic_start))
  3097. { int i;
  3098. for (i=0; i<topic_header_size; i++) getc_help();
  3099. }
  3100. cstackp = 0;
  3101. }
  3102. static void help_about_help_browser()
  3103. {
  3104. int ch;
  3105. erase();
  3106. move( 1, 0); addstr("*** HELP BROWSER COMMANDS ***");
  3107. move( 3, 0); addstr("b go Back to start of topic");
  3108. move( 4, 0); addstr("space move on one page through topic");
  3109. move( 5, 0); addstr("delete move back one page in topic");
  3110. move( 6, 0); addstr("?, h display this Help text");
  3111. move( 7, 0); addstr("n go to Next topic");
  3112. move( 8, 0); addstr("p go to Previous topic");
  3113. move( 9, 0); addstr("u go Up a level");
  3114. move(10, 0); addstr("q Quit");
  3115. move(11, 0); addstr("tab, m Select next Menu item");
  3116. move(12, 0); addstr("ENTER, f Follow selected menu item");
  3117. move(13, 0); addstr("1-9 First 9 menu items visible");
  3118. move(15, 0); addstr("[Type SPACE or ENTER to continue]");
  3119. refresh();
  3120. while ((ch = getch()) != ' ' && ch != '\n' && ch != '\r');
  3121. }
  3122. static int help_main(char *s)
  3123. {
  3124. int i, w;
  3125. initscr();
  3126. initkb();
  3127. if (!find_topic(s)) return 1;
  3128. for (;;)
  3129. { w = getch();
  3130. switch (tolower(w))
  3131. {
  3132. case 'q': break;
  3133. case 'n': if (next[0] != 0)
  3134. { if (!find_topic(next)) goto redisplay_current_topic;
  3135. }
  3136. continue;
  3137. case 'p': if (prev[0] != 0)
  3138. { if (!find_topic(prev)) goto redisplay_current_topic;
  3139. }
  3140. continue;
  3141. case 'u': if (up[0] != 0)
  3142. { if (!find_topic(up)) goto redisplay_current_topic;
  3143. }
  3144. continue;
  3145. case ' ': if (!at_end_of_topic) display_next_page();
  3146. continue;
  3147. case 0x8:
  3148. case 0x7f:
  3149. case 0xff:
  3150. if (shown_lines <= (LINES-2)) continue;
  3151. i = shown_lines - 2*LINES + 2;
  3152. if (i < 0) i = 0;
  3153. restart_topic();
  3154. shown_lines = 0;
  3155. skip_some_lines(i);
  3156. display_next_page();
  3157. continue;
  3158. case '?':
  3159. case 'h': help_about_help_browser();
  3160. /* Drop through */
  3161. redisplay_current_topic:
  3162. case 'b': restart_topic();
  3163. shown_lines = 0;
  3164. display_next_page();
  3165. continue;
  3166. case '\t':
  3167. case 'm': /* For this version I make "m" skip to the next menu item */
  3168. if (max_menu < 0) continue;
  3169. if (active_menu >= 0)
  3170. { move(menu_line[active_menu], menu_col[active_menu]);
  3171. addstr(menu_text[active_menu]);
  3172. active_menu++;
  3173. if (active_menu > max_menu) active_menu = 0;
  3174. }
  3175. else active_menu = 0;
  3176. move(menu_line[active_menu], menu_col[active_menu]);
  3177. standout();
  3178. addstr(menu_text[active_menu]);
  3179. standend();
  3180. refresh();
  3181. continue;
  3182. case '\n': /* Follow a menu item, as selected */
  3183. case '\r':
  3184. case 'f': if (max_menu >= 0 && active_menu >= 0)
  3185. { if (!find_topic(menu_text[active_menu]))
  3186. goto redisplay_current_topic;
  3187. }
  3188. continue;
  3189. case '1': case '2': case '3': case '4': case '5':
  3190. case '6': case '7': case '8': case '9':
  3191. w = w - '1';
  3192. if (w <= max_menu)
  3193. { if (!find_topic(menu_text[w]))
  3194. goto redisplay_current_topic;
  3195. }
  3196. continue;
  3197. default: continue;
  3198. }
  3199. break;
  3200. }
  3201. resetkb();
  3202. endwin();
  3203. return 0;
  3204. }
  3205. static void help(char *word, int len)
  3206. {
  3207. Ihandle save;
  3208. char key[32];
  3209. Icontext(&save);
  3210. if (Iopen_help(0)) debug_printf("\nNo heap available\n");
  3211. else
  3212. { if (len > 28) len = 28;
  3213. key[len] = 0;
  3214. while (--len >= 0) key[len] = word[len];
  3215. /* memcpy(key, word, len); <curses.h> on a sparc kills this!! */
  3216. /* key[len] = 0; by its attempts to mix BSD & sysV. */
  3217. if (help_main(key)) debug_printf("\nNo help available\n");
  3218. IcloseInput(NO);
  3219. }
  3220. Irestore_context(save);
  3221. return;
  3222. }
  3223. Lisp_Object lisp_help(Lisp_Object nil, Lisp_Object a)
  3224. {
  3225. switch ((int)a & TAG_BITS)
  3226. {
  3227. case TAG_SYMBOL:
  3228. #ifndef COMMON
  3229. if (a == nil)
  3230. { help("Top", 3); /* this tag is the default one to give */
  3231. return onevalue(nil);
  3232. }
  3233. #endif
  3234. a = get_pname(a);
  3235. errexit();
  3236. case TAG_VECTOR:
  3237. if (type_of_header(vechdr(a)) == TYPE_STRING)
  3238. { Header h = vechdr(a);
  3239. int32 len = length_of_header(h); /* counts in bytes */
  3240. len -= 4;
  3241. help(&celt(a, 0), len);
  3242. return onevalue(nil);
  3243. }
  3244. case TAG_CONS:
  3245. #ifdef COMMON
  3246. if (a == nil)
  3247. { help("Top", 3);
  3248. return onevalue(nil);
  3249. }
  3250. #endif
  3251. while (consp(a))
  3252. { push(a);
  3253. lisp_help(nil, qcar(a));
  3254. pop(a);
  3255. errexit();
  3256. a = qcdr(a);
  3257. }
  3258. return onevalue(nil);
  3259. case TAG_BOXFLOAT:
  3260. default:
  3261. return onevalue(nil);
  3262. }
  3263. }
  3264. Lisp_Object Lhelp(Lisp_Object nil, Lisp_Object a)
  3265. {
  3266. return lisp_help(nil, a);
  3267. }
  3268. Lisp_Object Lhelp_2(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
  3269. {
  3270. push(b);
  3271. lisp_help(nil, a);
  3272. pop(b);
  3273. errexit();
  3274. return lisp_help(nil, b);
  3275. }
  3276. Lisp_Object MS_CDECL Lhelp_n(Lisp_Object nil, int nargs, ...)
  3277. {
  3278. if (nargs == 0) help("Top", 0);
  3279. else
  3280. { va_list a;
  3281. int i;
  3282. va_start(a, nargs);
  3283. push_args(a, nargs);
  3284. for (i=0; i<nargs; i++)
  3285. { Lisp_Object c = stack[i-nargs+1];
  3286. lisp_help(nil, c);
  3287. errexitn(nargs);
  3288. }
  3289. popv(nargs);
  3290. }
  3291. return onevalue(nil);
  3292. }
  3293. #else
  3294. Lisp_Object Lwrite_help_module(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
  3295. {
  3296. return onevalue(nil);
  3297. }
  3298. Lisp_Object Lhelp(Lisp_Object nil, Lisp_Object a)
  3299. {
  3300. term_printf("HELP not built in to this version of the system\n");
  3301. return onevalue(nil);
  3302. }
  3303. Lisp_Object Lhelp_2(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
  3304. {
  3305. return Lhelp(nil, a);
  3306. }
  3307. Lisp_Object MS_CDECL Lhelp_n(Lisp_Object nil, int nargs, ...)
  3308. {
  3309. return Lhelp(nil, nil);
  3310. }
  3311. #endif /* HELP_SYSTEM */
  3312. char prompt_string[32];
  3313. Lisp_Object Lsetpchar(Lisp_Object nil, Lisp_Object a)
  3314. {
  3315. Lisp_Object old = prompt_thing;
  3316. CSL_IGNORE(nil);
  3317. prompt_thing = a;
  3318. #define escape_nolinebreak 0x80
  3319. escaped_printing = escape_nolinebreak;
  3320. set_stream_write_fn(lisp_work_stream, count_character);
  3321. memory_print_buffer[0] = 0;
  3322. set_stream_write_other(lisp_work_stream, write_action_list);
  3323. stream_char_pos(lisp_work_stream) = 0;
  3324. active_stream = lisp_work_stream;
  3325. push(old);
  3326. #ifdef DEMO_MODE
  3327. { char *s = "DemoRed";
  3328. while (*s != 0) count_character(*s++, lisp_work_stream);
  3329. }
  3330. #endif
  3331. internal_prin(a, 0);
  3332. pop(old);
  3333. errexit();
  3334. #ifdef CWIN
  3335. cwin_set_prompt(memory_print_buffer);
  3336. #endif
  3337. memcpy(prompt_string, memory_print_buffer, 32);
  3338. prompt_string[31] = 0;
  3339. return onevalue(old);
  3340. }
  3341. /* end of fasl.c */