print.c 141 KB

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