print.c 147 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509
  1. /* print.c Copyright (C) 1990-2002 Codemist Ltd */
  2. /*
  3. * Printing, plus some file-related operations.
  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: 7b59abaa 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 COMMON
  29. #include "clsyms.h"
  30. #endif
  31. #ifdef TIMEOUT
  32. #include "timeout.h"
  33. #endif
  34. #ifdef SOCKETS
  35. #include "sockhdr.h"
  36. #endif
  37. #ifdef CWIN
  38. #include "cwin.h"
  39. #endif
  40. FILE *spool_file = NULL;
  41. char spool_file_name[32];
  42. int32 terminal_column = 0;
  43. int32 terminal_line_length = (int32)0x80000000;
  44. #ifdef CWIN
  45. #define default_terminal_line_length cwin_linelength
  46. #else
  47. #define default_terminal_line_length 80
  48. #endif
  49. #define VPRINTF_CHUNK 256
  50. #ifdef BUFFERED_STDOUT
  51. static int print_buffn = 0;
  52. #define PRINT_BUFSIZE 8000
  53. static char print_buffer[PRINT_BUFSIZE+VPRINTF_CHUNK];
  54. clock_t last_flush = 0;
  55. void ensure_screen(void)
  56. {
  57. /*
  58. * Some of what is going on here is that I arrange to discount time spent
  59. * actually writing characters to the screen.
  60. */
  61. #ifdef SOCKETS
  62. if (socket_server != 0) flush_socket();
  63. #endif
  64. if (print_buffn != 0)
  65. { push_clock();
  66. /*
  67. * Time spend writing to the screen is explicitly discounted from measurements
  68. * of time spent in CSL...
  69. */
  70. #ifdef WINDOW_SYSTEM
  71. {
  72. #ifdef CWIN
  73. print_buffer[print_buffn] = 0;
  74. cwin_puts(print_buffer);
  75. #else
  76. int i;
  77. for (i=0; i<print_buffn; i++)
  78. putc_stdout(print_buffer[i]);
  79. #endif
  80. flush_screen();
  81. }
  82. #else
  83. fwrite(print_buffer, 1, print_buffn, stdout);
  84. fflush(stdout); fflush(stderr);
  85. #endif
  86. print_buffn = 0;
  87. pop_clock();
  88. last_flush = base_time;
  89. }
  90. else last_flush = read_clock();
  91. }
  92. #else
  93. void ensure_screen()
  94. {
  95. #ifdef SOCKETS
  96. if (socket_server != 0) flush_socket();
  97. #endif
  98. fflush(stdout);
  99. }
  100. #endif
  101. void MS_CDECL term_printf(char *fmt, ...)
  102. {
  103. va_list a;
  104. char print_temp[VPRINTF_CHUNK], *p;
  105. int n;
  106. va_start(a, fmt);
  107. n = vsprintf(print_temp, fmt, a);
  108. p = print_temp;
  109. while (n-- > 0) char_to_terminal(*p++, 0);
  110. va_end(a);
  111. }
  112. void MS_CDECL stdout_printf(char *fmt, ...)
  113. {
  114. va_list a;
  115. char print_temp[VPRINTF_CHUNK], *p;
  116. int n;
  117. nil_as_base
  118. Lisp_Object stream = qvalue(standard_output);
  119. if (!is_stream(stream)) stream = qvalue(terminal_io);
  120. if (!is_stream(stream)) stream = lisp_terminal_io;
  121. va_start(a, fmt);
  122. n = vsprintf(print_temp, fmt, a);
  123. p = print_temp;
  124. while (n-- > 0) putc_stream(*p++, stream);
  125. va_end(a);
  126. }
  127. void MS_CDECL err_printf(char *fmt, ...)
  128. {
  129. va_list a;
  130. char print_temp[VPRINTF_CHUNK], *p;
  131. int n;
  132. nil_as_base
  133. Lisp_Object stream = qvalue(error_output);
  134. if (!is_stream(stream)) stream = qvalue(terminal_io);
  135. if (!is_stream(stream)) stream = lisp_terminal_io;
  136. va_start(a, fmt);
  137. n = vsprintf(print_temp, fmt, a);
  138. p = print_temp;
  139. while (n-- > 0) putc_stream(*p++, stream);
  140. va_end(a);
  141. }
  142. void MS_CDECL debug_printf(char *fmt, ...)
  143. {
  144. va_list a;
  145. char print_temp[VPRINTF_CHUNK], *p;
  146. int n;
  147. nil_as_base
  148. Lisp_Object stream = qvalue(debug_io);
  149. if (!is_stream(stream)) stream = qvalue(terminal_io);
  150. if (!is_stream(stream)) stream = lisp_terminal_io;
  151. va_start(a, fmt);
  152. n = vsprintf(print_temp, fmt, a);
  153. p = print_temp;
  154. while (n-- > 0) putc_stream(*p++, stream);
  155. va_end(a);
  156. }
  157. void MS_CDECL trace_printf(char *fmt, ...)
  158. {
  159. va_list a;
  160. char print_temp[VPRINTF_CHUNK], *p;
  161. int n;
  162. nil_as_base
  163. Lisp_Object stream = qvalue(trace_output);
  164. if (!is_stream(stream)) stream = qvalue(terminal_io);
  165. if (!is_stream(stream)) stream = lisp_terminal_io;
  166. va_start(a, fmt);
  167. n = vsprintf(print_temp, fmt, a);
  168. p = print_temp;
  169. while (n-- > 0) putc_stream(*p++, stream);
  170. va_end(a);
  171. }
  172. Lisp_Object Ltyo(Lisp_Object nil, Lisp_Object a)
  173. {
  174. /*
  175. * Print a character given its character code. NOTE that in earlier
  176. * versions of CSL this always printed to the standard output regardless
  177. * of what output stream was selected. Such a curious behaviour was
  178. * provided for use when magic characters sent to the standard output had
  179. * odd behaviour (eg caused graphics effects). Now tyo is a more
  180. * sensible function for use across all systems. To be generous it
  181. * accepts either a character or a numeric code.
  182. */
  183. int c;
  184. Lisp_Object stream = qvalue(standard_output);
  185. CSL_IGNORE(nil);
  186. if (a == CHAR_EOF) return onevalue(a);
  187. else if (is_char(a)) c = (int)code_of_char(a);
  188. else if (is_fixnum(a)) c = (int)int_of_fixnum(a);
  189. else return aerror1("tyo", a);
  190. push(a);
  191. if (!is_stream(stream)) stream = qvalue(terminal_io);
  192. if (!is_stream(stream)) stream = lisp_terminal_io;
  193. putc_stream(c, stream);
  194. pop(a);
  195. errexit();
  196. return onevalue(a);
  197. }
  198. int char_to_illegal(int c, Lisp_Object f)
  199. {
  200. Lisp_Object nil = C_nil;
  201. CSL_IGNORE(c);
  202. CSL_IGNORE(f);
  203. if (exception_pending()) return 1;
  204. aerror1("Attempt to write to an input stream or one that has been closed",
  205. stream_type(f));
  206. return 1;
  207. }
  208. int char_from_illegal(Lisp_Object f)
  209. {
  210. Lisp_Object nil = C_nil;
  211. CSL_IGNORE(f);
  212. if (exception_pending()) return EOF;
  213. aerror1("Attempt to read from an output stream or one that has been closed",
  214. stream_type(f));
  215. return EOF;
  216. }
  217. int32 write_action_illegal(int32 op, Lisp_Object f)
  218. {
  219. CSL_IGNORE(f);
  220. if (op == WRITE_GET_INFO+WRITE_IS_CONSOLE) return 0;
  221. if (op != WRITE_CLOSE)
  222. aerror1("Illegal operation on stream",
  223. cons_no_gc(fixnum_of_int(op >> 8), stream_type(f)));
  224. return 0;
  225. }
  226. int32 write_action_file(int32 op, Lisp_Object f)
  227. {
  228. int32 w;
  229. switch (op & 0xf0000000)
  230. {
  231. case WRITE_CLOSE:
  232. if (stream_file(f) == NULL) op = 0;
  233. else op = fclose(stream_file(f));
  234. set_stream_write_fn(f, char_to_illegal);
  235. set_stream_write_other(f, write_action_illegal);
  236. set_stream_read_fn(f, char_from_illegal);
  237. set_stream_read_other(f, read_action_illegal);
  238. set_stream_file(f, NULL);
  239. return op;
  240. case WRITE_FLUSH:
  241. return fflush(stream_file(f));
  242. case WRITE_SET_LINELENGTH_DEFAULT:
  243. op = 80; /* drop through */
  244. case WRITE_SET_LINELENGTH:
  245. w = stream_line_length(f);
  246. stream_line_length(f) = op & 0x07ffffff;
  247. return w;
  248. case WRITE_SET_COLUMN:
  249. w = stream_char_pos(f);
  250. stream_char_pos(f) = op & 0x07ffffff;
  251. return w;
  252. case WRITE_GET_INFO:
  253. switch (op & 0xff)
  254. {
  255. case WRITE_GET_LINE_LENGTH: return stream_line_length(f);
  256. case WRITE_GET_COLUMN: return stream_char_pos(f);
  257. case WRITE_IS_CONSOLE: return 0;
  258. default:return 0;
  259. }
  260. default:
  261. return 0;
  262. }
  263. }
  264. #ifdef PIPES
  265. int32 write_action_pipe(int32 op, Lisp_Object f)
  266. {
  267. int32 w;
  268. if (op < 0) return -1;
  269. else switch (op & 0xf0000000)
  270. {
  271. case WRITE_CLOSE:
  272. my_pclose(stream_file(f));
  273. set_stream_write_fn(f, char_to_illegal);
  274. set_stream_write_other(f, write_action_illegal);
  275. set_stream_file(f, NULL);
  276. return 0;
  277. case WRITE_FLUSH:
  278. return my_pipe_flush(stream_file(f));
  279. case WRITE_SET_LINELENGTH_DEFAULT:
  280. op = 80; /* drop through */
  281. case WRITE_SET_LINELENGTH:
  282. w = stream_line_length(f);
  283. stream_line_length(f) = op & 0x07ffffff;
  284. return w;
  285. case WRITE_SET_COLUMN:
  286. w = stream_char_pos(f);
  287. stream_char_pos(f) = op & 0x07ffffff;
  288. return w;
  289. case WRITE_GET_INFO:
  290. switch (op & 0xff)
  291. {
  292. case WRITE_GET_LINE_LENGTH: return stream_line_length(f);
  293. case WRITE_GET_COLUMN: return stream_char_pos(f);
  294. case WRITE_IS_CONSOLE: return 0;
  295. default:return 0;
  296. }
  297. default:
  298. return 0;
  299. }
  300. }
  301. #else
  302. int32 write_action_pipe(int32 op, Lisp_Object f)
  303. {
  304. CSL_IGNORE(op); CSL_IGNORE(f);
  305. return -1;
  306. }
  307. #endif
  308. int32 write_action_terminal(int32 op, Lisp_Object dummy)
  309. {
  310. int32 w;
  311. CSL_IGNORE(dummy);
  312. if (op < 0) return -1;
  313. else switch (op & 0xf0000000)
  314. {
  315. case WRITE_CLOSE:
  316. return 0; /* I will never close the terminal stream */
  317. case WRITE_FLUSH:
  318. ensure_screen();
  319. return 0;
  320. case WRITE_SET_LINELENGTH_DEFAULT:
  321. w = terminal_line_length;
  322. terminal_line_length = 0x80000000;
  323. return w;
  324. case WRITE_SET_LINELENGTH:
  325. w = terminal_line_length;
  326. terminal_line_length = op & 0x07ffffff;
  327. return w;
  328. case WRITE_SET_COLUMN:
  329. w = terminal_column;
  330. terminal_column = op & 0x07ffffff;
  331. return w;
  332. case WRITE_GET_INFO:
  333. switch (op & 0xff)
  334. {
  335. case WRITE_GET_LINE_LENGTH: w = terminal_line_length;
  336. if (w == 0x80000000)
  337. w = default_terminal_line_length;
  338. return w;
  339. case WRITE_GET_COLUMN: return terminal_column;
  340. case WRITE_IS_CONSOLE: return 1;
  341. default:return 0;
  342. }
  343. default:
  344. return 0;
  345. }
  346. }
  347. int32 write_action_list(int32 op, Lisp_Object f)
  348. {
  349. int32 w;
  350. if (op < 0) return -1;
  351. else switch (op & 0xf0000000)
  352. {
  353. case WRITE_CLOSE:
  354. set_stream_write_fn(f, char_to_illegal);
  355. set_stream_write_other(f, write_action_illegal);
  356. set_stream_file(f, NULL);
  357. return 0;
  358. case WRITE_FLUSH:
  359. return 0;
  360. case WRITE_SET_LINELENGTH_DEFAULT:
  361. case WRITE_SET_LINELENGTH:
  362. return 0x03ffffff;
  363. case WRITE_SET_COLUMN:
  364. w = stream_char_pos(f);
  365. stream_char_pos(f) = op & 0x07ffffff;
  366. return w;
  367. case WRITE_GET_INFO:
  368. switch (op & 0xff)
  369. {
  370. case WRITE_GET_LINE_LENGTH: return 0x03ffffff;
  371. case WRITE_GET_COLUMN: return stream_char_pos(f);
  372. case WRITE_IS_CONSOLE: return 0;
  373. default:return 0;
  374. }
  375. default:
  376. return 0;
  377. }
  378. }
  379. Lisp_Object Lstreamp(Lisp_Object nil, Lisp_Object a)
  380. {
  381. return onevalue(Lispify_predicate(is_stream(a)));
  382. }
  383. Lisp_Object Lis_console(Lisp_Object nil, Lisp_Object a)
  384. {
  385. int r1, r2;
  386. if (!is_stream(a)) return onevalue(nil);
  387. r1 = other_write_action(WRITE_GET_INFO+WRITE_IS_CONSOLE, a);
  388. r2 = other_read_action(READ_IS_CONSOLE, a);
  389. return onevalue(Lispify_predicate(r1 || r2));
  390. }
  391. Lisp_Object make_stream_handle(void)
  392. {
  393. Lisp_Object w = getvector(TAG_VECTOR, TYPE_STREAM, STREAM_SIZE), nil;
  394. errexit();
  395. stream_type(w) = nil;
  396. stream_write_data(w) = nil;
  397. stream_read_data(w) = nil;
  398. set_stream_file(w, 0);
  399. set_stream_write_fn(w, char_to_illegal);
  400. set_stream_write_other(w, write_action_illegal);
  401. stream_line_length(w) = 80;
  402. stream_char_pos(w) = 0;
  403. set_stream_read_fn(w, char_from_illegal);
  404. set_stream_read_other(w, read_action_illegal);
  405. stream_pushed_char(w) = NOT_CHAR;
  406. return w;
  407. }
  408. #ifdef COMMON
  409. Lisp_Object MS_CDECL Lmake_broadcast_stream_n(Lisp_Object nil, int nargs, ...)
  410. {
  411. Lisp_Object r = nil, w, w1;
  412. va_list a;
  413. va_start(a, nargs);
  414. push_args(a, nargs);
  415. while (nargs > 1)
  416. { pop2(w, w1);
  417. nargs-=2;
  418. r = list2star(w1, w, r);
  419. errexitn(nargs);
  420. }
  421. while (nargs > 0)
  422. { pop(w);
  423. nargs--;
  424. r = cons(w, r);
  425. errexitn(nargs);
  426. }
  427. push(r);
  428. w = make_stream_handle();
  429. pop(r);
  430. errexit();
  431. set_stream_write_fn(w, char_to_broadcast);
  432. set_stream_write_other(w, write_action_broadcast);
  433. stream_write_data(w) = r;
  434. return onevalue(w);
  435. }
  436. Lisp_Object Lmake_broadcast_stream_1(Lisp_Object nil, Lisp_Object a)
  437. {
  438. return Lmake_broadcast_stream_n(nil, 1, a);
  439. }
  440. Lisp_Object Lmake_broadcast_stream_2(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
  441. {
  442. return Lmake_broadcast_stream_n(nil, 2, a, b);
  443. }
  444. Lisp_Object MS_CDECL Lmake_concatenated_stream_n(Lisp_Object nil, int nargs, ...)
  445. {
  446. Lisp_Object r = nil, w, w1;
  447. va_list a;
  448. va_start(a, nargs);
  449. push_args(a, nargs);
  450. while (nargs > 1)
  451. { pop2(w, w1);
  452. nargs-=2;
  453. r = list2star(w1, w, r);
  454. errexitn(nargs);
  455. }
  456. while (nargs > 0)
  457. { pop(w);
  458. nargs--;
  459. r = cons(w, r);
  460. errexitn(nargs);
  461. }
  462. push(r);
  463. w = make_stream_handle();
  464. pop(r);
  465. errexit();
  466. set_stream_read_fn(w, char_from_concatenated);
  467. set_stream_read_other(w, read_action_concatenated);
  468. stream_read_data(w) = r;
  469. return onevalue(w);
  470. }
  471. Lisp_Object Lmake_concatenated_stream_1(Lisp_Object nil, Lisp_Object a)
  472. {
  473. return Lmake_concatenated_stream_n(nil, 1, a);
  474. }
  475. Lisp_Object Lmake_concatenated_stream_2(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
  476. {
  477. return Lmake_concatenated_stream_n(nil, 2, a, b);
  478. }
  479. Lisp_Object Lmake_synonym_stream(Lisp_Object nil, Lisp_Object a)
  480. {
  481. Lisp_Object w;
  482. if (!is_symbol(a)) return aerror1("make-synonym-stream", a);
  483. push(a);
  484. w = make_stream_handle();
  485. pop(a);
  486. errexit();
  487. set_stream_write_fn(w, char_to_synonym);
  488. set_stream_write_other(w, write_action_synonym);
  489. stream_write_data(w) = a;
  490. set_stream_read_fn(w, char_from_synonym);
  491. set_stream_read_other(w, read_action_synonym);
  492. stream_read_data(w) = a;
  493. return onevalue(w);
  494. }
  495. Lisp_Object Lmake_two_way_stream(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
  496. {
  497. Lisp_Object w;
  498. if (!is_symbol(a)) return aerror1("make-two-way-stream", a);
  499. if (!is_symbol(b)) return aerror1("make-two-way-stream", b);
  500. push2(a, b);
  501. w = make_stream_handle();
  502. pop2(b, a);
  503. errexit();
  504. set_stream_write_fn(w, char_to_synonym);
  505. set_stream_write_other(w, write_action_synonym);
  506. stream_write_data(w) = b;
  507. set_stream_read_fn(w, char_from_synonym);
  508. set_stream_read_other(w, read_action_synonym);
  509. stream_read_data(w) = a;
  510. return onevalue(w);
  511. }
  512. Lisp_Object Lmake_echo_stream(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
  513. {
  514. Lisp_Object w;
  515. if (!is_symbol(a)) return aerror1("make-echo-stream", a);
  516. if (!is_symbol(b)) return aerror1("make-echo-stream", b);
  517. push2(a, b);
  518. w = make_stream_handle();
  519. pop2(b, a);
  520. errexit();
  521. set_stream_write_fn(w, char_to_synonym);
  522. set_stream_write_other(w, write_action_synonym);
  523. stream_write_data(w) = b;
  524. set_stream_read_fn(w, char_from_echo);
  525. set_stream_read_other(w, read_action_synonym);
  526. stream_read_data(w) = a;
  527. return onevalue(w);
  528. }
  529. Lisp_Object MS_CDECL Lmake_string_input_stream_n(Lisp_Object nil, int nargs, ...)
  530. {
  531. CSL_IGNORE(nil); CSL_IGNORE(nargs);
  532. return aerror("make-string-input-stream");
  533. }
  534. Lisp_Object Lmake_string_input_stream_1(Lisp_Object nil, Lisp_Object a)
  535. {
  536. return Lmake_string_input_stream_n(nil, 1, a);
  537. }
  538. Lisp_Object Lmake_string_input_stream_2(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
  539. {
  540. return Lmake_string_input_stream_n(nil, 2, a, b);
  541. }
  542. Lisp_Object MS_CDECL Lmake_string_output_stream(Lisp_Object nil, int nargs, ...)
  543. {
  544. Lisp_Object w;
  545. argcheck(nargs, 0, "make-string-output-stream");
  546. w = make_stream_handle();
  547. errexit();
  548. set_stream_write_fn(w, code_to_list);
  549. set_stream_write_other(w, write_action_list);
  550. return onevalue(w);
  551. }
  552. Lisp_Object Lget_output_stream_string(Lisp_Object nil, Lisp_Object a)
  553. {
  554. Lisp_Object w;
  555. int32 n, k;
  556. if (!is_stream(a)) return aerror1("get-output-stream-string", a);
  557. w = stream_write_data(a);
  558. n = stream_char_pos(a);
  559. stream_write_data(a) = nil;
  560. stream_char_pos(a) = 0;
  561. push(w);
  562. a = getvector(TAG_VECTOR, TYPE_STRING, CELL+n);
  563. pop(w);
  564. errexit();
  565. k = (n + 3) & ~(int32)7;
  566. *(int32 *)((char *)a + k + 4 - TAG_VECTOR) = 0;
  567. if (k != 0) *(int32 *)((char *)a + k - TAG_VECTOR) = 0;
  568. while (n > 0)
  569. { n--;
  570. celt(a, n) = int_of_fixnum(qcar(w));
  571. w = qcdr(w);
  572. }
  573. return a;
  574. }
  575. #endif /* COMMON */
  576. /*
  577. * (make-function-stream 'fn) makes a stream where output just passes
  578. * characters to the given function.
  579. */
  580. Lisp_Object Lmake_function_stream(Lisp_Object nil, Lisp_Object a)
  581. {
  582. Lisp_Object w;
  583. if (!is_symbol(a)) return aerror1("make-function-stream", a);
  584. push(a);
  585. w = make_stream_handle();
  586. pop(a);
  587. errexit();
  588. set_stream_write_fn(w, char_to_function);
  589. set_stream_write_other(w, write_action_list);
  590. stream_write_data(w) = a;
  591. return onevalue(w);
  592. }
  593. int char_to_terminal(int c, Lisp_Object dummy)
  594. {
  595. CSL_IGNORE(dummy);
  596. if (c == '\n' || c == '\f') terminal_column = 0;
  597. else terminal_column++;
  598. if (spool_file != NULL)
  599. { putc(c, spool_file);
  600. #ifdef DEBUG
  601. fflush(spool_file);
  602. #endif
  603. }
  604. if (procedural_output != NULL) return (*procedural_output)(c);
  605. #ifdef WINDOW_SYSTEM
  606. if (alternative_stdout != NULL)
  607. { putc(c, alternative_stdout);
  608. return 0;
  609. }
  610. #endif
  611. #ifdef BUFFERED_STDOUT
  612. print_buffer[print_buffn++] = (char)c;
  613. if (print_buffn > PRINT_BUFSIZE) ensure_screen();
  614. #else
  615. /*
  616. * Note that if I have a windowed system then BUFFERED_STDOUT will always
  617. * be set, so the case here is JUST for when I have direct output to the
  618. * ordinary stdout file, with no Lisp-level buffering.
  619. */
  620. putchar(c);
  621. #endif
  622. return 0; /* indicate success */
  623. }
  624. int char_to_file(int c, Lisp_Object stream)
  625. {
  626. if (c == '\n' || c == '\f') stream_char_pos(stream) = 0;
  627. else stream_char_pos(stream)++;
  628. putc(c, stream_file(stream));
  629. return 0; /* indicate success */
  630. }
  631. int char_to_synonym(int c, Lisp_Object f)
  632. {
  633. f = qvalue(stream_write_data(f));
  634. if (!is_stream(f)) return 1;
  635. return putc_stream(c, f);
  636. }
  637. int char_to_function(int c, Lisp_Object f)
  638. {
  639. Lisp_Object nil = C_nil;
  640. f = stream_write_data(f); /* name of the function to call */
  641. (*qfn1(f))(qenv(f), pack_char(0, 0, c & 0xff));
  642. errexit();
  643. return 0; /* return 0 for success */
  644. }
  645. int char_to_broadcast(int c, Lisp_Object f)
  646. {
  647. Lisp_Object l = stream_write_data(f);
  648. int r = 0;
  649. Lisp_Object nil = C_nil;
  650. while (consp(l))
  651. { f = qcar(l);
  652. l = qcdr(l);
  653. if (!is_symbol(f)) continue;
  654. f = qvalue(f);
  655. if (!is_stream(f)) continue;
  656. push(l);
  657. r = r | putc_stream(c, f);
  658. pop(l);
  659. errexit();
  660. }
  661. return r;
  662. }
  663. int32 write_action_synonym(int32 c, Lisp_Object f)
  664. {
  665. int r;
  666. Lisp_Object f1 = qvalue(stream_write_data(f));
  667. if (!is_stream(f1))
  668. return aerror1("attempt to act on",
  669. cons_no_gc(fixnum_of_int(c >> 8), f));
  670. r = other_write_action(c, f1);
  671. if (c == WRITE_CLOSE)
  672. { set_stream_write_fn(f, char_to_illegal);
  673. set_stream_write_other(f, write_action_illegal);
  674. set_stream_file(f, NULL);
  675. }
  676. return r;
  677. }
  678. int32 write_action_broadcast(int32 c, Lisp_Object f)
  679. {
  680. int r = 0, r1;
  681. Lisp_Object l = stream_write_data(f), f1;
  682. Lisp_Object nil = C_nil;
  683. while (consp(l))
  684. { f1 = qcar(l);
  685. l = qcdr(l);
  686. if (!is_symbol(f1)) continue;
  687. f1 = qvalue(f1);
  688. if (!is_stream(f1)) continue;
  689. push2(l, f);
  690. r1 = other_write_action(c, f1);
  691. pop2(f, l);
  692. errexit();
  693. if (r == 0) r = r1;
  694. }
  695. if (c == WRITE_CLOSE)
  696. { set_stream_write_fn(f, char_to_illegal);
  697. set_stream_write_other(f, write_action_illegal);
  698. set_stream_file(f, NULL);
  699. }
  700. return r;
  701. }
  702. #ifdef PIPES
  703. int char_to_pipeout(int c, Lisp_Object stream)
  704. {
  705. if (c == '\n' || c == '\f') stream_char_pos(stream) = 0;
  706. else stream_char_pos(stream)++;
  707. my_pipe_putc(c, stream_file(stream));
  708. return 0; /* indicate success */
  709. }
  710. #else
  711. int char_to_pipeout(int c, Lisp_Object stream)
  712. {
  713. return char_to_illegal(c, stream);
  714. }
  715. #endif
  716. char *get_string_data(Lisp_Object name, char *why, int32 *len)
  717. {
  718. Lisp_Object nil = C_nil;
  719. Header h;
  720. #ifdef COMMON
  721. if (complex_stringp(name))
  722. { name = simplify_string(name);
  723. nil = C_nil;
  724. if (exception_pending()) return NULL;
  725. h = vechdr(name);
  726. }
  727. else
  728. #endif
  729. if (symbolp(name))
  730. { name = get_pname(name);
  731. nil = C_nil;
  732. if (exception_pending()) return NULL;
  733. h = vechdr(name);
  734. }
  735. else if (!(is_vector(name)))
  736. { aerror1(why, name);
  737. return NULL;
  738. }
  739. else if (type_of_header(h = vechdr(name)) != TYPE_STRING)
  740. { aerror1(why, name);
  741. return NULL;
  742. }
  743. *len = length_of_header(h) - CELL;
  744. return &celt(name, 0);
  745. }
  746. static Lisp_Object Lfiledate(Lisp_Object nil, Lisp_Object name)
  747. {
  748. char filename[LONGEST_LEGAL_FILENAME], tt[32];
  749. int32 len;
  750. char *w = get_string_data(name, "filep", &len);
  751. errexit();
  752. if (len >= sizeof(filename)) len = sizeof(filename);
  753. if (!file_exists(filename, w,
  754. (size_t)len, tt)) return onevalue(nil);
  755. tt[24] = 0;
  756. name = make_string(tt);
  757. errexit();
  758. return onevalue(name);
  759. }
  760. static Lisp_Object Lfilep(Lisp_Object nil, Lisp_Object name)
  761. {
  762. name = Lfiledate(nil, name);
  763. errexit();
  764. if (name != nil) name = lisp_true;
  765. return onevalue(name);
  766. }
  767. Lisp_Object MS_CDECL Ltmpnam(Lisp_Object nil, int nargs, ...)
  768. /*
  769. * Returns a string that is suitable for use as the name of a temporary
  770. * file. Note that this is generally NOT a comfortable thing to use,
  771. * since after tmpnam() has generated the name but before you get around
  772. * to doing anything with the file somebody else may do something that
  773. * interferes. As a result some C compilers issue a warning when they
  774. * see use of tmpnam() at all... Here the potential security issues are
  775. * just left for the user to think about!
  776. */
  777. {
  778. char *s;
  779. Lisp_Object r;
  780. argcheck(nargs, 0, "tmpnam");
  781. s = tmpnam(NULL);
  782. if (s == NULL) return onevalue(nil); /* Sorry - can't do it */
  783. r = make_string(s);
  784. errexit();
  785. return onevalue(r);
  786. }
  787. #ifdef _DEBUG
  788. FILE *myopen(char *f, char *m)
  789. {
  790. FILE *s = fopen(f, m);
  791. trace_printf("fopen(%s, %s) = %p\n", f, m, s);
  792. return s;
  793. }
  794. #define fopen(a, b) myopen(a, b)
  795. #endif
  796. /*
  797. * The Common Lisp keywords for OPEN are a horrid mess. I arrange to decode
  798. * the syntax of the keywords in a Lisp-coded wrapper function, and in that
  799. * code I will also fill in default values for any that needs same. I then
  800. * pack all the information into a single integer, which has several
  801. * sub-fields
  802. *
  803. * x x xx xxx 00 direction PROBE
  804. * x x xx xxx 01 INPUT
  805. * x x xx xxx 10 OUTPUT
  806. * x x xx xxx 11 IO
  807. *
  808. * x x xx 000 xx if-exists NIL
  809. * x x xx 001 xx overwrite
  810. * x x xx 010 xx append
  811. * x x xx 011 xx rename
  812. * x x xx 100 xx error
  813. * x x xx 101 xx (new-version)
  814. * x x xx 110 xx (supersede)
  815. * x x xx 111 xx (rename-and-delete)
  816. *
  817. * x x 00 xxx xx if-does-not-exist NIL
  818. * x x 01 xxx xx create
  819. * x x 10 xxx xx error
  820. *
  821. * x 0 xx xxx xx regular text file
  822. * x 1 xx xxx xx open for binary access
  823. *
  824. * 0 x xx xxx xx regular file
  825. * 1 x xx xxx xx open as a pipe
  826. */
  827. #define DIRECTION_MASK 0x3
  828. #define DIRECTION_PROBE 0x0
  829. #define DIRECTION_INPUT 0x1
  830. #define DIRECTION_OUTPUT 0x2
  831. #define DIRECTION_IO 0x3
  832. #define IF_EXISTS_MASK 0x1c
  833. #define IF_EXISTS_NIL 0x00
  834. #define IF_EXISTS_OVERWRITE 0x04
  835. #define IF_EXISTS_APPEND 0x08
  836. #define IF_EXISTS_RENAME 0x0c
  837. #define IF_EXISTS_ERROR 0x10
  838. #define IF_EXISTS_NEW_VERSION 0x14
  839. #define IF_EXISTS_SUPERSEDE 0x18
  840. #define IF_EXISTS_RENAME_AND_DELETE 0x1c
  841. #define IF_MISSING_MASK 0x60
  842. #define IF_MISSING_NIL 0x00
  843. #define IF_MISSING_CREATE 0x20
  844. #define IF_MISSING_ERROR 0x40
  845. #define OPEN_BINARY 0x80
  846. #define OPEN_PIPE 0x100
  847. Lisp_Object Lopen(Lisp_Object nil, Lisp_Object name, Lisp_Object dir)
  848. {
  849. FILE *file;
  850. Lisp_Object r;
  851. char filename[LONGEST_LEGAL_FILENAME], fn1[LONGEST_LEGAL_FILENAME];
  852. int32 len;
  853. char *w;
  854. int d;
  855. #ifdef PIPES
  856. CSLbool pipep = NO;
  857. #endif
  858. if (!is_fixnum(dir)) return aerror1("open", dir);
  859. d = (int)int_of_fixnum(dir);
  860. #ifdef SOCKETS
  861. /*
  862. * If I am working as a socket server I will prohibit operations that
  863. * could (easily) corrupt the local machine. Here I prevent anybody from
  864. * opening files for output. I also prevent use of pipes.
  865. */
  866. if (socket_server != 0 &&
  867. ((d & DIRECTION_MASK) == DIRECTION_OUTPUT ||
  868. (d & DIRECTION_MASK) == DIRECTION_IO ||
  869. (d & OPEN_PIPE) != 0))
  870. return aerror1("open invalid in server mode", dir);
  871. #endif
  872. #ifdef DEBUG_OPENING_FILES
  873. trace_printf("Open file:");
  874. switch (d & DIRECTION_MASK)
  875. {
  876. case DIRECTION_PROBE: trace_printf(" probe"); break;
  877. case DIRECTION_INPUT: trace_printf(" input"); break;
  878. case DIRECTION_OUTPUT:trace_printf(" output"); break;
  879. case DIRECTION_IO: trace_printf(" io"); break;
  880. }
  881. switch (d & IF_EXISTS_MASK)
  882. {
  883. case IF_EXISTS_NIL: trace_printf(" if-exists-nil"); break;
  884. case IF_EXISTS_OVERWRITE: trace_printf(" if-exists-overwrite"); break;
  885. case IF_EXISTS_APPEND: trace_printf(" if-exists-append"); break;
  886. case IF_EXISTS_RENAME: trace_printf(" if-exists-rename"); break;
  887. case IF_EXISTS_ERROR: trace_printf(" if-exists-error"); break;
  888. case IF_EXISTS_NEW_VERSION: trace_printf(" if-exists-new-version"); break;
  889. case IF_EXISTS_SUPERSEDE: trace_printf(" if-exists-supersede"); break;
  890. case IF_EXISTS_RENAME_AND_DELETE: trace_printf(" if-exists-r-and-d"); break;
  891. }
  892. switch (d & IF_MISSING_MASK)
  893. {
  894. case IF_MISSING_NIL: trace_printf(" if-missing-nil"); break;
  895. case IF_MISSING_CREATE: trace_printf(" if-missing-create"); break;
  896. case IF_MISSING_ERROR: trace_printf(" if-missing-error"); break;
  897. }
  898. if (d & OPEN_BINARY) trace_printf(" binary");
  899. if (d & OPEN_PIPE) trace_printf(" pipe");
  900. trace_printf("\n");
  901. #endif
  902. w = get_string_data(name, "open", &len);
  903. errexit();
  904. if (len >= sizeof(filename)) len = sizeof(filename);
  905. file = NULL;
  906. switch (d & (DIRECTION_MASK | OPEN_PIPE))
  907. {
  908. case DIRECTION_PROBE: /* probe file - can not be used with pipes */
  909. file = open_file(filename, w, (size_t)len, "r", NULL);
  910. if (file == NULL)
  911. { switch (d & IF_MISSING_MASK)
  912. {
  913. case IF_MISSING_NIL:
  914. return onevalue(nil);
  915. case IF_MISSING_ERROR:
  916. return error(1, err_open_failed, name);
  917. case IF_MISSING_CREATE:
  918. /*
  919. * I thing that people who go (open xxx :direction :probe
  920. * :if-does-not-exist :create)
  921. * are to be considered unduly enthusiastic, but I will still try to do what
  922. * they tell me to!
  923. */
  924. file = open_file(filename, w, (size_t)len, "w", NULL);
  925. if (file == NULL) return error(1, err_open_failed, name);
  926. fclose(file);
  927. file = NULL;
  928. }
  929. }
  930. else
  931. { fclose(file);
  932. file = NULL;
  933. }
  934. break; /* Must then create a no-direction stream */
  935. case DIRECTION_INPUT:
  936. file = open_file(filename, w, (size_t)len,
  937. #ifdef NO_BINARY_OPEN
  938. "r",
  939. #else
  940. (d & OPEN_BINARY ? "rb" : "r"),
  941. #endif
  942. NULL);
  943. if (file == NULL)
  944. { switch (d & IF_MISSING_MASK)
  945. {
  946. case IF_MISSING_NIL:
  947. return onevalue(nil);
  948. case IF_MISSING_ERROR:
  949. return error(1, err_open_failed, name);
  950. case IF_MISSING_CREATE:
  951. file = open_file(filename, w,
  952. (size_t)len, "w", NULL);
  953. if (file == NULL) return error(1, err_open_failed, name);
  954. fclose(file);
  955. /*
  956. * I use fopen(xx,"w") to create the file, then close it again and re-open
  957. * for input, so that concurrent tasks can see the file now existing but
  958. * only open for reading. If opening the file I just created fails I will
  959. * give up.
  960. */
  961. file = open_file(filename, w, (size_t)len,
  962. #ifdef NO_BINARY_OPEN
  963. "r",
  964. #else
  965. (d & OPEN_BINARY ? "rb" : "r"),
  966. #endif
  967. NULL);
  968. if (file == NULL) return error(1, err_open_failed, name);
  969. break;
  970. }
  971. }
  972. break; /* if-exists ignored when opening for input */
  973. case DIRECTION_OUTPUT:
  974. case DIRECTION_IO:
  975. /*
  976. * I will start by trying to open the file to see if it exists. By using
  977. * mode "r+" I will only open it if I am able to obtain write-access, and
  978. * in some cases I will then be able to make use of the file. The fact that
  979. * it will have been opened for IO not just output will not harm me.
  980. */
  981. file = open_file(filename, w, (size_t)len,
  982. #ifdef NO_BINARY_OPEN
  983. "r+",
  984. #else
  985. (d & OPEN_BINARY ? "r+b" : "r+"),
  986. #endif
  987. NULL);
  988. if (file == NULL) switch (d & IF_MISSING_MASK)
  989. {
  990. case IF_MISSING_NIL:
  991. return onevalue(nil);
  992. case IF_MISSING_ERROR:
  993. return error(1, err_open_failed, name);
  994. case IF_MISSING_CREATE:
  995. break; /* usual case for output and IO files */
  996. }
  997. else switch (d & IF_EXISTS_MASK)
  998. {
  999. case IF_EXISTS_NIL:
  1000. fclose(file);
  1001. return onevalue(nil);
  1002. case IF_EXISTS_RENAME:
  1003. /*
  1004. * When I open a file with :if-exists :rename I will always rename to
  1005. * a fixed target, "oldfile.bak". If the rename fails I will not worry too
  1006. * much. I imagine some people would rather that the name I renamed to was
  1007. * based on the original file-name, but that seems excessive to me. And I
  1008. * would have little sympathy for users who relied on it!
  1009. */
  1010. fclose(file);
  1011. file = NULL;
  1012. rename_file(filename, w, (size_t)len,
  1013. fn1, "oldfile.bak", 11);
  1014. break;
  1015. case IF_EXISTS_ERROR:
  1016. fclose(file);
  1017. return error(1, err_open_failed, name);
  1018. /*
  1019. * Working through the standard C library the ideas of :new-version,
  1020. * :supersede and :rename-and-delete seem rather odd, so I will just treat
  1021. * them all as :new-version.
  1022. */
  1023. case IF_EXISTS_SUPERSEDE:
  1024. case IF_EXISTS_RENAME_AND_DELETE:
  1025. case IF_EXISTS_NEW_VERSION:
  1026. fclose(file);
  1027. delete_file(filename, w, (size_t)len);
  1028. file = NULL;
  1029. break;
  1030. case IF_EXISTS_OVERWRITE:
  1031. break;
  1032. case IF_EXISTS_APPEND:
  1033. fseek(file, 0L, SEEK_END);
  1034. break;
  1035. }
  1036. if (file == NULL)
  1037. { file = open_file(filename, w,
  1038. (size_t)len,
  1039. #ifdef NO_BINARY_OPEN
  1040. "w+",
  1041. #else
  1042. (d & OPEN_BINARY ? "w+b" : "w+"),
  1043. #endif
  1044. NULL);
  1045. if (file == NULL) return error(1, err_open_failed, name);
  1046. }
  1047. break;
  1048. case DIRECTION_OUTPUT | OPEN_PIPE:
  1049. #ifdef PIPES
  1050. pipep = YES;
  1051. memcpy(filename, w, (size_t)len);
  1052. filename[len] = 0;
  1053. #ifdef PIPES_SOMETIMES
  1054. if (!pipes_today) file = NULL;
  1055. else
  1056. #endif
  1057. file = my_popen(filename, "w");
  1058. if (file == NULL) return error(1, err_pipe_failed, name);
  1059. break;
  1060. #else
  1061. return aerror("pipes not available with this version of CSL");
  1062. #endif
  1063. case DIRECTION_INPUT | OPEN_PIPE:
  1064. case DIRECTION_IO | OPEN_PIPE:
  1065. return aerror("reading from pipes is not supported in CCL\n");
  1066. }
  1067. push(name);
  1068. r = make_stream_handle();
  1069. pop(name);
  1070. errexit();
  1071. stream_type(r) = name;
  1072. set_stream_file(r, file);
  1073. switch (d & (DIRECTION_MASK | OPEN_PIPE))
  1074. {
  1075. case DIRECTION_INPUT:
  1076. set_stream_read_fn(r, char_from_file);
  1077. set_stream_read_other(r, read_action_file);
  1078. break;
  1079. #ifdef PIPES
  1080. case DIRECTION_OUTPUT | OPEN_PIPE:
  1081. set_stream_write_fn(r, char_to_pipeout);
  1082. set_stream_write_other(r, write_action_pipe);
  1083. break;
  1084. #endif
  1085. case DIRECTION_OUTPUT:
  1086. set_stream_write_fn(r, char_to_file);
  1087. set_stream_write_other(r, write_action_file);
  1088. set_stream_read_other(r, read_action_output_file);
  1089. break;
  1090. case DIRECTION_IO:
  1091. set_stream_read_fn(r, char_from_file);
  1092. set_stream_read_other(r, read_action_output_file);
  1093. set_stream_write_fn(r, char_to_file);
  1094. set_stream_write_other(r, write_action_file);
  1095. break;
  1096. }
  1097. return onevalue(r);
  1098. }
  1099. Lisp_Object Lwrs(Lisp_Object nil, Lisp_Object a)
  1100. {
  1101. Lisp_Object old = qvalue(standard_output);
  1102. if (a == nil) a = qvalue(terminal_io);
  1103. if (a == old) return onevalue(old);
  1104. else if (!is_stream(a)) return aerror1("wrs", a);
  1105. else if (stream_write_fn(a) == char_to_illegal)
  1106. #ifdef COMMON
  1107. a = qvalue(terminal_io);
  1108. #else
  1109. return aerror("wrs (closed or input file)"); /* closed file or input file */
  1110. #endif
  1111. qvalue(standard_output) = a;
  1112. return onevalue(old);
  1113. }
  1114. Lisp_Object Lclose(Lisp_Object nil, Lisp_Object a)
  1115. {
  1116. /*
  1117. * I will not allow anybody to close the terminal streams
  1118. */
  1119. if (a == nil ||
  1120. a == lisp_terminal_io) return onevalue(nil);
  1121. else if (!is_stream(a)) return aerror1("close", a);
  1122. if (a == qvalue(standard_input))
  1123. qvalue(standard_input) = lisp_terminal_io;
  1124. else if (a == qvalue(standard_output))
  1125. qvalue(standard_output) = lisp_terminal_io;
  1126. other_read_action(READ_CLOSE, a);
  1127. other_write_action(WRITE_CLOSE, a);
  1128. #ifdef COMMON
  1129. return onevalue(lisp_true);
  1130. #else
  1131. return onevalue(nil);
  1132. #endif
  1133. }
  1134. Lisp_Object Ltruename(Lisp_Object nil, Lisp_Object name)
  1135. {
  1136. char filename[LONGEST_LEGAL_FILENAME];
  1137. Lisp_Object truename;
  1138. int32 len;
  1139. char *w = get_string_data(name, "truename", &len);
  1140. errexit();
  1141. if (len >= sizeof(filename)) len = sizeof(filename);
  1142. w = get_truename(filename,w,len);
  1143. truename = make_string(w);
  1144. free(w);
  1145. errexit();
  1146. return onevalue(truename);
  1147. }
  1148. Lisp_Object Lcreate_directory(Lisp_Object nil, Lisp_Object name)
  1149. {
  1150. char filename[LONGEST_LEGAL_FILENAME];
  1151. int32 len;
  1152. char *w = get_string_data(name, "create-directory", &len);
  1153. errexit();
  1154. if (len >= sizeof(filename)) len = sizeof(filename);
  1155. #ifdef SOCKETS
  1156. if (socket_server != 0) return aerror("create-directory");
  1157. #endif
  1158. len = create_directory(filename, w, (size_t)len);
  1159. return onevalue(Lispify_predicate(len == 0));
  1160. }
  1161. Lisp_Object Lfile_readable(Lisp_Object nil, Lisp_Object name)
  1162. {
  1163. char filename[LONGEST_LEGAL_FILENAME];
  1164. int32 len;
  1165. char *w = get_string_data(name, "file-readable", &len);
  1166. errexit();
  1167. if (len >= sizeof(filename)) len = sizeof(filename);
  1168. len = file_readable(filename, w, (size_t)len);
  1169. return onevalue(Lispify_predicate(len));
  1170. }
  1171. Lisp_Object Lchange_directory(Lisp_Object nil, Lisp_Object name)
  1172. {
  1173. char filename[LONGEST_LEGAL_FILENAME];
  1174. int32 len;
  1175. char *w = get_string_data(name, "change-directory", &len);
  1176. errexit();
  1177. if (len >= sizeof(filename)) len = sizeof(filename);
  1178. /*
  1179. * At present I will permit change-directory in server mode.
  1180. */
  1181. len = change_directory(filename, w, (size_t)len);
  1182. return onevalue(Lispify_predicate(len == 0));
  1183. }
  1184. Lisp_Object Lfile_writeable(Lisp_Object nil, Lisp_Object name)
  1185. {
  1186. char filename[LONGEST_LEGAL_FILENAME];
  1187. int32 len;
  1188. char *w;
  1189. /* First check whether file exists */
  1190. if (Lfilep(nil,name) == nil) return nil;
  1191. w = get_string_data(name, "file-writable", &len);
  1192. errexit();
  1193. if (len >= sizeof(filename)) len = sizeof(filename);
  1194. len = file_writeable(filename, w, (size_t)len);
  1195. return onevalue(Lispify_predicate(len));
  1196. }
  1197. Lisp_Object Ldelete_file(Lisp_Object nil, Lisp_Object name)
  1198. {
  1199. char filename[LONGEST_LEGAL_FILENAME];
  1200. int32 len;
  1201. char *w = get_string_data(name, "delete-file", &len);
  1202. errexit();
  1203. if (len >= sizeof(filename)) len = sizeof(filename);
  1204. #ifdef SOCKETS
  1205. if (socket_server != 0) return aerror("delete-file");
  1206. #endif
  1207. len = delete_file(filename, w, (size_t)len);
  1208. return onevalue(Lispify_predicate(len == 0));
  1209. }
  1210. /* Returns the length of a file in bytes */
  1211. Lisp_Object Lfile_length(Lisp_Object nil, Lisp_Object name)
  1212. {
  1213. char filename[LONGEST_LEGAL_FILENAME];
  1214. int32 len;
  1215. long size;
  1216. char *w = get_string_data(name, "file-length", &len);
  1217. errexit();
  1218. if (len >= sizeof(filename)) len = sizeof(filename);
  1219. size = file_length(filename, w, (size_t)len);
  1220. if (size < 0)
  1221. return nil;
  1222. else if (size < 268435456)
  1223. return fixnum_of_int(size);
  1224. else
  1225. return make_one_word_bignum(size);
  1226. }
  1227. Lisp_Object Ldirectoryp(Lisp_Object nil, Lisp_Object name)
  1228. {
  1229. char filename[LONGEST_LEGAL_FILENAME];
  1230. int32 len;
  1231. char *w = get_string_data(name, "directoryp", &len);
  1232. errexit();
  1233. if (len >= sizeof(filename)) len = sizeof(filename);
  1234. len = directoryp(filename, w, (size_t)len);
  1235. return onevalue(Lispify_predicate(len));
  1236. }
  1237. Lisp_Object MS_CDECL Lget_current_directory(Lisp_Object nil, int nargs, ...)
  1238. {
  1239. char filename[LONGEST_LEGAL_FILENAME];
  1240. int len;
  1241. Lisp_Object w;
  1242. argcheck(nargs, 0, "get-current-directory");
  1243. len = get_current_directory(filename, LONGEST_LEGAL_FILENAME);
  1244. if (len == 0) return onevalue(nil);
  1245. w = make_string(filename);
  1246. errexit();
  1247. return onevalue(w);
  1248. }
  1249. Lisp_Object MS_CDECL Luser_homedir_pathname(Lisp_Object nil, int32 nargs, ...)
  1250. {
  1251. char home[LONGEST_LEGAL_FILENAME];
  1252. int len;
  1253. Lisp_Object w;
  1254. argcheck(nargs, 0, "user-homedir-pathname")
  1255. len = get_home_directory(home, LONGEST_LEGAL_FILENAME);
  1256. if (len == 0) return onevalue(nil);
  1257. w = make_string(home);
  1258. errexit();
  1259. return onevalue(w);
  1260. }
  1261. Lisp_Object MS_CDECL Lget_lisp_directory(Lisp_Object nil, int nargs, ...)
  1262. {
  1263. char filename[LONGEST_LEGAL_FILENAME];
  1264. int len;
  1265. Lisp_Object w;
  1266. argcheck(nargs, 0, "get-lisp-directory");
  1267. strcpy(filename, standard_directory);
  1268. len = strlen(filename);
  1269. while (len-- > 0 &&
  1270. filename[len] != '/' &&
  1271. filename[len] != '\\');
  1272. if (len == 0) return onevalue(nil);
  1273. filename[len] = 0;
  1274. w = make_string(filename);
  1275. errexit();
  1276. return onevalue(w);
  1277. }
  1278. Lisp_Object Lrename_file(Lisp_Object nil, Lisp_Object from, Lisp_Object to)
  1279. {
  1280. char from_name[LONGEST_LEGAL_FILENAME], to_name[LONGEST_LEGAL_FILENAME];
  1281. int32 from_len, to_len;
  1282. char *from_w, *to_w;
  1283. #ifdef SOCKETS
  1284. if (socket_server != 0) return aerror("rename-file");
  1285. #endif
  1286. push(to);
  1287. from_w = get_string_data(from, "rename-file", &from_len);
  1288. pop(to);
  1289. errexit();
  1290. if (from_len >= sizeof(from_name)) from_len = sizeof(from_name);
  1291. from = (Lisp_Object)(from_w + TAG_VECTOR - CELL);
  1292. push(from);
  1293. to_w = get_string_data(to, "rename-file", &to_len);
  1294. pop(from);
  1295. from_w = &celt(from, 0);
  1296. errexit();
  1297. if (to_len >= sizeof(to_name)) to_len = sizeof(to_name);
  1298. to_len = rename_file(from_name, from_w, (size_t)from_len,
  1299. to_name, to_w, (size_t)to_len);
  1300. return onevalue(Lispify_predicate(to_len == 0));
  1301. }
  1302. /*
  1303. * This function is a call-back from the file-scanning routine.
  1304. */
  1305. static void make_dir_list(char *name, int why, long int size)
  1306. {
  1307. Lisp_Object nil = C_nil, w;
  1308. CSL_IGNORE(why);
  1309. CSL_IGNORE(size);
  1310. errexitv();
  1311. if (scan_leafstart >= (int)strlen(name)) return;
  1312. w = make_string(name+scan_leafstart);
  1313. errexitv();
  1314. w = cons(w, stack[0]);
  1315. errexitv();
  1316. stack[0] = w;
  1317. }
  1318. Lisp_Object Llist_directory(Lisp_Object nil, Lisp_Object name)
  1319. {
  1320. Lisp_Object result;
  1321. char filename[LONGEST_LEGAL_FILENAME];
  1322. int32 len;
  1323. char *w = get_string_data(name, "list-directory", &len);
  1324. errexit();
  1325. if (len >= sizeof(filename)) len = sizeof(filename);
  1326. push(nil);
  1327. list_directory_members(filename, w,
  1328. (size_t)len, make_dir_list);
  1329. pop(result);
  1330. errexit();
  1331. result = nreverse(result);
  1332. errexit();
  1333. return onevalue(result);
  1334. }
  1335. /*****************************************************************************/
  1336. /* Printing. */
  1337. /*****************************************************************************/
  1338. int escaped_printing;
  1339. #define escape_yes 0x0001 /* make output re-readable */
  1340. #define escape_fold_down 0x0002 /* force lower case output */
  1341. #define escape_fold_up 0x0004 /* FORCE UPPER CASE OUTPUT */
  1342. #define escape_capitalize 0x0008 /* Force Capitalisation (!) */
  1343. #define escape_binary 0x0010 /* print format for numbers */
  1344. #define escape_octal 0x0020 /* (including bignums) */
  1345. #define escape_hex 0x0040
  1346. #define escape_nolinebreak 0x0080 /* use infinite line-length */
  1347. #define escape_hexwidth 0x3f00 /* 6 bits to specify width of hex/bin */
  1348. #define escape_width(n) (((n) & escape_hexwidth) >> 8)
  1349. #define escape_checksum 0x4000 /* doing a checksum operation */
  1350. static void outprefix(CSLbool blankp, int32 len)
  1351. /*
  1352. * This function takes most of the responsibility for splitting lines.
  1353. * when called we are about to print an item with (len) characters.
  1354. * If blankp is true we need to display a blank or newline before
  1355. * the item.
  1356. */
  1357. {
  1358. nil_as_base
  1359. int32 line_length =
  1360. other_write_action(WRITE_GET_INFO+WRITE_GET_LINE_LENGTH,
  1361. active_stream);
  1362. int32 column =
  1363. other_write_action(WRITE_GET_INFO+WRITE_GET_COLUMN,
  1364. active_stream);
  1365. if (column+len > line_length &&
  1366. (escaped_printing & escape_nolinebreak) == 0)
  1367. putc_stream('\n', active_stream);
  1368. else if (blankp) putc_stream(' ', active_stream);
  1369. }
  1370. static Lisp_Object Lprint_precision(Lisp_Object nil, Lisp_Object a)
  1371. {
  1372. int32 old = print_precision;
  1373. if (a == nil) return onevalue(fixnum_of_int(old));
  1374. if (!is_fixnum(a)) return aerror1("print-precision", a);
  1375. print_precision = int_of_fixnum(a);
  1376. if (print_precision > 16)
  1377. print_precision = 15;
  1378. return onevalue(fixnum_of_int(old));
  1379. }
  1380. static void prin_buf(char *buf, int blankp)
  1381. {
  1382. Lisp_Object nil = C_nil;
  1383. int len = strlen(buf), i;
  1384. outprefix(blankp, len);
  1385. for (i=0; i<len; i++)
  1386. { putc_stream(*buf++, active_stream);
  1387. errexitv();
  1388. }
  1389. }
  1390. static int32 local_gensym_count;
  1391. void internal_prin(Lisp_Object u, int blankp)
  1392. {
  1393. Lisp_Object w, nil = C_nil;
  1394. int32 len, k;
  1395. char my_buff[68];
  1396. #ifdef COMMON
  1397. int bl = blankp & 2;
  1398. /*
  1399. * There is a fairly shameless FUDGE here. When I come to need to print
  1400. * the package part of a symbol as in ppp:xxx (or even |)p(|::|.| if I
  1401. * have names with silly characters in them) I will have a STRING that is the
  1402. * name of the relevant package, but I want it displayed as if it was an
  1403. * identifier. I achieve this by setting the "2" bit in blankp (which is
  1404. * otherwise a simple boolean), and when this is detected I go and join the
  1405. * code for printing symbols. But in that case I MUST have been passed
  1406. * a (simple) string, or else things can collapse utterly.
  1407. */
  1408. blankp &= 1;
  1409. if (bl != 0)
  1410. { w = u;
  1411. push(u);
  1412. goto tag_symbol;
  1413. }
  1414. restart:
  1415. #endif
  1416. #ifdef SOFTWARE_TICKS
  1417. if (--countdown < 0) deal_with_tick();
  1418. #endif
  1419. errexitv();
  1420. if (stack >= stacklimit)
  1421. { u = reclaim(u, "stack", GC_STACK, 0);
  1422. errexitv();
  1423. }
  1424. switch ((int)u & TAG_BITS)
  1425. {
  1426. case TAG_CONS:
  1427. #ifdef COMMON
  1428. if (u == nil) /* BEWARE - nil is tagged as a cons cell */
  1429. { outprefix(blankp, 3);
  1430. putc_stream('N', active_stream);
  1431. putc_stream('I', active_stream);
  1432. putc_stream('L', active_stream);
  1433. return;
  1434. }
  1435. #endif
  1436. if (u == 0) u = nil; /* Bug security here */
  1437. push(u);
  1438. outprefix(blankp, 1);
  1439. putc_stream('(', active_stream);
  1440. errexitvn(1);
  1441. internal_prin(qcar(stack[0]), 0);
  1442. errexitvn(1);
  1443. w = stack[0];
  1444. while (is_cons(w = qcdr(w)))
  1445. {
  1446. #ifdef COMMON
  1447. if (w == nil) break; /* Again BEWARE the tag code of NIL */
  1448. #endif
  1449. stack[0] = w;
  1450. internal_prin(qcar(stack[0]), 1);
  1451. errexitvn(1);
  1452. w = stack[0];
  1453. }
  1454. if (w != nil)
  1455. { stack[0] = w;
  1456. outprefix(YES, 1);
  1457. putc_stream('.', active_stream);
  1458. errexitvn(1);
  1459. internal_prin(stack[0], 1);
  1460. }
  1461. popv(1);
  1462. outprefix(NO, 1);
  1463. putc_stream(')', active_stream);
  1464. return;
  1465. #ifdef COMMON
  1466. case TAG_SFLOAT:
  1467. { Float_union uu;
  1468. uu.i = u - TAG_SFLOAT;
  1469. sprintf(my_buff, "%#.6g", (double)uu.f);
  1470. }
  1471. goto float_print_tidyup;
  1472. #endif
  1473. case TAG_FIXNUM:
  1474. if (escaped_printing & escape_hex)
  1475. { int32 v = int_of_fixnum(u);
  1476. int width = escape_width(escaped_printing);
  1477. int32 mask;
  1478. /*
  1479. * The printing style adopted here for negative numbers follows that used in
  1480. * the big number printing code. A prefix "~" stands for an infinite initial
  1481. * string of 'f' digits, and what follows will be exactly one 'f' (just to
  1482. * remind you) and then the remaining hex digits. E.g. -2 should display
  1483. * as ~fe. Note that any fixnum will start off with 0xf in the top 4 of
  1484. * 32 bits. If an explicit width had been specified then I want that many
  1485. * charcters to be displayed, with full leading zeros etc. A width is taken as
  1486. * minimum number of chars to be displayed, so a width of zero (or in fact 1)
  1487. * would have the effect of no constraint. The width-specification field
  1488. * only allows for the range 0 to 63, and that is just as well since I put
  1489. * characters in a buffer (my_buff) which would almost fill up at the
  1490. * widest...
  1491. */
  1492. len = 0;
  1493. if (v < 0)
  1494. { mask = 0x0f000000;
  1495. my_buff[len++] = '~';
  1496. width--;
  1497. while ((v & mask) == mask && mask != 0)
  1498. { v = v ^ (mask << 4);
  1499. mask = mask >> 4;
  1500. }
  1501. k = 'f';
  1502. }
  1503. else k = '0';
  1504. mask = 0xf;
  1505. while ((v & mask) != v)
  1506. { width--;
  1507. mask = (mask<<4) | 0xf;
  1508. }
  1509. while (--width > 0) my_buff[len++] = (char)k;
  1510. sprintf(&my_buff[len], "%lx", (long)v);
  1511. }
  1512. else if (escaped_printing & escape_octal)
  1513. { int32 v = int_of_fixnum(u);
  1514. int width = escape_width(escaped_printing);
  1515. int32 mask;
  1516. len = 0;
  1517. if (v < 0)
  1518. { mask = 0x38000000;
  1519. my_buff[len++] = '~';
  1520. width--;
  1521. while ((v & mask) == mask && mask != 0)
  1522. { v = v ^ (mask << 3);
  1523. mask = mask >> 3;
  1524. }
  1525. k = '7';
  1526. }
  1527. else k = '0';
  1528. mask = 0x7;
  1529. while ((v & mask) != v)
  1530. { width--;
  1531. mask = (mask<<3) | 0x7;
  1532. }
  1533. while (--width > 0) my_buff[len++] = (char)k;
  1534. sprintf(&my_buff[len], "%lo", (long)v);
  1535. }
  1536. else if (escaped_printing & escape_binary)
  1537. { int32 v = int_of_fixnum(u);
  1538. /* int width = escape_width(escaped_printing); */
  1539. unsigned32 mask = 0x40000000;
  1540. len = 0;
  1541. if (v < 0)
  1542. { while ((v & mask) == mask && mask != 0)
  1543. { v = v ^ (mask << 1);
  1544. mask = mask >> 1;
  1545. }
  1546. my_buff[len++] = '~';
  1547. k = '1';
  1548. }
  1549. else k = '0';
  1550. /*
  1551. * /* Width specifier not processed here (yet), sorry.
  1552. */
  1553. mask = 0x80000000;
  1554. while ((v & mask) == 0 && mask != 1) mask = mask >> 1;
  1555. while (mask != 0)
  1556. { my_buff[len++] = (v & mask) ? '1' : '0';
  1557. mask = mask >> 1;
  1558. }
  1559. my_buff[len] = 0;
  1560. }
  1561. else
  1562. sprintf(my_buff, "%ld", (long)int_of_fixnum(u));
  1563. break;
  1564. case TAG_ODDS:
  1565. if (is_bps(u))
  1566. { Header h = *(Header *)(data_of_bps(u) - CELL);
  1567. len = length_of_header(h) - CELL;
  1568. push(u);
  1569. outprefix(blankp, 3+2*len);
  1570. putc_stream('#', active_stream); putc_stream('[', active_stream);
  1571. for (k = 0; k < len; k++)
  1572. { int ch = ((char *)data_of_bps(stack[0]))[k];
  1573. static char *hexdig = "0123456789abcdef";
  1574. /*
  1575. * Code vectors are not ever going to be re-readable (huh - I suppose there
  1576. * is no big reason why they should not be!) so I split them across multiple
  1577. * lines if that seems useful. Anyway a reader for them could understand to
  1578. * expect that.
  1579. */
  1580. outprefix(NO, 2);
  1581. #ifdef DEMO_MODE
  1582. putc_stream('?', active_stream);
  1583. putc_stream('?', active_stream);
  1584. #else
  1585. putc_stream(hexdig[(ch >> 4) & 0xf], active_stream);
  1586. putc_stream(hexdig[ch & 0xf], active_stream);
  1587. #endif
  1588. }
  1589. popv(1);
  1590. putc_stream(']', active_stream);
  1591. return;
  1592. }
  1593. /*
  1594. * A SPID is an object used internally by CSL in various places, and the
  1595. * rules of the system are that it ought never to be visible to the user.
  1596. * I print it here in case it arises because of a bug, or while I am testing.
  1597. */
  1598. else if (is_spid(u))
  1599. { switch (u & 0xffff)
  1600. {
  1601. /*
  1602. * The decoding of readable names for SPIDs here is somewhat over the top
  1603. * except while somebdy is hard at work debugging....
  1604. */
  1605. case SPID_NIL: strcpy(my_buff, "SPID_NIL"); break;
  1606. case SPID_FBIND: strcpy(my_buff, "SPID_FBIND"); break;
  1607. case SPID_CATCH: strcpy(my_buff, "SPID_CATCH"); break;
  1608. case SPID_PROTECT: strcpy(my_buff, "SPID_PROTECT"); break;
  1609. case SPID_NOARG: strcpy(my_buff, "SPID_NOARG"); break;
  1610. case SPID_HASH0: strcpy(my_buff, "SPID_HASH0"); break;
  1611. case SPID_HASH1: strcpy(my_buff, "SPID_HASH1"); break;
  1612. case SPID_GCMARK: strcpy(my_buff, "SPID_GCMARK"); break;
  1613. case SPID_NOINPUT: strcpy(my_buff, "SPID_NOINPUT"); break;
  1614. case SPID_ERROR: strcpy(my_buff, "SPID_ERROR"); break;
  1615. case SPID_PVBIND: strcpy(my_buff, "SPID_PVBIND"); break;
  1616. case SPID_NOPROP: strcpy(my_buff, "SPID_NOPROP"); break;
  1617. case SPID_LIBRARY: u = (u >> 20) & 0xfff;
  1618. /*
  1619. * When I print the name of a library I will truncate the displayed name
  1620. * to 30 characters. This is somewhat arbitrary (but MUST relate to the
  1621. * size of my_buff), but will tend to keep output more compact.
  1622. */
  1623. sprintf(my_buff, "#{%.30s}", fasl_paths[u]);
  1624. break;
  1625. default: sprintf(my_buff, "SPID_%lx",
  1626. (long)((u >> 8) & 0x00ffffff));
  1627. break;
  1628. }
  1629. len = strlen(my_buff);
  1630. outprefix(blankp, len);
  1631. for (k=0; k<len; k++) putc_stream(my_buff[k], active_stream);
  1632. return;
  1633. }
  1634. /*
  1635. * Assume if is a CHAR here
  1636. */
  1637. outprefix(blankp, escaped_printing & escape_yes ? 3 : 1);
  1638. if (u != CHAR_EOF)
  1639. /* I know that a char is immediate data and so does not need GC protection */
  1640. { if (escaped_printing & escape_yes)
  1641. putc_stream('#', active_stream), putc_stream('\\', active_stream);
  1642. putc_stream((int)code_of_char(u), active_stream);
  1643. }
  1644. return;
  1645. case TAG_VECTOR:
  1646. { Header h = vechdr(u);
  1647. len = length_of_header(h) - CELL; /* counts in bytes */
  1648. push(u);
  1649. #ifdef COMMON
  1650. print_non_simple_string:
  1651. #endif
  1652. switch (type_of_header(h))
  1653. {
  1654. case TYPE_STRING:
  1655. { int32 slen = 0;
  1656. if (escaped_printing & escape_yes)
  1657. { for (k = 0; k < len; k++)
  1658. { int ch = celt(stack[0], k);
  1659. if (ch == '"') slen += 2;
  1660. #ifdef COMMON
  1661. else if (ch == '\\') slen += 2;
  1662. #endif
  1663. else if (iscntrl(ch)) slen += 3;
  1664. else slen += 1;
  1665. }
  1666. slen += 2;
  1667. }
  1668. else slen = len;
  1669. outprefix(blankp, slen);
  1670. /*
  1671. * I will write out the fast, easy, common case here
  1672. */
  1673. if (!(escaped_printing &
  1674. (escape_yes | escape_fold_down |
  1675. escape_fold_up | escape_capitalize)))
  1676. { for (k = 0; k < len; k++)
  1677. { int ch = celt(stack[0], k);
  1678. putc_stream(ch, active_stream);
  1679. }
  1680. }
  1681. else
  1682. { if (escaped_printing & escape_yes) putc_stream('"', active_stream);
  1683. for (k = 0; k < len; k++)
  1684. { int ch = celt(stack[0], k);
  1685. static char *hexdig = "0123456789abcdef";
  1686. #ifdef COMMON
  1687. if ((escaped_printing & escape_yes) &&
  1688. (ch == '"' || ch == '\\'))
  1689. { putc_stream('\\', active_stream);
  1690. putc_stream(ch, active_stream);
  1691. }
  1692. #else
  1693. if ((escaped_printing & escape_yes) && ch == '"')
  1694. { putc_stream('"', active_stream);
  1695. putc_stream('"', active_stream);
  1696. }
  1697. #endif
  1698. else if (iscntrl(ch))
  1699. { putc_stream('\\', active_stream);
  1700. putc_stream(hexdig[(ch >> 4) & 0xf], active_stream);
  1701. putc_stream(hexdig[ch & 0xf], active_stream);
  1702. }
  1703. else
  1704. {
  1705. if (escaped_printing & escape_fold_down)
  1706. ch = tolower(ch);
  1707. else if (escaped_printing & escape_fold_up)
  1708. ch = toupper(ch);
  1709. /* Just For Now I Will Not Implement The Option To Capitalize Things */
  1710. putc_stream(ch, active_stream);
  1711. }
  1712. }
  1713. }
  1714. popv(1);
  1715. if (escaped_printing & escape_yes) putc_stream('"', active_stream);
  1716. }
  1717. return;
  1718. case TYPE_SP:
  1719. pop(u);
  1720. sprintf(my_buff, "#<closure: %p>",
  1721. (void *)elt(u, 0));
  1722. goto print_my_buff;
  1723. case TYPE_SPARE:
  1724. pop(u);
  1725. sprintf(my_buff, "#<encapsulated pointer: %p>",
  1726. (void *)elt(u, 0));
  1727. goto print_my_buff;
  1728. #ifdef COMMON
  1729. case TYPE_BITVEC1: bl = 1; break;
  1730. case TYPE_BITVEC2: bl = 2; break;
  1731. case TYPE_BITVEC3: bl = 3; break;
  1732. case TYPE_BITVEC4: bl = 4; break;
  1733. case TYPE_BITVEC5: bl = 5; break;
  1734. case TYPE_BITVEC6: bl = 6; break;
  1735. case TYPE_BITVEC7: bl = 7; break;
  1736. case TYPE_BITVEC8: bl = 8; break;
  1737. #endif
  1738. #ifndef COMMON
  1739. case TYPE_STRUCTURE:
  1740. pop(u);
  1741. sprintf(my_buff, "[e-vector:%.8lx]", (long)(unsigned32)u);
  1742. goto print_my_buff;
  1743. #else
  1744. case TYPE_STRUCTURE:
  1745. if (elt(stack[0], 0) == package_symbol)
  1746. { outprefix(blankp, 3);
  1747. putc_stream('#', active_stream); putc_stream('P', active_stream); putc_stream(':', active_stream);
  1748. pop(u);
  1749. u = elt(u, 8); /* The name of the package */
  1750. blankp = 0;
  1751. goto restart;
  1752. }
  1753. /* Drop through */
  1754. #endif
  1755. case TYPE_ARRAY:
  1756. #ifdef COMMON
  1757. { Lisp_Object dims = elt(stack[0], 1);
  1758. /*
  1759. * I suppose that really I need to deal with non-simple bitvectors too.
  1760. * And generally get Common Lisp style array printing "right".
  1761. */
  1762. if (consp(dims) && !consp(qcdr(dims)) &&
  1763. elt(stack[0], 0) == string_char_sym)
  1764. { len = int_of_fixnum(qcar(dims));
  1765. dims = elt(stack[0], 5); /* Fill pointer */
  1766. if (is_fixnum(dims)) len = int_of_fixnum(dims);
  1767. stack[0] = elt(stack[0], 2);
  1768. /*
  1769. * The demand here is that the object within the non-simple-string was
  1770. * a simple string, so I can restart printing to deal with it. This will
  1771. * not support strings that were over-large so got represented in
  1772. * chunks. Tough luck about that for now!
  1773. */
  1774. h = TYPE_STRING;
  1775. goto print_non_simple_string;
  1776. }
  1777. }
  1778. /* Drop through */
  1779. #endif
  1780. case TYPE_SIMPLE_VEC:
  1781. case TYPE_HASH:
  1782. {
  1783. #ifndef COMMON
  1784. if (type_of_header(h) == TYPE_SIMPLE_VEC)
  1785. { outprefix(blankp, 1);
  1786. putc_stream('[', active_stream);
  1787. }
  1788. else
  1789. #endif
  1790. if (type_of_header(h) == TYPE_STRUCTURE)
  1791. { outprefix(blankp, 3);
  1792. putc_stream('#', active_stream); putc_stream('S', active_stream); putc_stream('(', active_stream);
  1793. }
  1794. else if (type_of_header(h) == TYPE_HASH)
  1795. { outprefix(blankp, 3);
  1796. putc_stream('#', active_stream); putc_stream('H', active_stream); putc_stream('(', active_stream);
  1797. }
  1798. else
  1799. { outprefix(blankp, 2);
  1800. putc_stream('#', active_stream); putc_stream('(', active_stream);
  1801. }
  1802. #ifdef COMMON
  1803. if (qvalue(print_array_sym) == nil)
  1804. { putc_stream('.', active_stream);
  1805. putc_stream('.', active_stream);
  1806. putc_stream('.', active_stream);
  1807. }
  1808. else
  1809. #endif
  1810. for (k=0; k<len; k+=CELL)
  1811. { Lisp_Object vv = *(Lisp_Object *)
  1812. ((char *)stack[0] + (CELL - TAG_VECTOR) + k);
  1813. internal_prin(vv, (k != 0) ? 1 : 0);
  1814. errexitvn(1);
  1815. }
  1816. popv(1);
  1817. outprefix(NO, 1);
  1818. #ifndef COMMON
  1819. if (type_of_header(h) == TYPE_SIMPLE_VEC) putc_stream(']', active_stream);
  1820. else
  1821. #endif
  1822. putc_stream(')', active_stream);
  1823. return;
  1824. }
  1825. case TYPE_MIXED1: /* An experimental addition to CSL */
  1826. case TYPE_MIXED2:
  1827. case TYPE_MIXED3:
  1828. case TYPE_STREAM:
  1829. { outprefix(blankp, 3);
  1830. putc_stream('#', active_stream);
  1831. if (type_of_header(h) == TYPE_STREAM)
  1832. putc_stream('F', active_stream);
  1833. else if (type_of_header(h) == TYPE_MIXED1)
  1834. putc_stream('1', active_stream);
  1835. else if (type_of_header(h) == TYPE_MIXED2)
  1836. putc_stream('2', active_stream);
  1837. else putc_stream('3', active_stream);
  1838. putc_stream('[', active_stream);
  1839. #ifdef COMMON
  1840. if (qvalue(print_array_sym) == nil)
  1841. { putc_stream('.', active_stream);
  1842. putc_stream('.', active_stream);
  1843. putc_stream('.', active_stream);
  1844. }
  1845. else
  1846. #endif
  1847. { internal_prin(elt(stack[0], 0), 0);
  1848. errexitvn(1);
  1849. outprefix(NO, 1);
  1850. internal_prin(elt(stack[0], 1), 1);
  1851. errexitvn(1);
  1852. outprefix(NO, 1);
  1853. internal_prin(elt(stack[0], 2), 1);
  1854. errexitvn(1);
  1855. }
  1856. for (k=3*CELL; k<len; k+=CELL)
  1857. { sprintf(my_buff, "%.8lx", (long)*(Lisp_Object *)
  1858. ((char *)stack[0] + (CELL - TAG_VECTOR) + k));
  1859. prin_buf(my_buff, YES);
  1860. }
  1861. popv(1);
  1862. outprefix(NO, 1);
  1863. putc_stream(']', active_stream);
  1864. return;
  1865. }
  1866. case TYPE_VEC8:
  1867. outprefix(blankp, 4);
  1868. putc_stream('#', active_stream); putc_stream('V', active_stream);
  1869. putc_stream('8', active_stream); putc_stream('(', active_stream);
  1870. for (k=0; k<len; k++)
  1871. { sprintf(my_buff, "%d", scelt(stack[0], k));
  1872. prin_buf(my_buff, k != 0);
  1873. }
  1874. outprefix(NO, 1);
  1875. putc_stream(')', active_stream);
  1876. popv(1);
  1877. return;
  1878. case TYPE_VEC16:
  1879. outprefix(blankp, 5);
  1880. putc_stream('#', active_stream); putc_stream('V', active_stream);
  1881. putc_stream('1', active_stream); putc_stream('6', active_stream); putc_stream('(', active_stream);
  1882. len = len >> 1;
  1883. for (k=0; k<len; k++)
  1884. { sprintf(my_buff, "%d", helt(stack[0], k));
  1885. prin_buf(my_buff, k != 0);
  1886. }
  1887. outprefix(NO, 1);
  1888. putc_stream(')', active_stream);
  1889. popv(1);
  1890. return;
  1891. case TYPE_VEC32:
  1892. outprefix(blankp, 5);
  1893. putc_stream('#', active_stream); putc_stream('V', active_stream);
  1894. putc_stream('3', active_stream); putc_stream('2', active_stream); putc_stream('(', active_stream);
  1895. len = len >> 2;
  1896. for (k=0; k<len; k++)
  1897. { sprintf(my_buff, "%d", ielt(stack[0], k));
  1898. prin_buf(my_buff, k != 0);
  1899. }
  1900. outprefix(NO, 1);
  1901. putc_stream(')', active_stream);
  1902. popv(1);
  1903. return;
  1904. case TYPE_FLOAT32:
  1905. outprefix(blankp, 4);
  1906. putc_stream('#', active_stream); putc_stream('F', active_stream);
  1907. putc_stream('S', active_stream); putc_stream('(', active_stream);
  1908. len = len >> 2;
  1909. for (k=0; k<len; k++)
  1910. { sprintf(my_buff, "%#.7g", (double)felt(stack[0], k));
  1911. prin_buf(my_buff, k != 0);
  1912. }
  1913. outprefix(NO, 1);
  1914. putc_stream(')', active_stream);
  1915. popv(1);
  1916. return;
  1917. case TYPE_FLOAT64:
  1918. outprefix(blankp, 4);
  1919. putc_stream('#', active_stream); putc_stream('F', active_stream);
  1920. putc_stream('D', active_stream); putc_stream('(', active_stream);
  1921. len = (len-CELL)/8;
  1922. /* I will not worry about print-precision bugs here... */
  1923. for (k=0; k<len; k++)
  1924. { sprintf(my_buff, "%#.*g",
  1925. (int)print_precision, delt(stack[0], k));
  1926. prin_buf(my_buff, k != 0);
  1927. }
  1928. outprefix(NO, 1);
  1929. putc_stream(')', active_stream);
  1930. popv(1);
  1931. return;
  1932. default: goto error_case;
  1933. }
  1934. #ifdef COMMON
  1935. /* Here for bit-vectors */
  1936. outprefix(blankp, 2+8*(len-1)+bl);
  1937. putc_stream('#', active_stream), putc_stream('*', active_stream);
  1938. { int z, q;
  1939. for (k = 0; k < len-1; k++)
  1940. { z = ucelt(stack[0], k);
  1941. for (q=0; q<8; q++)
  1942. { if (z & 1) putc_stream('1', active_stream);
  1943. else putc_stream('0', active_stream);
  1944. z >>= 1;
  1945. }
  1946. }
  1947. if (len != 0) /* Empty bitvec */
  1948. { z = ucelt(stack[0], len-1);
  1949. for (q=0; q<bl; q++)
  1950. { if (z & 1) putc_stream('1', active_stream);
  1951. else putc_stream('0', active_stream);
  1952. z >>= 1;
  1953. }
  1954. }
  1955. }
  1956. popv(1);
  1957. return;
  1958. #endif
  1959. }
  1960. #ifdef VERY_CAUTIOUS
  1961. /*
  1962. * It seems probable that I could never get here, but this "return" is
  1963. * just in case, as a safety measure.
  1964. */
  1965. popv(1);
  1966. return;
  1967. #endif
  1968. case TAG_SYMBOL:
  1969. push(u);
  1970. /*
  1971. * When computing checksums with the "md5" function I count gensyms as being
  1972. * purely local to the current expression. The strange effect is that
  1973. * (md5 (gensym))
  1974. * always gives the same result, even though the gensyms involved are
  1975. * different. But it is REASONABLE compatible with a view that I am forming
  1976. * a digest of a printed representation and is needed if digests are to
  1977. * be acceptably consistent across lisp images.
  1978. */
  1979. if (escaped_printing & escape_checksum)
  1980. { if ((qheader(u) & (SYM_CODEPTR+SYM_ANY_GENSYM)) == SYM_ANY_GENSYM)
  1981. { Lisp_Object al = stream_write_data(active_stream);
  1982. while (al != nil &&
  1983. qcar(qcar(al)) != u) al = qcdr(al);
  1984. pop(u);
  1985. if (al == nil)
  1986. { al = acons(u, fixnum_of_int(local_gensym_count),
  1987. stream_write_data(active_stream));
  1988. local_gensym_count++;
  1989. if (exception_pending()) return;
  1990. stream_write_data(active_stream) = al;
  1991. }
  1992. al = qcdr(qcar(al));
  1993. sprintf(my_buff, "#G%lx", (long)int_of_fixnum(al));
  1994. break;
  1995. }
  1996. }
  1997. w = get_pname(u); /* allocates name for gensym if needbe */
  1998. u = stack[0];
  1999. #ifdef COMMON
  2000. tag_symbol:
  2001. #endif
  2002. nil = C_nil;
  2003. if (!exception_pending())
  2004. { Header h = vechdr(w);
  2005. int32 slen = 0;
  2006. int raised = 0;
  2007. #ifdef COMMON
  2008. int pkgid = 0; /* No package marker needed */
  2009. /*
  2010. * 0 no package marker needed
  2011. * 1 display as #:xxx (ie as a gensym)
  2012. * 2 display as :xxx (ie in keyword package)
  2013. * 3 display as ppp:xxx (external in its home package)
  2014. * 4 display as ppp::xxx (internal in its home package)
  2015. */
  2016. if (escaped_printing & escape_yes)
  2017. { if (!is_symbol(u)) pkgid = 0; /* Support for a HACK */
  2018. else if (qpackage(u) == nil) pkgid = 1; /* gensym */
  2019. else if (qpackage(u) == qvalue(keyword_package)) pkgid = 2;
  2020. else if (qpackage(u) == CP) pkgid = 0; /* home is current */
  2021. else
  2022. { pkgid = 3;
  2023. k = packflags_(CP);
  2024. if (k != 0 && k <= SYM_IN_PKG_COUNT)
  2025. { k = ((int32)1) << (k+SYM_IN_PKG_SHIFT-1);
  2026. if (k & qheader(u)) pkgid = 0;
  2027. }
  2028. else k = 0;
  2029. if (pkgid != 0)
  2030. { push(w);
  2031. w = Lfind_symbol_1(nil, w);
  2032. nil = C_nil;
  2033. if (exception_pending())
  2034. { popv(2);
  2035. return;
  2036. }
  2037. u = stack[-1];
  2038. if (mv_2 != nil && w == u)
  2039. { pkgid = 0;
  2040. /*
  2041. * Here I update the cache it that keeps telling me that the symbol is
  2042. * is "available" in the package that is current at present. I guess that
  2043. * I need to clear this bit if I unintern or otherwise mess around with
  2044. * package structures.
  2045. */
  2046. qheader(u) |= k;
  2047. }
  2048. else if (qheader(u) & SYM_EXTERN_IN_HOME) pkgid = 3;
  2049. else pkgid = 4;
  2050. pop(w);
  2051. }
  2052. }
  2053. }
  2054. #endif
  2055. len = length_of_header(h); /* counts in bytes */
  2056. /*
  2057. * When I come to print things I will assume that I want them re-readable
  2058. * with values of !*raise and !*lower as in effect when the printing took
  2059. * place, and insert escape characters accordingly. I optimise the case
  2060. * of printing without any effects...
  2061. */
  2062. if (!(escaped_printing &
  2063. (escape_yes | escape_fold_down |
  2064. escape_fold_up | escape_capitalize)))
  2065. { stack[0] = w;
  2066. len -= CELL;
  2067. #ifdef COMMON
  2068. switch (pkgid)
  2069. {
  2070. case 1: outprefix(blankp, len+2);
  2071. putc_stream('#', active_stream);
  2072. putc_stream(':', active_stream);
  2073. break;
  2074. case 2: outprefix(blankp, len+1);
  2075. putc_stream(':', active_stream);
  2076. break;
  2077. case 3:
  2078. case 4: internal_prin(packname_(qpackage(u)), blankp | 2);
  2079. putc_stream(':', active_stream);
  2080. if (pkgid == 4) putc_stream(':', active_stream);
  2081. break;
  2082. default:outprefix(blankp, len);
  2083. break;
  2084. }
  2085. #else
  2086. outprefix(blankp, len);
  2087. #endif
  2088. for (k = 0; k < len; k++)
  2089. { int ch = celt(stack[0], k);
  2090. putc_stream(ch, active_stream);
  2091. }
  2092. }
  2093. else
  2094. { int extralen = 0;
  2095. if (qvalue(lower_symbol) != nil) raised = -1;
  2096. else if (qvalue(raise_symbol) != nil) raised = 1;
  2097. stack[0] = w;
  2098. len -= CELL;
  2099. /* A really horrid case here - digits are special at the start of names! */
  2100. if (len > 0)
  2101. { int ch = celt(stack[0], 0);
  2102. if (escaped_printing & escape_yes &&
  2103. (isdigit(ch)
  2104. #ifdef COMMON
  2105. || (ch=='.')
  2106. #else
  2107. || (ch=='_')
  2108. #endif
  2109. )) extralen++;
  2110. }
  2111. for (k = 0; k < len; k++)
  2112. { int ch = celt(stack[0], k);
  2113. if (escaped_printing & escape_yes &&
  2114. !(escaped_printing &
  2115. (escape_fold_down |
  2116. escape_fold_up |
  2117. escape_capitalize)) &&
  2118. #ifdef COMMON
  2119. (ch=='.' || ch=='\\' || ch=='|') ||
  2120. #endif
  2121. (!is_constituent(ch) ||
  2122. #ifdef COMMON
  2123. (ch=='.' || ch=='\\' || ch=='|' || ch==':') ||
  2124. #endif
  2125. (raised < 0 && isupper(ch)) ||
  2126. (raised > 0 && islower(ch)))) extralen++;
  2127. slen++;
  2128. }
  2129. #ifdef COMMON
  2130. /*
  2131. * The |xxx| notation is where the "2" here comes from, but that does not
  2132. * make full allowance for names with '\\' in them. Tough!
  2133. */
  2134. if (extralen != 0) extralen = 2;
  2135. switch (pkgid)
  2136. {
  2137. case 1: outprefix(blankp, slen+extralen+2);
  2138. putc_stream('#', active_stream);
  2139. putc_stream(':', active_stream);
  2140. break;
  2141. case 2: outprefix(blankp, slen+extralen+1);
  2142. putc_stream(':', active_stream);
  2143. break;
  2144. case 3:
  2145. case 4: internal_prin(packname_(qpackage(u)), blankp | 2);
  2146. putc_stream(':', active_stream);
  2147. if (pkgid == 4) putc_stream(':', active_stream);
  2148. break;
  2149. default:outprefix(blankp, len);
  2150. break;
  2151. }
  2152. #else
  2153. outprefix(blankp, slen+extralen);
  2154. #endif
  2155. #ifdef COMMON
  2156. if (extralen != 0) putc_stream('|', active_stream);
  2157. #endif
  2158. if (len > 0)
  2159. { int ch = celt(stack[0], 0);
  2160. #ifdef COMMON
  2161. if (ch == '\\' || ch=='|')
  2162. putc_stream(ESCAPE_CHAR, active_stream);
  2163. #else
  2164. if (!is_constituent(ch) ||
  2165. isdigit(ch) ||
  2166. (ch == '_') ||
  2167. (!(escaped_printing &
  2168. (escape_fold_down | escape_fold_up |
  2169. escape_capitalize)) &&
  2170. ((raised < 0 && isupper(ch)) ||
  2171. (raised > 0 && islower(ch)))))
  2172. putc_stream(ESCAPE_CHAR, active_stream);
  2173. #endif
  2174. if (escaped_printing & escape_fold_down)
  2175. ch = tolower(ch);
  2176. else if (escaped_printing & escape_fold_up)
  2177. ch = toupper(ch);
  2178. putc_stream(ch, active_stream);
  2179. }
  2180. for (k = 1; k < len; k++)
  2181. { int ch = celt(stack[0], k);
  2182. #ifdef COMMON
  2183. if (ch == '\\' || ch=='|')
  2184. putc_stream(ESCAPE_CHAR, active_stream);
  2185. #else
  2186. if (!(escaped_printing &
  2187. (escape_fold_down | escape_fold_up |
  2188. escape_capitalize)) &&
  2189. (!is_constituent(ch) ||
  2190. (raised < 0 && isupper(ch)) ||
  2191. (raised > 0 && islower(ch))))
  2192. putc_stream(ESCAPE_CHAR, active_stream);
  2193. #endif
  2194. if (escaped_printing & escape_fold_down)
  2195. ch = tolower(ch);
  2196. else if (escaped_printing & escape_fold_up)
  2197. ch = toupper(ch);
  2198. putc_stream(ch, active_stream);
  2199. }
  2200. #ifdef COMMON
  2201. if (extralen != 0) putc_stream('|', active_stream);
  2202. #endif
  2203. }
  2204. }
  2205. popv(1);
  2206. return;
  2207. case TAG_BOXFLOAT:
  2208. switch (type_of_header(flthdr(u)))
  2209. {
  2210. #ifdef COMMON
  2211. case TYPE_SINGLE_FLOAT:
  2212. sprintf(my_buff, "%#.7g", (double)single_float_val(u));
  2213. break;
  2214. #endif
  2215. case TYPE_DOUBLE_FLOAT:
  2216. /*
  2217. * Hexadecimal printing of floating point numbers is only provided for
  2218. * here to help with nasty low-level debugging. The output will not be
  2219. * directly re-readable. It is only provided for the (default) double-
  2220. * precision numbers. Use (prinhex ..) to activate it.
  2221. */
  2222. if (escaped_printing & escape_hex)
  2223. { unsigned32 *p = (unsigned32 *)((char *)u + 1);
  2224. int q = current_fp_rep & FP_WORD_ORDER;
  2225. sprintf(my_buff, "{%.8lx/%.8lx:%#.8g}",
  2226. (long)(unsigned32)p[1-q],
  2227. (long)(unsigned32)p[q],
  2228. double_float_val(u));
  2229. }
  2230. else if (escaped_printing & escape_octal)
  2231. { unsigned32 *p = (unsigned32 *)((char *)u + 1);
  2232. int q = current_fp_rep & FP_WORD_ORDER;
  2233. sprintf(my_buff, "{%.11lo/%.11lo:%#.8g}",
  2234. (long)p[1-q], (long)p[q],
  2235. double_float_val(u));
  2236. }
  2237. else
  2238. #if defined __WATCOMC__
  2239. { double d = double_float_val(u);
  2240. /*
  2241. * version 10.0a of Watcom C (which I was using in April 1995) had a bug
  2242. * whereby the specified precision is handled incorrectly.
  2243. * Version 10.5 seems to have a different but also dubious behaviour!
  2244. * The following code uses simpler formats to try to avoid trouble. It
  2245. * MIGHT make sense to enable if for all systems not just Watcom, if I
  2246. * ever see precision problems elsewhere... Note however that there are
  2247. * delicacies here with numbers like 0.0001 which do not have exact (binary
  2248. * floating point) representations but are boundary cases for print-format
  2249. * selection. I am bound to get numbers very close to such boundaries
  2250. * "wrong" at times here. To be more precise, values just less than the
  2251. * above will be displayed using E format and values just greater using F
  2252. * format, despite the numeric display not being able to show any
  2253. * difference in the value.
  2254. * An alternative approach would be for me to convert the number to decimal
  2255. * at as high a precision as possible and then do the formatting for myself
  2256. * based on the character-string so generated. That seems too much effort for
  2257. * now, and also raises difficulties of double-rounding...
  2258. */
  2259. double ad = 10000.0*(d < 0.0 ? -d : d);
  2260. double xx = 1.0;
  2261. for (k=-4; k<=(int)print_precision && xx<=ad; k++) xx *= 10.0;
  2262. if (k==-4 || k>(int)print_precision)
  2263. sprintf(my_buff, "%#.*e", (int)print_precision-1, d);
  2264. else sprintf(my_buff, "%#.*f", (int)print_precision-k, d);
  2265. }
  2266. #else
  2267. sprintf(my_buff, "%#.*g", (int)print_precision,
  2268. double_float_val(u));
  2269. #endif
  2270. break;
  2271. #ifdef COMMON
  2272. case TYPE_LONG_FLOAT:
  2273. sprintf(my_buff, "%#.17g", (double)long_float_val(u));
  2274. break;
  2275. #endif
  2276. default:
  2277. sprintf(my_buff, "?%.8lx?", (long)(unsigned32)u);
  2278. break;
  2279. }
  2280. /*
  2281. * I want to trim off trailing zeros, but ensure I leave a digit after the
  2282. * decimal point. Things are made more complicated by the presence of an
  2283. * exponent. Note that the '#' in the format conversions should mean that
  2284. * I ALWAYS have a '.' in the number that has been printed. However on some
  2285. * systems this proves not to be the case - in particular IEEE infinities
  2286. * (and maybe NaNs?) get displayed without a '.' in some environments where
  2287. * they are supported. I also see that some C libraries in some of the cases
  2288. * I generate above dump out nonsense like 0.0e+000 with unreasonably wide
  2289. * exponents, so I will try to rationalise that sort of mess too.
  2290. */
  2291. #ifdef COMMON
  2292. float_print_tidyup:
  2293. #endif
  2294. { int i = 0, j, c;
  2295. while ((c = my_buff[i]) != 0 && c != '.') i++;
  2296. if (c == 0) break; /* No '.' found, so leave unaltered */
  2297. j = i+1;
  2298. /* Find the end of the fraction (= end of number or start of exponent) */
  2299. while ((c = my_buff[j]) != 'e' && c != 0) j++;
  2300. if (c == 'e')
  2301. { /* check for leading zeros in an exponent component */
  2302. while (my_buff[j+1] == '+' || my_buff[j+1] == '0')
  2303. { int m = j+1;
  2304. for (;;)
  2305. { if ((my_buff[m] = my_buff[m+1]) == 0) break;
  2306. m++;
  2307. }
  2308. }
  2309. if (my_buff[j+1] == '-') /* kill leading zeros after '-' */
  2310. { while (my_buff[j+2] == '0')
  2311. { int m = j+2;
  2312. for (;;)
  2313. { if ((my_buff[m] = my_buff[m+1]) == 0) break;
  2314. m++;
  2315. }
  2316. }
  2317. if (my_buff[j+2] == 0) my_buff[j+1] = 0;
  2318. }
  2319. if (my_buff[j+1] == 0) my_buff[j] = 0; /* "e" now at end? */
  2320. }
  2321. k = j - 1;
  2322. if (k == i) /* no digits after the '.' - push in a '0' */
  2323. { int l = j;
  2324. while (my_buff[l] != 0) l++;
  2325. while (l >= j)
  2326. { my_buff[l+1] = my_buff[l];
  2327. l--;
  2328. }
  2329. my_buff[j++] = '0';
  2330. }
  2331. else
  2332. /* Scan back past any trailing zeroes */
  2333. { i++;
  2334. while (k > i && my_buff[k] == '0') k--;
  2335. /* Copy data down to strip out the unnecessary '0' characters */
  2336. if (k != j-1)
  2337. { k++;
  2338. while ((my_buff[k++] = my_buff[j++]) != 0) /* nothing */ ;
  2339. }
  2340. }
  2341. }
  2342. /*
  2343. * For my purposes I do not want to see "-0.0" - it causes muddle and loses
  2344. * portability. I know that losing the information here removes a facility
  2345. * from people but it also removes pain from naive users!
  2346. */
  2347. if (strcmp(my_buff, "-0.0") == 0) strcpy(my_buff, "0.0");
  2348. break;
  2349. case TAG_NUMBERS:
  2350. if (is_bignum(u))
  2351. {
  2352. if (escaped_printing & escape_hex)
  2353. print_bighexoctbin(u, 16, escape_width(escaped_printing),
  2354. blankp, escaped_printing & escape_nolinebreak);
  2355. else if (escaped_printing & escape_octal)
  2356. print_bighexoctbin(u, 8, escape_width(escaped_printing),
  2357. blankp, escaped_printing & escape_nolinebreak);
  2358. else if (escaped_printing & escape_binary)
  2359. print_bighexoctbin(u, 2, escape_width(escaped_printing),
  2360. blankp, escaped_printing & escape_nolinebreak);
  2361. else
  2362. print_bignum(u, blankp, escaped_printing & escape_nolinebreak);
  2363. return;
  2364. }
  2365. #ifdef COMMON
  2366. else if (is_ratio(u))
  2367. { push(u);
  2368. /*
  2369. * Here I have a line-break problem --- I do not measure the size of the
  2370. * denominator, and hence may well split a line between numerator and
  2371. * denominator. This would be HORRID. I guess that the correct recipe will
  2372. * involve measuring the size of the denominator first... Let's not bother
  2373. * just at the moment.
  2374. */
  2375. internal_prin(numerator(stack[0]), blankp);
  2376. outprefix(NO, 1);
  2377. putc_stream('/', active_stream);
  2378. pop(u);
  2379. internal_prin(denominator(u), 0);
  2380. return;
  2381. }
  2382. else if (is_complex(u))
  2383. { push(u);
  2384. outprefix(blankp, 3);
  2385. putc_stream('#', active_stream), putc_stream('C', active_stream); putc_stream('(', active_stream);
  2386. nil = C_nil;
  2387. if (exception_pending()) { popv(1); return; }
  2388. internal_prin(real_part(stack[0]), 0);
  2389. pop(u);
  2390. internal_prin(imag_part(u), 1);
  2391. outprefix(NO, 1);
  2392. putc_stream(')', active_stream);
  2393. return;
  2394. }
  2395. #endif
  2396. /* Else drop through to treat as an error */
  2397. default:
  2398. error_case:
  2399. sprintf(my_buff, "?%.8lx?", (long)(unsigned32)u);
  2400. break;
  2401. }
  2402. print_my_buff:
  2403. { char *p = my_buff;
  2404. int ch;
  2405. outprefix(blankp, strlen(my_buff));
  2406. while ((ch = *p++) != 0) putc_stream(ch, active_stream);
  2407. }
  2408. return;
  2409. }
  2410. Lisp_Object prin(Lisp_Object u)
  2411. {
  2412. nil_as_base
  2413. escaped_printing = escape_yes;
  2414. push(u);
  2415. active_stream = qvalue(standard_output);
  2416. if (!is_stream(active_stream)) active_stream = qvalue(terminal_io);
  2417. if (!is_stream(active_stream)) active_stream = lisp_terminal_io;
  2418. internal_prin(u, 0);
  2419. pop(u);
  2420. return u;
  2421. }
  2422. void prin_to_terminal(Lisp_Object u)
  2423. {
  2424. Lisp_Object nil = C_nil;
  2425. escaped_printing = escape_yes;
  2426. active_stream = qvalue(terminal_io);
  2427. if (!is_stream(active_stream)) active_stream = lisp_terminal_io;
  2428. internal_prin(u, 0);
  2429. ignore_exception();
  2430. ensure_screen();
  2431. /*
  2432. * The various "prin_to_xxx()" functions here are generally used (only) for
  2433. * diagnostic printing. So to try to keep interaction as smooth as possible
  2434. * in such cases I arrange that the operating system (eg window manager) will
  2435. * be polled rather soon...
  2436. */
  2437. #ifdef SOFTWARE_TICKS
  2438. if (countdown > 5) countdown = 5;
  2439. #endif
  2440. }
  2441. void prin_to_stdout(Lisp_Object u)
  2442. {
  2443. Lisp_Object nil = C_nil;
  2444. escaped_printing = escape_yes;
  2445. active_stream = qvalue(standard_output);
  2446. if (!is_stream(active_stream)) active_stream = lisp_standard_output;
  2447. internal_prin(u, 0);
  2448. ignore_exception();
  2449. ensure_screen();
  2450. #ifdef SOFTWARE_TICKS
  2451. if (countdown > 5) countdown = 5;
  2452. #endif
  2453. }
  2454. void prin_to_error(Lisp_Object u)
  2455. {
  2456. Lisp_Object nil = C_nil;
  2457. escaped_printing = escape_yes;
  2458. active_stream = qvalue(error_output);
  2459. if (!is_stream(active_stream)) active_stream = lisp_error_output;
  2460. internal_prin(u, 0);
  2461. ignore_exception();
  2462. ensure_screen();
  2463. #ifdef SOFTWARE_TICKS
  2464. if (countdown > 5) countdown = 5;
  2465. #endif
  2466. }
  2467. void prin_to_trace(Lisp_Object u)
  2468. {
  2469. Lisp_Object nil = C_nil;
  2470. escaped_printing = escape_yes;
  2471. active_stream = qvalue(trace_output);
  2472. if (!is_stream(active_stream)) active_stream = lisp_trace_output;
  2473. internal_prin(u, 0);
  2474. ignore_exception();
  2475. ensure_screen();
  2476. #ifdef SOFTWARE_TICKS
  2477. if (countdown > 5) countdown = 5;
  2478. #endif
  2479. }
  2480. void prin_to_debug(Lisp_Object u)
  2481. {
  2482. Lisp_Object nil = C_nil;
  2483. escaped_printing = escape_yes;
  2484. active_stream = qvalue(debug_io);
  2485. if (!is_stream(active_stream)) active_stream = lisp_debug_io;
  2486. internal_prin(u, 0);
  2487. ignore_exception();
  2488. ensure_screen();
  2489. #ifdef SOFTWARE_TICKS
  2490. if (countdown > 5) countdown = 5;
  2491. #endif
  2492. }
  2493. void prin_to_query(Lisp_Object u)
  2494. {
  2495. Lisp_Object nil = C_nil;
  2496. escaped_printing = escape_yes;
  2497. active_stream = qvalue(query_io);
  2498. if (!is_stream(active_stream)) active_stream = lisp_query_io;
  2499. internal_prin(u, 0);
  2500. ignore_exception();
  2501. ensure_screen();
  2502. #ifdef SOFTWARE_TICKS
  2503. if (countdown > 5) countdown = 5;
  2504. #endif
  2505. }
  2506. void loop_print_stdout(Lisp_Object o)
  2507. {
  2508. Lisp_Object nil = C_nil;
  2509. int32 sx = exit_reason;
  2510. one_args *f;
  2511. Lisp_Object lp = qvalue(traceprint_symbol);
  2512. if (lp == nil || lp == unset_var) lp = prinl_symbol;
  2513. if (!is_symbol(lp) ||
  2514. (f = qfn1(lp)) == undefined1) prin_to_stdout(o);
  2515. else
  2516. { CSLbool bad = NO;
  2517. Lisp_Object env = qenv(lp);
  2518. push2(lp, env);
  2519. ifn1(lp) = (int32)undefined1; /* To avoid recursion if it fails */
  2520. qenv(lp) = lp; /* make it an undefined function */
  2521. (*f)(env, o);
  2522. nil = C_nil;
  2523. if (exception_pending()) flip_exception(), bad = YES;
  2524. pop2(env, lp);
  2525. if (!bad) ifn1(lp) = (intxx)f, qenv(lp) = env; /* Restore if OK */
  2526. }
  2527. exit_reason = sx;
  2528. }
  2529. void loop_print_error(Lisp_Object o)
  2530. {
  2531. nil_as_base
  2532. Lisp_Object w = qvalue(standard_output);
  2533. push(w);
  2534. if (is_stream(qvalue(error_output)))
  2535. qvalue(standard_output) = qvalue(error_output);
  2536. loop_print_stdout(o);
  2537. pop(w);
  2538. qvalue(standard_output) = w;
  2539. #ifdef COMMON
  2540. /*
  2541. * This is to help me debug in the face of low level system crashes
  2542. */
  2543. if (spool_file) fflush(spool_file);
  2544. #endif
  2545. }
  2546. void loop_print_trace(Lisp_Object o)
  2547. {
  2548. nil_as_base
  2549. Lisp_Object w = qvalue(standard_output);
  2550. push(w);
  2551. if (is_stream(qvalue(trace_output)))
  2552. qvalue(standard_output) = qvalue(trace_output);
  2553. loop_print_stdout(o);
  2554. pop(w);
  2555. qvalue(standard_output) = w;
  2556. #ifdef COMMON
  2557. /*
  2558. * This is to help me debug in the face of low level system crashes
  2559. */
  2560. if (spool_file) fflush(spool_file);
  2561. #endif
  2562. }
  2563. void loop_print_debug(Lisp_Object o)
  2564. {
  2565. nil_as_base
  2566. Lisp_Object w = qvalue(standard_output);
  2567. push(w);
  2568. if (is_stream(qvalue(debug_io)))
  2569. qvalue(standard_output) = qvalue(debug_io);
  2570. loop_print_stdout(o);
  2571. pop(w);
  2572. qvalue(standard_output) = w;
  2573. }
  2574. void loop_print_query(Lisp_Object o)
  2575. {
  2576. nil_as_base
  2577. Lisp_Object w = qvalue(standard_output);
  2578. push(w);
  2579. if (is_stream(qvalue(query_io)))
  2580. qvalue(standard_output) = qvalue(query_io);
  2581. loop_print_stdout(o);
  2582. pop(w);
  2583. qvalue(standard_output) = w;
  2584. }
  2585. void loop_print_terminal(Lisp_Object o)
  2586. {
  2587. nil_as_base
  2588. Lisp_Object w = qvalue(standard_output);
  2589. push(w);
  2590. if (is_stream(qvalue(terminal_io)))
  2591. qvalue(standard_output) = qvalue(terminal_io);
  2592. loop_print_stdout(o);
  2593. pop(w);
  2594. qvalue(standard_output) = w;
  2595. }
  2596. static Lisp_Object prinhex(Lisp_Object u, int n)
  2597. {
  2598. nil_as_base
  2599. escaped_printing = escape_yes+escape_hex+((n & 0x3f)<<8);
  2600. push(u);
  2601. active_stream = qvalue(standard_output);
  2602. if (!is_stream(active_stream)) active_stream = qvalue(terminal_io);
  2603. if (!is_stream(active_stream)) active_stream = lisp_terminal_io;
  2604. internal_prin(u, 0);
  2605. pop(u);
  2606. return u;
  2607. }
  2608. static Lisp_Object prinoctal(Lisp_Object u, int n)
  2609. {
  2610. nil_as_base
  2611. escaped_printing = escape_yes+escape_octal+((n & 0x3f)<<8);
  2612. push(u);
  2613. active_stream = qvalue(standard_output);
  2614. if (!is_stream(active_stream)) active_stream = qvalue(terminal_io);
  2615. if (!is_stream(active_stream)) active_stream = lisp_terminal_io;
  2616. internal_prin(u, 0);
  2617. pop(u);
  2618. return u;
  2619. }
  2620. static Lisp_Object prinbinary(Lisp_Object u, int n)
  2621. {
  2622. nil_as_base
  2623. escaped_printing = escape_yes+escape_binary+((n & 0x3f)<<8);
  2624. push(u);
  2625. active_stream = qvalue(standard_output);
  2626. if (!is_stream(active_stream)) active_stream = qvalue(terminal_io);
  2627. if (!is_stream(active_stream)) active_stream = lisp_terminal_io;
  2628. internal_prin(u, 0);
  2629. pop(u);
  2630. return u;
  2631. }
  2632. Lisp_Object princ(Lisp_Object u)
  2633. {
  2634. nil_as_base
  2635. escaped_printing = 0;
  2636. push(u);
  2637. active_stream = qvalue(standard_output);
  2638. if (!is_stream(active_stream)) active_stream = qvalue(terminal_io);
  2639. if (!is_stream(active_stream)) active_stream = lisp_terminal_io;
  2640. internal_prin(u, 0);
  2641. pop(u);
  2642. return u;
  2643. }
  2644. Lisp_Object print(Lisp_Object u)
  2645. {
  2646. nil_as_base
  2647. Lisp_Object stream = qvalue(standard_output);
  2648. push(u);
  2649. escaped_printing = escape_yes;
  2650. if (!is_stream(stream)) stream = qvalue(terminal_io);
  2651. if (!is_stream(stream)) stream = lisp_terminal_io;
  2652. active_stream = stream;
  2653. putc_stream('\n', stream);
  2654. internal_prin(u, 0);
  2655. pop(u);
  2656. return u;
  2657. }
  2658. Lisp_Object printc(Lisp_Object u)
  2659. {
  2660. nil_as_base
  2661. Lisp_Object stream = qvalue(standard_output);
  2662. push(u);
  2663. escaped_printing = 0;
  2664. if (!is_stream(stream)) stream = qvalue(terminal_io);
  2665. if (!is_stream(stream)) stream = lisp_terminal_io;
  2666. active_stream = stream;
  2667. putc_stream('\n', stream);
  2668. internal_prin(u, 0);
  2669. pop(u);
  2670. return u;
  2671. }
  2672. void freshline_trace(void)
  2673. {
  2674. nil_as_base
  2675. if (other_write_action(WRITE_GET_INFO+WRITE_GET_COLUMN,
  2676. qvalue(trace_output)) != 0)
  2677. putc_stream('\n', qvalue(trace_output));
  2678. }
  2679. void freshline_debug(void)
  2680. {
  2681. nil_as_base
  2682. if (other_write_action(WRITE_GET_INFO+WRITE_GET_COLUMN,
  2683. qvalue(debug_io)) != 0)
  2684. putc_stream('\n', qvalue(debug_io));
  2685. }
  2686. int char_to_list(int c, Lisp_Object f)
  2687. {
  2688. Lisp_Object k, nil = C_nil;
  2689. /*
  2690. * return at once if a previous call raised an exception
  2691. */
  2692. if (exception_pending()) return 1;
  2693. k = elt(charvec, c & 0xff);
  2694. if (k == nil)
  2695. { celt(boffo, 0) = (char)c;
  2696. push(f);
  2697. /*
  2698. * It could very well be that in Common Lisp I ought to generate a list of
  2699. * character objects here. As it is I hand back symbols, but I do take care
  2700. * that they are in the LISP package.
  2701. */
  2702. k = iintern(boffo, 1, lisp_package, 0);
  2703. pop(f);
  2704. nil = C_nil;
  2705. if (exception_pending()) return 1;
  2706. elt(charvec, c & 0xff) = k;
  2707. }
  2708. push(f);
  2709. k = cons(k, stream_write_data(f));
  2710. pop(f);
  2711. nil = C_nil;
  2712. if (!exception_pending())
  2713. { stream_write_data(f) = k;
  2714. return 0;
  2715. }
  2716. else return 1;
  2717. }
  2718. static Lisp_Object explode(Lisp_Object u)
  2719. {
  2720. Lisp_Object nil = C_nil;
  2721. stream_write_data(lisp_work_stream) = nil;
  2722. set_stream_write_fn(lisp_work_stream, char_to_list);
  2723. set_stream_write_other(lisp_work_stream, write_action_list);
  2724. active_stream = lisp_work_stream;
  2725. internal_prin(u, 0);
  2726. errexit();
  2727. u = stream_write_data(lisp_work_stream);
  2728. stream_write_data(lisp_work_stream) = nil;
  2729. return nreverse(u);
  2730. }
  2731. static unsigned char checksum_buffer[64];
  2732. static int checksum_count;
  2733. int char_to_checksum(int c, Lisp_Object f)
  2734. {
  2735. Lisp_Object nil = C_nil;
  2736. /*
  2737. * return at once if a previous call raised an exception
  2738. */
  2739. CSL_IGNORE(f);
  2740. if (exception_pending()) return 1;
  2741. checksum_buffer[checksum_count++] = (char)c;
  2742. if (checksum_count == sizeof(checksum_buffer))
  2743. { MD5_Update(checksum_buffer, sizeof(checksum_buffer));
  2744. checksum_count = 0;
  2745. }
  2746. return 0;
  2747. }
  2748. void checksum(Lisp_Object u)
  2749. {
  2750. Lisp_Object nil = C_nil;
  2751. escaped_printing = escape_yes+escape_nolinebreak+escape_checksum;
  2752. set_stream_write_fn(lisp_work_stream, char_to_checksum);
  2753. set_stream_write_other(lisp_work_stream, write_action_list); /* sic */
  2754. active_stream = lisp_work_stream;
  2755. MD5_Init();
  2756. local_gensym_count = checksum_count = 0;
  2757. internal_prin(u, 0);
  2758. if (exception_pending()) return;
  2759. stream_write_data(lisp_work_stream) = nil;
  2760. if (checksum_count != 0)
  2761. MD5_Update(checksum_buffer, checksum_count);
  2762. }
  2763. int code_to_list(int c, Lisp_Object f)
  2764. {
  2765. Lisp_Object k, nil = C_nil;
  2766. /*
  2767. * return at once if a previous call raised an exception
  2768. */
  2769. if (exception_pending()) return 1;
  2770. k = fixnum_of_int((int32)c);
  2771. push(f);
  2772. k = cons(k, stream_write_data(f));
  2773. pop(f);
  2774. nil = C_nil;
  2775. if (!exception_pending())
  2776. { stream_write_data(f) = k;
  2777. stream_char_pos(f)++;
  2778. return 0;
  2779. }
  2780. else return 1;
  2781. }
  2782. static Lisp_Object exploden(Lisp_Object u)
  2783. {
  2784. Lisp_Object nil = C_nil;
  2785. stream_write_data(lisp_work_stream) = nil;
  2786. set_stream_write_fn(lisp_work_stream, code_to_list);
  2787. set_stream_write_other(lisp_work_stream, write_action_list);
  2788. active_stream = lisp_work_stream;
  2789. internal_prin(u, 0);
  2790. errexit();
  2791. u = stream_write_data(lisp_work_stream);
  2792. stream_write_data(lisp_work_stream) = nil;
  2793. return nreverse(u);
  2794. }
  2795. /*
  2796. * To cope with the needs of windowed implementations I am (unilaterally)
  2797. * altering the specification of the LINELENGTH function that I implement.
  2798. * The new rules are:
  2799. * (linelength nil) returns current width, always an integer
  2800. * (linelength n) sets new with to n, returns old
  2801. * (linelength T) sets new width to default for current stream,
  2802. * and returns old.
  2803. * the "old" value returned in the last two cases will often be the current
  2804. * linelength as returnd by (linelength nil), but it CAN be the value T.
  2805. * On some windowed systems after (linelength T) the value of (linelength nil)
  2806. * will track changes that the user makes by re-sizing the main output
  2807. * window on their screen. The linelength function inspects and sets
  2808. * information for the current standard output stream, and separate
  2809. * record is kept of the linelength associated with each stream.
  2810. */
  2811. Lisp_Object Llinelength(Lisp_Object nil, Lisp_Object a)
  2812. {
  2813. int32 oll;
  2814. Lisp_Object stream = qvalue(standard_output);
  2815. if (!is_stream(stream)) stream = qvalue(terminal_io);
  2816. if (!is_stream(stream)) stream = lisp_terminal_io;
  2817. if (a == nil)
  2818. oll = other_write_action(WRITE_GET_INFO+WRITE_GET_LINE_LENGTH, stream);
  2819. else if (a == lisp_true)
  2820. oll = other_write_action(WRITE_SET_LINELENGTH_DEFAULT, stream);
  2821. else if (!is_fixnum(a)) return aerror1("linelength", a);
  2822. else
  2823. { oll = int_of_fixnum(a);
  2824. if (oll < 10) oll = 10;
  2825. oll = other_write_action(WRITE_SET_LINELENGTH | oll, stream);
  2826. }
  2827. if (oll == 0x80000000) return onevalue(lisp_true);
  2828. else return onevalue(fixnum_of_int(oll));
  2829. }
  2830. static Lisp_Object MS_CDECL Llinelength0(Lisp_Object nil, int nargs, ...)
  2831. {
  2832. argcheck(nargs, 0, "linelength");
  2833. return Llinelength(nil, nil);
  2834. }
  2835. Lisp_Object Lprin(Lisp_Object nil, Lisp_Object a)
  2836. {
  2837. push(a);
  2838. escaped_printing = escape_yes;
  2839. active_stream = qvalue(standard_output);
  2840. if (!is_stream(active_stream)) active_stream = qvalue(terminal_io);
  2841. if (!is_stream(active_stream)) active_stream = lisp_terminal_io;
  2842. internal_prin(a, 0);
  2843. pop(a);
  2844. errexit();
  2845. return onevalue(a);
  2846. }
  2847. static Lisp_Object Lprinhex(Lisp_Object nil, Lisp_Object a)
  2848. {
  2849. push(a);
  2850. prinhex(a, 0);
  2851. pop(a);
  2852. errexit();
  2853. return onevalue(a);
  2854. }
  2855. static Lisp_Object Lprinoctal(Lisp_Object nil, Lisp_Object a)
  2856. {
  2857. push(a);
  2858. prinoctal(a, 0);
  2859. pop(a);
  2860. errexit();
  2861. return onevalue(a);
  2862. }
  2863. static Lisp_Object Lprinbinary(Lisp_Object nil, Lisp_Object a)
  2864. {
  2865. push(a);
  2866. prinbinary(a, 0);
  2867. pop(a);
  2868. errexit();
  2869. return onevalue(a);
  2870. }
  2871. static Lisp_Object Lprinhex2(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
  2872. {
  2873. if (!is_fixnum(b)) return aerror1("prinhex", b);
  2874. push(a);
  2875. prinhex(a, int_of_fixnum(b));
  2876. pop(a);
  2877. errexit();
  2878. return onevalue(a);
  2879. }
  2880. static Lisp_Object Lprinoctal2(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
  2881. {
  2882. if (!is_fixnum(b)) return aerror1("prinoctal", b);
  2883. push(a);
  2884. prinoctal(a, int_of_fixnum(b));
  2885. pop(a);
  2886. errexit();
  2887. return onevalue(a);
  2888. }
  2889. static Lisp_Object Lprinbinary2(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
  2890. {
  2891. if (!is_fixnum(b)) return aerror1("prinbinary", b);
  2892. push(a);
  2893. prinbinary(a, int_of_fixnum(b));
  2894. pop(a);
  2895. errexit();
  2896. return onevalue(a);
  2897. }
  2898. Lisp_Object MS_CDECL Lposn(Lisp_Object nil, int nargs, ...)
  2899. {
  2900. CSL_IGNORE(nil);
  2901. argcheck(nargs, 0, "posn");
  2902. return onevalue(fixnum_of_int((int32)
  2903. other_write_action(WRITE_GET_INFO+WRITE_GET_COLUMN,
  2904. qvalue(standard_output))));
  2905. }
  2906. Lisp_Object Lposn_1(Lisp_Object nil, Lisp_Object stream)
  2907. {
  2908. CSL_IGNORE(nil);
  2909. if (!is_stream(stream)) stream = qvalue(terminal_io);
  2910. if (!is_stream(stream)) stream = lisp_terminal_io;
  2911. return onevalue(fixnum_of_int((int32)
  2912. other_write_action(WRITE_GET_INFO+WRITE_GET_COLUMN, stream)));
  2913. }
  2914. Lisp_Object MS_CDECL Llposn(Lisp_Object nil, int nargs, ...)
  2915. {
  2916. CSL_IGNORE(nil);
  2917. argcheck(nargs, 0, "lposn");
  2918. return onevalue(fixnum_of_int(0));
  2919. }
  2920. Lisp_Object Lpagelength(Lisp_Object nil, Lisp_Object a)
  2921. {
  2922. CSL_IGNORE(nil);
  2923. return onevalue(a);
  2924. }
  2925. Lisp_Object Lprinc_upcase(Lisp_Object nil, Lisp_Object a)
  2926. {
  2927. CSL_IGNORE(nil);
  2928. push(a);
  2929. escaped_printing = escape_fold_up;
  2930. active_stream = qvalue(standard_output);
  2931. if (!is_stream(active_stream)) active_stream = qvalue(terminal_io);
  2932. if (!is_stream(active_stream)) active_stream = lisp_terminal_io;
  2933. internal_prin(a, 0);
  2934. pop(a);
  2935. errexit();
  2936. return onevalue(a);
  2937. }
  2938. Lisp_Object Lprinc_downcase(Lisp_Object nil, Lisp_Object a)
  2939. {
  2940. CSL_IGNORE(nil);
  2941. push(a);
  2942. escaped_printing = escape_fold_down;
  2943. active_stream = qvalue(standard_output);
  2944. if (!is_stream(active_stream)) active_stream = qvalue(terminal_io);
  2945. if (!is_stream(active_stream)) active_stream = lisp_terminal_io;
  2946. internal_prin(a, 0);
  2947. pop(a);
  2948. errexit();
  2949. return onevalue(a);
  2950. }
  2951. Lisp_Object Lprinc(Lisp_Object nil, Lisp_Object a)
  2952. {
  2953. CSL_IGNORE(nil);
  2954. push(a);
  2955. escaped_printing = 0;
  2956. active_stream = qvalue(standard_output);
  2957. if (!is_stream(active_stream)) active_stream = qvalue(terminal_io);
  2958. if (!is_stream(active_stream)) active_stream = lisp_terminal_io;
  2959. internal_prin(a, 0);
  2960. pop(a);
  2961. errexit();
  2962. return onevalue(a);
  2963. }
  2964. Lisp_Object Lprin2a(Lisp_Object nil, Lisp_Object a)
  2965. {
  2966. CSL_IGNORE(nil);
  2967. push(a);
  2968. escaped_printing = escape_nolinebreak;
  2969. active_stream = qvalue(standard_output);
  2970. if (!is_stream(active_stream)) active_stream = qvalue(terminal_io);
  2971. if (!is_stream(active_stream)) active_stream = lisp_terminal_io;
  2972. internal_prin(a, 0);
  2973. pop(a);
  2974. errexit();
  2975. return onevalue(a);
  2976. }
  2977. char memory_print_buffer[32];
  2978. int count_character(int c, Lisp_Object f)
  2979. {
  2980. int n = stream_char_pos(f);
  2981. if (n < 31)
  2982. { memory_print_buffer[n] = (char)c;
  2983. memory_print_buffer[n+1] = 0;
  2984. }
  2985. stream_char_pos(f) = n+1;
  2986. return 0; /* indicate success */
  2987. }
  2988. Lisp_Object Llengthc(Lisp_Object nil, Lisp_Object a)
  2989. {
  2990. CSL_IGNORE(nil);
  2991. escaped_printing = escape_nolinebreak;
  2992. set_stream_write_fn(lisp_work_stream, count_character);
  2993. memory_print_buffer[0] = 0;
  2994. set_stream_write_other(lisp_work_stream, write_action_list);
  2995. stream_char_pos(lisp_work_stream) = 0;
  2996. active_stream = lisp_work_stream;
  2997. internal_prin(a, 0);
  2998. errexit();
  2999. return onevalue(fixnum_of_int(stream_char_pos(lisp_work_stream)));
  3000. }
  3001. Lisp_Object Lprint(Lisp_Object nil, Lisp_Object a)
  3002. {
  3003. Lisp_Object stream = qvalue(standard_output);
  3004. if (!is_stream(stream)) stream = qvalue(terminal_io);
  3005. if (!is_stream(stream)) stream = lisp_terminal_io;
  3006. push(a);
  3007. #ifdef COMMON
  3008. escaped_printing = escape_yes;
  3009. active_stream = stream;
  3010. putc_stream('\n', stream);
  3011. internal_prin(a, 0);
  3012. #else
  3013. escaped_printing = escape_yes;
  3014. active_stream = stream;
  3015. internal_prin(a, 0);
  3016. putc_stream('\n', active_stream);
  3017. #endif
  3018. pop(a);
  3019. errexit();
  3020. return onevalue(a);
  3021. }
  3022. Lisp_Object Lprintc(Lisp_Object nil, Lisp_Object a)
  3023. {
  3024. Lisp_Object stream = qvalue(standard_output);
  3025. CSL_IGNORE(nil);
  3026. if (!is_stream(stream)) stream = qvalue(terminal_io);
  3027. if (!is_stream(stream)) stream = lisp_terminal_io;
  3028. push(a);
  3029. #ifdef COMMON
  3030. escaped_printing = 0;
  3031. active_stream = stream;
  3032. putc_stream('\n', stream);
  3033. internal_prin(a, 0);
  3034. #else
  3035. escaped_printing = 0;
  3036. active_stream = stream;
  3037. internal_prin(a, 0);
  3038. putc_stream('\n', active_stream);
  3039. #endif
  3040. pop(a);
  3041. errexit();
  3042. return onevalue(a);
  3043. }
  3044. Lisp_Object MS_CDECL Lterpri(Lisp_Object nil, int nargs, ...)
  3045. {
  3046. Lisp_Object stream = qvalue(standard_output);
  3047. argcheck(nargs, 0, "terpri");
  3048. if (!is_stream(stream)) stream = qvalue(terminal_io);
  3049. if (!is_stream(stream)) stream = lisp_terminal_io;
  3050. putc_stream('\n', stream);
  3051. return onevalue(nil);
  3052. }
  3053. Lisp_Object MS_CDECL Lflush(Lisp_Object nil, int nargs, ...)
  3054. {
  3055. Lisp_Object stream = qvalue(standard_output);
  3056. #ifdef COMMON
  3057. argcheck(nargs, 0, "finish-output");
  3058. #else
  3059. argcheck(nargs, 0, "flush");
  3060. #endif
  3061. if (!is_stream(stream)) stream = qvalue(terminal_io);
  3062. if (!is_stream(stream)) stream = lisp_terminal_io;
  3063. other_write_action(WRITE_FLUSH, stream);
  3064. return onevalue(nil);
  3065. }
  3066. Lisp_Object Lflush1(Lisp_Object nil, Lisp_Object stream)
  3067. {
  3068. if (!is_stream(stream)) stream = qvalue(terminal_io);
  3069. if (!is_stream(stream)) stream = lisp_terminal_io;
  3070. other_write_action(WRITE_FLUSH, stream);
  3071. return onevalue(nil);
  3072. }
  3073. Lisp_Object Lttab(Lisp_Object nil, Lisp_Object a)
  3074. {
  3075. int32 n;
  3076. Lisp_Object stream = qvalue(standard_output);
  3077. if (!is_fixnum(a)) return aerror1("ttab", a);
  3078. n = int_of_fixnum(a);
  3079. if (!is_stream(stream)) stream = qvalue(terminal_io);
  3080. if (!is_stream(stream)) stream = lisp_terminal_io;
  3081. active_stream = stream;
  3082. while (other_write_action(WRITE_GET_INFO+WRITE_GET_COLUMN, stream) < n)
  3083. putc_stream(' ', active_stream);
  3084. return onevalue(nil);
  3085. }
  3086. Lisp_Object Lxtab(Lisp_Object nil, Lisp_Object a)
  3087. {
  3088. int32 n;
  3089. Lisp_Object stream = qvalue(standard_output);
  3090. if (!is_fixnum(a)) return aerror1("xtab", a);
  3091. n = int_of_fixnum(a);
  3092. if (!is_stream(stream)) stream = qvalue(terminal_io);
  3093. if (!is_stream(stream)) stream = lisp_terminal_io;
  3094. active_stream = stream;
  3095. while (n-- > 0) putc_stream(' ', active_stream);
  3096. return onevalue(nil);
  3097. }
  3098. Lisp_Object MS_CDECL Leject(Lisp_Object nil, int nargs, ...)
  3099. {
  3100. Lisp_Object stream = qvalue(standard_output);
  3101. argcheck(nargs, 0, "eject");
  3102. if (!is_stream(stream)) stream = qvalue(terminal_io);
  3103. if (!is_stream(stream)) stream = lisp_terminal_io;
  3104. putc_stream('\f', stream);
  3105. return onevalue(nil);
  3106. }
  3107. Lisp_Object Lexplode(Lisp_Object nil, Lisp_Object a)
  3108. {
  3109. escaped_printing = escape_yes+escape_nolinebreak;
  3110. a = explode(a);
  3111. errexit();
  3112. return onevalue(a);
  3113. }
  3114. Lisp_Object Lexplodehex(Lisp_Object nil, Lisp_Object a)
  3115. {
  3116. escaped_printing = escape_yes+escape_hex+escape_nolinebreak;
  3117. a = explode(a);
  3118. errexit();
  3119. return onevalue(a);
  3120. }
  3121. Lisp_Object Lexplodeoctal(Lisp_Object nil, Lisp_Object a)
  3122. {
  3123. escaped_printing = escape_yes+escape_octal+escape_nolinebreak;
  3124. a = explode(a);
  3125. errexit();
  3126. return onevalue(a);
  3127. }
  3128. Lisp_Object Lexplodebinary(Lisp_Object nil, Lisp_Object a)
  3129. {
  3130. escaped_printing = escape_yes+escape_binary+escape_nolinebreak;
  3131. a = explode(a);
  3132. errexit();
  3133. return onevalue(a);
  3134. }
  3135. Lisp_Object Lexplodec(Lisp_Object nil, Lisp_Object a)
  3136. {
  3137. escaped_printing = escape_nolinebreak;
  3138. a = explode(a);
  3139. errexit();
  3140. return onevalue(a);
  3141. }
  3142. Lisp_Object Lexplode2lc(Lisp_Object nil, Lisp_Object a)
  3143. {
  3144. escaped_printing = escape_fold_down+escape_nolinebreak;
  3145. a = explode(a);
  3146. errexit();
  3147. return onevalue(a);
  3148. }
  3149. Lisp_Object Lexplode2uc(Lisp_Object nil, Lisp_Object a)
  3150. {
  3151. escaped_printing = escape_fold_up+escape_nolinebreak;
  3152. a = explode(a);
  3153. errexit();
  3154. return onevalue(a);
  3155. }
  3156. Lisp_Object Lexploden(Lisp_Object nil, Lisp_Object a)
  3157. {
  3158. escaped_printing = escape_yes+escape_nolinebreak;
  3159. a = exploden(a);
  3160. errexit();
  3161. return onevalue(a);
  3162. }
  3163. Lisp_Object Lexplodecn(Lisp_Object nil, Lisp_Object a)
  3164. {
  3165. escaped_printing = escape_nolinebreak;
  3166. a = exploden(a);
  3167. errexit();
  3168. return onevalue(a);
  3169. }
  3170. Lisp_Object Lexplode2lcn(Lisp_Object nil, Lisp_Object a)
  3171. {
  3172. escaped_printing = escape_fold_down+escape_nolinebreak;
  3173. a = exploden(a);
  3174. errexit();
  3175. return onevalue(a);
  3176. }
  3177. Lisp_Object Lexplode2ucn(Lisp_Object nil, Lisp_Object a)
  3178. {
  3179. escaped_printing = escape_fold_up+escape_nolinebreak;
  3180. a = exploden(a);
  3181. errexit();
  3182. return onevalue(a);
  3183. }
  3184. /*
  3185. * Now a bunch of binary file access code, as required for the RAND simulation
  3186. * package. Note that these are NOT smoothly integrated with the use of
  3187. * variables like *standard-output* to hold file handles, but I will leave them
  3188. * pending until other things are more stable... or until they are needed!
  3189. */
  3190. static FILE *binary_outfile, *binary_infile;
  3191. static FILE *binary_open(Lisp_Object nil, Lisp_Object name, char *dir, char *e)
  3192. {
  3193. FILE *file;
  3194. char filename[LONGEST_LEGAL_FILENAME];
  3195. int32 len;
  3196. char *w = get_string_data(name, e, &len);
  3197. nil = C_nil;
  3198. if (exception_pending()) return NULL;
  3199. if (len >= sizeof(filename)) len = sizeof(filename);
  3200. file = open_file(filename, w,
  3201. (size_t)len, dir, NULL);
  3202. if (file == NULL)
  3203. { error(1, err_open_failed, name);
  3204. return NULL;
  3205. }
  3206. return file;
  3207. }
  3208. static Lisp_Object Lbinary_open_output(Lisp_Object nil, Lisp_Object name)
  3209. {
  3210. #ifdef SOCKETS
  3211. if (socket_server != 0) return aerror("binary-open-output");
  3212. #endif
  3213. binary_outfile = binary_open(nil, name, "wb", "binary_open_output");
  3214. errexit();
  3215. return onevalue(nil);
  3216. }
  3217. int binary_outchar(int c, Lisp_Object dummy)
  3218. {
  3219. CSL_IGNORE(dummy);
  3220. if (binary_outfile == NULL) return 1;
  3221. putc(c, binary_outfile);
  3222. return 0; /* indicate success */
  3223. }
  3224. static Lisp_Object Lbinary_prin1(Lisp_Object nil, Lisp_Object a)
  3225. {
  3226. push(a);
  3227. escaped_printing = escape_yes;
  3228. set_stream_write_fn(lisp_work_stream, binary_outchar);
  3229. set_stream_write_other(lisp_work_stream, write_action_file);
  3230. set_stream_file(lisp_work_stream, binary_outfile);
  3231. active_stream = lisp_work_stream;
  3232. internal_prin(a, 0);
  3233. pop(a);
  3234. errexit();
  3235. return onevalue(a);
  3236. }
  3237. static Lisp_Object Lbinary_princ(Lisp_Object nil, Lisp_Object a)
  3238. {
  3239. CSL_IGNORE(nil);
  3240. escaped_printing = 0;
  3241. push(a);
  3242. set_stream_write_fn(lisp_work_stream, binary_outchar);
  3243. set_stream_write_other(lisp_work_stream, write_action_file);
  3244. set_stream_file(lisp_work_stream, binary_outfile);
  3245. active_stream = lisp_work_stream;
  3246. internal_prin(a, 0);
  3247. pop(a);
  3248. return a;
  3249. }
  3250. static Lisp_Object Lbinary_prinbyte(Lisp_Object nil, Lisp_Object a)
  3251. {
  3252. int x;
  3253. if (binary_outfile == NULL) return onevalue(nil);
  3254. if (!is_fixnum(a)) return aerror1("binary_prinbyte", a);
  3255. x = (int)int_of_fixnum(a);
  3256. putc(x, binary_outfile);
  3257. return onevalue(nil);
  3258. }
  3259. static Lisp_Object Lbinary_prin2(Lisp_Object nil, Lisp_Object a)
  3260. {
  3261. unsigned32 x;
  3262. if (binary_outfile == NULL) return onevalue(nil);
  3263. if (!is_fixnum(a)) return aerror1("binary_prin2", a);
  3264. x = int_of_fixnum(a);
  3265. putc((int)(x >> 8), binary_outfile);
  3266. putc((int)x, binary_outfile);
  3267. return onevalue(nil);
  3268. }
  3269. static Lisp_Object Lbinary_prin3(Lisp_Object nil, Lisp_Object a)
  3270. {
  3271. unsigned32 x;
  3272. if (binary_outfile == NULL) return onevalue(nil);
  3273. if (!is_fixnum(a)) return aerror1("binary_prin3", a);
  3274. x = int_of_fixnum(a);
  3275. putc((int)(x >> 16), binary_outfile);
  3276. putc((int)(x >> 8), binary_outfile);
  3277. putc((int)x, binary_outfile);
  3278. return onevalue(nil);
  3279. }
  3280. static Lisp_Object Lbinary_prinfloat(Lisp_Object nil, Lisp_Object a)
  3281. {
  3282. unsigned32 *w, x;
  3283. if (binary_outfile == NULL) return onevalue(nil);
  3284. if (!is_float(a)) return aerror1("binary_prinfloat", a);
  3285. w = (unsigned32 *)&double_float_val(a);
  3286. x = w[0];
  3287. putc((int)(x >> 24), binary_outfile);
  3288. putc((int)(x >> 16), binary_outfile);
  3289. putc((int)(x >> 8), binary_outfile);
  3290. putc((int)x, binary_outfile);
  3291. x = w[1];
  3292. putc((int)(x >> 24), binary_outfile);
  3293. putc((int)(x >> 16), binary_outfile);
  3294. putc((int)(x >> 8), binary_outfile);
  3295. putc((int)x, binary_outfile);
  3296. return onevalue(nil);
  3297. }
  3298. static Lisp_Object MS_CDECL Lbinary_terpri(Lisp_Object nil, int nargs, ...)
  3299. {
  3300. argcheck(nargs, 0, "binary_terpri");
  3301. if (binary_outfile != NULL) putc('\n', binary_outfile);
  3302. return onevalue(nil);
  3303. }
  3304. static Lisp_Object MS_CDECL Lbinary_close_output(Lisp_Object nil, int nargs, ...)
  3305. {
  3306. argcheck(nargs, 0, "binary-close-output");
  3307. if (binary_outfile != NULL)
  3308. { fclose(binary_outfile);
  3309. binary_outfile = NULL;
  3310. }
  3311. return onevalue(nil);
  3312. }
  3313. static Lisp_Object Lbinary_open_input(Lisp_Object nil, Lisp_Object name)
  3314. {
  3315. Lisp_Object r;
  3316. FILE *fh = binary_open(nil, name, "rb", "binary_open_input");
  3317. errexit();
  3318. r = make_stream_handle();
  3319. errexit();
  3320. set_stream_read_fn(r, char_from_file);
  3321. set_stream_read_other(r, read_action_file);
  3322. set_stream_file(r, fh);
  3323. return onevalue(r);
  3324. }
  3325. static Lisp_Object Lbinary_select_input(Lisp_Object nil, Lisp_Object a)
  3326. {
  3327. if (!is_stream(a) ||
  3328. stream_file(a) == NULL ||
  3329. stream_write_fn(a) != 0)
  3330. return aerror1("binary-select-input", a); /* closed file or output file */
  3331. binary_infile = stream_file(a);
  3332. return onevalue(nil);
  3333. }
  3334. static Lisp_Object MS_CDECL Lbinary_readbyte(Lisp_Object nil, int nargs, ...)
  3335. {
  3336. CSL_IGNORE(nil);
  3337. argcheck(nargs, 0, "binary-readbyte");
  3338. if (binary_infile == NULL) return onevalue(fixnum_of_int(-1));
  3339. return onevalue(fixnum_of_int((int32)getc(binary_infile) & 0xff));
  3340. }
  3341. static Lisp_Object MS_CDECL Lbinary_read2(Lisp_Object nil, int nargs, ...)
  3342. {
  3343. CSL_IGNORE(nil);
  3344. argcheck(nargs, 0, "binary-read2");
  3345. if (binary_infile == NULL) return onevalue(fixnum_of_int(-1));
  3346. { int32 c1 = (int32)getc(binary_infile) & 0xff;
  3347. int32 c2 = (int32)getc(binary_infile) & 0xff;
  3348. return onevalue(fixnum_of_int((c1<<8) | c2));
  3349. }
  3350. }
  3351. static Lisp_Object MS_CDECL Lbinary_read3(Lisp_Object nil, int nargs, ...)
  3352. {
  3353. CSL_IGNORE(nil);
  3354. argcheck(nargs, 0, "binary-read3");
  3355. if (binary_infile == NULL) return onevalue(fixnum_of_int(-1));
  3356. { int32 c1 = (int32)getc(binary_infile) & 0xff;
  3357. int32 c2 = (int32)getc(binary_infile) & 0xff;
  3358. int32 c3 = (int32)getc(binary_infile) & 0xff;
  3359. return onevalue(fixnum_of_int((c1<<16) | (c2<<8) | c3));
  3360. }
  3361. }
  3362. static Lisp_Object MS_CDECL Lbinary_read4(Lisp_Object nil, int nargs, ...)
  3363. {
  3364. CSL_IGNORE(nil);
  3365. argcheck(nargs, 0, "binary-read4");
  3366. if (binary_infile == NULL) return onevalue(fixnum_of_int(-1));
  3367. { int32 c1 = (int32)getc(binary_infile) & 0xff;
  3368. int32 c2 = (int32)getc(binary_infile) & 0xff;
  3369. int32 c3 = (int32)getc(binary_infile) & 0xff;
  3370. int32 c4 = (int32)getc(binary_infile) & 0xff;
  3371. int32 r = (c1 << 24) | (c2 << 16) | (c3 << 8) | c4;
  3372. return onevalue(fixnum_of_int(r));
  3373. }
  3374. }
  3375. static Lisp_Object MS_CDECL Lbinary_readfloat(Lisp_Object nil, int nargs, ...)
  3376. {
  3377. Lisp_Object r = make_boxfloat(0.0, TYPE_DOUBLE_FLOAT);
  3378. unsigned32 w;
  3379. errexit();
  3380. argcheck(nargs, 0, "binary-readfloat");
  3381. if (binary_infile == NULL) return onevalue(r);
  3382. w = (int32)getc(binary_infile) & 0xff;
  3383. w = (w<<8) | ((int32)getc(binary_infile) & 0xff);
  3384. w = (w<<8) | ((int32)getc(binary_infile) & 0xff);
  3385. w = (w<<8) | ((int32)getc(binary_infile) & 0xff);
  3386. ((unsigned32 *)&double_float_val(r))[0] = w;
  3387. w = (int32)getc(binary_infile) & 0xff;
  3388. w = (w<<8) | ((int32)getc(binary_infile) & 0xff);
  3389. w = (w<<8) | ((int32)getc(binary_infile) & 0xff);
  3390. w = (w<<8) | ((int32)getc(binary_infile) & 0xff);
  3391. ((unsigned32 *)&double_float_val(r))[1] = w;
  3392. return onevalue(r);
  3393. }
  3394. static Lisp_Object MS_CDECL Lbinary_close_input(Lisp_Object nil, int nargs, ...)
  3395. {
  3396. argcheck(nargs, 0, "binary-close-input");
  3397. if (binary_infile != NULL)
  3398. { fclose(binary_infile);
  3399. binary_infile = NULL;
  3400. }
  3401. return onevalue(nil);
  3402. }
  3403. /*
  3404. * (open-library "file" dirn) opens a new library (for use with the
  3405. * fasl mechanism etc). If dirn=nil (or not specified) the library is
  3406. * opened for input only. If dirn is non-nil an attempt is made to open
  3407. * the library so that it can be updated, and if it does not exist to start
  3408. * with it is created. The resulting handle can be passed to close-library
  3409. * or used in the variables input-libraries or output-library.
  3410. */
  3411. static Lisp_Object Lopen_library(Lisp_Object nil, Lisp_Object file,
  3412. Lisp_Object dirn)
  3413. {
  3414. char filename[LONGEST_LEGAL_FILENAME];
  3415. int32 len;
  3416. CSLbool forinput = (dirn==nil);
  3417. int i;
  3418. char *w = get_string_data(file, "open-library", &len);
  3419. errexit();
  3420. if (len >= sizeof(filename)) len = sizeof(filename)-1;
  3421. memcpy(filename, w, len);
  3422. filename[len] = 0;
  3423. for (i=0; i<number_of_fasl_paths; i++)
  3424. { if (fasl_files[i] == NULL) goto found;
  3425. }
  3426. if (number_of_fasl_paths>=MAX_FASL_PATHS-1)
  3427. return aerror("open-library (too many open libraries)");
  3428. number_of_fasl_paths++;
  3429. found:
  3430. fasl_files[i] = open_pds(filename, forinput);
  3431. /*
  3432. * allocating space using malloc() here is dodgy, because the matching
  3433. * place in close-library does not do a corresponding free() operation.
  3434. */
  3435. w = (char *)malloc(strlen(filename)+1);
  3436. if (w == NULL) w = "Unknown file";
  3437. else strcpy(w, filename);
  3438. fasl_paths[i] = w;
  3439. return onevalue(SPID_LIBRARY + (((int32)i)<<20));
  3440. }
  3441. static Lisp_Object Lopen_library_1(Lisp_Object nil, Lisp_Object file)
  3442. {
  3443. return Lopen_library(nil, file, nil);
  3444. }
  3445. static Lisp_Object Lclose_library(Lisp_Object nil, Lisp_Object lib)
  3446. {
  3447. if (!is_library(lib)) return aerror1("close-library", lib);
  3448. finished_with(library_number(lib));
  3449. return onevalue(nil);
  3450. }
  3451. static Lisp_Object Llibrary_name(Lisp_Object nil, Lisp_Object lib)
  3452. {
  3453. Lisp_Object a;
  3454. if (!is_library(lib)) return aerror1("library-name", lib);
  3455. a = make_string(fasl_paths[library_number(lib)]);
  3456. errexit();
  3457. return onevalue(a);
  3458. }
  3459. #ifdef CJAVA
  3460. extern void process_java_file(FILE *file);
  3461. static Lisp_Object Ljava(Lisp_Object nil, Lisp_Object name)
  3462. {
  3463. char filename[LONGEST_LEGAL_FILENAME];
  3464. int32 len;
  3465. FILE *file;
  3466. char *w = get_string_data(name, "java", &len);
  3467. nil = C_nil;
  3468. if (exception_pending()) return nil;
  3469. if (len >= sizeof(filename)) len = sizeof(filename);
  3470. file = open_file(filename, w, (size_t)len, "rb", NULL);
  3471. if (file == NULL)
  3472. { error(1, err_open_failed, name);
  3473. return NULL;
  3474. }
  3475. process_java_file(file);
  3476. fclose(file);
  3477. return onevalue(nil);
  3478. }
  3479. #endif
  3480. #ifdef SOCKETS
  3481. /*
  3482. * If a Winsock function fails it leaves an error code that
  3483. * WSAGetLastError() can retrieve. This function converts the numeric
  3484. * codes to some printable text. Still cryptic, but maybe better than
  3485. * the raw numbers!
  3486. */
  3487. static char error_name[32];
  3488. char *WSAErrName(int i)
  3489. {
  3490. switch (i)
  3491. {
  3492. default: sprintf(error_name, "Socket error %d", i);
  3493. return error_name;
  3494. #ifdef ms_windows
  3495. case WSAEINTR: return "WSAEINTR";
  3496. case WSAEBADF: return "WSAEBADF";
  3497. case WSAEACCES: return "WSAEACCES";
  3498. #ifdef WSAEDISCON
  3499. case WSAEDISCON: return "WSAEDISCON";
  3500. #endif
  3501. case WSAEFAULT: return "WSAEFAULT";
  3502. case WSAEINVAL: return "WSAEINVAL";
  3503. case WSAEMFILE: return "WSAEMFILE";
  3504. case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
  3505. case WSAEINPROGRESS: return "WSAEINPROGRESS";
  3506. case WSAEALREADY: return "WSAEALREADY";
  3507. case WSAENOTSOCK: return "WSAENOTSOCK";
  3508. case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
  3509. case WSAEMSGSIZE: return "WSAEMSGSIZE";
  3510. case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
  3511. case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
  3512. case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
  3513. case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
  3514. case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
  3515. case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
  3516. case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
  3517. case WSAEADDRINUSE: return "WSAEADDRINUSE";
  3518. case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
  3519. case WSAENETDOWN: return "WSAENETDOWN";
  3520. case WSAENETUNREACH: return "WSAENETUNREACH";
  3521. case WSAENETRESET: return "WSAENETRESET";
  3522. case WSAECONNABORTED: return "WSAECONNABORTED";
  3523. case WSAECONNRESET: return "WSAECONNRESET";
  3524. case WSAENOBUFS: return "WSAENOBUFS";
  3525. case WSAEISCONN: return "WSAEISCONN";
  3526. case WSAENOTCONN: return "WSAENOTCONN";
  3527. case WSAESHUTDOWN: return "WSAESHUTDOWN";
  3528. case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
  3529. case WSAETIMEDOUT: return "WSAETIMEDOUT";
  3530. case WSAECONNREFUSED: return "WSAECONNREFUSED";
  3531. case WSAELOOP: return "WSAELOOP";
  3532. case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
  3533. case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
  3534. case WSAEHOSTUNREACH: return "WSAEHOSTUNREACH";
  3535. case WSASYSNOTREADY: return "WSASYSNOTREADY";
  3536. case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
  3537. case WSANOTINITIALISED: return "WSANOTINITIALISED";
  3538. case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
  3539. case WSATRY_AGAIN: return "WSATRY_AGAIN";
  3540. case WSANO_RECOVERY: return "WSANO_RECOVERY";
  3541. case WSANO_DATA: return "WSANO_DATA";
  3542. #else
  3543. /*
  3544. * When I run under Unix I display both the Unix and Windows form of the
  3545. * error code. I guess that shows you which of those platforms is the one
  3546. * I am doing initial development on!
  3547. */
  3548. case EINTR: return "WSAEINTR/EINTR";
  3549. case EBADF: return "WSAEBADF/EBADF";
  3550. case EACCES: return "WSAEACCES/EACCES";
  3551. case EFAULT: return "WSAEFAULT/EFAULT";
  3552. case EINVAL: return "WSAEINVAL/EINVAL";
  3553. case EMFILE: return "WSAEMFILE/EMFILE";
  3554. case EWOULDBLOCK: return "WSAEWOULDBLOCK/EWOULDBLOCK";
  3555. case EINPROGRESS: return "WSAEINPROGRESS/EINPROGRESS";
  3556. case EALREADY: return "WSAEALREADY/EALREADY";
  3557. case ENOTSOCK: return "WSAENOTSOCK/ENOTSOCK";
  3558. case EDESTADDRREQ: return "WSAEDESTADDRREQ/EDESTADDRREQ";
  3559. case EMSGSIZE: return "WSAEMSGSIZE/EMSGSIZE";
  3560. case EPROTOTYPE: return "WSAEPROTOTYPE/EPROTOTYPE";
  3561. case ENOPROTOOPT: return "WSAENOPROTOOPT/ENOPROTOOPT";
  3562. case EPROTONOSUPPORT: return "WSAEPROTONOSUPPORT/EPROTONOSUPPORT";
  3563. case ESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT/ESOCKTNOSUPPORT";
  3564. case EOPNOTSUPP: return "WSAEOPNOTSUPP/EOPNOTSUPP";
  3565. case EPFNOSUPPORT: return "WSAEPFNOSUPPORT/EPFNOSUPPORT";
  3566. case EAFNOSUPPORT: return "WSAEAFNOSUPPORT/EAFNOSUPPORT";
  3567. case EADDRINUSE: return "WSAEADDRINUSE/EADDRINUSE";
  3568. case EADDRNOTAVAIL: return "WSAEADDRNOTAVAIL/EADDRNOTAVAIL";
  3569. case ENETDOWN: return "WSAENETDOWN/ENETDOWN";
  3570. case ENETUNREACH: return "WSAENETUNREACH/ENETUNREACH";
  3571. case ENETRESET: return "WSAENETRESET/ENETRESET";
  3572. case ECONNABORTED: return "WSAECONNABORTED/ECONNABORTED";
  3573. case ECONNRESET: return "WSAECONNRESET/ECONNRESET";
  3574. case ENOBUFS: return "WSAENOBUFS/ENOBUFS";
  3575. case EISCONN: return "WSAEISCONN/EISCONN";
  3576. case ENOTCONN: return "WSAENOTCONN/ENOTCONN";
  3577. case ESHUTDOWN: return "WSAESHUTDOWN/ESHUTDOWN";
  3578. case ETOOMANYREFS: return "WSAETOOMANYREFS/ETOOMANYREFS";
  3579. case ETIMEDOUT: return "WSAETIMEDOUT/ETIMEDOUT";
  3580. case ECONNREFUSED: return "WSAECONNREFUSED/ECONNREFUSED";
  3581. case ELOOP: return "WSAELOOP/ELOOP";
  3582. case ENAMETOOLONG: return "WSAENAMETOOLONG/ENAMETOOLONG";
  3583. case EHOSTDOWN: return "WSAEHOSTDOWN/EHOSTDOWN";
  3584. case EHOSTUNREACH: return "WSAEHOSTUNREACH/EHOSTUNREACH";
  3585. case HOST_NOT_FOUND: return "WSAHOST_NOT_FOUND/HOST_NOT_FOUND";
  3586. case TRY_AGAIN: return "WSATRY_AGAIN/TRY_AGAIN";
  3587. case NO_RECOVERY: return "WSANO_RECOVERY/NO_RECOVERY";
  3588. #ifdef never
  3589. /*
  3590. * Duplicated EINTR, at least on Linux.
  3591. */
  3592. case NO_DATA: return "WSANO_DATA/NO_DATA";
  3593. #endif
  3594. #endif
  3595. }
  3596. }
  3597. int ensure_sockets_ready(void)
  3598. {
  3599. if (!sockets_ready)
  3600. {
  3601. #ifdef ms_windows
  3602. /*
  3603. * Under Windows the socket stuff is not automatically active, so some
  3604. * system calls have to be made at the start of a run. I demand a
  3605. * Winsock 1.1, and fail if that is not available.
  3606. */
  3607. WSADATA wsadata;
  3608. int i = WSAStartup(MAKEWORD(1,1), &wsadata);
  3609. if (i) return i; /* Failed to start winsock for some reason */;
  3610. if (LOBYTE(wsadata.wVersion) != 1 ||
  3611. HIBYTE(wsadata.wVersion) != 1)
  3612. { WSACleanup();
  3613. return 1; /* Version 1.1 of winsock needed */
  3614. }
  3615. #endif
  3616. sockets_ready = 1;
  3617. }
  3618. return 0;
  3619. }
  3620. #define SOCKET_BUFFER_SIZE 256
  3621. /*
  3622. * A stream attached to a socket is represented by putting the socket handle
  3623. * into the field that would otherwise hold a FILE. The stream_read_data
  3624. * field then holds a string. The first 4 characters of this contain
  3625. * two packed integers saying how much buffered data is available,
  3626. * and then there is just a chunk of buffered text.
  3627. */
  3628. int char_from_socket(Lisp_Object stream)
  3629. {
  3630. nil_as_base
  3631. int ch = stream_pushed_char(stream);
  3632. if (ch == NOT_CHAR)
  3633. { Lisp_Object w = stream_read_data(stream);
  3634. int32 sb_data = elt(w, 0);
  3635. int sb_start = sb_data & 0xffff, sb_end = (sb_data >> 16) & 0xffff;
  3636. /*
  3637. * Note use of ucelt in the next line even if char is a signed type. This
  3638. * is because getc() etc are expected to return an UNSIGNED char cast to
  3639. * an int.
  3640. */
  3641. if (sb_start != sb_end) ch = ucelt(w, sb_start++);
  3642. else
  3643. { ch = recv((SOCKET)(intxx)stream_file(stream),
  3644. &celt(w, 4), SOCKET_BUFFER_SIZE, 0);
  3645. if (ch == 0) return EOF;
  3646. if (ch == SOCKET_ERROR)
  3647. { err_printf("socket read error (%s)\n",
  3648. WSAErrName(WSAGetLastError()));
  3649. return EOF;
  3650. }
  3651. sb_start = 5;
  3652. sb_end = ch + 4;
  3653. ch = ucelt(w, 4);
  3654. }
  3655. sb_data = sb_start | (sb_end << 16);
  3656. elt(w, 0) = sb_data;
  3657. return ch;
  3658. }
  3659. else stream_pushed_char(stream) = NOT_CHAR;
  3660. return ch;
  3661. }
  3662. /*
  3663. * Seek and tell will be just quiet no-ops on socket streams.
  3664. */
  3665. int32 read_action_socket(int32 op, Lisp_Object f)
  3666. {
  3667. if (op < -1) return 0;
  3668. else if (op <= 0xff) return (stream_pushed_char(f) = op);
  3669. else switch (op)
  3670. {
  3671. case READ_CLOSE:
  3672. if (stream_file(f) == NULL) op = 0;
  3673. else op = closesocket((SOCKET)(intxx)stream_file(f));
  3674. set_stream_read_fn(f, char_from_illegal);
  3675. set_stream_read_other(f, read_action_illegal);
  3676. set_stream_file(f, NULL);
  3677. stream_read_data(f) = C_nil;
  3678. return op;
  3679. case READ_FLUSH:
  3680. stream_pushed_char(f) = NOT_CHAR;
  3681. return 0;
  3682. default:
  3683. return 0;
  3684. }
  3685. }
  3686. int fetch_response(char *buffer, Lisp_Object r)
  3687. {
  3688. int i;
  3689. for (i = 0; i < LONGEST_LEGAL_FILENAME; i++)
  3690. { int ch = char_from_socket(r);
  3691. if (ch == EOF) return 1;
  3692. buffer[i] = (char)ch;
  3693. if (ch == 0x0a)
  3694. { buffer[i] = 0;
  3695. /*
  3696. * The keys returned at the start of a response line are supposed to be
  3697. * case insensitive, so I fold things to lower case right here.
  3698. */
  3699. for (i=0; buffer[i]!=0 && buffer[i]!=' '; i++)
  3700. buffer[i] = (char)tolower(buffer[i]);
  3701. return 0;
  3702. }
  3703. }
  3704. return 1; /* fail if response was over-long */
  3705. }
  3706. static Lisp_Object Lopen_url(Lisp_Object nil, Lisp_Object url)
  3707. {
  3708. char filename[LONGEST_LEGAL_FILENAME],
  3709. filename1[LONGEST_LEGAL_FILENAME], *p;
  3710. char *user, *pass, *proto, *hostaddr, *port, *path;
  3711. int nuser, npass, nproto, nhostaddr, nport, npath;
  3712. int32 len;
  3713. struct hostent *host;
  3714. long int hostnum;
  3715. SOCKET s;
  3716. int i, retcode, retry_count=0;
  3717. Lisp_Object r;
  3718. char *w = get_string_data(url, "open-url", &len);
  3719. errexit();
  3720. start_again:
  3721. if (len >= sizeof(filename)) len = sizeof(filename)-1;
  3722. memcpy(filename, w, len);
  3723. filename[len] = 0;
  3724. trace_printf("OPEN_URL(%s)\n", filename);
  3725. /*
  3726. * I want to parse the URL. I leave the result as a collection of
  3727. * pointers (usually to the start of text within the URL itself, but
  3728. * sometimes elsewhere, together with lengths of the substrings as found.
  3729. */
  3730. user = pass = proto = hostaddr = port = path = " ";
  3731. nuser = npass = nproto = nhostaddr = nport = npath = 0;
  3732. p = filename;
  3733. /*
  3734. * If the start of the URL is of the form "xyz:" with xyz alphanumeric
  3735. * then that is a protocol name, and I will force it into lower case.
  3736. */
  3737. for (i=0; i<len; i++)
  3738. if (!isalnum(p[i])) break;
  3739. if (p[i] == ':')
  3740. { proto = p;
  3741. nproto = i; /* Could still be zero! */
  3742. p += i+1;
  3743. len -= i+1;
  3744. for (i=0; i<nproto; i++) proto[i] = (char)tolower(proto[i]);
  3745. trace_printf("Protocol found as <%.*s>\n", nproto, proto);
  3746. }
  3747. /*
  3748. * After any protocol specification I may have a host name, introduced
  3749. * by "//".
  3750. */
  3751. if (p[0] == '/' && p[1] == '/')
  3752. { p += 2;
  3753. len -= 2;
  3754. /*
  3755. * If the URL (sans protocol) contains a "@" then I will take it to be
  3756. * in the form
  3757. * user:password@hostaddr/...
  3758. * and will split the user bit off. This will be particularly used in the
  3759. * case of FTP requests. The password will be allowed to contain ":" and
  3760. * "@" characters. Furthermore I will also allow the password to be
  3761. * enclosed in quote marks ("), although since I scan for the "@" from
  3762. * the right and for the ":" from the left these are not needed at all,
  3763. * so if I notice them here all I have to do is to discard them!
  3764. */
  3765. for (i=len-1; i>=0; i--)
  3766. if (p[i] == '@') break;
  3767. if (i >= 0)
  3768. { user = p;
  3769. p += i+1;
  3770. len -= i+1;
  3771. while (user[nuser] != ':' && user[nuser] != '@') nuser++;
  3772. if (user[nuser] == ':')
  3773. { pass = user+nuser+1;
  3774. npass = i - nuser - 1;
  3775. if (pass[0] == '"' && pass[npass-1] == '"')
  3776. pass++, npass -= 2;
  3777. }
  3778. }
  3779. /*
  3780. * Now what is left is a host, port number and path, written as
  3781. * hostaddr:port/... but note that the "/" should be treated as
  3782. * part of the path-name.
  3783. */
  3784. hostaddr = p;
  3785. for (;;)
  3786. { switch (hostaddr[nhostaddr])
  3787. {
  3788. default:
  3789. nhostaddr++;
  3790. continue;
  3791. case '/':
  3792. p += nhostaddr;
  3793. len -= nhostaddr;
  3794. break;
  3795. case 0: len = 0;
  3796. break;
  3797. case ':': /* port number given */
  3798. port = hostaddr+nhostaddr+1;
  3799. for (;;)
  3800. { switch (port[nport])
  3801. {
  3802. default:
  3803. nport++;
  3804. continue;
  3805. case '/':
  3806. p += nhostaddr + nport + 1;
  3807. len -= nhostaddr + nport + 1;
  3808. break;
  3809. case 0: len = 0;
  3810. break;
  3811. }
  3812. break;
  3813. }
  3814. break;
  3815. }
  3816. break;
  3817. }
  3818. }
  3819. path = p;
  3820. npath = len;
  3821. if (npath == 0) path = "/", npath = 1; /* Default path */
  3822. /*
  3823. * If a protocol was not explicitly given I will try to deduce one from the
  3824. * start of the name of the hostaddr. Failing that I will just use a default.
  3825. */
  3826. if (nproto == 0)
  3827. { if (strncmp(hostaddr, "www.", 4) == 0 ||
  3828. strncmp(hostaddr, "wwwcgi.", 7) == 0)
  3829. { proto = "http";
  3830. nproto = 4;
  3831. }
  3832. else
  3833. { proto = "ftp";
  3834. nproto = 3;
  3835. }
  3836. }
  3837. /*
  3838. * If the user gave an explicit port number I will try to use it. If the
  3839. * port was not numeric I ignore it and drop down to trying to use
  3840. * a default port based on the selected protocol.
  3841. */
  3842. if (nport != 0)
  3843. { int w;
  3844. memcpy(filename1, port, nport);
  3845. filename1[nport] = 0;
  3846. if (sscanf(filename1, "%d", &w) == 1) nport = w;
  3847. else nport = 0;
  3848. }
  3849. if (nport == 0)
  3850. { if (nproto == 3 && memcmp(proto, "ftp", 3) == 0) nport = 21;
  3851. else if (nproto == 6 && memcmp(proto, "gopher", 6) == 0) nport = 70;
  3852. else if (nproto == 6 && memcmp(proto, "telnet", 6) == 0) nport = 23;
  3853. else if (nproto == 4 && memcmp(proto, "wais", 4) == 0) nport = 210;
  3854. else if (nproto == 4 && memcmp(proto, "http", 4) == 0) nport = 80;
  3855. else return aerror("Unknown protocol");
  3856. }
  3857. /*
  3858. * If no host-name was given then the object concerned is on the
  3859. * local machine. This is a funny case maybe, but I will just chain
  3860. * through and open it as an ordinary file (without regard to
  3861. * protocol etc).
  3862. */
  3863. if (nhostaddr == 0)
  3864. { FILE *file = open_file(filename1, path, (size_t)npath, "r", NULL);
  3865. if (file == NULL) return onevalue(nil);
  3866. push(url);
  3867. r = make_stream_handle();
  3868. pop(url);
  3869. errexit();
  3870. stream_type(r) = url;
  3871. set_stream_file(r, file);
  3872. set_stream_read_fn(r, char_from_file);
  3873. set_stream_read_other(r, read_action_file);
  3874. return onevalue(r);
  3875. }
  3876. if (nproto == 3 && strcmp(proto, "ftp") == 0 && nuser == 0)
  3877. { user = "anonymous";
  3878. nuser = strlen(user);
  3879. if (npass == 0)
  3880. { pass = "acn1@cam.ac.uk";
  3881. npass = strlen(pass);
  3882. }
  3883. }
  3884. trace_printf(
  3885. "User <%.*s> Pass <%.*s> Proto <%.*s>\n"
  3886. "Host <%.*s> Port <%d> Path <%.*s>\n",
  3887. nuser, user, npass, pass, nproto, proto,
  3888. nhostaddr, hostaddr, nport, npath, path);
  3889. if (ensure_sockets_ready() != 0) return nil;
  3890. memcpy(filename1, hostaddr, nhostaddr);
  3891. filename1[nhostaddr] = 0;
  3892. /* I try to accept either "." form or named host specifications */
  3893. hostnum = inet_addr(filename1);
  3894. if (hostnum == INADDR_NONE)
  3895. { host = gethostbyname(filename1);
  3896. if (host != NULL)
  3897. hostnum = ((struct in_addr *)host->h_addr)->s_addr;
  3898. }
  3899. if (hostnum == INADDR_NONE)
  3900. { err_printf("Host not found (%s)\n", WSAErrName(WSAGetLastError()));
  3901. return onevalue(nil);
  3902. }
  3903. else
  3904. { err_printf("Host number %d.%d.%d.%d\n",
  3905. hostnum & 0xff,
  3906. (hostnum>>8) & 0xff,
  3907. (hostnum>>16) & 0xff,
  3908. (hostnum>>24) & 0xff);
  3909. }
  3910. s = socket(PF_INET, SOCK_STREAM, 0); /* Make a new socket */
  3911. { struct sockaddr_in sin;
  3912. memset(&sin, 0, sizeof(sin));
  3913. sin.sin_family = AF_INET;
  3914. sin.sin_port = htons(nport);
  3915. sin.sin_addr.s_addr = hostnum;
  3916. trace_printf("Contacting %.*s...\n", nhostaddr, hostaddr);
  3917. ensure_screen();
  3918. if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR)
  3919. { err_printf("connect failed %s\n", WSAErrName(WSAGetLastError()));
  3920. closesocket(s);
  3921. return onevalue(nil);
  3922. }
  3923. trace_printf("Connection created\n");
  3924. }
  3925. sprintf(filename1, "GET %.*s HTTP/1.0\x0d\x0a\x0d\x0a", npath, path);
  3926. /* MD addition from webcore.c*/
  3927. i = strlen(filename1);
  3928. /*
  3929. * Certainly if the Web server I am accessing is the one that comes as
  3930. * standard with Windows NT I need to reassure it that I want the document
  3931. * returned to me WHATEVER its media type is. If I do not add in the
  3932. * line "Accept: *//*" the GET request will only allow me to fetch simple
  3933. * text (?)
  3934. * Note that above I write "*//*" where I only really mean a single "/"
  3935. * but where C comment conventions intrude!
  3936. */
  3937. sprintf(&filename1[i], "Accept: */*\x0d\x0a\x0d\x0a");
  3938. /* err_printf("About to send <%s>\n", filename1); */
  3939. if (send(s, filename1, strlen(filename1), 0) == SOCKET_ERROR)
  3940. { err_printf("Send error (%s)\n", WSAErrName(WSAGetLastError()));
  3941. closesocket(s);
  3942. return onevalue(nil);
  3943. }
  3944. push(url);
  3945. r = make_stream_handle();
  3946. pop(url);
  3947. errexit();
  3948. stream_type(r) = url;
  3949. push(r);
  3950. url = getvector(TAG_VECTOR, TYPE_STRING, CELL+4+SOCKET_BUFFER_SIZE);
  3951. pop(r);
  3952. errexit();
  3953. elt(url, 0) = 0;
  3954. stream_read_data(r) = url;
  3955. set_stream_file(r, (FILE *)(intxx)s);
  3956. set_stream_read_fn(r, char_from_socket);
  3957. set_stream_read_other(r, read_action_socket);
  3958. /*
  3959. Now fetch the status line.
  3960. */
  3961. if (fetch_response(filename1, r))
  3962. { err_printf("Error fetching status line from the server\n");
  3963. Lclose(nil,r);
  3964. return onevalue(nil);
  3965. }
  3966. /*
  3967. * I check if the first line returned is in the form "HTTP/n.n nnn " and if
  3968. * it is not I assume that I have reached an HTTP/0.9 server and all the
  3969. * text that comes back will be the body.
  3970. */
  3971. { int major, minor;
  3972. /*
  3973. * I will not worry much about just which version of HTTP the system reports
  3974. * that it is using, provided it says something! I expect to see the return
  3975. * code as a three digit number. I verify that it is in the range 0 to 999 but
  3976. * do not check for (and thus reject) illegal responses such as 0000200.
  3977. */
  3978. if (sscanf(filename1,"http/%d.%d %d", &major, &minor, &retcode) != 3 ||
  3979. retcode < 0 || retcode > 999)
  3980. { err_printf("Bad protocol specification returned\n");
  3981. Lclose(nil,r);
  3982. return onevalue(nil);
  3983. }
  3984. }
  3985. /*
  3986. * In this code I treat all unexpected responses as errors and I do not
  3987. * attempt to continue. This is sometimes going to be overly pessimistic
  3988. * and RFC1945 tells me that I should treat unidentified codes as the
  3989. * n00 variant thereupon.
  3990. */
  3991. switch (retcode)
  3992. {
  3993. default:retcode = 0;
  3994. break;
  3995. case 200:
  3996. break; /* A success code for GET requests */
  3997. case 301: /* Redirection request */
  3998. case 302:
  3999. do
  4000. { if (fetch_response(filename1, r))
  4001. { err_printf("Unexpected response from the server\n");
  4002. retcode = 0;
  4003. break;
  4004. }
  4005. if (filename1[0] == 0)
  4006. { err_printf("Document has moved, but I can not trace it\n");
  4007. retcode = 0;
  4008. break;
  4009. }
  4010. }
  4011. while (memcmp(filename1, "location: ", 10) != 0);
  4012. if (retcode == 0) break;
  4013. /*
  4014. * At present I take a somewhat simplistic view of redirection, and just
  4015. * look for the first alternative URL and start my entire unpicking
  4016. * process afresh from there.
  4017. */
  4018. for (i = 10; filename1[i] == ' '; i++);
  4019. w = &filename1[i];
  4020. while (filename1[i]!=' ' && filename1[i]!=0) i++;
  4021. filename1[i] = 0;
  4022. len = strlen(w);
  4023. closesocket(s);
  4024. if (++retry_count > 5)
  4025. { err_printf("Apparent loop in redirection information\n");
  4026. retcode = 0;
  4027. break;
  4028. }
  4029. goto start_again;
  4030. break;
  4031. case 401:
  4032. err_printf("Authorisation required for this access\n");
  4033. retcode = 0;
  4034. break;
  4035. case 404:
  4036. err_printf("Object not found\n");
  4037. retcode = 0;
  4038. break;
  4039. }
  4040. if (retcode == 0)
  4041. { Lclose(nil,r);
  4042. return onevalue(nil);
  4043. }
  4044. /*
  4045. * Skip further information returned by the server until a line containing
  4046. * just the end-of-line marker is fetched
  4047. */
  4048. do
  4049. { for (i = 0; i < LONGEST_LEGAL_FILENAME; i++)
  4050. { int ch = char_from_socket(r);
  4051. if (ch == EOF)
  4052. { err_printf("Error fetching additional info from the server\n");
  4053. Lclose(nil,r);
  4054. return onevalue(nil);
  4055. }
  4056. if (ch == 0x0a) break;
  4057. }
  4058. } while (i > 1);
  4059. return onevalue(r);
  4060. }
  4061. #endif
  4062. int window_heading = 0;
  4063. Lisp_Object Lwindow_heading2(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
  4064. {
  4065. #ifdef CWIN
  4066. int32 n, bit;
  4067. char *s, txt[32];
  4068. if (is_fixnum(b)) n = int_of_fixnum(b);
  4069. else n = 2; /* default to setting the right section */
  4070. if (is_vector(a) && type_of_header(vechdr(a)) == TYPE_STRING)
  4071. { int32 l = length_of_header(vechdr(a));
  4072. if (l > 30) l = 30;
  4073. memcpy(txt, &celt(a, 0), l);
  4074. txt[l] = 0;
  4075. s = txt;
  4076. }
  4077. else if (b == 2) s = "";
  4078. else s = NULL;
  4079. switch (n)
  4080. {
  4081. case 0: cwin_report_left(s); bit = 1; break;
  4082. case 1: cwin_report_mid(s); bit = 2; break;
  4083. default:cwin_report_right(s); bit = 4; break;
  4084. }
  4085. if (s == NULL || *s == 0) window_heading &= ~bit;
  4086. else window_heading |= bit;
  4087. #endif
  4088. return onevalue(nil);
  4089. }
  4090. Lisp_Object Lwindow_heading1(Lisp_Object nil, Lisp_Object a)
  4091. {
  4092. return Lwindow_heading2(nil, a, nil);
  4093. }
  4094. setup_type const print_setup[] =
  4095. {
  4096. #ifdef CJAVA
  4097. {"java", Ljava, too_many_1, wrong_no_1},
  4098. #endif
  4099. #ifdef SOCKETS
  4100. {"open-url", Lopen_url, too_many_1, wrong_no_1},
  4101. #endif
  4102. {"window-heading", Lwindow_heading1, Lwindow_heading2, wrong_no_1},
  4103. {"eject", wrong_no_na, wrong_no_nb, Leject},
  4104. {"filep", Lfilep, too_many_1, wrong_no_1},
  4105. {"filedate", Lfiledate, too_many_1, wrong_no_1},
  4106. {"flush", Lflush1, wrong_no_nb, Lflush},
  4107. {"streamp", Lstreamp, too_many_1, wrong_no_1},
  4108. {"is-console", Lis_console, too_many_1, wrong_no_1},
  4109. {"lengthc", Llengthc, too_many_1, wrong_no_1},
  4110. {"linelength", Llinelength, too_many_1, Llinelength0},
  4111. {"lposn", wrong_no_na, wrong_no_nb, Llposn},
  4112. {"~open", too_few_2, Lopen, wrong_no_2},
  4113. {"open-library", Lopen_library_1, Lopen_library, wrong_no_2},
  4114. {"close-library", Lclose_library, too_many_1, wrong_no_1},
  4115. {"library-name", Llibrary_name, too_many_1, wrong_no_1},
  4116. {"create-directory", Lcreate_directory, too_many_1, wrong_no_1},
  4117. {"delete-file", Ldelete_file, too_many_1, wrong_no_1},
  4118. {"rename-file", too_few_2, Lrename_file, wrong_no_2},
  4119. {"file-readablep", Lfile_readable, too_many_1, wrong_no_1},
  4120. {"file-writeablep", Lfile_writeable, too_many_1, wrong_no_1},
  4121. {"directoryp", Ldirectoryp, too_many_1, wrong_no_1},
  4122. {"file-length", Lfile_length, too_many_1, wrong_no_1},
  4123. #ifdef COMMON
  4124. {"truename", Ltruename, too_many_1, wrong_no_1},
  4125. #endif
  4126. {"list-directory", Llist_directory, too_many_1, wrong_no_1},
  4127. {"chdir", Lchange_directory, too_many_1, wrong_no_1},
  4128. {"make-function-stream", Lmake_function_stream, too_many_1, wrong_no_1},
  4129. {"get-current-directory", wrong_no_na, wrong_no_nb, Lget_current_directory},
  4130. {"user-homedir-pathname", wrong_no_na, wrong_no_nb, Luser_homedir_pathname},
  4131. {"get-lisp-directory", wrong_no_na, wrong_no_nb, Lget_lisp_directory},
  4132. {"pagelength", Lpagelength, too_many_1, wrong_no_1},
  4133. {"posn", Lposn_1, wrong_no_nb, Lposn},
  4134. {"spaces", Lxtab, too_many_1, wrong_no_1},
  4135. {"terpri", wrong_no_na, wrong_no_nb, Lterpri},
  4136. {"tmpnam", wrong_no_na, wrong_no_nb, Ltmpnam},
  4137. {"ttab", Lttab, too_many_1, wrong_no_1},
  4138. {"wrs", Lwrs, too_many_1, wrong_no_1},
  4139. {"xtab", Lxtab, too_many_1, wrong_no_1},
  4140. {"princ-upcase", Lprinc_upcase, too_many_1, wrong_no_1},
  4141. {"princ-downcase", Lprinc_downcase, too_many_1, wrong_no_1},
  4142. {"binary_open_output", Lbinary_open_output, too_many_1, wrong_no_1},
  4143. {"binary_prin1", Lbinary_prin1, too_many_1, wrong_no_1},
  4144. {"binary_princ", Lbinary_princ, too_many_1, wrong_no_1},
  4145. {"binary_prinbyte", Lbinary_prinbyte, too_many_1, wrong_no_1},
  4146. {"binary_prin2", Lbinary_prin2, too_many_1, wrong_no_1},
  4147. {"binary_prin3", Lbinary_prin3, too_many_1, wrong_no_1},
  4148. {"binary_prinfloat", Lbinary_prinfloat, too_many_1, wrong_no_1},
  4149. {"binary_terpri", wrong_no_na, wrong_no_nb, Lbinary_terpri},
  4150. {"binary_close_output", wrong_no_na, wrong_no_nb, Lbinary_close_output},
  4151. {"binary_open_input", Lbinary_open_input, too_many_1, wrong_no_1},
  4152. {"binary_select_input", Lbinary_select_input, too_many_1, wrong_no_1},
  4153. {"binary_readbyte", wrong_no_na, wrong_no_nb, Lbinary_readbyte},
  4154. {"binary_read2", wrong_no_na, wrong_no_nb, Lbinary_read2},
  4155. {"binary_read3", wrong_no_na, wrong_no_nb, Lbinary_read3},
  4156. {"binary_read4", wrong_no_na, wrong_no_nb, Lbinary_read4},
  4157. {"binary_readfloat", wrong_no_na, wrong_no_nb, Lbinary_readfloat},
  4158. {"binary_close_input", wrong_no_na, wrong_no_nb, Lbinary_close_input},
  4159. {"prinhex", Lprinhex, Lprinhex2, wrong_no_1},
  4160. {"prinoctal", Lprinoctal, Lprinoctal2, wrong_no_1},
  4161. {"prinbinary", Lprinbinary, Lprinbinary2, wrong_no_1},
  4162. #ifdef COMMON
  4163. {"charpos", Lposn_1, wrong_no_nb, Lposn},
  4164. {"finish-output", Lflush1, wrong_no_nb, Lflush},
  4165. {"make-synonym-stream", Lmake_synonym_stream, too_many_1, wrong_no_1},
  4166. {"make-broadcast-stream", Lmake_broadcast_stream_1, Lmake_broadcast_stream_2, Lmake_broadcast_stream_n},
  4167. {"make-concatenated-stream",Lmake_concatenated_stream_1, Lmake_concatenated_stream_2, Lmake_concatenated_stream_n},
  4168. {"make-two-way-stream", too_few_2, Lmake_two_way_stream, wrong_no_2},
  4169. {"make-echo-stream", too_few_2, Lmake_echo_stream, wrong_no_2},
  4170. {"make-string-input-stream",Lmake_string_input_stream_1, Lmake_string_input_stream_2, Lmake_string_input_stream_n},
  4171. {"make-string-output-stream",wrong_no_na, wrong_no_nb, Lmake_string_output_stream},
  4172. {"get-output-stream-string",Lget_output_stream_string, too_many_1, wrong_no_1},
  4173. {"close", Lclose, too_many_1, wrong_no_1},
  4174. {"~tyo", Ltyo, too_many_1, wrong_no_1},
  4175. /* At least as a temporary measure I provide these in COMMON mode too */
  4176. {"explode", Lexplode, too_many_1, wrong_no_1},
  4177. {"explodec", Lexplodec, too_many_1, wrong_no_1},
  4178. {"explode2", Lexplodec, too_many_1, wrong_no_1},
  4179. {"explode2lc", Lexplode2lc, too_many_1, wrong_no_1},
  4180. {"exploden", Lexploden, too_many_1, wrong_no_1},
  4181. {"explodecn", Lexplodecn, too_many_1, wrong_no_1},
  4182. {"explode2n", Lexplodecn, too_many_1, wrong_no_1},
  4183. {"explode2lcn", Lexplode2lcn, too_many_1, wrong_no_1},
  4184. {"explodehex", Lexplodehex, too_many_1, wrong_no_1},
  4185. {"explodeoctal", Lexplodeoctal, too_many_1, wrong_no_1},
  4186. {"explodebinary", Lexplodebinary, too_many_1, wrong_no_1},
  4187. {"prin", Lprin, too_many_1, wrong_no_1},
  4188. {"prin1", Lprin, too_many_1, wrong_no_1},
  4189. {"princ", Lprinc, too_many_1, wrong_no_1},
  4190. {"prin2", Lprinc, too_many_1, wrong_no_1},
  4191. {"prin2a", Lprin2a, too_many_1, wrong_no_1},
  4192. {"print", Lprint, too_many_1, wrong_no_1},
  4193. {"printc", Lprintc, too_many_1, wrong_no_1},
  4194. {"set-print-precision", Lprint_precision, too_many_1, wrong_no_1},
  4195. #else
  4196. {"close", Lclose, too_many_1, wrong_no_1},
  4197. {"explode", Lexplode, too_many_1, wrong_no_1},
  4198. {"explodec", Lexplodec, too_many_1, wrong_no_1},
  4199. {"explode2", Lexplodec, too_many_1, wrong_no_1},
  4200. {"explode2lc", Lexplode2lc, too_many_1, wrong_no_1},
  4201. {"explode2uc", Lexplode2uc, too_many_1, wrong_no_1},
  4202. {"exploden", Lexploden, too_many_1, wrong_no_1},
  4203. {"explodecn", Lexplodecn, too_many_1, wrong_no_1},
  4204. {"explode2n", Lexplodecn, too_many_1, wrong_no_1},
  4205. {"explode2lcn", Lexplode2lcn, too_many_1, wrong_no_1},
  4206. {"explode2ucn", Lexplode2ucn, too_many_1, wrong_no_1},
  4207. {"explodehex", Lexplodehex, too_many_1, wrong_no_1},
  4208. {"explodeoctal", Lexplodeoctal, too_many_1, wrong_no_1},
  4209. {"explodebinary", Lexplodebinary, too_many_1, wrong_no_1},
  4210. {"prin", Lprin, too_many_1, wrong_no_1},
  4211. {"prin1", Lprin, too_many_1, wrong_no_1},
  4212. {"princ", Lprinc, too_many_1, wrong_no_1},
  4213. {"prin2", Lprinc, too_many_1, wrong_no_1},
  4214. {"prin2a", Lprin2a, too_many_1, wrong_no_1},
  4215. {"print", Lprint, too_many_1, wrong_no_1},
  4216. {"printc", Lprintc, too_many_1, wrong_no_1},
  4217. {"set-print-precision", Lprint_precision, too_many_1, wrong_no_1},
  4218. {"tyo", Ltyo, too_many_1, wrong_no_1},
  4219. #endif
  4220. {NULL, 0, 0, 0}
  4221. };
  4222. /* end of print.c */