fasl.c 117 KB

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