csl.c 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365
  1. /* csl.c Copyright (C) 1989-99 Codemist Ltd */
  2. /*
  3. * This is Lisp system for use when delivering Lisp applications
  4. * (such as REDUCE) on pretty-well any computer that has an ANSI
  5. * C compiler where sizeof(void *)==4 and there is in integral
  6. * type that is also 4 bytes wide. In fact I can also manage if
  7. * sizeof(void *)==8 provided that it can be arranged that all
  8. * addresses returned by malloc() have only their bottom 32 bits
  9. * set...
  10. */
  11. /* Signature: 22abf0f6 07-Mar-2000 */
  12. #include <stdarg.h>
  13. #include <string.h>
  14. #include <ctype.h>
  15. #include "machine.h"
  16. #include "tags.h"
  17. #include "externs.h"
  18. #include "arith.h"
  19. #include "read.h"
  20. #include "stream.h"
  21. #include "entries.h"
  22. #include "version.h"
  23. #define INCLUDE_ERROR_STRING_TABLE 1
  24. #include "cslerror.h"
  25. #undef INCLUDE_ERROR_STRING_TABLE
  26. #ifdef TIMEOUT
  27. #include "timeout.h"
  28. #endif
  29. #ifdef OLD_THINK_C
  30. #include <console.h>
  31. #include <memory.h>
  32. #undef nil /* Yuk - this is defined by <types.h> which <memory.h> loads */
  33. #endif
  34. #ifdef __WATCOMC__
  35. #include <float.h>
  36. #endif
  37. #ifdef SOCKETS
  38. #include "sockhdr.h"
  39. #ifndef ms_windows
  40. #include <sys/wait.h>
  41. #endif
  42. static int port_number, remote_store, current_users, max_users;
  43. SOCKET socket_server;
  44. int sockets_ready;
  45. clock_t cpu_timeout;
  46. time_t elapsed_timeout;
  47. static int char_to_socket(int c);
  48. #endif
  49. #ifdef WINDOW_SYSTEM
  50. CSLbool use_wimp;
  51. #endif
  52. #ifdef USE_MPI
  53. int32 mpi_rank,mpi_size;
  54. #endif
  55. /*****************************************************************************/
  56. /* Error reporting and recovery */
  57. /*****************************************************************************/
  58. #ifdef CHECK_STACK
  59. /*
  60. * Some computers are notably unhelpful about their behaviour when the system
  61. * stack overflows. As a debugging tool on such machines I can do limited
  62. * software checking by inserting explicit calls to this function in places
  63. * I think may be critical. I impose an arbitrary limit on the stack size,
  64. * but that is better than no checking and random corruption - maybe. Please
  65. * do not enable CHECK_STACK unless it is really necessary to hunt a bug,
  66. * since it is miserably expensive and crude.
  67. */
  68. #define C_STACK_ALLOCATION 240000
  69. static int spset = 0;
  70. static int32 spbase = 0, spmin;
  71. static int stack_depth[C_STACK_ALLOCATION], stack_line[C_STACK_ALLOCATION];
  72. static char *stack_file[C_STACK_ALLOCATION];
  73. static int c_stack_ptr = 0;
  74. int check_stack(char *file, int line)
  75. {
  76. int32 temp = (int32)&temp;
  77. if (!spset)
  78. { spbase = spmin = temp;
  79. spset = 1;
  80. c_stack_ptr = 0;
  81. stack_depth[0] = temp;
  82. stack_line[0] = line;
  83. stack_file[0] = file;
  84. }
  85. if (temp < stack_depth[c_stack_ptr] && c_stack_ptr<C_STACK_ALLOCATION-2)
  86. c_stack_ptr++;
  87. else while (temp > stack_depth[c_stack_ptr] && c_stack_ptr>0)
  88. c_stack_ptr--;
  89. stack_depth[c_stack_ptr] = temp;
  90. stack_line[c_stack_ptr] = line;
  91. stack_file[c_stack_ptr] = file;
  92. if (temp < spmin-250) /* Only check at granularity of 250 bytes */
  93. { int i;
  94. term_printf("Stack depth %d at file %s line %d\n",
  95. spbase-temp, file, line);
  96. for (i=c_stack_ptr; i>=0 && i > c_stack_ptr-30; i--)
  97. term_printf(" %s:%d", stack_file[i], stack_line[i]);
  98. term_printf("\n");
  99. spmin = temp;
  100. if (temp < spbase-C_STACK_ALLOCATION) return 1;
  101. }
  102. return 0;
  103. }
  104. #endif
  105. /*
  106. * error_message_table was defined in cslerror.h since that way I can keep its
  107. * contents textually close to the definitions of the message codes that it
  108. * has to relate to.
  109. */
  110. #define errcode(n) error_message_table[n]
  111. Lisp_Object MS_CDECL error(int nargs, int code, ...)
  112. /*
  113. * nargs indicates how many values have been provided AFTER the
  114. * code. Thus nargs==0 will just display a simple message, nargs==1
  115. * will be a message plus a value and so on. I will expect that the
  116. * number of actual args here is well within any limits that I ought to
  117. * impose.
  118. */
  119. {
  120. va_list a;
  121. int i;
  122. Lisp_Object nil = C_nil, w1;
  123. Lisp_Object *w = (Lisp_Object *)&work_1;
  124. if (nargs > ARG_CUT_OFF) nargs = ARG_CUT_OFF;
  125. if (miscflags & HEADLINE_FLAG)
  126. { err_printf("\n+++ Error %s: ", errcode(code));
  127. /*
  128. * There is now some painful shuffling around to get all the args
  129. * to error() moved over onto the Lisp stack so that is garbage collection
  130. * is triggered during printing all will be well.
  131. */
  132. va_start(a, code);
  133. for (i=0; i<nargs; i++) *w++ = va_arg(a, Lisp_Object);
  134. va_end(a);
  135. for (i=0; i<nargs; i++) push(*--w);
  136. if (code != err_stack_overflow) /* Be cautious here! */
  137. { stackcheck0(nargs);
  138. }
  139. for (i=0; i<nargs; i++)
  140. { Lisp_Object p;
  141. pop(p);
  142. loop_print_error(p);
  143. err_printf("\n");
  144. }
  145. }
  146. if ((w1 = qvalue(break_function)) != nil &&
  147. symbolp(w1) &&
  148. qfn1(w1) != undefined1)
  149. { (*qfn1(w1))(qenv(w1), nil);
  150. ignore_exception();
  151. }
  152. /*
  153. * After doing this is is necessary to be VERY careful, since nil is
  154. * used as a base register for lots of things... Still this is the
  155. * cheapest way I can see to mark the need for unwinding.
  156. */
  157. exit_reason = (miscflags & MESSAGES_FLAG) ? UNWIND_ERROR : UNWIND_UNWIND;
  158. exit_value = exit_tag = nil;
  159. exit_count = 0;
  160. flip_exception();
  161. return nil;
  162. }
  163. Lisp_Object MS_CDECL cerror(int nargs, int code1, int code2, ...)
  164. /*
  165. * nargs indicated the number of EXTRA args after code1 & code2.
  166. */
  167. {
  168. Lisp_Object nil = C_nil, w1;
  169. va_list a;
  170. int i;
  171. Lisp_Object *w = (Lisp_Object *)&work_1;
  172. if (nargs > ARG_CUT_OFF) nargs = ARG_CUT_OFF;
  173. if (miscflags & HEADLINE_FLAG)
  174. { err_printf("\n+++ Error %s, %s: ", errcode(code1), errcode(code2));
  175. va_start(a, code2);
  176. for (i=0; i<nargs; i++) *w++ = va_arg(a, Lisp_Object);
  177. va_end(a);
  178. for (i=0; i<nargs; i++) push(*--w);
  179. stackcheck0(nargs-2);
  180. nil = C_nil;
  181. for (i=0; i<nargs; i++)
  182. { Lisp_Object p;
  183. pop(p);
  184. loop_print_error(p);
  185. err_printf("\n");
  186. }
  187. }
  188. if ((w1 = qvalue(break_function)) != nil &&
  189. symbolp(w1) &&
  190. qfn1(w1) != undefined1)
  191. { (*qfn1(w1))(qenv(w1), nil);
  192. ignore_exception();
  193. }
  194. /*
  195. * After doing this is is necessary to be VERY careful, since nil is
  196. * used as a base register for lots of things... Still this is the
  197. * cheapest way I can see to mark the need for unwinding.
  198. */
  199. exit_reason = (miscflags & MESSAGES_FLAG) ? UNWIND_ERROR : UNWIND_UNWIND;
  200. exit_value = exit_tag = nil;
  201. exit_count = 0;
  202. flip_exception();
  203. return nil;
  204. }
  205. Lisp_Object interrupted(Lisp_Object p)
  206. /*
  207. * Could return onevalue(p) to proceed from the interrupt event...
  208. */
  209. {
  210. Lisp_Object nil = C_nil, w;
  211. #ifdef WINDOW_SYSTEM
  212. /*
  213. * If I have a windowed system I expect that the mechanism for
  214. * raising an exception will have had a menu that gave me a chance
  215. * to decide whether to proceed or abort. Thus the following code
  216. * is only needed if there is no window system active. On some systems
  217. * this may be an active check.
  218. */
  219. if (!use_wimp)
  220. #endif
  221. {
  222. if (clock_stack == &consolidated_time[0])
  223. { clock_t t0 = read_clock();
  224. /*
  225. * On at least some (Unix) systems clock_t is a 32-bit signed value
  226. * and CLOCKS_PER_SEC = 1000000. The effect is that integer overflow
  227. * occurs after around 35 minutes of running. I must therefore check the
  228. * clock and move information into a floating point variable at least
  229. * every half-hour. With luck I will do it more like 20 times per second
  230. * because I have code muck like this in a tick handler that is activated
  231. * on a rather regular basis.
  232. */
  233. double delta = (double)(t0 - base_time)/(double)CLOCKS_PER_SEC;
  234. base_time = t0;
  235. consolidated_time[0] += delta;
  236. }
  237. term_printf(
  238. "\n+++ [%.2f+%.2f] Type C to continue, A to abort, X to exit\n",
  239. consolidated_time[0], gc_time);
  240. ensure_screen(); nil = C_nil;
  241. if (exception_pending()) return nil;
  242. push(prompt_thing);
  243. prompt_thing = CHAR_EOF;
  244. other_read_action(READ_FLUSH, lisp_terminal_io);
  245. for (;;)
  246. { int c = char_from_terminal(nil);
  247. /*
  248. * Note that I explicitly say "char_from_terminal()" here - this is because
  249. * I do not expect to be interrupted unless there was a terminal available
  250. * to send the interrupt! This is in fact a slightly marginal assumption.
  251. */
  252. switch (c)
  253. {
  254. case 'c': case 'C': /* proceed as if no interrupt */
  255. pop(prompt_thing);
  256. return onevalue(p);
  257. case 'a': case 'A': /* raise an exception */
  258. break;
  259. case 'x': case 'X':
  260. my_exit(EXIT_FAILURE); /* Rather abrupt */
  261. case '\n':
  262. term_printf("C to continue, A to abort, X to exit: ");
  263. ensure_screen(); nil = C_nil;
  264. if (exception_pending()) return nil;
  265. continue;
  266. default: /* wait for A or C */
  267. continue;
  268. }
  269. break;
  270. }
  271. pop(prompt_thing);
  272. }
  273. if (miscflags & HEADLINE_FLAG) err_printf("+++ Interrupted\n");
  274. if ((w = qvalue(break_function)) != nil &&
  275. symbolp(w) &&
  276. qfn1(w) != undefined1)
  277. { (*qfn1(w))(qenv(w), nil);
  278. ignore_exception();
  279. }
  280. exit_reason = (miscflags & MESSAGES_FLAG) ? UNWIND_ERROR : UNWIND_UNWIND;
  281. exit_value = exit_tag = nil;
  282. exit_count = 0;
  283. flip_exception();
  284. return nil;
  285. }
  286. Lisp_Object aerror(char *s)
  287. {
  288. Lisp_Object nil = C_nil, w;
  289. if (miscflags & HEADLINE_FLAG) err_printf("+++ Error bad args for %s\n", s);
  290. if ((w = qvalue(break_function)) != nil &&
  291. symbolp(w) &&
  292. qfn1(w) != undefined1)
  293. { (*qfn1(w))(qenv(w), nil);
  294. ignore_exception();
  295. }
  296. exit_reason = (miscflags & MESSAGES_FLAG) ? UNWIND_ERROR : UNWIND_UNWIND;
  297. exit_value = exit_tag = nil;
  298. exit_count = 0;
  299. flip_exception();
  300. return nil;
  301. }
  302. Lisp_Object aerror0(char *s)
  303. {
  304. Lisp_Object nil = C_nil, w;
  305. if (miscflags & HEADLINE_FLAG) err_printf("+++ Error: %s\n", s);
  306. if ((w = qvalue(break_function)) != nil &&
  307. symbolp(w) &&
  308. qfn1(w) != undefined1)
  309. { (*qfn1(w))(qenv(w), nil);
  310. ignore_exception();
  311. }
  312. exit_reason = (miscflags & MESSAGES_FLAG) ? UNWIND_ERROR : UNWIND_UNWIND;
  313. exit_value = exit_tag = nil;
  314. exit_count = 0;
  315. flip_exception();
  316. #ifdef COMMON
  317. /*
  318. * This is to help me debug in the face of low level system crashes
  319. */
  320. if (spool_file) fflush(spool_file);
  321. #endif
  322. return nil;
  323. }
  324. Lisp_Object aerror1(char *s, Lisp_Object a)
  325. {
  326. Lisp_Object nil = C_nil, w;
  327. if (miscflags & HEADLINE_FLAG)
  328. { err_printf("+++ Error: %s ", s);
  329. loop_print_error(a);
  330. err_printf("\n");
  331. }
  332. if ((w = qvalue(break_function)) != nil &&
  333. symbolp(w) &&
  334. qfn1(w) != undefined1)
  335. { (*qfn1(w))(qenv(w), nil);
  336. ignore_exception();
  337. }
  338. exit_reason = (miscflags & MESSAGES_FLAG) ? UNWIND_ERROR : UNWIND_UNWIND;
  339. exit_value = exit_tag = nil;
  340. exit_count = 0;
  341. flip_exception();
  342. #ifdef COMMON
  343. /*
  344. * This is to help me debug in the face of low level system crashes
  345. */
  346. if (spool_file) fflush(spool_file);
  347. #endif
  348. return nil;
  349. }
  350. Lisp_Object aerror2(char *s, Lisp_Object a, Lisp_Object b)
  351. {
  352. Lisp_Object nil = C_nil, w;
  353. if (miscflags & HEADLINE_FLAG)
  354. { err_printf("+++ Error: %s ", s);
  355. loop_print_error(a);
  356. err_printf(" ");
  357. loop_print_error(b);
  358. err_printf("\n");
  359. }
  360. if ((w = qvalue(break_function)) != nil &&
  361. symbolp(w) &&
  362. qfn1(w) != undefined1)
  363. { (*qfn1(w))(qenv(w), nil);
  364. ignore_exception();
  365. }
  366. exit_reason = (miscflags & MESSAGES_FLAG) ? UNWIND_ERROR : UNWIND_UNWIND;
  367. exit_value = exit_tag = nil;
  368. exit_count = 0;
  369. flip_exception();
  370. #ifdef COMMON
  371. /*
  372. * This is to help me debug in the face of low level system crashes
  373. */
  374. if (spool_file) fflush(spool_file);
  375. #endif
  376. return nil;
  377. }
  378. static Lisp_Object wrong(int wanted, int given, Lisp_Object env)
  379. {
  380. char msg[64];
  381. Lisp_Object nil = C_nil;
  382. CSL_IGNORE(nil);
  383. sprintf(msg, "Function called with %d args where %d wanted", given, wanted);
  384. if (is_cons(env)) env = qcdr(env);
  385. if ((miscflags & HEADLINE_FLAG) && is_vector(env))
  386. { Lisp_Object fname = elt(env, 0);
  387. err_printf("\nCalling ");
  388. loop_print_error(fname);
  389. err_printf("\n");
  390. }
  391. return aerror(msg);
  392. }
  393. Lisp_Object too_few_2(Lisp_Object env, Lisp_Object a1)
  394. {
  395. CSL_IGNORE(a1);
  396. return wrong(2, 1, env);
  397. }
  398. Lisp_Object too_many_1(Lisp_Object env, Lisp_Object a1, Lisp_Object a2)
  399. {
  400. CSL_IGNORE(a1);
  401. CSL_IGNORE(a2);
  402. return wrong(1, 2, env);
  403. }
  404. Lisp_Object wrong_no_0a(Lisp_Object env, Lisp_Object a1)
  405. {
  406. CSL_IGNORE(a1);
  407. return wrong(0, 1, env);
  408. }
  409. Lisp_Object wrong_no_0b(Lisp_Object env, Lisp_Object a1, Lisp_Object a2)
  410. {
  411. CSL_IGNORE(a1);
  412. CSL_IGNORE(a2);
  413. return wrong(0, 2, env);
  414. }
  415. Lisp_Object wrong_no_3a(Lisp_Object env, Lisp_Object a1)
  416. {
  417. CSL_IGNORE(a1);
  418. return wrong(3, 1, env);
  419. }
  420. Lisp_Object wrong_no_3b(Lisp_Object env, Lisp_Object a1, Lisp_Object a2)
  421. {
  422. CSL_IGNORE(a1);
  423. CSL_IGNORE(a2);
  424. return wrong(3, 2, env);
  425. }
  426. Lisp_Object wrong_no_na(Lisp_Object env, Lisp_Object a1)
  427. {
  428. CSL_IGNORE(a1);
  429. if (is_cons(env) && is_bps(qcar(env)))
  430. return wrong(((unsigned char *)data_of_bps(qcar(env)))[0], 1, env);
  431. else return aerror("function called with 1 arg when 0 or >= 3 wanted");
  432. }
  433. Lisp_Object wrong_no_nb(Lisp_Object env, Lisp_Object a1, Lisp_Object a2)
  434. {
  435. CSL_IGNORE(a1);
  436. CSL_IGNORE(a2);
  437. if (is_cons(env) && is_bps(qcar(env)))
  438. return wrong(((unsigned char *)data_of_bps(qcar(env)))[0], 2, env);
  439. else return aerror("function called with 2 args when 0 or >= 3 wanted");
  440. }
  441. Lisp_Object MS_CDECL wrong_no_1(Lisp_Object env, int nargs, ...)
  442. {
  443. CSL_IGNORE(env);
  444. CSL_IGNORE(nargs);
  445. return wrong(1, nargs, env);
  446. }
  447. Lisp_Object MS_CDECL wrong_no_2(Lisp_Object env, int nargs, ...)
  448. {
  449. CSL_IGNORE(env);
  450. CSL_IGNORE(nargs);
  451. return wrong(2, nargs, env);
  452. }
  453. Lisp_Object bad_special2(Lisp_Object env, Lisp_Object a1, Lisp_Object a2)
  454. {
  455. CSL_IGNORE(env);
  456. CSL_IGNORE(a1);
  457. CSL_IGNORE(a2);
  458. return aerror("call to special form");
  459. }
  460. Lisp_Object MS_CDECL bad_specialn(Lisp_Object env, int nargs, ...)
  461. {
  462. CSL_IGNORE(env);
  463. CSL_IGNORE(nargs);
  464. return aerror("call to special form");
  465. }
  466. void MS_CDECL fatal_error(int code, ...)
  467. {
  468. /*
  469. * Note that FATAL error messages are sent to the terminal, not to the
  470. * error output stream. This is because the error output stream may be
  471. * corrupted in such dire circumstances.
  472. */
  473. term_printf("+++ Fatal error %s\n", errcode(code));
  474. if (spool_file != NULL)
  475. {
  476. #ifdef COMMON
  477. fprintf(spool_file, "\nFinished dribbling to %s.\n", spool_file_name);
  478. #else
  479. fprintf(spool_file, "\n+++ Transcript terminated after error +++\n");
  480. #endif
  481. fclose(spool_file);
  482. spool_file = NULL;
  483. }
  484. my_exit(EXIT_FAILURE);
  485. }
  486. #ifndef __cplusplus
  487. static jmp_buf my_exit_buffer;
  488. #endif
  489. void my_exit(int n)
  490. {
  491. #ifdef USE_MPI
  492. MPI_Finalize();
  493. #endif
  494. #if defined(FLEX) && defined(WINDOWS_NT) && defined(CWIN) && defined(NAG)
  495. extern void rlnag();
  496. rlnag();
  497. #endif
  498. #ifdef BUFFERED_STDOUT
  499. ensure_screen();
  500. #endif
  501. #ifdef SOCKETS
  502. if (sockets_ready) WSACleanup();
  503. #endif
  504. #ifdef WINDOW_SYSTEM
  505. pause_for_user();
  506. #endif
  507. #ifdef CWIN
  508. #ifdef __cplusplus
  509. throw n;
  510. #else
  511. if (n == 0) n = 0x80000000;
  512. longjmp(my_exit_buffer, n);
  513. #endif
  514. #else
  515. #if defined(WINDOWS_NT) && defined(NAG)
  516. { extern void sys_abort(int);
  517. sys_abort(n);
  518. }
  519. #else
  520. #ifdef TICK_STREAM
  521. remove_ticker();
  522. #endif
  523. exit(n);
  524. #endif
  525. #endif
  526. }
  527. static int return_code = 0;
  528. CSLbool segvtrap = YES;
  529. CSLbool batch_flag = NO;
  530. CSLbool ignore_restart_fn = NO;
  531. static void lisp_main(void)
  532. {
  533. Lisp_Object nil;
  534. #ifndef __cplusplus
  535. /*
  536. * The setjmp here is to provide a long-stop for untrapped
  537. * floating point exceptions.
  538. */
  539. jmp_buf this_level, *save_level = errorset_buffer;
  540. #endif
  541. tty_count = 0;
  542. while (YES)
  543. /*
  544. * The sole purpose of the while loop here is to allow me to proceed
  545. * for a second try if I get a (cold-start) call.
  546. */
  547. { Lisp_Object *save = stack;
  548. nil = C_nil;
  549. #ifndef __cplusplus
  550. errorset_buffer = &this_level;
  551. #endif
  552. errorset_msg = NULL;
  553. #ifdef __cplusplus
  554. try
  555. #else
  556. if (!setjmp(this_level))
  557. #endif
  558. { if (supervisor != nil && !ignore_restart_fn)
  559. { miscflags |= HEADLINE_FLAG | MESSAGES_FLAG;
  560. if (exit_charvec != NULL)
  561. { Lisp_Object a = read_from_vector(exit_charvec);
  562. nil = C_nil;
  563. if (exception_pending())
  564. { flip_exception();
  565. a = nil;
  566. }
  567. exit_charvec = NULL;
  568. push(a);
  569. apply(supervisor, 1, nil, supervisor);
  570. }
  571. else apply(supervisor, 0, nil, supervisor);
  572. }
  573. /*
  574. * Here the default read-eval-print loop used if the user has not provided
  575. * a supervisor function.
  576. */
  577. else read_eval_print(lisp_true);
  578. }
  579. #ifdef __cplusplus
  580. catch (char *)
  581. #else
  582. else
  583. #endif
  584. { if (errorset_msg != NULL)
  585. { term_printf("\n%s detected\n", errorset_msg);
  586. errorset_msg = NULL;
  587. }
  588. unwind_stack(save, NO);
  589. exit_reason = UNWIND_ERROR;
  590. flip_exception();
  591. signal(SIGFPE, low_level_signal_handler);
  592. #ifdef __WATCOMC__
  593. _control87(_EM_OVERFLOW | _EM_INVALID | _EM_DENORMAL |
  594. _EM_ZERODIVIDE | _EM_INEXACT | _EM_UNDERFLOW,
  595. _MCW_EM);
  596. #endif
  597. if (segvtrap) signal(SIGSEGV, low_level_signal_handler);
  598. #ifdef SIGBUS
  599. if (segvtrap) signal(SIGBUS, low_level_signal_handler);
  600. #endif
  601. #ifdef SIGILL
  602. if (segvtrap) signal(SIGILL, low_level_signal_handler);
  603. #endif
  604. }
  605. nil = C_nil;
  606. if (exception_pending())
  607. { flip_exception();
  608. if (exit_reason == UNWIND_RESTART)
  609. { if (exit_tag == fixnum_of_int(0)) /* "stop" */
  610. return_code = (int)int_of_fixnum(exit_value);
  611. else if (exit_tag == fixnum_of_int(1)) /* "preserve" */
  612. { char *msg = "";
  613. return_code = EXIT_SUCCESS;
  614. compression_worth_while = 128;
  615. if (is_vector(exit_value) &&
  616. type_of_header(vechdr(exit_value)) == TYPE_STRING)
  617. msg = &celt(exit_value, 0);
  618. preserve(msg);
  619. nil = C_nil;
  620. if (exception_pending())
  621. { flip_exception();
  622. return_code = EXIT_FAILURE;
  623. }
  624. }
  625. else /* "restart" */
  626. { int32 fd = stream_pushed_char(lisp_terminal_io);
  627. char new_module[64], new_fn[64]; /* Limited name length */
  628. int cold_start;
  629. cold_start = (exit_value == nil);
  630. #ifdef TICK_STREAM
  631. remove_ticker();
  632. /*
  633. * Of course a tick may very well have happened rather recently - so
  634. * I will flush it out now just to clear the air.
  635. */
  636. if (stack >= stacklimit)
  637. { reclaim(nil, "stack", GC_STACK, 0);
  638. ignore_exception();
  639. }
  640. #endif
  641. cold_start = (exit_value == nil);
  642. Lrds(nil, nil);
  643. Lwrs(nil, nil);
  644. /*
  645. * If either of the above two calls to rds/wrs were to fail I would
  646. * be in a big mess.
  647. */
  648. if (!cold_start)
  649. { new_module[0] = 0;
  650. new_fn[0] = 0;
  651. if (exit_value != lisp_true)
  652. { Lisp_Object modname = nil;
  653. if (is_cons(exit_value))
  654. { modname = qcar(exit_value);
  655. exit_value = qcdr(exit_value);
  656. if (is_cons(exit_value))
  657. exit_value = qcar(exit_value);
  658. }
  659. if (symbolp(modname) && modname != nil)
  660. { modname = get_pname(modname);
  661. if (exception_pending()) ignore_exception();
  662. else
  663. { Header h = vechdr(modname);
  664. int32 len = length_of_header(h) - 4;
  665. if (len > 63) len = 63;
  666. memcpy(new_module,
  667. (char *)modname + (4 - TAG_VECTOR),
  668. (size_t)len);
  669. new_module[len] = 0;
  670. }
  671. }
  672. if (symbolp(exit_value) && exit_value != nil)
  673. { exit_value = get_pname(exit_value);
  674. if (exception_pending()) ignore_exception();
  675. else
  676. { Header h = vechdr(exit_value);
  677. int32 len = length_of_header(h) - 4;
  678. if (len > 63) len = 63;
  679. memcpy(new_fn,
  680. (char *)exit_value + (4 - TAG_VECTOR),
  681. (size_t)len);
  682. new_fn[len] = 0;
  683. }
  684. }
  685. }
  686. }
  687. while (vheap_pages_count != 0)
  688. pages[pages_count++] = vheap_pages[--vheap_pages_count];
  689. while (heap_pages_count != 0)
  690. pages[pages_count++] = heap_pages[--heap_pages_count];
  691. while (bps_pages_count != 0)
  692. pages[pages_count++] = bps_pages[--bps_pages_count];
  693. /*
  694. * When I call restart-csl I will leave the random number generator where it
  695. * was. Anybody who wants to reset if either to a freshly randomised
  696. * configuration or to a defined condition must do so for themselves. For
  697. * people who do not care too much what I do here is probably acceptable!
  698. */
  699. MD5_Init();
  700. MD5_Update((unsigned char *)errcode(err_registration), 32);
  701. IreInit();
  702. setup(cold_start ? 0 : 1, 0.0);
  703. exit_tag = exit_value = nil;
  704. exit_reason = UNWIND_NULL;
  705. stream_pushed_char(lisp_terminal_io) = fd;
  706. interrupt_pending = already_in_gc = NO;
  707. polltick_pending = tick_pending = tick_on_gc_exit = NO;
  708. if (!cold_start && new_fn[0] != 0)
  709. { Lisp_Object w;
  710. if (new_module[0] != 0)
  711. { w = make_undefined_symbol(new_module);
  712. Lload_module(nil, w);
  713. ignore_exception();
  714. }
  715. w = make_undefined_symbol(new_fn);
  716. nil = C_nil;
  717. if (exception_pending()) ignore_exception();
  718. else supervisor = w;
  719. }
  720. #ifdef TICK_STREAM
  721. add_ticker();
  722. #endif
  723. continue;
  724. }
  725. }
  726. }
  727. /*
  728. * In all normal cases when read_eval_print exits (i.e. all cases except
  729. * if it terminates after (cold-start)) I exit here.
  730. */
  731. #ifndef __cplusplus
  732. errorset_buffer = save_level;
  733. #endif
  734. break;
  735. }
  736. }
  737. #ifndef MS_DOS
  738. #ifndef WINDOWS_NT
  739. CSLbool sigint_must_longjmp = NO;
  740. #ifndef __cplusplus
  741. jmp_buf sigint_buf;
  742. #endif
  743. void sigint_handler(int code)
  744. {
  745. /*
  746. * Note that the only things that I am really allowed to do in a routine
  747. * like this involve setting variables of type sig_atomic_t, which can not
  748. * be viewed as much more than boolean. The code actually used here is
  749. * somewhat more ambitious (== non-portable!) so must be viewed as delicate.
  750. * ANSI guarantee that longjmp-ing out of a non-nested signal handler
  751. * is valid, but some earlier C libraries have not supported this. Note that
  752. * with C++ I will use throw rather than longjmp.
  753. */
  754. /*
  755. * tick_pending etc allow a steady stream of clock events to
  756. * be handed to Lisp.
  757. */
  758. interrupt_pending = 1;
  759. signal(SIGINT, sigint_handler);
  760. if (sigint_must_longjmp)
  761. {
  762. sigint_must_longjmp = NO;
  763. #ifdef __cplusplus
  764. throw((int *)0);
  765. #else
  766. longjmp(sigint_buf, 1);
  767. #endif
  768. }
  769. #ifndef TICK_STREAM
  770. /*
  771. * If there is not a separate regular stream of ticks I will simulate
  772. * the receipt of a tick here. Thus I need to be able to recognize "ticks"
  773. * even on systems where there are no "real" ones.
  774. */
  775. if (!tick_pending)
  776. {
  777. if (already_in_gc) tick_on_gc_exit = YES;
  778. else
  779. {
  780. #ifndef NILSEG_EXTERNS
  781. Lisp_Object nil = C_nil;
  782. CSLbool xxx = NO;
  783. if (exception_pending()) flip_exception(), xxx = YES;
  784. #endif
  785. tick_pending = YES;
  786. saveheaplimit = heaplimit;
  787. heaplimit = fringe;
  788. savevheaplimit = vheaplimit;
  789. vheaplimit = vfringe;
  790. savecodelimit = codelimit;
  791. codelimit = codefringe;
  792. savestacklimit = stacklimit;
  793. stacklimit = stackbase;
  794. #ifndef NILSEG_EXTERNS
  795. if (xxx) flip_exception();
  796. #endif
  797. }
  798. }
  799. #endif /* TICK_STREAM */
  800. return;
  801. }
  802. #endif
  803. #endif
  804. #ifdef SOFTWARE_TICKS
  805. int32 number_of_ticks = 0;
  806. int32 countdown;
  807. int deal_with_tick()
  808. {
  809. number_of_ticks++;
  810. if (!tick_pending)
  811. {
  812. if (already_in_gc) tick_on_gc_exit = YES;
  813. else
  814. {
  815. #ifndef NILSEG_EXTERNS
  816. Lisp_Object nil = C_nil;
  817. CSLbool xxx = NO;
  818. if (exception_pending()) flip_exception(), xxx = YES;
  819. #endif
  820. tick_pending = YES;
  821. saveheaplimit = heaplimit;
  822. heaplimit = fringe;
  823. savevheaplimit = vheaplimit;
  824. vheaplimit = vfringe;
  825. savecodelimit = codelimit;
  826. codelimit = codefringe;
  827. savestacklimit = stacklimit;
  828. stacklimit = stackbase;
  829. #ifndef NILSEG_EXTERNS
  830. if (xxx) flip_exception();
  831. #endif
  832. }
  833. }
  834. #ifdef SOFTWARE_TICKS
  835. countdown = SOFTWARE_TICKS;
  836. #endif
  837. return 1;
  838. }
  839. #endif
  840. static long int initial_random_seed, seed2;
  841. char *files_to_read[MAX_INPUT_FILES],
  842. *symbols_to_define[MAX_SYMBOLS_TO_DEFINE],
  843. *fasl_paths[MAX_FASL_PATHS];
  844. int output_directory;
  845. character_reader *procedural_input;
  846. character_writer *procedural_output;
  847. CSLbool undefine_this_one[MAX_SYMBOLS_TO_DEFINE];
  848. int number_of_input_files = 0,
  849. number_of_symbols_to_define = 0,
  850. number_of_fasl_paths = 0,
  851. init_flags = 0;
  852. #ifdef WINDOW_SYSTEM
  853. FILE *alternative_stdout = NULL;
  854. #endif
  855. /*
  856. * standard_directory holds the name of the default image file that CSL
  857. * would load.
  858. */
  859. char *standard_directory;
  860. /*
  861. * If non-NULL the string module_enquiry is a name presenetd on the
  862. * command line in a "-T name" request, and this will cause the system
  863. * to behave in a totally odd manner - it does not run Lisp at all but
  864. * performs a directory enquiry within the image file.
  865. */
  866. static char *module_enquiry = NULL;
  867. void cslstart(int argc, char *argv[], character_writer *wout)
  868. {
  869. int i;
  870. CSLbool restartp;
  871. double store_size = 0.0;
  872. stack_segsize = 1;
  873. module_enquiry = NULL;
  874. #ifdef SOFTWARE_TICKS
  875. countdown = 0x7fffffff;
  876. #endif
  877. /*
  878. * Note that I will set up clock_stack AGAIN later on! The one further down
  879. * happens after command line options have been decoded and is where I really
  880. * want to consider Lisp to be starting. The setting here is because
  881. * if I call ensure_screen() it can push and pop the clock stack, and
  882. * especially if I have an error in my options I may print to the terminal
  883. * and then flush it. Thus I need SOMETHING set up early to prevent any
  884. * possible frivolous disasters in that area.
  885. */
  886. base_time = read_clock();
  887. consolidated_time[0] = gc_time = 0.0;
  888. clock_stack = &consolidated_time[0];
  889. #ifdef WINDOW_SYSTEM
  890. /*
  891. * On some systems (Archimedes/RISCOS) the same executable
  892. * may run either under a window manager or using a command line.
  893. * I select which to use based on a command line option, which
  894. * I scan for VERY early since until I know what I am doing
  895. * I can not report errors etc etc
  896. */
  897. #ifdef RISCOS
  898. use_wimp = NO;
  899. for (i=1; i<argc; i++)
  900. { char *opt = argv[i];
  901. if (opt == NULL) continue;
  902. if (opt[0] == '-' && tolower(opt[1] == 'w'))
  903. { use_wimp = !use_wimp;
  904. break; /* Repeating "-w" flips the effect */
  905. }
  906. }
  907. #else
  908. use_wimp = YES; /* Other than on RISCOS always enable window system */
  909. #ifdef CWIN
  910. cwin_pause_at_end = 1;
  911. #endif
  912. #ifdef macintosh
  913. { extern int _w_font;
  914. extern void winit(void);
  915. extern int wgetargs(char ***);
  916. SetApplLimit(GetApplLimit() - 64000); /* Try to reserve plenty of stack space */
  917. _w_font = 4; winit();
  918. winitargs(&argc, &argv); /* THINK_C does not do arguments! */
  919. argc = wgetargs(&argv); /* Use dialog box for arguments */
  920. }
  921. #endif
  922. start_up_window_manager(use_wimp);
  923. #endif
  924. #ifdef SOCKETS
  925. sockets_ready = 0;
  926. socket_server = 0;
  927. #endif
  928. /*
  929. * Now that the window manager is active I can send output through
  930. * xx_printf() and get it on the screen neatly.
  931. * On the Archimedes start_up_window_manager() hangs up until somebody
  932. * hits the right icon with a mouse click, so most of the mallocs etc
  933. * will not happen until then.
  934. */
  935. #endif
  936. procedural_input = NULL;
  937. procedural_output = wout;
  938. standard_directory = find_image_directory(argc, argv);
  939. #ifdef OLD_THINK_C
  940. /*
  941. * Note amazingly well that on the Macintosh I identify the image directory
  942. * BEFORE I grab command-line options etc, since the Think C "ccommand"
  943. * function can reset the current directory, and I need access to same
  944. * (but not to the faked command line!) while establishing my image
  945. * location.
  946. */
  947. argc = ccommand(&argv);
  948. #endif
  949. restartp = YES;
  950. ignore_restart_fn = NO;
  951. spool_file = NULL;
  952. spool_file_name[0] = 0;
  953. output_directory = 0x80000000;
  954. number_of_input_files = 0;
  955. number_of_symbols_to_define = 0;
  956. number_of_fasl_paths = 0;
  957. gc_method = fasl_output_file = NO;
  958. initial_random_seed = seed2 = 0;
  959. init_flags = INIT_EXPANDABLE;
  960. return_code = EXIT_SUCCESS;
  961. segvtrap = YES;
  962. batch_flag = NO;
  963. { char *s = REGISTRATION_VERSION;
  964. #define hexval(c) ('0'<=c && c<='9' ? c - '0' : c - 'a' + 10)
  965. #define gx() (s+=2, hexval(s[-1]) + 16*hexval(s[-2]))
  966. unsigned char *p = registration_data;
  967. memset(registration_data, 0, sizeof(REGISTRATION_SIZE));
  968. while (*s != 0) *p++ = *s++;
  969. s = REG1;
  970. while (*s != 0) *p++ = gx();
  971. s = REG2;
  972. while (*s != 0) *p++ = gx();
  973. MD5_Init();
  974. MD5_Update((unsigned char *)errcode(err_registration), 32);
  975. }
  976. #ifdef MEMORY_TRACE
  977. car_counter = 0x7fffffff;
  978. car_low = 0;
  979. car_high = 0xffffffff;
  980. #endif
  981. #ifdef __WATCOMC__
  982. _control87(_EM_OVERFLOW | _EM_INVALID | _EM_DENORMAL |
  983. _EM_ZERODIVIDE | _EM_INEXACT | _EM_UNDERFLOW,
  984. _MCW_EM);
  985. #endif
  986. argc--;
  987. for (i=1; i<=argc; i++)
  988. { char *opt = argv[i];
  989. /*
  990. * The next line ought never to be activated, but I have sometimes seen
  991. * unwanted NULL args on the end of command lines so I filter them out
  992. * here as a matter of security.
  993. */
  994. if (opt == NULL || *opt == 0) continue;
  995. if (opt[0] == '-')
  996. { char *w;
  997. int c1 = opt[1], c2 = opt[2];
  998. if (isupper(c1)) c1 = tolower(c1);
  999. switch (c1)
  1000. {
  1001. /*
  1002. * -- <outfile> arranges that output is sent to the indicated file. It is
  1003. * intended to behave a little like "> outfile" as command-line output
  1004. * redirection, but is for usin in windowed environments (in particular
  1005. * Windows NT) where this would not work. I had intended to use "->" here,
  1006. * but then the ">" tends to get spotted as a command-line request for
  1007. * redirection, and I would not be using this if command-line redirection
  1008. * worked properly!
  1009. */
  1010. case '-':
  1011. if (c2 != 0) w = &opt[2];
  1012. else if (i != argc) w = argv[++i];
  1013. else break; /* Illegal at end of command-line */
  1014. { char filename[LONGEST_LEGAL_FILENAME];
  1015. FILE *f;
  1016. #ifdef WINDOW_SYSTEM
  1017. f = open_file(filename, w, strlen(w), "w", NULL);
  1018. if (f == NULL)
  1019. {
  1020. #ifdef CWIN
  1021. /*
  1022. * Under CWIN if there is a "--" among the arguments I will start off
  1023. * with the main window minimized. Thus if an error is detected at a
  1024. * stage that the transcript file is not properly opened I need to
  1025. * maximize the window so I can see the error!
  1026. */
  1027. cwin_maximize();
  1028. #endif
  1029. term_printf("Unable to write to \"%s\"\n", filename);
  1030. continue;
  1031. }
  1032. else
  1033. { term_printf("Output redirected to \"%s\"\n",
  1034. filename);
  1035. }
  1036. if (alternative_stdout != NULL)
  1037. fclose(alternative_stdout);
  1038. alternative_stdout = f;
  1039. #else
  1040. /*
  1041. * I use freopen() on stdout here to get my output sent elsewhere. Quite
  1042. * what sort of mess I am in if the freopen fails is hard to understand!
  1043. * Thus I write a message to stderr and exit promptly in case of trouble.
  1044. * I print a message explaining what I am doing BEFORE actually performing
  1045. * the redirection.
  1046. */
  1047. fprintf(stderr, "Output to be redirected to \"%s\"\n", w);
  1048. f = open_file(filename, w, strlen(w), "w", stdout);
  1049. if (f == NULL)
  1050. { fprintf(stderr, "Unable to write to \"%s\"\n",
  1051. filename);
  1052. #ifdef CWIN
  1053. #ifdef __cplusplus
  1054. throw EXIT_FAILURE;
  1055. #else
  1056. longjmp(my_exit_buffer, EXIT_FAILURE);
  1057. #endif
  1058. #else
  1059. exit(EXIT_FAILURE);
  1060. #endif
  1061. }
  1062. #endif
  1063. }
  1064. continue;
  1065. /*
  1066. * -b is a curious option, not intended for general or casual use. If given
  1067. * it causes the (batchp) function to return the opposite result from
  1068. * normal! Without "-b" (batchp) returns T either if at least one file
  1069. * was specified on the command line, or if the standard input is "not
  1070. * a tty" (under some operating systems this makes sense - for instance
  1071. * the standard input might not be a "tty" if it is provided via file
  1072. * redirection). Otherwise (ie primary input is directly from a keyboard)
  1073. * (batchp) returns nil. Sometimes this judgement about how "batch" the
  1074. * current run is will be wrong or unhelpful, so "-b" allows the user to
  1075. * coax the system into better behaviour.
  1076. */
  1077. case 'b':
  1078. batch_flag = YES;
  1079. continue;
  1080. /*
  1081. * The option "-C" just prints a dull and unimaginative copyright notice -
  1082. * having this option in there will tend to ensure that a copyright
  1083. * message is embedded in the object code somehow, while with luck nobody
  1084. * will be bothered too much by the fact that there is a stray option to get
  1085. * it displayed. Note that on some systems there is a proper character
  1086. * for the Copyright symbol... but there is little agreement about what
  1087. * that code is!
  1088. */
  1089. case 'c':
  1090. #ifdef CWIN
  1091. cwin_maximize();
  1092. #endif
  1093. #ifdef macintosh
  1094. term_printf("\nCopyright \231 Codemist Ltd, 1988-99\n");
  1095. #else
  1096. term_printf("\nCopyright (C) Codemist Ltd, 1988-99\n");
  1097. #endif
  1098. continue;
  1099. /*
  1100. * -D name=val defines a symbol at the start of a run
  1101. * I permit either
  1102. * -Dname=val
  1103. * or -D name=val
  1104. */
  1105. case 'd':
  1106. if (c2 != 0) w = &opt[2];
  1107. else if (i != argc) w = argv[++i];
  1108. else break; /* Illegal at end of command-line */
  1109. if (number_of_symbols_to_define < MAX_SYMBOLS_TO_DEFINE)
  1110. symbols_to_define[number_of_symbols_to_define] = w,
  1111. undefine_this_one[number_of_symbols_to_define++] = NO;
  1112. else
  1113. {
  1114. #ifdef CWIN
  1115. cwin_maximize();
  1116. #endif
  1117. term_printf("Too many \"-D\" requests: ignored\n");
  1118. }
  1119. continue;
  1120. case 'e':
  1121. /*
  1122. * -E
  1123. * This option is for an EXPERIMENT. It may do different things in different
  1124. * releases of CSL.
  1125. */
  1126. continue;
  1127. #ifdef SOCKETS
  1128. case 'f':
  1129. /*
  1130. * -F
  1131. * This is used with syntax -Fnnn or -F nnn (with nnn a number above
  1132. * 1000 but less than 65536) to cause the system to run not as a normal
  1133. * interactive application but as a server listening on the indicated port.
  1134. * The case -F- (which could of course be "-F -") indicates use of the
  1135. * default port for CSL, which I hereby declare to be 1206. This number may
  1136. * need to be changed later if I find it conflicts with some other common
  1137. * package or usage, but was selected in memory of the project number
  1138. * at one time allocated to the Archimedeans Computing Group.
  1139. * On some systems if I want to set up a server that can serve multiple
  1140. * clients I may need to re-invoke CSL afresh for each new client, and in
  1141. * such cases the internally generated tasks can be passed information
  1142. * from their parent task using -F followed by non-numeric information.
  1143. * Any user who attempts such usage will get "what they deserve".
  1144. */
  1145. if (c2 != 0) w = &opt[2];
  1146. else if (i != argc) w = argv[++i];
  1147. else break; /* Illegal at end of command-line */
  1148. port_number = default_csl_server_port;
  1149. remote_store = REMOTE_STORE;
  1150. max_users = MAX_USERS;
  1151. if (strcmp(w, "-") == 0)
  1152. port_number = default_csl_server_port;
  1153. else if (sscanf(w, "%d:%d:%d",
  1154. &port_number, &max_users, &remote_store) < 1 ||
  1155. port_number <= 1000 ||
  1156. port_number >= 65536 ||
  1157. max_users < 2 || max_users > 50 ||
  1158. remote_store < 4000 || remote_store > 20000)
  1159. {
  1160. #ifdef CWIN
  1161. cwin_maximize();
  1162. #endif
  1163. term_printf("\"%s\" is valid (want port:users:store\n", w);
  1164. continue;
  1165. }
  1166. store_size = (double)remote_store;
  1167. init_flags &= ~INIT_EXPANDABLE;
  1168. current_users = 0;
  1169. /*
  1170. * The code here is probably a bit painfully system-specific, and so one
  1171. * could argue that it should go in a separate file. However a LOT of the
  1172. * socket interface is the same regardless of the host, or a few simple
  1173. * macros can have made it so. So if SOCKETS has been defined I will
  1174. * suppose I can continue here on that basis. I do quite want to put the
  1175. * basic socket code in csl.c since it is concerned with system startup and
  1176. * the selection of sources and sinks for IO.
  1177. */
  1178. if (ensure_sockets_ready() == 0)
  1179. { SOCKET sock1, sock2;
  1180. struct sockaddr_in server_address, client_address;
  1181. int sin_size;
  1182. sock1 = socket(AF_INET, SOCK_STREAM, 0);
  1183. if (sock1 == SOCKET_ERROR)
  1184. {
  1185. #ifdef CWIN
  1186. cwin_maximize();
  1187. #endif
  1188. term_printf("Unable to create a socket\n");
  1189. continue;
  1190. }
  1191. server_address.sin_family = AF_INET;
  1192. server_address.sin_port = htons(port_number);
  1193. server_address.sin_addr.s_addr = INADDR_ANY;
  1194. memset((char *)&(server_address.sin_zero), 0, 8);
  1195. if (bind(sock1, (struct sockaddr *)&server_address,
  1196. sizeof(struct sockaddr)) == SOCKET_ERROR)
  1197. {
  1198. #ifdef CWIN
  1199. cwin_maximize();
  1200. #endif
  1201. term_printf("Unable to bind socket to port %d\n",
  1202. port_number);
  1203. closesocket(sock1);
  1204. continue;
  1205. }
  1206. if (listen(sock1, PERMITTED_BACKLOG) == SOCKET_ERROR)
  1207. {
  1208. #ifdef CWIN
  1209. cwin_maximize();
  1210. #endif
  1211. term_printf("Failure in listen() on port %d\n",
  1212. port_number);
  1213. closesocket(sock1);
  1214. continue;
  1215. }
  1216. for (;;)
  1217. { struct hostent *h;
  1218. time_t t0;
  1219. sin_size = sizeof(struct sockaddr_in);
  1220. sock2 = accept(sock1,
  1221. (struct sockaddr *)&client_address,
  1222. &sin_size);
  1223. if (sock2 == SOCKET_ERROR)
  1224. {
  1225. #ifdef CWIN
  1226. cwin_maximize();
  1227. #endif
  1228. term_printf("Trouble with accept()\n");
  1229. continue; /* NB local continue here */
  1230. }
  1231. t0 = time(NULL);
  1232. term_printf("%.24s from %s",
  1233. ctime(&t0),
  1234. inet_ntoa(client_address.sin_addr));
  1235. h = gethostbyaddr((char *)&client_address.sin_addr,
  1236. sizeof(client_address.sin_addr), AF_INET);
  1237. if (h != NULL)
  1238. term_printf(" = %s", h->h_name);
  1239. else term_printf(" [unknown host]");
  1240. /*
  1241. * Here I have a bit of a mess. Under Unix I can do a fork() so that the
  1242. * requests that are coming in are handled by a separate process. The
  1243. * code is pretty easy. However with Windows I can only create a fresh process
  1244. * by re-launching CSL from the file it was originally fetched from. I
  1245. * will try to do that in a while, but for now I will leave the
  1246. * Windows version of this code only able to handle a single client
  1247. * session.
  1248. */
  1249. #ifdef ms_windows
  1250. closesocket(sock1);
  1251. socket_server = sock2;
  1252. cpu_timeout = clock() + CLOCKS_PER_SEC*MAX_CPU_TIME;
  1253. elapsed_timeout = time(NULL) + 60*MAX_ELAPSED_TIME;
  1254. procedural_output = char_to_socket;
  1255. term_printf("Welcome to the Codemist server\n");
  1256. ensure_screen();
  1257. break;
  1258. #else /* ms_windows */
  1259. while (waitpid(-1, NULL, WNOHANG) > 0) current_users--;
  1260. if (current_users >= max_users)
  1261. { term_printf(" refused\n");
  1262. socket_server = sock2;
  1263. ensure_screen();
  1264. procedural_output = char_to_socket;
  1265. term_printf(
  1266. "\nSorry, there are already %d people using this service\n",
  1267. current_users);
  1268. term_printf("Please try again later.\n");
  1269. ensure_screen();
  1270. procedural_output = NULL;
  1271. closesocket(socket_server);
  1272. socket_server = 0;
  1273. continue;
  1274. }
  1275. else term_printf(" %d of %d\n",
  1276. ++current_users, max_users);
  1277. ensure_screen();
  1278. if (!fork())
  1279. { /* Child process here */
  1280. closesocket(sock1);
  1281. fcntl(sock2, F_SETFL, O_NONBLOCK);
  1282. socket_server = sock2;
  1283. cpu_timeout = clock() + CLOCKS_PER_SEC*MAX_CPU_TIME;
  1284. elapsed_timeout = time(NULL) + 60*MAX_ELAPSED_TIME;
  1285. ensure_screen();
  1286. procedural_output = char_to_socket;
  1287. term_printf("Welcome, you are user %d of %d\n",
  1288. current_users, max_users);
  1289. term_printf(
  1290. "You have been allocated %d seconds CPU time"
  1291. " and %d minutes elapsed time\n",
  1292. MAX_CPU_TIME, MAX_ELAPSED_TIME);
  1293. break;
  1294. }
  1295. else
  1296. { closesocket(sock2);
  1297. if (current_users < 0) current_users = 0;
  1298. continue;
  1299. /*
  1300. * This loops serving as many clients as happen to come along. Having said
  1301. * "csl -fnnn" it will be necessary (in due course) to kill the daemon
  1302. * by interrupting it with a ^C or some such. When the master process is
  1303. * terminated in that way any clients that remain active may continue to
  1304. * hang around until they have finished in the usual way.
  1305. */
  1306. }
  1307. #endif /* ms_windows */
  1308. }
  1309. }
  1310. /*
  1311. * The "continue" here gets executed when I have been contacted by some
  1312. * client and have an active socket open. It parses the rest of the
  1313. * command line and then completes the process of getting CSL running.
  1314. */
  1315. continue;
  1316. #endif
  1317. /*
  1318. * -G
  1319. * is a debugging option - it sets !*backtrace to true, which applications
  1320. * may inspect when they want to do errorsets etc.
  1321. */
  1322. case 'g':
  1323. if (number_of_symbols_to_define < MAX_SYMBOLS_TO_DEFINE)
  1324. symbols_to_define[number_of_symbols_to_define] =
  1325. "*backtrace",
  1326. undefine_this_one[number_of_symbols_to_define++] = NO;
  1327. else
  1328. {
  1329. #ifdef CWIN
  1330. cwin_maximize();
  1331. #endif
  1332. term_printf("Too many requests: \"-G\" ignored\n");
  1333. }
  1334. continue;
  1335. /*
  1336. * -I is used to specify an image file to be used when CSL starts up.
  1337. * The case -I- indicated the "standard" file associated with this
  1338. * executable binary. Several images can be given.
  1339. */
  1340. case 'i':
  1341. if (c2 != 0) w = &opt[2];
  1342. else if (i != argc) w = argv[++i];
  1343. else break; /* Illegal at end of command-line */
  1344. if (w[0] == '-' && w[1] == 0) w = standard_directory;
  1345. if (number_of_fasl_paths < MAX_FASL_PATHS-1)
  1346. fasl_paths[number_of_fasl_paths++] = w;
  1347. else
  1348. {
  1349. #ifdef CWIN
  1350. cwin_maximize();
  1351. #endif
  1352. term_printf("Too many \"-I/-O\" requests: ignored\n");
  1353. }
  1354. continue;
  1355. /*
  1356. * -K nnn sets the size of heap to be used. If it is given then that much
  1357. * memory will be allocated and the heap will never expand. Without this
  1358. * option a default amount is used, and (on many machines) it will grow
  1359. * if space seems tight.
  1360. * The extended version of this option is "-K nnn/ss" and then ss is the
  1361. * number of "CSL pages" to be allocated to the Lisp stack. The default
  1362. * value (which is 1) should suffice for almost all users, and it should
  1363. * be noted that the C stack is separate from and independent of this one and
  1364. * it too could overflow.
  1365. */
  1366. case 'k':
  1367. if (c2 != 0) w = &opt[2];
  1368. else if (i != argc) w = argv[++i];
  1369. else break; /* Illegal at end of command-line */
  1370. { char buffer[16];
  1371. int i = 0;
  1372. while (*w != '/' && *w != 0 & i<sizeof(buffer)-1)
  1373. buffer[i++] = *w++;
  1374. buffer[i] = 0;
  1375. /*
  1376. * store size gets set here - 0.0 is left if either that is specified
  1377. * explictly or if no -K option is given.
  1378. */
  1379. store_size = atof(buffer);
  1380. if (store_size == 0.0) init_flags |= INIT_EXPANDABLE;
  1381. else init_flags &= ~INIT_EXPANDABLE;
  1382. if (*w == '/')
  1383. { stack_segsize = atoi(w+1);
  1384. if (stack_segsize < 1 || stack_segsize > 10)
  1385. stack_segsize = 1;
  1386. }
  1387. }
  1388. continue;
  1389. /*
  1390. * -L <logfile> arranges that a transcript of the standard output is
  1391. * sent to the given file, just as if (spool '<logfile>) had been executed
  1392. * at the start of the run.
  1393. */
  1394. case 'l':
  1395. if (c2 != 0) w = &opt[2];
  1396. else if (i != argc) w = argv[++i];
  1397. else break; /* Illegal at end of command-line */
  1398. { char filename[LONGEST_LEGAL_FILENAME];
  1399. spool_file = open_file(filename, w,
  1400. strlen(w), "w", NULL);
  1401. if (spool_file == NULL)
  1402. {
  1403. #ifdef CWIN
  1404. cwin_maximize();
  1405. #endif
  1406. term_printf("Unable to write to \"%s\"\n", filename);
  1407. }
  1408. else
  1409. { time_t t0 = time(NULL);
  1410. strncpy(spool_file_name, filename, 32);
  1411. spool_file_name[31] = 0;
  1412. #ifdef COMMON
  1413. fprintf(spool_file,
  1414. "Starts dribbling to %s (%.24s).\n",
  1415. spool_file_name, ctime(&t0));
  1416. #else
  1417. fprintf(spool_file,
  1418. "+++ Transcript to %s started at %.24s +++\n",
  1419. spool_file_name, ctime(&t0));
  1420. #endif
  1421. }
  1422. }
  1423. continue;
  1424. #ifdef MEMORY_TRACE
  1425. /*
  1426. * If MEMORY_TRACE is set up then I can cause an exception by providing
  1427. * an option -M n:l:h
  1428. * This interrupts after n memory records when a reference in the (inclusive)
  1429. * range l..h is next made.
  1430. */
  1431. case 'm':
  1432. if (c2 != 0) w = &opt[2];
  1433. else if (i != argc) w = argv[++i];
  1434. else break; /* Illegal at end of command-line */
  1435. switch(sscanf(w, "%ld:%lu:%lu",
  1436. &car_counter, &car_low, &car_high))
  1437. {
  1438. case 0: car_counter = 0x7fffffff;
  1439. case 1: car_low = 0;
  1440. case 2: car_high = 0xffffffff;
  1441. default:break;
  1442. }
  1443. continue;
  1444. #endif
  1445. /*
  1446. * -N tells CSL that even if the image being loaded contains a restart-
  1447. * function this should be ignored, and Lisp should run the default
  1448. * read-eval-print loop. The only expected use for this is when an image
  1449. * has been created but it is seriously broken, so the way it would
  1450. * usually restart would crash - then "-N" may allow a suitable expert to
  1451. * test and diagnose the trouble at the Lisp level. Ordinary users are
  1452. * NOT expected to want to know about this!
  1453. */
  1454. case 'n': /* Ignore restart function (-N) */
  1455. ignore_restart_fn = YES;
  1456. continue;
  1457. /*
  1458. * -O <file> specifies an image file for output (via FASLOUT or PRESERVE).
  1459. */
  1460. case 'o':
  1461. if (c2 != 0) w = &opt[2];
  1462. else if (i != argc) w = argv[++i];
  1463. else break; /* Illegal at end of command-line */
  1464. if (w[0] == '-' && w[1] == 0) w = standard_directory;
  1465. if (number_of_fasl_paths < MAX_FASL_PATHS-1)
  1466. { output_directory = number_of_fasl_paths;
  1467. fasl_paths[number_of_fasl_paths++] = w;
  1468. }
  1469. else
  1470. {
  1471. #ifdef CWIN
  1472. cwin_maximize();
  1473. #endif
  1474. term_printf("Too many \"-I/-O\" requests: ignored\n");
  1475. }
  1476. continue;
  1477. /*
  1478. * -P is reserved for profile options.
  1479. */
  1480. case 'p':
  1481. /*
  1482. * Please implement something for your favourite system here... what I would
  1483. * like would be a call to monitor() or some such...
  1484. */
  1485. #ifdef CWIN
  1486. cwin_maximize();
  1487. #endif
  1488. term_printf("Unimplemented option \"-%c\"\n", c1);
  1489. continue;
  1490. /*
  1491. * -Q selects "quiet" mode. See -V for the converse.
  1492. */
  1493. case 'q':
  1494. if (number_of_symbols_to_define < MAX_SYMBOLS_TO_DEFINE)
  1495. /*
  1496. * symbols_to_define[number_of_symbols_to_define] =
  1497. * "*echo=nil",
  1498. * undefine_this_one[number_of_symbols_to_define++] = NO,
  1499. */
  1500. init_flags &= ~INIT_VERBOSE,
  1501. init_flags |= INIT_QUIET;
  1502. else
  1503. {
  1504. #ifdef CWIN
  1505. cwin_maximize();
  1506. #endif
  1507. term_printf("Too many requests: \"-Q\" ignored\n");
  1508. }
  1509. continue;
  1510. /*
  1511. * -R nnn sets the initial random seed, for reproducible runs. -R 0
  1512. * (the default) sets the initial seed based on the time of day etc.
  1513. * The version -R nnn,mmm makes it possible to pass 64-bits of seed info.
  1514. */
  1515. case 'r':
  1516. if (c2 != 0) w = &opt[2];
  1517. else if (i != argc) w = argv[++i];
  1518. else break; /* Illegal at end of command-line */
  1519. if (sscanf(w, "%ld,%ld", &initial_random_seed, &seed2) != 2)
  1520. { initial_random_seed = seed2 = 0;
  1521. sscanf(w, "%ld", &initial_random_seed);
  1522. }
  1523. continue;
  1524. /*
  1525. * -S sets the variable !*plap, which causes the compiler to list the
  1526. * bytecodes that it generates.
  1527. */
  1528. case 's':
  1529. if (number_of_symbols_to_define < MAX_SYMBOLS_TO_DEFINE)
  1530. symbols_to_define[number_of_symbols_to_define] =
  1531. "*plap",
  1532. undefine_this_one[number_of_symbols_to_define++] = NO;
  1533. else
  1534. {
  1535. #ifdef CWIN
  1536. cwin_maximize();
  1537. #endif
  1538. term_printf("Too many requests: \"-S\" ignored\n");
  1539. }
  1540. continue;
  1541. /*
  1542. * -T name reports the time-stamp on the named module, and then
  1543. * exits. This is for use in perl scripts and the like, and is
  1544. * needed because the stamps on modules within an image or
  1545. * library file are not otherwise instantly available.
  1546. *
  1547. * Note that especially on windowed systems it may be
  1548. * necessary to use this with "-- filename" since the information
  1549. * generated here goes to the default output unit, which in
  1550. * some cases is just the screen.
  1551. */
  1552. case 't':
  1553. if (c2 != 0) w = &opt[2];
  1554. else if (i != argc) w = argv[++i];
  1555. else break; /* Illegal at end of command-line */
  1556. module_enquiry = w;
  1557. continue;
  1558. /*
  1559. * -U name undefines the symbol <name> at the start of the run
  1560. */
  1561. case 'u':
  1562. if (c2 != 0) w = &opt[2];
  1563. else if (i != argc) w = argv[++i];
  1564. else break; /* Illegal at end of command-line */
  1565. if (number_of_symbols_to_define < MAX_SYMBOLS_TO_DEFINE)
  1566. symbols_to_define[number_of_symbols_to_define] = w,
  1567. undefine_this_one[number_of_symbols_to_define++] = YES;
  1568. else
  1569. {
  1570. #ifdef CWIN
  1571. cwin_maximize();
  1572. #endif
  1573. term_printf("Too many \"-U\" requests: ignored\n");
  1574. }
  1575. continue;
  1576. /*
  1577. * -V selects "verbose" options at the start of the run
  1578. */
  1579. case 'v':
  1580. if (number_of_symbols_to_define < MAX_SYMBOLS_TO_DEFINE)
  1581. /*
  1582. * symbols_to_define[number_of_symbols_to_define] =
  1583. * "*echo",
  1584. * undefine_this_one[number_of_symbols_to_define++] = NO,
  1585. */
  1586. init_flags &= ~INIT_QUIET,
  1587. init_flags |= INIT_VERBOSE;
  1588. else
  1589. {
  1590. #ifdef CWIN
  1591. cwin_maximize();
  1592. #endif
  1593. term_printf("Too many requests: \"-V\" ignored\n");
  1594. }
  1595. continue;
  1596. #ifdef WINDOW_SYSTEM
  1597. /*
  1598. * For the Archimedes I insist on a command-line option "-w" to enable
  1599. * use of the windowed version of the code. For other window systems I
  1600. * reserve the option for fine control over window behaviour.
  1601. */
  1602. case 'w':
  1603. /*
  1604. * I need to detect and process this flag especially early, and so by the time
  1605. * I get to regular command decoding there is nothing to be done.
  1606. */
  1607. continue;
  1608. #endif
  1609. /*
  1610. * -x is an "undocumented" option intended for use only by system
  1611. * support experts - it disables trapping if segment violations by
  1612. * errorset and so makes it easier to track down low level disasters -
  1613. * maybe! Only those who have access to the source code can make
  1614. * good use of the -X option, so it is only described here!
  1615. */
  1616. case 'x':
  1617. segvtrap = NO;
  1618. continue;
  1619. /*
  1620. * -Y sets the variable !*hankaku , which causes the lisp reader convert
  1621. * a Zenkaku code to Hankaku one when read. I leave this option decoded
  1622. * on the command line even if the Kanji support code is not otherwise
  1623. * compiled into CSL just so I can reduce conditional compilation.
  1624. */
  1625. case 'y':
  1626. if (number_of_symbols_to_define < MAX_SYMBOLS_TO_DEFINE)
  1627. symbols_to_define[number_of_symbols_to_define] =
  1628. "*hankaku",
  1629. undefine_this_one[number_of_symbols_to_define++] = NO;
  1630. else
  1631. term_printf("Too many requests: \"-Y\" ignored\n");
  1632. continue;
  1633. /*
  1634. * -Z tells CSL that it should not load an initial heap image, but should
  1635. * run in "cold start" mode. This is only intended to be useful for
  1636. * system builders.
  1637. */
  1638. case 'z': /* Cold start option -z */
  1639. restartp = NO;
  1640. continue;
  1641. default:
  1642. #ifdef CWIN
  1643. cwin_maximize();
  1644. #endif
  1645. term_printf("Unrecognized option \"-%c\"\n", c1);
  1646. continue;
  1647. }
  1648. /*
  1649. * I do a "break" out of the switch() block if a key occurs at the end
  1650. * of the command line in an invalid manner.
  1651. */
  1652. #ifdef CWIN
  1653. cwin_maximize();
  1654. #endif
  1655. term_printf("Option \"-%c\" needs an argument: ignored\n", c1);
  1656. break;
  1657. }
  1658. else files_to_read[number_of_input_files++] = opt;
  1659. }
  1660. if (number_of_fasl_paths == 0)
  1661. { char *p = standard_directory, *p1;
  1662. char cur[LONGEST_LEGAL_FILENAME];
  1663. /*
  1664. * If the user does not specify any image files then the behaviour
  1665. * defaults as follows:
  1666. * Suppose that the current executable is xxx/yyy/zzz then the
  1667. * system behaves as if the user had written
  1668. * zzz -o zzz.img -i xxx/yyy/zzz.img
  1669. * however if the executable seemed to be in the current directory
  1670. * already this is reduced to just
  1671. * zzz -o zzz.img
  1672. * so that I do not have two different handles on the same image file
  1673. * (with the potential muddle that that could result in).
  1674. *
  1675. * NOTE: this used very generally mean that you ended up with an empty image
  1676. * file (eg csl.img or r37.img) in whatever directory you run this
  1677. * code from. This could be avoided by running it as
  1678. * xxx -i-
  1679. * that explicitly sets up the normal image file as the one to use with
  1680. * no extras. However these days I try to arrange that an output image file
  1681. * only ever gets created if somebody calls FASLOUT or PRESERVE, so what
  1682. * I describe here will usually not cause confusion....
  1683. */
  1684. if (standard_directory[0] == '.' &&
  1685. (standard_directory[1] == '/' ||
  1686. standard_directory[1] == '\\')) strcpy(cur, standard_directory);
  1687. else get_current_directory(cur, sizeof(cur));
  1688. p += strlen(p);
  1689. while (p != standard_directory &&
  1690. *--p != '/' &&
  1691. *p != '\\') /* nothing */;
  1692. if (strncmp(standard_directory, cur, p-standard_directory) != 0)
  1693. p1 = (char *)malloc(strlen(p));
  1694. else p1 = NULL;
  1695. if (p == standard_directory || p1 == NULL)
  1696. { fasl_paths[0] = standard_directory;
  1697. /*
  1698. * If output_directory has the 0x40000000 bit set then the directory
  1699. * involved is one that should be opened now if it exists, but if
  1700. * it does not its creation should be deferred for as long as possible.
  1701. */
  1702. output_directory = 0x40000000 + 0;
  1703. number_of_fasl_paths = 1;
  1704. if (p1 != NULL) free(p1);
  1705. }
  1706. else
  1707. { strcpy(p1, p+1);
  1708. fasl_paths[0] = p1;
  1709. fasl_paths[1] = standard_directory;
  1710. output_directory = 0x40000000 + 0;
  1711. number_of_fasl_paths = 2;
  1712. }
  1713. }
  1714. Iinit();
  1715. #ifdef WINDOW_SYSTEM
  1716. #ifdef RISCOS
  1717. /*
  1718. * Under RISCOS I must delat starting up the window manager until about
  1719. * here for two reasons. Firstly a command-line option might have been
  1720. * used to decide whether or not it was wanted after all. Secondly a
  1721. * side effect of find_image_directory() under RISCOS is the discovery
  1722. * of the name that this application is being run as, and I want that to
  1723. * go as the title in my window.
  1724. */
  1725. start_up_window_manager(use_wimp);
  1726. #endif
  1727. #endif
  1728. if (module_enquiry != NULL)
  1729. { char datestamp[32], fullname[LONGEST_LEGAL_FILENAME];
  1730. int32 size;
  1731. int i;
  1732. Lisp_Object nil;
  1733. /*
  1734. * Imodulep expects input_libraries to be set up. So I will fudge the
  1735. * creation of something that looks sufficiently like a list to pass muster
  1736. * here despite the full system not being loaded. I use references to the
  1737. * nil-segment and cons().
  1738. */
  1739. nilsegment = (Lisp_Object *)my_malloc(NIL_SEGMENT_SIZE);
  1740. #ifdef COMMON
  1741. nil = doubleword_align_up(nilsegment) + TAG_CONS + 8;
  1742. #else
  1743. nil = doubleword_align_up(nilsegment) + TAG_SYMBOL;
  1744. #endif
  1745. C_nil = nil;
  1746. pages_count = heap_pages_count = vheap_pages_count =
  1747. bps_pages_count = native_pages_count = 0;
  1748. stacksegment = (Lisp_Object *)my_malloc(CSL_PAGE_SIZE);
  1749. /*
  1750. * I am lazy about protection against malloc failure here.
  1751. */
  1752. heaplimit = doubleword_align_up(stacksegment);
  1753. fringe = heaplimit + CSL_PAGE_SIZE - 16;
  1754. input_libraries = heaplimit + 16 + TAG_SYMBOL;
  1755. heaplimit += 64;
  1756. /*
  1757. * I have now fudged up enough simulation of a Lisp heap that maybe I can
  1758. * build the library search-list.
  1759. */
  1760. qheader(input_libraries) |= SYM_SPECIAL_FORM;
  1761. qvalue(input_libraries) = nil;
  1762. for (i=number_of_fasl_paths-1; i>=0; i--)
  1763. qvalue(input_libraries) = cons(SPID_LIBRARY + (((int32)i)<<20),
  1764. qvalue(input_libraries));
  1765. if (Imodulep(module_enquiry, strlen(module_enquiry),
  1766. datestamp, &size, fullname))
  1767. { strcpy(datestamp, "unknown");
  1768. size = 0;
  1769. strcpy(fullname, module_enquiry);
  1770. }
  1771. term_printf("%.24s size=%ld file=%s\n",
  1772. datestamp, (long)size, fullname);
  1773. init_flags &= ~INIT_VERBOSE;
  1774. #ifdef CWIN
  1775. cwin_pause_at_end = 0;
  1776. #endif
  1777. }
  1778. else
  1779. { base_time = read_clock();
  1780. consolidated_time[0] = gc_time = 0.0;
  1781. clock_stack = &consolidated_time[0];
  1782. push_clock();
  1783. if (init_flags & INIT_VERBOSE)
  1784. {
  1785. #ifndef WINDOW_SYSTEM
  1786. /*
  1787. * If I do NOT have a window system I will print a newline here so that I
  1788. * can be very certain that my banner appears at the start of a line.
  1789. * With a window system I should have a brand-new frash window for output
  1790. * and the newline would intrude as an initial blank line.
  1791. */
  1792. term_printf("\n");
  1793. #endif
  1794. #ifndef COMMON
  1795. term_printf("Codemist Standard Lisp %s for %s: %s\n",
  1796. VERSION, IMPNAME, __DATE__);
  1797. #else
  1798. term_printf("Codemist Common Lisp %s for %s: %s\n",
  1799. VERSION, IMPNAME, __DATE__);
  1800. #endif
  1801. }
  1802. #ifdef MEMORY_TRACE
  1803. if (car_counter != 0x7fffffff)
  1804. term_printf("Stop after %ld %lu..%lu\n",
  1805. car_counter, car_low, car_high);
  1806. #endif
  1807. #ifdef WINDOW_SYSTEM
  1808. ensure_screen();
  1809. /* If the user hits the close button here I may be in trouble */
  1810. #endif
  1811. /*
  1812. * Here (potentially) I could set qualifier information into native_code_tag
  1813. * based on run-time checks. This might allow me to discriminate between
  1814. * systems that are exactly the same as far as the CSL-controlled bits of C
  1815. * code are concerned but have extra differences that a bit of system-specific
  1816. * code here can detect. I will reserve the bits 0xe0 (3 bits) for such
  1817. * information. Note that a system that does not support hard code MUST leave
  1818. * hard_code_tag set to zero.
  1819. */
  1820. native_code_tag = NATIVE_CODE_TAG;
  1821. /*
  1822. * Now dynamic code detects the floating point representation that is in use.
  1823. * I thougt/hoped that doing it this way would be safer than relying on having
  1824. * pre-defined symbols that tracked the machine architecture.
  1825. */
  1826. { union fpch { double d; unsigned char c[8]; } d;
  1827. /*
  1828. * The following looks at the floating point representation of the
  1829. * number 1/7 (in double precision) and picks out two bytes from
  1830. * the middle of the first word - where I hope that rounding issues
  1831. * will be remote. Investigation shows that these two bytes can be
  1832. * used to discriminate among at least a worthwhile range of
  1833. * representations, and I will exploit this to help me re-load
  1834. * heap-images in a way that allows images to be portable across
  1835. * different architectures.
  1836. */
  1837. d.d = 1.0/7.0;
  1838. switch ((d.c[1] << 8) | d.c[2])
  1839. {
  1840. case 0x49c2: current_fp_rep = FP_ARM; break;
  1841. case 0x2492: current_fp_rep = FP_370; break;
  1842. case 0x2449: current_fp_rep = FP_MIPS; break;
  1843. case 0x3f24: current_fp_rep = FP_VAX; break;
  1844. case 0xc249: current_fp_rep = FP_88K; break;
  1845. /*
  1846. * The next line is probably not very good under a window manager, but
  1847. * it is a case that ought never to arise, so I will not bother.
  1848. */
  1849. default: term_printf("Unknown floating point format\n");
  1850. my_exit(EXIT_FAILURE);
  1851. }
  1852. }
  1853. /*
  1854. * Up until the time I call setup() I may only use term_printf for
  1855. * output, because the other relevant streams will not have been set up.
  1856. */
  1857. setup(restartp ? 3 : 2, store_size);
  1858. #ifndef COMMON
  1859. #ifdef CWIN
  1860. /*
  1861. * Note that it may make sense to enable this for windowed versions other
  1862. * than CWIN-based ones...
  1863. */
  1864. cwin_menus(loadable_packages, switches);
  1865. #endif
  1866. #endif
  1867. /*
  1868. * Now that setup is complete (and I have done any authorisation I want to)
  1869. * I will seed the random number generator as requested by the user. The
  1870. * default will be to put it in an unpredictable (well hard to predict!)
  1871. * state
  1872. */
  1873. Csrand((unsigned32)initial_random_seed, (unsigned32)seed2);
  1874. gc_time += pop_clock();
  1875. interrupt_pending = already_in_gc = NO;
  1876. polltick_pending = tick_pending = tick_on_gc_exit = NO;
  1877. sigint_must_longjmp = NO;
  1878. signal(SIGINT, sigint_handler);
  1879. #ifdef TICK_STREAM
  1880. /*
  1881. * Now I have enough in place that I am prepared to accept regular clock-
  1882. * tick events.
  1883. */
  1884. add_ticker();
  1885. /*
  1886. * atexit(remove_ticker); Maybe "atexit() is itself dangerous!
  1887. * I should try (quite hard) to disable the
  1888. * ticker at some earlier safer stage.
  1889. */
  1890. #endif
  1891. ensure_screen();
  1892. procedural_output = NULL;
  1893. #ifdef CWIN
  1894. /*
  1895. * OK, if I get this far I will suppose that any messages that report utter
  1896. * disasters will have reached the user, so I can allow CWIN to terminate
  1897. * rather more promptly.
  1898. */
  1899. cwin_pause_at_end = 0;
  1900. #endif
  1901. }
  1902. }
  1903. #ifdef SOCKETS
  1904. #define SOCKET_BUFFER_SIZE 1024
  1905. #define CH_PROMPT 0x9a
  1906. #define CH_ENDPROMPT 0x9c
  1907. static char socket_in[SOCKET_BUFFER_SIZE], socket_out[SOCKET_BUFFER_SIZE];
  1908. static int socket_in_p = 0, socket_in_n = 0,
  1909. socket_out_p = 0, socket_prev = '\n';
  1910. static int char_from_socket(void)
  1911. {
  1912. int c;
  1913. clock_t c0;
  1914. time_t t0;
  1915. if (socket_server == 0)
  1916. { socket_prev = ' ';
  1917. return EOF;
  1918. }
  1919. /*
  1920. * I generate a prompt whenever I am about to read the character that
  1921. * follows a newline. The prompt is issued surrounded by control
  1922. * characters 0x9a and 0x9c. That curious arrangement is inherited from
  1923. * internal behaviour in my Windows interface code and could be altered
  1924. * if something truly better could be invented.
  1925. */
  1926. if (socket_prev == '\n')
  1927. { term_printf("%c%s%c", CH_PROMPT, prompt_string, CH_ENDPROMPT);
  1928. ensure_screen();
  1929. }
  1930. if (socket_in_n == 0)
  1931. { for (;;)
  1932. { socket_in_n = recv(socket_server, socket_in, SOCKET_BUFFER_SIZE, 0);
  1933. c0 = clock();
  1934. t0 = time(NULL);
  1935. if (c0 > cpu_timeout || t0 > elapsed_timeout)
  1936. { cpu_timeout = c0 + 20;
  1937. elapsed_timeout = t0 + 20;
  1938. term_printf(
  1939. "\nSorry: timeout on this session. Closing down.\n");
  1940. socket_prev = ' ';
  1941. return EOF;
  1942. }
  1943. if (socket_in_n <= 0)
  1944. #ifndef EWOULDBLOCK
  1945. # define EWOULDBLOCK WSAEWOULDBLOCK
  1946. #endif
  1947. { if (errno == EWOULDBLOCK)
  1948. {
  1949. #ifdef _MSC_VER
  1950. Sleep(300); /* Arg in milliseconds here */
  1951. #else
  1952. sleep(1); /* Delay 1 second before re-polling */
  1953. #endif
  1954. continue;
  1955. }
  1956. closesocket(socket_server);
  1957. socket_server = 0;
  1958. socket_prev = ' ';
  1959. return EOF;
  1960. }
  1961. else break;
  1962. }
  1963. socket_in_p = 0;
  1964. }
  1965. c = socket_in[socket_in_p++];
  1966. if (c == 0x0a || c == 0x0d) c = '\n';
  1967. socket_in_n--;
  1968. socket_prev = c;
  1969. return c & 0xff;
  1970. }
  1971. static int char_to_socket(int c)
  1972. {
  1973. if (socket_server == 0) return 1;
  1974. socket_out[socket_out_p++] = c;
  1975. if (c == '\n' || socket_out_p == SOCKET_BUFFER_SIZE)
  1976. { if (send(socket_server, socket_out, socket_out_p, 0) < 0)
  1977. { closesocket(socket_server);
  1978. socket_server = 0;
  1979. return 1;
  1980. }
  1981. socket_out_p = 0;
  1982. }
  1983. return 0;
  1984. }
  1985. void flush_socket()
  1986. {
  1987. if (socket_server == 0) return;
  1988. if (send(socket_server, socket_out, socket_out_p, 0) < 0)
  1989. { closesocket(socket_server);
  1990. socket_server = 0;
  1991. }
  1992. socket_out_p = 0;
  1993. }
  1994. #endif
  1995. void cslaction()
  1996. /*
  1997. * This is the "standard" route into CSL activity - it uses file-names
  1998. * from the decoded command-line as files to be read and processed
  1999. * unless the system was launched with the flag that says it ought to try
  2000. * to provide a network service on some socket.
  2001. */
  2002. {
  2003. #ifdef __cplusplus
  2004. errorset_msg = NULL;
  2005. try
  2006. #else
  2007. jmp_buf this_level;
  2008. errorset_buffer = &this_level;
  2009. errorset_msg = NULL;
  2010. if (!setjmp(this_level))
  2011. #endif
  2012. { signal(SIGFPE, low_level_signal_handler);
  2013. #ifdef __WATCOMC__
  2014. _control87(_EM_OVERFLOW | _EM_INVALID | _EM_DENORMAL |
  2015. _EM_ZERODIVIDE | _EM_INEXACT | _EM_UNDERFLOW,
  2016. _MCW_EM);
  2017. #endif
  2018. if (segvtrap) signal(SIGSEGV, low_level_signal_handler);
  2019. #ifdef SIGBUS
  2020. if (segvtrap) signal(SIGBUS, low_level_signal_handler);
  2021. #endif
  2022. #ifdef SIGILL
  2023. if (segvtrap) signal(SIGILL, low_level_signal_handler);
  2024. #endif
  2025. non_terminal_input = NULL;
  2026. #ifdef SOCKETS
  2027. if (socket_server)
  2028. { ensure_screen();
  2029. procedural_input = char_from_socket;
  2030. procedural_output = char_to_socket;
  2031. lisp_main();
  2032. ensure_screen();
  2033. procedural_input = NULL;
  2034. procedural_output = NULL;
  2035. }
  2036. else
  2037. #endif
  2038. if (number_of_input_files == 0) lisp_main();
  2039. else
  2040. { int i;
  2041. for (i=0; i<number_of_input_files; i++)
  2042. { char filename[LONGEST_LEGAL_FILENAME];
  2043. FILE *f = open_file(filename, files_to_read[i],
  2044. strlen(files_to_read[i]), "r", NULL);
  2045. if (f == NULL)
  2046. err_printf("\n+++ Could not read file \"%s\"\n",
  2047. files_to_read[i]);
  2048. else
  2049. { nil_as_base
  2050. if (init_flags & INIT_VERBOSE)
  2051. term_printf("\n+++ About to read file \"%s\"\n",
  2052. files_to_read[i]);
  2053. non_terminal_input = f;
  2054. lisp_main();
  2055. fclose(f);
  2056. }
  2057. }
  2058. }
  2059. }
  2060. #ifdef __cplusplus
  2061. catch (char *)
  2062. #else
  2063. else
  2064. #endif
  2065. { if (errorset_msg != NULL)
  2066. { term_printf("\n%s detected\n", errorset_msg);
  2067. errorset_msg = NULL;
  2068. }
  2069. return;
  2070. }
  2071. }
  2072. int cslfinish(character_writer *w)
  2073. {
  2074. procedural_output = w;
  2075. if (Ifinished())
  2076. term_printf("\n+++ Errors on checkpoint-image file\n");
  2077. #ifdef TRACED_EQUAL
  2078. dump_equals();
  2079. #endif
  2080. /*
  2081. * clock_t is an arithmetic type but I do not know what sort - so I
  2082. * widen to double to do arithmetic on it. Actually what I MUST do is
  2083. * to compute a time difference in the type clock_t and hope I never
  2084. * get a difference that that overflows. The worst case I know of overflows
  2085. * after 35 minutes.
  2086. */
  2087. if (init_flags & INIT_VERBOSE)
  2088. { long int t = (long int)(100.0 * (consolidated_time[0] +
  2089. (double)(read_clock() - base_time)/
  2090. (double)CLOCKS_PER_SEC));
  2091. long int gct = (long int)(100.0 * gc_time);
  2092. term_printf("\n\nEnd of Lisp run after %ld.%.2ld+%ld.%.2ld seconds\n",
  2093. t/100, t%100, gct/100, gct%100);
  2094. }
  2095. #ifdef TICK_STREAM
  2096. #ifdef SOFTWARE_TICKS
  2097. #ifdef DEBUG_SOFTWARE_TICKS
  2098. term_printf("%d ticks processed (%d)\n",
  2099. number_of_ticks, SOFTWARE_TICKS);
  2100. #endif
  2101. #endif
  2102. remove_ticker();
  2103. #endif
  2104. drop_heap_segments();
  2105. if (spool_file != NULL)
  2106. {
  2107. #ifdef COMMON
  2108. fprintf(spool_file, "\nFinished dribbling to %s.\n", spool_file_name);
  2109. #else
  2110. fprintf(spool_file, "\n+++ Transcript closed at end of run +++\n");
  2111. #endif
  2112. #ifndef _DEBUG
  2113. fclose(spool_file);
  2114. spool_file = NULL;
  2115. #endif
  2116. }
  2117. ensure_screen();
  2118. procedural_output = NULL;
  2119. return return_code;
  2120. }
  2121. /*
  2122. * The next fragment of code is to help with the use of CSL (and hence
  2123. * packages written in Lisp and supported under CSL) as OEM products
  2124. * embedded within larger C-coded packages. There is (of course) a
  2125. * significant issue about clashes between the names of external symbols
  2126. * if CSL is to be linked with anything else, but I will not worry about that
  2127. * just yet.
  2128. * The protocol for calling Lisp code from C is as follows:
  2129. *
  2130. * cslstart(argc, argv, writer);allocate memory and Lisp heap etc. Args
  2131. * should be "as if" CSL was being called
  2132. * directly and this was the main entrypoint.
  2133. * The extra arg accepts output from this
  2134. * stage. Use NULL to get standard I/O.
  2135. * execute_lisp_function(fname, reader, writer);
  2136. * fname is a (C) string that names a Lisp
  2137. * function of 0 args. This is called with
  2138. * stdin/stdout access redirected to use the
  2139. * two character-at-a-time functions passed
  2140. * down. [Value returned indicates if
  2141. * the evaluation succeeded?]
  2142. * cslfinish(writer); Tidies up ready to stop.
  2143. */
  2144. int execute_lisp_function(char *fname,
  2145. character_reader *r, character_writer *w)
  2146. {
  2147. Lisp_Object nil;
  2148. Lisp_Object ff = make_undefined_symbol(fname);
  2149. nil = C_nil;
  2150. if (exception_pending())
  2151. { flip_exception();
  2152. return 1; /* Failed to make the symbol */
  2153. }
  2154. procedural_input = r;
  2155. procedural_output = w;
  2156. Lapply0(nil, ff);
  2157. ensure_screen();
  2158. procedural_input = NULL;
  2159. procedural_output = NULL;
  2160. nil = C_nil;
  2161. if (exception_pending())
  2162. { flip_exception();
  2163. return 2; /* Failure during evaluation */
  2164. }
  2165. return 0;
  2166. }
  2167. #ifdef SAMPLE_OF_PROCEDURAL_INTERFACE
  2168. static char ibuff[100], obuff[100];
  2169. static int ibufp = 0, obufp = 0;
  2170. static int iget()
  2171. {
  2172. int c = ibuff[ibufp++];
  2173. if (c == 0) return EOF;
  2174. else return c;
  2175. }
  2176. static void iput(int c)
  2177. {
  2178. if (obufp < sizeof(obuff)-1)
  2179. { obuff[obufp++] = c;
  2180. obuff[obufp] = 0;
  2181. }
  2182. }
  2183. #endif
  2184. static int submain(int argc, char *argv[])
  2185. {
  2186. cslstart(argc, argv, NULL);
  2187. #ifdef SAMPLE_OF_PROCEDURAL_INTERFACE
  2188. strcpy(ibuff, "(print '(a b c d))");
  2189. execute_lisp_function("oem-supervisor", iget, iput);
  2190. printf("Buffered output is <%s>\n", obuff);
  2191. #else
  2192. if (module_enquiry == NULL) cslaction();
  2193. #endif
  2194. my_exit(cslfinish(NULL));
  2195. return 0;
  2196. }
  2197. #if !defined(WINDOWS_NT) || defined(CWIN) || !defined(NAG)
  2198. #ifdef CWIN
  2199. #define ENTRYPOINT cwin_main
  2200. #else
  2201. #define ENTRYPOINT main
  2202. #endif
  2203. int ENTRYPOINT(int argc, char *argv[])
  2204. {
  2205. int res;
  2206. #ifdef USE_MPI
  2207. MPI_Init(&argc,&argv);
  2208. MPI_Comm_rank(MPI_COMM_WORLD,&mpi_rank);
  2209. MPI_Comm_size(MPI_COMM_WORLD,&mpi_size);
  2210. printf("I am mpi instance %d of %d.\n", mpi_rank+1, mpi_size);
  2211. #endif
  2212. #ifdef CWIN
  2213. #ifdef NAG
  2214. strcpy(about_box_title, "About AXIOM for Windows");
  2215. strcpy(about_box_description, "CWIN interface");
  2216. strcpy(about_box_rights_1,"Copyright NAG Ltd.");
  2217. strcpy(about_box_rights_2,"1991-6");
  2218. #else
  2219. strcpy(about_box_title, "About CSL");
  2220. strcpy(about_box_description, "Codemist Standard Lisp");
  2221. #endif
  2222. #endif
  2223. #ifdef __cplusplus
  2224. try { res = submain(argc, argv); }
  2225. catch(int r) { res = r; }
  2226. #else
  2227. res = setjmp(my_exit_buffer);
  2228. if (res == 0) res = submain(argc, argv);
  2229. if (res == 0x80000000) res = 0;
  2230. #endif
  2231. #ifdef TICK_STREAM
  2232. remove_ticker();
  2233. #endif
  2234. return res;
  2235. #ifdef USE_MPI
  2236. MPI_Finalize();
  2237. #endif
  2238. }
  2239. #endif /* NAG */
  2240. /* End of csl.c */