sysxwin.c 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061
  1. /* sysxwin.c Copyright (C) 1993-2003 Codemist Ltd */
  2. /*
  3. * General Unix/X/StdWin system-specific code. Not currently
  4. * tested or working, but possibly valuable as a skeleton or
  5. * framework.
  6. */
  7. /*
  8. * This code may be used and modified, and redistributed in binary
  9. * or source form, subject to the "CCL Public License", which should
  10. * accompany it. This license is a variant on the BSD license, and thus
  11. * permits use of code derived from this in either open and commercial
  12. * projects: but it does require that updates to this code be made
  13. * available back to the originators of the package.
  14. * Before merging other code in with this or linking this code
  15. * with other packages or libraries please check that the license terms
  16. * of the other material are compatible with those of this.
  17. */
  18. /* Signature: 061156c6 13-Jul-2003 */
  19. #include "machine.h"
  20. #ifndef NO_UNISTD_AVAILABLE
  21. /*
  22. * Posix mandates a header <unistd.h>, which is why I feel entitled to
  23. * include it here. But for systems that do not I can assert
  24. * NO_UNISTD_AVAILABLE in machine.h and worry about other ways to
  25. * reference the relevant facilities...
  26. */
  27. #include <unistd.h>
  28. #endif
  29. #ifdef __hpux
  30. /*
  31. * Get the regular headers to define a few more things...
  32. */
  33. #define _SYSCALL_INCLUDED
  34. #endif
  35. #include <stdarg.h>
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #include <ctype.h>
  39. #include <sys/types.h>
  40. #include <sys/stat.h>
  41. #include <dirent.h>
  42. #include <errno.h>
  43. #include "tags.h"
  44. #include "externs.h"
  45. #include "sys.h"
  46. #ifdef TIMEOUT
  47. #include "timeout.h"
  48. #endif
  49. #include "filename.c"
  50. int change_directory(char *filename, char *old, size_t n)
  51. {
  52. process_file_name(filename, old, n);
  53. if (*filename == 0) return 1;
  54. if (chdir(filename))
  55. { char err_buf[LONGEST_LEGAL_FILENAME+100];
  56. char *msg;
  57. switch (errno)
  58. {
  59. case ENOTDIR:
  60. msg = "A component of %s is not a directory.";
  61. break;
  62. case ENOENT:
  63. msg = "The directory %s does not exist.";
  64. break;
  65. case EACCES:
  66. msg = "Insufficient permission for %s.";
  67. break;
  68. case ELOOP:
  69. msg = "Pathname %s has too many symbolic links.";
  70. break;
  71. case ENAMETOOLONG:
  72. msg = "The pathname %s is too long.";
  73. break;
  74. default:
  75. msg = "Cannot change directory to %s.";
  76. break;
  77. }
  78. sprintf(err_buf, msg, filename);
  79. aerror0(err_buf);
  80. return 1;
  81. }
  82. else return 0;
  83. }
  84. int create_directory(char *filename, char *old, size_t n)
  85. {
  86. process_file_name(filename, old, n);
  87. if (*filename == 0) return 1;
  88. return mkdir(filename, 0x1f8);
  89. }
  90. static void remove_files(char *name, int dirp, long int size)
  91. /* Remove a file, or a directory and all its contents */
  92. {
  93. if (dirp)
  94. rmdir(name);
  95. else
  96. remove(name);
  97. }
  98. int delete_file(char *filename, char *old, size_t n)
  99. {
  100. process_file_name(filename, old, n);
  101. if (*filename == 0) return 0;
  102. /*
  103. * We cannot simply use remove here, since this will not
  104. * work with directories and their contents. Hence the
  105. * use of scan_directory.
  106. */
  107. scan_directory(filename, remove_files);
  108. return 0;
  109. }
  110. /*#include <direct.h> */
  111. int get_current_directory(char *s, int n)
  112. {
  113. if (getcwd(s, n) == 0)
  114. { switch(errno)
  115. {
  116. case ERANGE:
  117. aerror0("the pathname of the current directory is too long.");
  118. break;
  119. case EACCES:
  120. aerror0("insufficient permission to get pathname.");
  121. break;
  122. default:
  123. aerror0("cannot get current directory name.");
  124. break;
  125. }
  126. *s = 0;
  127. return 0;
  128. }
  129. else return strlen(s);
  130. }
  131. int directoryp(char *filename, char *old, size_t n)
  132. {
  133. struct stat buf;
  134. process_file_name(filename, old, n);
  135. if (*filename == 0) return 0;
  136. if (stat(filename,&buf) == -1) return 0;
  137. return ((buf.st_mode & S_IFMT) == S_IFDIR);
  138. }
  139. char *get_truename(char *filename, char *old, size_t n)
  140. {
  141. struct stat buf;
  142. char *temp, *fn, *dir, *pwd;
  143. process_file_name(filename, old, n);
  144. if (*filename == 0) aerror("truename");
  145. /* Find out whether we have a file or a directory */
  146. if (stat(filename,&buf) == -1) aerror0("truename: cannot stat file");
  147. /* Store current directory */
  148. /* /*
  149. * The next line is UNSATISFACTORY because Posix explicitly says (at least in
  150. * in the copy of 1003.1 that I have) that getcwd has undefined behaviour
  151. * if its first argument is NULL.
  152. */
  153. if ((pwd = (char *)getcwd((char *)NULL, LONGEST_LEGAL_FILENAME)) == NULL)
  154. aerror0("truename: cannot get current working directory");
  155. if ((buf.st_mode & S_IFMT) == S_IFDIR)
  156. { /* We have a directory */
  157. char *dir = (char*) (*malloc_hook)(LONGEST_LEGAL_FILENAME);
  158. if (chdir(filename) != 0)
  159. aerror0("truename: cannot change directory");
  160. if (getcwd(dir,LONGEST_LEGAL_FILENAME) == NULL)
  161. aerror0("truename: cannot get current working directory");
  162. if (chdir(pwd) != 0)
  163. aerror0("truename: cannot change directory");
  164. (*free_hool)(pwd);
  165. /*
  166. * Axiom-specific hack: truename preserves '/' at the end of
  167. * a path
  168. */
  169. if (old[n-1] == '/' && dir[strlen(dir)-1] != '/')
  170. { n = strlen(dir);
  171. dir[n] = '/';
  172. dir[n+1] = '\0';
  173. }
  174. return dir;
  175. }
  176. else
  177. { /* Assume we have some kind of file */
  178. temp = strrchr(filename,'/');
  179. if (temp)
  180. { /* Found a directory component */
  181. fn = strdup(temp);
  182. *temp = '\0';
  183. /* fn is now "/file" and filename is the directory */
  184. if (chdir(filename) != 0)
  185. aerror0("truename: cannot change directory");
  186. /* /* getcwd(NULL,...) invalid */
  187. if ((temp = (char *)getcwd((char *)NULL,LONGEST_LEGAL_FILENAME)) == NULL)
  188. aerror0("truename: cannot get current working directory");
  189. if (chdir(pwd) != 0)
  190. aerror0("truename: cannot change directory");
  191. dir = (char *)(*malloc_hook)((strlen(temp) + strlen(fn) + 1)*sizeof(char));
  192. /* /*
  193. * No check for malloc failure...
  194. */
  195. strcpy(dir, temp);
  196. (*free_hool)(temp);
  197. (*free_hool)(pwd);
  198. strcat(dir, fn);
  199. (*free_hool)(fn);
  200. return dir;
  201. }
  202. else
  203. { dir = (char *)(*malloc_hook)((strlen(pwd) + strlen(filename) + 2)*sizeof(char));
  204. /* /* No check for malloc failure */
  205. strcpy(dir,pwd);
  206. strcat(dir, "/");
  207. strcat(dir, filename);
  208. (*free_hool)(pwd);
  209. return dir;
  210. }
  211. }
  212. }
  213. #ifndef DO_NOT_USE_STAT
  214. int file_readable(char *filename, char *old, size_t n)
  215. {
  216. struct stat buf;
  217. process_file_name(filename, old, n);
  218. if (*filename == 0) return 0;
  219. if (stat(filename,&buf) == -1)
  220. return 0; /* File probably does not exist */
  221. else if (geteuid() == buf.st_uid)
  222. return (buf.st_mode & S_IRUSR);
  223. else if (getegid() == buf.st_gid)
  224. return (buf.st_mode & S_IRGRP);
  225. else
  226. return (buf.st_mode & S_IROTH);
  227. }
  228. int file_writeable(char *filename, char *old, size_t n)
  229. {
  230. struct stat buf;
  231. process_file_name(filename, old, n);
  232. if (*filename == 0) return 0;
  233. if (stat(filename,&buf) == -1)
  234. return 0; /* Should we check to see if the directory is writeable? */
  235. else if (geteuid() == buf.st_uid)
  236. return (buf.st_mode & S_IWUSR);
  237. else if (getegid() == buf.st_gid)
  238. return (buf.st_mode & S_IWGRP);
  239. else
  240. return (buf.st_mode & S_IWOTH);
  241. }
  242. #else
  243. int file_readable(char *filename, char *old, size_t n)
  244. {
  245. FILE *fp;
  246. process_file_name(filename, old, n);
  247. if (*filename == 0) return 0;
  248. /* The "correct" way to do this is via stat, but this is much simpler! */
  249. fp = fopen(filename,"r");
  250. if (fp == NULL) return 0;
  251. else
  252. { fclose(fp);
  253. return 1;
  254. }
  255. }
  256. int file_writeable(char *filename, char *old, size_t n)
  257. {
  258. FILE *fp;
  259. process_file_name(filename, old, n);
  260. if (*filename == 0) return 0;
  261. fp = fopen(filename,"a");
  262. if (fp == NULL) return 0;
  263. else
  264. { fclose(fp);
  265. return 1;
  266. }
  267. }
  268. #endif
  269. int rename_file(char *from_name, char *from_old, size_t from_size,
  270. char *to_name, char *to_old, size_t to_size)
  271. {
  272. process_file_name(from_name, from_old, from_size);
  273. process_file_name(to_name, to_old, to_size);
  274. if (*from_name == 0 || *to_name == 0) return 0;
  275. return rename(from_name,to_name);
  276. }
  277. #ifdef NAG_VERSION
  278. int list_directory_members(char *filename, char *old, char **filelist[],
  279. size_t n)
  280. { struct dirent **namelist;
  281. int number_of_entries, i;
  282. char **files;
  283. process_file_name(filename, old, n);
  284. /* scandir expects "." for the current directory */
  285. if (*filename == 0) number_of_entries = scandir(".",&namelist,NULL,NULL);
  286. else number_of_entries = scandir(filename,&namelist,NULL,NULL);
  287. /*
  288. * If the scandir failed then return now, since we make an assumption later
  289. * that we found at least two entries: "." and "..".
  290. */
  291. if (number_of_entries == -1) return -1;
  292. files=(char **)(*malloc_hook)(number_of_entries*sizeof(char *));
  293. for (i=0;i<number_of_entries;++i)
  294. { files[i] = strdup(namelist[i]->d_name);
  295. (*free_hool)(namelist[i]);
  296. }
  297. (*free_hool)(namelist);
  298. *filelist = files;
  299. /*
  300. * When we return we will prepend the directory name to the files, so we
  301. * must make sure it is suitable for that. This is done here since it is
  302. * platform dependent (i.e. in DOS we would need to ensure the last
  303. * character was "\").
  304. */
  305. /*
  306. i=strlen(filename);
  307. if (i > 0 && filename[i-1] != '/')
  308. { filename[i]='/';
  309. filename[i+1]='\0';
  310. }
  311. */
  312. return number_of_entries;
  313. }
  314. #else
  315. void list_directory_members(char *filename, char *old,
  316. size_t n, directory_callback *fn)
  317. {
  318. process_file_name(filename, old, n);
  319. scan_files(filename, fn);
  320. }
  321. #endif
  322. CSLbool file_exists(char *filename, char *old, size_t n, char *tt)
  323. /*
  324. * This returns YES if the file exists, and as a side-effect copies a
  325. * textual form of the last-changed-time of the file into the buffer tt.
  326. */
  327. {
  328. struct stat statbuff;
  329. process_file_name(filename, old, n);
  330. if (*filename == 0) return NO;
  331. if (stat(filename, &statbuff) != 0) return NO;
  332. strcpy(tt, ctime(&(statbuff.st_mtime)));
  333. return YES;
  334. }
  335. /*
  336. * getenv() is a mild pain in two respects - firstly Ultrix uses
  337. * a non-ANSI definition (using 2 args not 1), and the MSDOS seems
  338. * to have a strong preference for upper case names. To allow for
  339. * all this I do not call getenv() directly but go via the following
  340. * code that can patch things up.
  341. */
  342. #ifdef TWO_ARG_GETENV
  343. char *my_getenv(char *s)
  344. {
  345. static char value[LONGEST_LEGAL_FILENAME];
  346. getenv(s, value);
  347. return value;
  348. }
  349. #else
  350. char *my_getenv(char *s)
  351. {
  352. return getenv(s);
  353. }
  354. #endif
  355. int my_system(char *s)
  356. {
  357. return system(s);
  358. }
  359. FILE *my_popen(char *a, char *b)
  360. {
  361. #ifdef NCC_LIB
  362. return NULL;
  363. #else
  364. return (FILE *)popen(a, b);
  365. #endif
  366. }
  367. void my_pclose(FILE *a)
  368. {
  369. #ifndef NCC_LIB
  370. pclose(a);
  371. #endif
  372. }
  373. /*
  374. * I do not expect that the following will work exactly unchanged
  375. * on all possible versions of Unix - e.g. header file names may need
  376. * altering and suchlike mess. But the idea should be reasonable and
  377. * changes when needed ought to be small.
  378. */
  379. #ifdef USE_GETUID
  380. /*
  381. * "machine.h" should set USE_GETUID if that is a good way of doing things.
  382. * This is NOT made the default, since it seems that getuid and getpwuid
  383. * are distinctly not comfortably available on all systems. The alternative
  384. * of using getenv("HOME") when expanding "~/xxx" is reasonably good, but
  385. * for "~user/xxx" I give up and just look in the current directory.
  386. */
  387. #include <pwd.h>
  388. extern int getuid(void);
  389. int void get_home_directory(char *b, int len)
  390. {
  391. int i;
  392. struct passwd *pw = getpwuid(getuid());
  393. strcpy(b, pw->pw_dir);
  394. i = strlen(b);
  395. /* Here the directory handed back has "/" forced in as its final character */
  396. if ( b[i-1] != '/')
  397. { b[i++] = '/';
  398. b[i] = 0;
  399. }
  400. return i;
  401. }
  402. int get_users_home_directory(char *b, int len)
  403. {
  404. struct passwd *pw = getpwnam(b);
  405. if (pw != NULL) strcpy(b, pw->pw_dir);
  406. else strcpy(b, "."); /* use current directory if getpwnam() fails */
  407. return strlen(b);
  408. }
  409. #else /* USE_GETUID */
  410. int get_home_directory(char *b, int len)
  411. {
  412. int i;
  413. strcpy(b, getenv("HOME")); /* Probably works with most shells */
  414. i = strlen(b);
  415. if ( b[i-1] != '/')
  416. { b[i++] = '/';
  417. b[i] = 0;
  418. }
  419. return i;
  420. }
  421. int get_users_home_directory(char *b, int len)
  422. {
  423. strcpy(b, "."); /* use current directory if getpwnam() no available */
  424. return 1;
  425. }
  426. #endif /* USE_GETUID */
  427. #ifdef UNIX_TIMES
  428. /*
  429. * This is a BSD-style clock facility, possibly giving a resolution of
  430. * only 1/100 second. I believe that Portable Standard Lisp typically
  431. * reports user time, which is why I do this. A further nasty here
  432. * is that I am probably compiling this file in ANSI mode, and on
  433. * at least some computers this makes #include <sys/times.h> fairly
  434. * ineffective (ugh), so I declare all the structures and functions I
  435. * want directly (ugh ugh) and hope they are as needed. Consider this
  436. * when you port to a new machine.
  437. */
  438. clock_t read_clock(void)
  439. {
  440. struct my_tms {
  441. clock_t tms_utime;
  442. clock_t tms_stime;
  443. clock_t tms_cutime;
  444. clock_t tms_cstime;
  445. } tmsbuf;
  446. clock_t w1, w2, w3;
  447. extern void times(/*struct my_tms * */);
  448. times(&tmsbuf);
  449. w1 = tmsbuf.tms_utime; /* User time in UNIX_TIMES ticks */
  450. w2 = CLOCKS_PER_SEC;
  451. w3 = UNIX_TIMES;
  452. return (clock_t)((double)w1 * ((double)w2/(double)w3));
  453. }
  454. #endif
  455. #ifdef __kcm
  456. extern int _ttyhandle;
  457. int batchp(void)
  458. {
  459. return (_ttyhandle != 0);
  460. }
  461. #else
  462. #ifdef NCC_LIB
  463. int batchp(void)
  464. {
  465. extern int _fisatty(FILE*);
  466. return !_fisatty(stdin);
  467. }
  468. #else
  469. #if BSD_LIB
  470. int batchp(void)
  471. {
  472. return !isatty(fileno(stdin));
  473. }
  474. #else
  475. #error "Unknown Library type"
  476. #endif /* BSD_LIB */
  477. #endif /* NCC_LIB */
  478. #endif /* __kcm */
  479. /*
  480. * The next procedure is responsible for establishing information about
  481. * where the main checkpoint image should be recovered from, and where
  482. * and fasl files should come from.
  483. */
  484. char *find_image_directory(int argc, char *argv[])
  485. {
  486. char image[LONGEST_LEGAL_FILENAME];
  487. char pgmname[LONGEST_LEGAL_FILENAME];
  488. char *w;
  489. /*
  490. * Here I assume Unix, or something sufficiently like it, and
  491. * if the current program is called xxx, then I want an environment
  492. * variable called xxx.img to tell me where to find the image file
  493. * and the fasl directory.
  494. */
  495. #ifdef PUBLIC
  496. strcpy(pgmname, "/usr/local/lib/reduce"); /* fixed name */
  497. w = my_getenv("reduceimg");
  498. if (w != NULL) strcpy(image, w);
  499. else strcpy(image, pgmname);
  500. #else
  501. if (argc > 0 && argv[0] != NULL)
  502. { int i;
  503. w = argv[0];
  504. i = strlen(w);
  505. while (i > 0 && w[i-1] != '/') i--;
  506. sprintf(pgmname, "%s.img", &w[i]); /* final component of argv[0] */
  507. strncpy(program_name, &w[i], 63);
  508. program_name[63] = 0;
  509. }
  510. else strcpy(pgmname, "csl.img"); /* even argv[0] is not available! */
  511. w = my_getenv(pgmname);
  512. #endif
  513. if (w != NULL) strcpy(image, w);
  514. else strcpy(image, pgmname);
  515. /*
  516. * I copy from local vectors into malloc'd space to hand my
  517. * answer back.
  518. */
  519. w = (char *)(*malloc_hook)(1+strlen(image));
  520. /*
  521. * The error exit here seem unsatisfactory...
  522. */
  523. if (w == NULL)
  524. { fprintf(stderr, "\n+++ Panic - run out of space\n");
  525. exit(EXIT_FAILURE);
  526. }
  527. strcpy(w, image);
  528. return w;
  529. }
  530. /*
  531. * The following function controls memory allocation policy
  532. */
  533. int32 ok_to_grab_memory(int32 current)
  534. {
  535. #ifdef COMMON
  536. return current;
  537. #else
  538. return 3*current + 2;
  539. #endif
  540. }
  541. #include "fileops.c"
  542. #include "scandir.c"
  543. /* **************** THIS TICKER STUFF IS NOT WORKING CORRECTLY ******* */
  544. #ifndef SOFTWARE_TICKS
  545. #include <sys/time.h>
  546. struct itimerval value, ovalue;
  547. #endif
  548. static CSLbool ticker_active = NO;
  549. void add_ticker(void)
  550. {
  551. void wimp_tick(int);
  552. /*putc('+', stderr); */
  553. if (ticker_active) return;
  554. #ifdef SOFTWARE_TICKS
  555. if (countdown<0) countdown = SOFTWARE_TICKS; /* Reset if expired */
  556. #else
  557. value.it_interval.tv_sec = 1;
  558. value.it_interval.tv_usec = 0;
  559. value.it_value.tv_sec = 1;
  560. value.it_value.tv_usec = 0;
  561. setitimer(ITIMER_VIRTUAL, &value, NULL); /* Set up a 1 sec interrupt */
  562. signal(SIGVTALRM, wimp_tick);
  563. #endif
  564. ticker_active = YES;
  565. }
  566. void remove_ticker(void)
  567. {
  568. /*putc('-', stderr); */
  569. if (!ticker_active) return;
  570. #ifndef SOFTWARE_TICKS
  571. value.it_interval.tv_sec = 0;
  572. value.it_interval.tv_usec = 0;
  573. value.it_value.tv_sec = 0;
  574. value.it_value.tv_usec = 0;
  575. setitimer(ITIMER_VIRTUAL, &value, NULL); /* Remove all interrupt */
  576. signal(SIGVTALRM, SIG_IGN); /* Ignore the clock ticks */
  577. #endif
  578. ticker_active = NO;
  579. }
  580. #ifndef SOFTWARE_TICKS
  581. void wimp_tick(int sig)
  582. {
  583. /* putc('.', stderr);*/
  584. if (!ticker_active) return;
  585. signal(SIGVTALRM, wimp_tick);
  586. if (tick_pending) return;
  587. else if (already_in_gc) tick_on_gc_exit = YES;
  588. else {
  589. Lisp_Object nil = C_nil;
  590. tick_pending = YES;
  591. saveheaplimit = heaplimit;
  592. heaplimit = fringe;
  593. savevheaplimit = vheaplimit;
  594. vheaplimit = vfringe;
  595. savecodelimit = codelimit;
  596. codelimit = codefringe;
  597. savestacklimit = stacklimit;
  598. stacklimit = stackbase;
  599. }
  600. return;
  601. }
  602. #endif
  603. /* ************************************************************ */
  604. /* ********** StdWin Interface ******************************** */
  605. /* ************************************************************ */
  606. /* ************************************************************ */
  607. #include "stdwin.h"
  608. #include "tools.h"
  609. #include "editwin.h"
  610. #include "text.h" /* Rather a cheat as I need to look
  611. * low down in here */
  612. static WINDOW *CSL_window;
  613. static EDITWIN *CSL_ew;
  614. static EDITWIN *help_ew;
  615. int max_nlines = 250;
  616. #ifndef HELP_DATA
  617. #define HELP_DATA "help.data"
  618. #endif
  619. #ifndef HELP_INDEX
  620. #define HELP_INDEX "help.index"
  621. #endif
  622. static MENU *adminmenu;
  623. static MENU *editmenu;
  624. static MENU *loadmenu;
  625. static MENU *libmenu;
  626. static MENU *switchmenu;
  627. static MENU *helpmenu;
  628. /* static MENU *fontmenu; */
  629. /* static MENU *sizemenu; */
  630. #define ADMIN_MENU (1)
  631. #define MMFile 0
  632. #define MMSaveas 1
  633. #define MMHelp 2 /* main window menu items */
  634. #define MMHelpSel 3
  635. #define MMHelpAsk 4
  636. #define MMInt 5
  637. #define MMAbort 6
  638. #define MMPause 7
  639. #define MMDummy 8
  640. #define MMTime 9
  641. #define MMSpace 10
  642. #define MMOTime 11
  643. #define EDIT_MENU (2)
  644. #define MMCut 0
  645. #define MMCopy 1
  646. #define MMPaste 2
  647. #define MMClear 3
  648. #define MMSelAll 4
  649. #define HELP_LEN (36)
  650. #define HELP_MENU (3)
  651. static struct hlp {
  652. char name[HELP_LEN];
  653. long offset;
  654. int length;
  655. } *hlp;
  656. int help_length;
  657. int helpstamp;
  658. #define LOAD_MENU (4)
  659. static char *loads[] = {
  660. "arnum", "assist", "boolean", "changevr", "compact", "complex",
  661. "decompos", "defint", "dfpart", "elem", "excalc", "gentran", "groebner",
  662. "gnuplot",
  663. "laplace", "linalg", "normform", "numeric", "odesolve", "residue",
  664. "rlfi", "rsolve", "scope", "sets", "specfn", "taylor", "tps", "tri",
  665. "trigsimp", "zeilberg",
  666. (char*)NULL};
  667. #define LIB_MENU (5)
  668. static char *libraries[] = {
  669. "algint", "applysym", "avector", "cali", "camal", "crack", "cvit",
  670. "desir", "dummy", "fide", "fps", "ideals", "ineq", "invbase", "lie",
  671. "modsr", "ncpoly", "orthovec", "physop", "pmrules", "randpoly",
  672. "reacteqn", "spde", "symmetry", "wu", "xcolor", "xideal", "ztrans",
  673. (char*)NULL};
  674. #define SWITCH_MENU (6)
  675. static struct sw {
  676. char *name;
  677. int state;
  678. } switches[] = {
  679. {"algint", NO}, {"adjprec", NO}, {"allbranch", NO}, {"allfac", YES},
  680. {"arbvars", NO}, {"asterisk", YES}, {"backtrace", NO},
  681. {"balanced_mod", NO},{"bfspace", NO}, {"combineexpt", NO},
  682. {"combinelogs", NO}, {"comp", NO}, {"complex", NO},
  683. {"compxroots", NO}, {"cramer", NO}, {"cref", NO}, {"defn", NO},
  684. {"demo", NO}, {"dfprint", NO}, {"div", NO}, {"echo", NO},
  685. {"errcont", NO}, {"evallhseqp", NO}, {"exp", YES},
  686. {"expandexpt", YES}, {"expandlogs", NO}, {"ezgcd", NO},
  687. {"factor", NO}, {"fastfor", NO}, {"force", NO}, {"fort", NO},
  688. {"fortupper", NO}, {"fullprec", NO},{"fullprecision", NO},
  689. {"fullroots", NO}, {"gcd", NO}, {"heugcd", NO}, {"horner", NO},
  690. {"ifactor", NO}, {"int", NO}, {"intstr", NO}, {"lcm", YES},
  691. {"lessspace", NO}, {"limitedfactors", NO}, {"list", NO},
  692. {"listargs", NO}, {"lower", YES}, {"mcd", YES}, {"modular", NO},
  693. {"msg", YES}, {"multiplicities", NO}, {"nat", YES},
  694. {"nero", NO}, {"noarg", YES}, {"noconvert", NO}, {"nonlnr", NO},
  695. {"nosplit", YES}, {"numval", YES}, {"output", YES}, {"period", YES},
  696. {"pgwd", NO}, {"plap", NO}, {"precise", YES},
  697. {"pret", NO}, {"pri", YES}, {"pwrds", YES},
  698. {"quotenewnam", YES},{"raise", NO}, {"rat", NO}, {"ratarg", NO},
  699. {"rational", NO}, {"rationalize", NO}, {"ratpri", YES},
  700. {"reduced", NO}, {"revpri", NO}, {"rlisp88", NO}, {"rootmsg", NO},
  701. {"roundall", YES}, {"roundbf", NO}, {"rounded", NO},
  702. {"savestructr", NO}, {"solvesingular", NO}, {"time", NO},
  703. {"trallfac", NO}, {"trfac", NO}, {"trint", NO}, {"trroot", NO},
  704. {(char*)NULL, 0}};
  705. static void menusetup(void)
  706. {
  707. MENU *mp;
  708. int i;
  709. adminmenu= mp= wmenucreate(ADMIN_MENU, "Admin");
  710. wmenuadditem(mp, "Input file...", 'F');
  711. wmenuadditem(mp, "Saveas...", -1);
  712. wmenuadditem(mp, "Help Window", 'H');
  713. wmenuadditem(mp, "Help Selection", 'S');
  714. wmenuadditem(mp, "Help Topic...", -1);
  715. wmenuadditem(mp, "Interrupt", 'I');
  716. wmenuadditem(mp, "Quit", 'Q');
  717. wmenuadditem(mp, "Pause", 'P');
  718. wmenuadditem(mp, "---------", -1);
  719. wmenuadditem(mp, "0.00", -1);
  720. wmenuadditem(mp, "[GC 0]", -1);
  721. wmenuadditem(mp, "", -1);
  722. wmenuadditem(mp, "", -1);
  723. wmenuenable(mp, MMDummy, NO);
  724. wmenuenable(mp, MMTime, NO);
  725. wmenuenable(mp, MMSpace, NO);
  726. wmenuenable(mp, MMOTime, NO);
  727. editmenu= mp= wmenucreate(EDIT_MENU, "Edit");
  728. wmenuadditem(mp, "Cut", 'X');
  729. wmenuadditem(mp, "Copy", 'C');
  730. wmenuadditem(mp, "Paste", 'V');
  731. wmenuadditem(mp, "Clear", 'B');
  732. wmenuadditem(mp, "Select All", 'A');
  733. helpmenu= mp= wmenucreate(HELP_MENU, "Help");
  734. {
  735. FILE* hlpindx = fopen(HELP_INDEX, "r");
  736. if (hlpindx != NULL) {
  737. fscanf(hlpindx, "%d\n", &helpstamp);
  738. fscanf(hlpindx, "%d", &help_length);
  739. hlp = (struct hlp*) calloc(1+help_length, sizeof(struct hlp));
  740. if (hlp == NULL) {
  741. help_length = 0;
  742. goto loader; /* Insufficient memory */
  743. }
  744. for (i=0; i<help_length; i++) {
  745. int ch, p=0;
  746. fscanf(hlpindx, "%d %d ", &(hlp[i].offset), &(hlp[i].length));
  747. while (p<HELP_LEN-1) {
  748. ch = getc(hlpindx);
  749. if (ch == '\n') break;
  750. hlp[i].name[p++] = ch; /* Was toupper here */
  751. }
  752. while (ch != '\n') ch = getc(hlpindx);
  753. hlp[i].name[p] = '\0';
  754. wmenuadditem(mp, hlp[i].name, -1);
  755. }
  756. fclose(hlpindx);
  757. }
  758. else {
  759. help_length = 0;
  760. strcpy(hlp[0].name, "No help");
  761. hlp[0].offset = -1;
  762. hlp[0].length = 0;
  763. }
  764. }
  765. loader:
  766. loadmenu= mp= wmenucreate(LOAD_MENU, "Load");
  767. for (i=0; loads[i]!= NULL; i++)
  768. wmenuadditem(mp, loads[i], -1);
  769. libmenu= mp= wmenucreate(LIB_MENU, "Library");
  770. for (i=0; libraries[i]!= NULL; i++)
  771. wmenuadditem(mp, libraries[i], -1);
  772. switchmenu= mp= wmenucreate(SWITCH_MENU, "Switch");
  773. for (i=0; switches[i].name!= NULL; i++) {
  774. wmenuadditem(mp, switches[i].name, -1);
  775. wmenucheck(mp, i, switches[i].state);
  776. }
  777. }
  778. static fixmenus(void)
  779. {
  780. CSLbool focus;
  781. focus= (CSL_ew->tp->foclen != 0);
  782. wmenuenable(editmenu, MMCut, focus);
  783. wmenuenable(editmenu, MMCopy, focus);
  784. wmenuenable(editmenu, MMClear, focus);
  785. wmenuenable(adminmenu, MMHelpSel, focus);
  786. /* wmenuenable(editmenu, MMPaste, YES); */
  787. if (help_ew != NULL) {
  788. focus= (help_ew->tp->foclen != 0);
  789. if (focus) {
  790. wmenuenable(editmenu, MMCut, focus);
  791. wmenuenable(editmenu, MMCopy, focus);
  792. wmenuenable(editmenu, MMClear, focus);
  793. wmenuenable(adminmenu, MMHelpSel, focus);
  794. }
  795. }
  796. }
  797. #define TTYBUF_SIZE 256
  798. static char tty_buff[TTYBUF_SIZE];
  799. static int tty_index = 0;
  800. static CSLbool tty_ready = NO;
  801. static int tty_nnl = 0;
  802. static int tty_offset;
  803. #define STDOUT_BUFSIZE 1024
  804. #define LONGEST_PRINTF 120
  805. static char stdout_buffer[STDOUT_BUFSIZE];
  806. static char *stdout_p;
  807. static int stdout_n;
  808. void start_up_window_manager(int use_wimp)
  809. {
  810. static char* def_args[]= {"X-Reduce 3.6", (char*)NULL};
  811. int argc= 1;
  812. char **argv= def_args;
  813. int CSL_width, CSL_height;
  814. signal(SIGVTALRM, SIG_IGN); /* Ensure it is off */
  815. wargs(&argc, &argv); /* Fiddle the argument decode for now */
  816. winit();
  817. wsetfont("6x13"); /* For now */
  818. menusetup();
  819. wsetdefwinsize(82*wcharwidth('0'), 25*wlineheight());
  820. CSL_ew = ewcreate(NULL);
  821. CSL_window = CSL_ew->win;
  822. wsettitle(CSL_window, "Reduce 3.6");
  823. fixmenus();
  824. /* wmenudetach(CSL_window, helpmenu); */
  825. wmenuenable(editmenu, MMTime, NO); /* These are not selectable */
  826. wmenuenable(editmenu, MMOTime, NO); /* These are not selectable */
  827. wmenuenable(editmenu, MMSpace, NO);
  828. wmenudetach(CSL_window, loadmenu); /* These are only valid when reading */
  829. wmenudetach(CSL_window, libmenu);
  830. wmenudetach(CSL_window, switchmenu);
  831. /* wmessage("Welcome to X-Reduce\n\n"); */
  832. wflush();
  833. stdout_n = 0;
  834. stdout_p = stdout_buffer;
  835. #ifndef SOFTWARE_TICKS
  836. value.it_interval.tv_sec = 1;
  837. value.it_interval.tv_usec = 0;
  838. value.it_value.tv_sec = 1; /* ?? 10 seconds */
  839. value.it_value.tv_usec = 0;
  840. signal(SIGVTALRM, wimp_tick);
  841. setitimer(ITIMER_VIRTUAL, &value, NULL); /* Set up a 1 sec interrupt */
  842. #endif
  843. help_ew = NULL; /* Help window */
  844. }
  845. static char *help_buff;
  846. CSLbool
  847. helpwindow(int index)
  848. {
  849. FILE* help = fopen(HELP_DATA, "r");
  850. int ch;
  851. int width, height;
  852. int size = hlp[index].length;
  853. if (help == NULL) return;
  854. /* fprintf(stderr, "Help on index %d offset=%d size=%d\n",
  855. index, hlp[index].offset, hlp[index].length); */
  856. fscanf(help, "%d\n", &ch);
  857. if (ch != helpstamp) return; /* Check help data in in line with index */
  858. fseek(help, hlp[index].offset, SEEK_SET);
  859. if (help_ew) {
  860. (*free_hool)(help_buff);
  861. tesetfocus(help_ew->tp, 0, tegetlen(help_ew->tp));
  862. ewreplace(help_ew, "");
  863. }
  864. else {
  865. help_ew = ewcreate(NULL);
  866. wsettitle(help_ew->win, "Help for Reduce 3.6");
  867. }
  868. help_buff = (*malloc_hook)(size+1);
  869. if (help_buff == NULL) {
  870. dprintf("Insufficient memory");
  871. wfleep();
  872. return FALSE;
  873. }
  874. /* fprintf(stderr, "reading %d bytes to buffer\n", size); */
  875. fread(help_buff, size, 1, help);
  876. /* fprintf(stderr, "help starts as %.100s\n", help_buff); */
  877. help_buff[size] = '\0';
  878. wmenudetach(help_ew->win, loadmenu);
  879. wmenudetach(help_ew->win, libmenu);
  880. wmenudetach(help_ew->win, switchmenu);
  881. /* wmenudetach(help_ew->win, adminmenu); */
  882. ewreplace(help_ew, help_buff);
  883. tesetfocus(help_ew->tp, 0, 0);
  884. fclose(help);
  885. return TRUE;
  886. }
  887. void help_buffer(char *buf, int len)
  888. {
  889. int i;
  890. for (i=0; i<help_length; i++) {
  891. /* fprintf(stderr, "Check against %s\n", hlp[i].name); */
  892. if (strncmp(hlp[i].name, buf, len) == 0) {
  893. helpwindow(i);
  894. break;
  895. }
  896. }
  897. if (i == help_length) wfleep();
  898. }
  899. void help_selection(EDITWIN *ew)
  900. {
  901. int i;
  902. char *text;
  903. TEXTEDIT *tp = ew->tp;
  904. if (tp->foclen == 0) {
  905. wfleep();
  906. return;
  907. }
  908. text= tegettext(tp);
  909. help_buffer(text+tp->foc, tp->foclen);
  910. }
  911. extern int pause_set = 0;
  912. void event_loop(void)
  913. {
  914. for (;;) { /* Loop while there are events */
  915. EVENT e;
  916. EDITWIN *ew;
  917. CSLbool closed;
  918. /* putc('%', stderr); */
  919. wgetevent(&e);
  920. /* printf("Event: type=%d win=%p data=%d\n", e.type, e.window, e.u.command); */
  921. ew = ewfind(e.window);
  922. if (ew == CSL_ew) {
  923. switch (e.type) {
  924. case WE_CHAR:
  925. switch(e.u.character) {
  926. case 'A'-'@': /* ^A == beginning of line */
  927. {
  928. TEXTEDIT* tp = CSL_ew->tp;
  929. tesetfocus(tp,
  930. zsubgap(tp->start[tewhichline(tp,
  931. zaddgap(tp->foc),
  932. tp->focprev)]),
  933. -1);
  934. break;
  935. }
  936. case 'B'-'@': /* ^B back a character */
  937. tearrow(CSL_ew->tp, WC_LEFT);
  938. break;
  939. case 127: /* Delete character */
  940. case 'D'-'@': /* ^D delete at cursor */
  941. {
  942. TEXTEDIT* tp = CSL_ew->tp;
  943. tearrow(tp, WC_RIGHT);
  944. {
  945. int f1 = tp->foc;
  946. int i;
  947. int ss = tp->start[tp->nlines-tty_nnl];
  948. int ee = ss + tty_offset;
  949. if (ss <= f1 && f1 < ee) {
  950. if (tty_offset>0) tty_offset--;
  951. }
  952. e.type = WE_COMMAND;
  953. e.u.command = WC_BACKSPACE;
  954. ewevent(ew,&e, NULL);
  955. break;
  956. }
  957. }
  958. case 'E'-'@': /* ^E end of line */
  959. {
  960. TEXTEDIT* tp = CSL_ew->tp;
  961. int line = tewhichline(tp, zaddgap(tp->foc), tp->focprev);
  962. int xxx = zsubgap(tetextround(tp, line, tp->right));
  963. tesetfocus(tp, xxx, -1);
  964. break;
  965. }
  966. case 'F'-'@': /* ^F forward a character */
  967. tearrow(CSL_ew->tp, WC_RIGHT);
  968. break;
  969. case 'K'-'@': /* ^K kill to end of line */
  970. { /* This does not take notice of offset */
  971. TEXTEDIT* tp = CSL_ew->tp;
  972. int f1;
  973. int i;
  974. int ss;
  975. int ee;
  976. tesetfocus(tp,
  977. tp->foc,
  978. zsubgap(tetextround(tp,
  979. tewhichline(tp, zaddgap(tp->foc),
  980. tp->focprev),
  981. tp->right)));
  982. f1 = tp->foc;
  983. ss = tp->start[tp->nlines-tty_nnl];
  984. ee = ss + tty_offset;
  985. for (i=0; i<tp->foclen; i++)
  986. if (ss <= f1+i && f1+i < ee) {
  987. if (tty_offset>0) tty_offset--;
  988. }
  989. ewreplace(ew, "");
  990. break;
  991. }
  992. case 'N'-'@': /* ^N next line */
  993. tearrow(CSL_ew->tp, WC_DOWN);
  994. break;
  995. case 'P'-'@': /* ^P previous line */
  996. tearrow(CSL_ew->tp, WC_UP);
  997. break;
  998. case 'Z'-'@': /* ^Z move to end of buffer */
  999. {
  1000. TEXTEDIT* tp = CSL_ew->tp;
  1001. tesetfocus(tp, tp->buflen - tp->gaplen, -1);
  1002. break;
  1003. }
  1004. default:
  1005. ewevent(ew, &e, &closed);
  1006. if (tty_ready == YES && !pause_set) return;
  1007. }
  1008. break;
  1009. case WE_COMMAND:
  1010. switch (e.u.command) {
  1011. case WC_CANCEL:
  1012. interrupt_pending = YES;
  1013. break;
  1014. case WC_CLOSE:
  1015. pause_for_user();
  1016. exit(1);
  1017. case WC_RETURN:
  1018. {
  1019. TEXTEDIT* tp = CSL_ew->tp;
  1020. int f1 = zaddgap(tp->foc);
  1021. int ee = tp->start[tp->nlines-tty_nnl] + tty_offset;
  1022. /* printf("f1=%d ee=%d offset=%d\n", f1, ee, tty_offset); */
  1023. if (f1 >= ee) {
  1024. tty_nnl++;
  1025. if (f1 == tp->buflen) {
  1026. ewevent(ew, &e, &closed);
  1027. tty_ready = YES;
  1028. if (!pause_set) return;
  1029. }
  1030. }
  1031. }
  1032. break;
  1033. case WC_DEL:
  1034. case WC_BACKSPACE:
  1035. /* Need to check to see if we are deleting
  1036. * in the offset area */
  1037. {
  1038. TEXTEDIT* tp = CSL_ew->tp;
  1039. int f1 = tp->foc;
  1040. int i;
  1041. int ss = tp->start[tp->nlines-tty_nnl];
  1042. int ee = ss + tty_offset;
  1043. if (tp->foclen == 0) {
  1044. if (ss < f1 && f1 <= ee && tty_offset>0) tty_offset--;
  1045. }
  1046. else {
  1047. for (i=0; i<tp->foclen; i++) {
  1048. if (ss <= f1+i && f1+i < ee && tty_offset>0) tty_offset--;
  1049. }
  1050. }
  1051. }
  1052. break;
  1053. case WC_LEFT:
  1054. case WC_RIGHT:
  1055. default:
  1056. break;
  1057. }
  1058. ewevent(ew, &e, &closed);
  1059. break;
  1060. case WE_MENU:
  1061. switch (e.u.m.id) {
  1062. case ADMIN_MENU:
  1063. switch (e.u.m.item) {
  1064. case MMFile:
  1065. {
  1066. short wd;
  1067. TEXTEDIT *tp = CSL_ew->tp;
  1068. char name[42];
  1069. if (waskstr("Input file name", name, 40)) {
  1070. tesetfocus(tp, tp->buflen - tp->gaplen, -1);
  1071. ewreplace(CSL_ew, "in \"");
  1072. ewreplace(CSL_ew, name);
  1073. ewreplace(CSL_ew, "\"");
  1074. /*tetoend(tp); */
  1075. }
  1076. break;
  1077. }
  1078. case MMSaveas:
  1079. ewsaveas(CSL_ew);
  1080. break;
  1081. case MMHelp:
  1082. helpwindow(0);
  1083. break;
  1084. case MMHelpSel:
  1085. help_selection(ew);
  1086. break;
  1087. case MMHelpAsk:
  1088. {
  1089. char buf[40];
  1090. int len;
  1091. if (waskstr("Help on topic", buf, 40)) {
  1092. len = strlen(buf);
  1093. help_buffer(buf, len);
  1094. }
  1095. }
  1096. break;
  1097. case MMAbort:
  1098. pause_for_user();
  1099. exit(1);
  1100. case MMInt:
  1101. interrupt_pending = YES;
  1102. return;
  1103. case MMPause:
  1104. pause_set = !pause_set;
  1105. wmenucheck(adminmenu, MMPause, pause_set);
  1106. if (pause_set) wsettitle(CSL_window, "<Paused> Reduce 3.6");
  1107. else wsettitle(CSL_window, "Reduce 3.6");
  1108. break;
  1109. }
  1110. break;
  1111. case EDIT_MENU:
  1112. switch (e.u.m.item) {
  1113. case MMCopy:
  1114. ewcopy(ew);
  1115. break;
  1116. case MMPaste:
  1117. {
  1118. char* text = wgetclip();
  1119. char* tt = text;
  1120. int valid = YES;
  1121. if (text == NULL) wfleep();
  1122. else {
  1123. TEXTEDIT *tp = CSL_ew->tp;
  1124. tesetfocus(tp, tp->buflen - tp->gaplen, -1);
  1125. while (*tt != '\0')
  1126. if (*tt++=='\n') valid = NO;
  1127. if (valid) ewreplace(ew, text);
  1128. else wmessage("Cannot Paste text including new line");
  1129. }
  1130. }
  1131. break;
  1132. case MMCut:
  1133. ewcopy(ew);
  1134. case MMClear:
  1135. /* Need to check to see if we are deleting
  1136. * in the offset area */
  1137. {
  1138. TEXTEDIT* tp = CSL_ew->tp;
  1139. int f1 = tp->foc;
  1140. int i;
  1141. int ss = tp->start[tp->nlines-tty_nnl];
  1142. int ee = ss + tty_offset;
  1143. for (i=0; i<tp->foclen; i++)
  1144. if (ss <= f1+i && f1+i < ee) {
  1145. if (tty_offset>0) tty_offset--;
  1146. }
  1147. }
  1148. ewreplace(ew, "");
  1149. break;
  1150. case MMSelAll:
  1151. tesetfocus(ew->tp, 0, tegetlen(ew->tp));
  1152. break;
  1153. }
  1154. break;
  1155. case LOAD_MENU:
  1156. {
  1157. char *load = "load_package ";
  1158. char *tt = loads[e.u.m.item];
  1159. TEXTEDIT *tp = CSL_ew->tp;
  1160. tesetfocus(tp, tp->buflen - tp->gaplen, -1);
  1161. tp->aim= UNDEF;
  1162. tp->focprev= FALSE;
  1163. ewreplace(CSL_ew, load);
  1164. ewreplace(CSL_ew, tt);
  1165. tty_ready = YES;
  1166. ewreplace(CSL_ew, ";\n");
  1167. tty_nnl++;
  1168. wmenuenable(loadmenu, e.u.m.item, NO);
  1169. return;
  1170. }
  1171. case LIB_MENU:
  1172. {
  1173. char *load = "load_package ";
  1174. char *tt = libraries[e.u.m.item];
  1175. TEXTEDIT *tp = CSL_ew->tp;
  1176. tesetfocus(tp, tp->buflen - tp->gaplen, -1);
  1177. tp->aim= UNDEF;
  1178. tp->focprev= FALSE;
  1179. ewreplace(CSL_ew, load);
  1180. ewreplace(CSL_ew, tt);
  1181. tty_ready = YES;
  1182. ewreplace(CSL_ew, ";\n");
  1183. tty_nnl++;
  1184. wmenuenable(loadmenu, e.u.m.item, NO);
  1185. return;
  1186. }
  1187. case SWITCH_MENU:
  1188. {
  1189. char *load = (switches[e.u.m.item].state ? "off " : "on ");
  1190. char *tt = switches[e.u.m.item].name;
  1191. TEXTEDIT *tp = CSL_ew->tp;
  1192. tesetfocus(tp, tp->buflen - tp->gaplen, -1);
  1193. ewreplace(CSL_ew, load);
  1194. ewreplace(CSL_ew, tt);
  1195. tty_ready = YES;
  1196. ewreplace(CSL_ew, ";\n");
  1197. tty_nnl++;
  1198. switches[e.u.m.item].state = ~ switches[e.u.m.item].state;
  1199. wmenucheck(switchmenu, e.u.m.item, switches[e.u.m.item].state);
  1200. return;
  1201. }
  1202. case HELP_MENU:
  1203. helpwindow(e.u.m.item);
  1204. break;
  1205. }
  1206. break;
  1207. case WE_CLOSE:
  1208. pause_for_user();
  1209. exit(1);
  1210. default:
  1211. ewevent(ew, &e, &closed);
  1212. break;
  1213. }
  1214. }
  1215. else if (ew == help_ew) {
  1216. switch (e.type) {
  1217. case WE_MOUSE_UP: /* Extend to a word on single click */
  1218. if (!ew->tp->mdown) break;
  1219. ew->tp->mdown= FALSE;
  1220. if (e.u.where.clicks > 1) {
  1221. teclicknew(ew->tp, e.u.where.h, e.u.where.v, FALSE, TRUE);
  1222. help_selection(ew);
  1223. }
  1224. break;
  1225. case WE_CHAR:
  1226. switch(e.u.character) {
  1227. case 'A'-'@': /* ^A == beginning of line */
  1228. {
  1229. TEXTEDIT* tp = help_ew->tp;
  1230. tesetfocus(tp,
  1231. zsubgap(tp->start[tewhichline(tp,
  1232. zaddgap(tp->foc),
  1233. tp->focprev)]),
  1234. -1);
  1235. break;
  1236. }
  1237. case 'B'-'@': /* ^B back a character */
  1238. tearrow(help_ew->tp, WC_LEFT);
  1239. break;
  1240. case 'E'-'@': /* ^E end of line */
  1241. {
  1242. TEXTEDIT* tp = help_ew->tp;
  1243. int line = tewhichline(tp, zaddgap(tp->foc), tp->focprev);
  1244. int xxx = zsubgap(tetextround(tp, line, tp->right));
  1245. tesetfocus(tp, xxx, -1);
  1246. break;
  1247. }
  1248. case 'F'-'@': /* ^F forward a character */
  1249. tearrow(help_ew->tp, WC_RIGHT);
  1250. break;
  1251. case 'K'-'@': /* ^K is Page up */
  1252. {
  1253. int i;
  1254. int j;
  1255. wgetdefwinsize(&i, &j);
  1256. j = j/wlineheight() -1;
  1257. for (i=0; i<j; i++) tearrow(help_ew->tp, WC_UP);
  1258. break;
  1259. }
  1260. case 'N'-'@': /* ^N next line */
  1261. tearrow(help_ew->tp, WC_DOWN);
  1262. break;
  1263. case 'P'-'@': /* ^P previous line */
  1264. tearrow(help_ew->tp, WC_UP);
  1265. break;
  1266. case 'Z'-'@': /* ^Z move to end of buffer */
  1267. {
  1268. TEXTEDIT* tp = help_ew->tp;
  1269. tesetfocus(tp, tp->buflen - tp->gaplen, -1);
  1270. break;
  1271. }
  1272. case 'V'-'@': /* ^V page down */
  1273. case ' ':
  1274. case 'L'-'@': /* ^L is Page down */
  1275. {
  1276. int i;
  1277. int j;
  1278. wgetdefwinsize(&i, &j);
  1279. j = j/wlineheight() -1;
  1280. for (i=0; i<j; i++) tearrow(help_ew->tp, WC_DOWN);
  1281. break;
  1282. }
  1283. case 'i':
  1284. case 'I':
  1285. {
  1286. char buf[40];
  1287. int len;
  1288. if (waskstr("Help on topic", buf, 40)) {
  1289. len = strlen(buf);
  1290. help_buffer(buf, len);
  1291. }
  1292. break;
  1293. }
  1294. case 'n':
  1295. case 'N':
  1296. {
  1297. extern char *strstr(const char*, const char*);
  1298. char *p = strstr((const char*)help_buff, (const char*)"Next: ");
  1299. int i = 0;
  1300. if (p == NULL) {
  1301. wfleep(); break;
  1302. }
  1303. p += 6;
  1304. while (p[i]!= ',') i++;
  1305. help_buffer(p,i);
  1306. break;
  1307. }
  1308. case 'p':
  1309. case 'P':
  1310. {
  1311. extern char *strstr(const char*, const char*);
  1312. char *p = strstr((const char*)help_buff, "Prev: ");
  1313. int i = 0;
  1314. if (p == NULL) {
  1315. wfleep(); break;
  1316. }
  1317. p += 6;
  1318. while (p[i]!= ',') i++;
  1319. help_buffer(p,i);
  1320. break;
  1321. }
  1322. case 'q':
  1323. case 'Q':
  1324. help_ew->saved = TRUE; /* Fake it */
  1325. (*free_hool)(help_buff);
  1326. ewclose(help_ew);
  1327. help_ew = 0;
  1328. break;
  1329. case 'u':
  1330. case 'U':
  1331. {
  1332. extern char *strstr(const char*, const char*);
  1333. char *p = strstr((const char*)help_buff, "Up: ");
  1334. int i = 0;
  1335. if (p == NULL) {
  1336. wfleep(); break;
  1337. }
  1338. p += 4;
  1339. while (p[i]!= '\n') i++;
  1340. help_buffer(p,i);
  1341. break;
  1342. }
  1343. }
  1344. break;
  1345. case WE_MENU:
  1346. switch (e.u.m.id) {
  1347. case ADMIN_MENU:
  1348. switch (e.u.m.item) {
  1349. case MMSaveas:
  1350. ewsaveas(help_ew);
  1351. break;
  1352. case MMHelp:
  1353. if (help_length) helpwindow(0);
  1354. break;
  1355. case MMHelpSel:
  1356. help_selection(ew);
  1357. break;
  1358. case MMHelpAsk:
  1359. {
  1360. char buf[40];
  1361. int len;
  1362. if (waskstr("Help on topic", buf, 40)) {
  1363. len = strlen(buf);
  1364. help_buffer(buf, len);
  1365. }
  1366. break;
  1367. }
  1368. case MMAbort:
  1369. help_ew->saved = TRUE; /* Fake it */
  1370. (*free_hool)(help_buff);
  1371. ewclose(help_ew);
  1372. help_ew = 0;
  1373. break;
  1374. }
  1375. break;
  1376. case EDIT_MENU:
  1377. switch (e.u.m.item) {
  1378. case MMCopy:
  1379. ewcopy(ew);
  1380. break;
  1381. case MMSelAll:
  1382. tesetfocus(ew->tp, 0, tegetlen(ew->tp));
  1383. break;
  1384. }
  1385. break;
  1386. case HELP_MENU:
  1387. helpwindow(e.u.m.item);
  1388. break;
  1389. }
  1390. break;
  1391. case WE_COMMAND:
  1392. switch (e.u.command) {
  1393. case WC_CANCEL:
  1394. interrupt_pending=YES;
  1395. break;
  1396. case WC_RETURN:
  1397. help_selection(ew);
  1398. break;
  1399. case WC_DEL:
  1400. case WC_BACKSPACE:
  1401. helpwindow(0);
  1402. break;
  1403. default:
  1404. ewevent(ew, &e, &closed);
  1405. break;
  1406. }
  1407. if (e.u.command != WC_CLOSE) {
  1408. break;
  1409. }
  1410. case WE_CLOSE:
  1411. help_ew->saved = TRUE; /* Fake it */
  1412. (*free_hool)(help_buff);
  1413. ewclose(help_ew);
  1414. help_ew = 0;
  1415. break;
  1416. default:
  1417. ewevent(ew, &e, &closed);
  1418. if (closed) {
  1419. help_ew->saved = TRUE; /* Fake it */
  1420. (*free_hool)(help_buff);
  1421. ewclose(help_ew);
  1422. help_ew = 0;
  1423. }
  1424. break;
  1425. }
  1426. }
  1427. else if (ew != NULL) ewevent(ew, &e, &closed);
  1428. else wfleep();
  1429. fixmenus();
  1430. }
  1431. }
  1432. void poll_for_attn(void)
  1433. {
  1434. EVENT e;
  1435. EDITWIN *ew;
  1436. /* putc('#', stderr); */
  1437. if (!pause_set) {
  1438. if (!wpollevent(&e)) {
  1439. /* putc('<', stderr); */
  1440. return;
  1441. }
  1442. }
  1443. else wgetevent(&e);
  1444. /* fprintf(stderr, "PollEvent: type=%d win=%p data=%d\n", e.type,e.window,e.u.command); */
  1445. for (;;) { /* Loop while there are events */
  1446. CSLbool closed;
  1447. ew = ewfind(e.window);
  1448. if (ew == CSL_ew) {
  1449. switch (e.type) {
  1450. case WE_CHAR:
  1451. switch(e.u.character) {
  1452. case 'A'-'@': /* ^A == beginning of line */
  1453. {
  1454. TEXTEDIT* tp = CSL_ew->tp;
  1455. tesetfocus(tp,
  1456. zsubgap(tp->start[tewhichline(tp,
  1457. zaddgap(tp->foc),
  1458. tp->focprev)]),
  1459. -1);
  1460. break;
  1461. }
  1462. case 'B'-'@': /* ^B back a character */
  1463. tearrow(CSL_ew->tp, WC_LEFT);
  1464. break;
  1465. case 'D'-'@': /* ^D delete at cursor */
  1466. {
  1467. TEXTEDIT* tp = CSL_ew->tp;
  1468. tearrow(tp, WC_RIGHT);
  1469. e.type = WE_COMMAND;
  1470. e.u.command = WC_BACKSPACE;
  1471. ewevent(ew,&e, NULL);
  1472. break;
  1473. }
  1474. case 'E'-'@': /* ^E end of line */
  1475. {
  1476. TEXTEDIT* tp = CSL_ew->tp;
  1477. int line = tewhichline(tp, zaddgap(tp->foc), tp->focprev);
  1478. int xxx = zsubgap(tetextround(tp, line, tp->right));
  1479. tesetfocus(tp, xxx, -1);
  1480. break;
  1481. }
  1482. case 'F'-'@': /* ^F forward a character */
  1483. tearrow(CSL_ew->tp, WC_RIGHT);
  1484. break;
  1485. case 'K'-'@': /* ^K kill all type ahead */
  1486. tty_index = 0;
  1487. break;
  1488. case 'N'-'@': /* ^N next line */
  1489. tearrow(CSL_ew->tp, WC_DOWN);
  1490. break;
  1491. case 'P'-'@': /* ^P previous line */
  1492. tearrow(CSL_ew->tp, WC_UP);
  1493. break;
  1494. case 'Z'-'@': /* ^Z move to end of buffer */
  1495. {
  1496. TEXTEDIT* tp = CSL_ew->tp;
  1497. tesetfocus(tp, tp->buflen - tp->gaplen, -1);
  1498. break;
  1499. }
  1500. case 'V'-'@': /* ^V page down */
  1501. case ' ':
  1502. {
  1503. int i;
  1504. int j;
  1505. wgetdefwinsize(&i, &j);
  1506. j = j/wlineheight() -1;
  1507. for (i=0; i<j; i++) tearrow(help_ew->tp, WC_DOWN);
  1508. break;
  1509. }
  1510. default:
  1511. if (tty_index > TTYBUF_SIZE-2) wfleep();
  1512. else tty_buff[tty_index++] = e.u.character;
  1513. break;
  1514. }
  1515. break;
  1516. case WE_COMMAND:
  1517. switch (e.u.command) {
  1518. case WC_CANCEL:
  1519. interrupt_pending = YES;
  1520. break;
  1521. case WC_CLOSE:
  1522. pause_for_user();
  1523. exit(1);
  1524. case WC_RETURN:
  1525. if (tty_index > TTYBUF_SIZE-2) wfleep();
  1526. else tty_buff[tty_index++] = '\n';
  1527. break;
  1528. case WC_TAB:
  1529. if (tty_index > TTYBUF_SIZE-2) wfleep();
  1530. else tty_buff[tty_index++] = '\t';
  1531. break;
  1532. case WC_DEL:
  1533. case WC_BACKSPACE:
  1534. if (tty_index>0) tty_index--;
  1535. break;
  1536. }
  1537. break;
  1538. case WE_MENU:
  1539. switch (e.u.m.id) {
  1540. case ADMIN_MENU:
  1541. switch (e.u.m.item) {
  1542. case MMHelp:
  1543. helpwindow(0);
  1544. break;
  1545. case MMHelpSel:
  1546. help_selection(ew);
  1547. break;
  1548. case MMAbort:
  1549. pause_for_user();
  1550. exit(1);
  1551. case MMInt:
  1552. interrupt_pending = YES;
  1553. return;
  1554. case MMPause:
  1555. pause_set = !pause_set;
  1556. wmenucheck(adminmenu, MMPause, pause_set);
  1557. if (pause_set) wsettitle(CSL_window, "<Paused> Reduce 3.6");
  1558. else wsettitle(CSL_window, "Reduce 3.6");
  1559. break;
  1560. }
  1561. break;
  1562. case EDIT_MENU:
  1563. switch (e.u.m.item) {
  1564. case MMCopy:
  1565. ewcopy(ew);
  1566. break;
  1567. case MMPaste:
  1568. break;
  1569. case MMCut:
  1570. ewcopy(ew);
  1571. case MMClear:
  1572. ewreplace(ew, "");
  1573. break;
  1574. case MMSelAll:
  1575. tesetfocus(ew->tp, 0, tegetlen(ew->tp));
  1576. break;
  1577. }
  1578. break;
  1579. case HELP_MENU:
  1580. helpwindow(e.u.m.item);
  1581. break;
  1582. }
  1583. break;
  1584. case WE_CLOSE:
  1585. pause_for_user();
  1586. exit(1);
  1587. default:
  1588. ewevent(ew, &e, &closed);
  1589. break;
  1590. }
  1591. }
  1592. else if (ew == help_ew) {
  1593. switch (e.type) {
  1594. case WE_MOUSE_UP: /* Extend to a word on single click */
  1595. if (!ew->tp->mdown)
  1596. break;
  1597. ew->tp->mdown= FALSE;
  1598. if (e.u.where.clicks > 1) {
  1599. teclicknew(ew->tp, e.u.where.h, e.u.where.v, FALSE, TRUE);
  1600. help_selection(ew);
  1601. }
  1602. break;
  1603. case WE_CHAR:
  1604. /* fprintf(stderr, "WE_CHAR %d(%c)\n", e.u.character,e.u.character); */
  1605. switch(e.u.character) {
  1606. case 'A'-'@': /* ^A == beginning of line */
  1607. {
  1608. TEXTEDIT* tp = help_ew->tp;
  1609. tesetfocus(tp,
  1610. zsubgap(tp->start[tewhichline(tp,
  1611. zaddgap(tp->foc),
  1612. tp->focprev)]),
  1613. -1);
  1614. break;
  1615. }
  1616. case 'B'-'@': /* ^B back a character */
  1617. tearrow(help_ew->tp, WC_LEFT);
  1618. break;
  1619. case 'E'-'@': /* ^E end of line */
  1620. {
  1621. TEXTEDIT* tp = help_ew->tp;
  1622. int line = tewhichline(tp, zaddgap(tp->foc), tp->focprev);
  1623. int xxx = zsubgap(tetextround(tp, line, tp->right));
  1624. tesetfocus(tp, xxx, -1);
  1625. break;
  1626. }
  1627. case 'F'-'@': /* ^F forward a character */
  1628. tearrow(help_ew->tp, WC_RIGHT);
  1629. break;
  1630. case 'N'-'@': /* ^N next line */
  1631. tearrow(help_ew->tp, WC_DOWN);
  1632. break;
  1633. case 'P'-'@': /* ^P previous line */
  1634. tearrow(help_ew->tp, WC_UP);
  1635. break;
  1636. case 'Z'-'@': /* ^Z move to end of buffer */
  1637. {
  1638. TEXTEDIT* tp = help_ew->tp;
  1639. tesetfocus(tp, tp->buflen - tp->gaplen, -1);
  1640. break;
  1641. }
  1642. case 'L'-'@': /* ^L is PgDn */
  1643. case 'V'-'@': /* ^V page down */
  1644. case ' ':
  1645. {
  1646. int i;
  1647. int j;
  1648. wgetdefwinsize(&i, &j);
  1649. j = j/wlineheight() -1;
  1650. for (i=0; i<j; i++) tearrow(help_ew->tp, WC_DOWN);
  1651. break;
  1652. }
  1653. case 'K'-'@': /* ^K is PgUp */
  1654. {
  1655. int i;
  1656. int j;
  1657. wgetdefwinsize(&i, &j);
  1658. j = j/wlineheight() -1;
  1659. for (i=0; i<j; i++) tearrow(help_ew->tp, WC_UP);
  1660. break;
  1661. }
  1662. }
  1663. break;
  1664. case WE_MENU:
  1665. switch (e.u.m.id) {
  1666. case ADMIN_MENU:
  1667. switch (e.u.m.item) {
  1668. case MMHelp:
  1669. if (help_length) helpwindow(0);
  1670. break;
  1671. case MMHelpSel:
  1672. help_selection(ew);
  1673. break;
  1674. }
  1675. break;
  1676. case EDIT_MENU:
  1677. switch (e.u.m.item) {
  1678. case MMCopy:
  1679. ewcopy(ew);
  1680. break;
  1681. case MMSelAll:
  1682. tesetfocus(ew->tp, 0,
  1683. tegetlen(ew->tp));
  1684. break;
  1685. }
  1686. break;
  1687. case HELP_MENU:
  1688. helpwindow(e.u.m.item);
  1689. break;
  1690. }
  1691. break;
  1692. case WE_COMMAND:
  1693. switch (e.u.command) {
  1694. case WC_CANCEL:
  1695. interrupt_pending = YES;
  1696. break;
  1697. case WC_RETURN:
  1698. help_selection(ew);
  1699. break;
  1700. case WC_DEL:
  1701. case WC_BACKSPACE:
  1702. helpwindow(0);
  1703. break;
  1704. default:
  1705. ewevent(ew, &e, &closed);
  1706. break;
  1707. }
  1708. if (e.u.command != WC_CLOSE) {
  1709. break;
  1710. }
  1711. case WE_CLOSE:
  1712. help_ew->saved = TRUE; /* Fake it */
  1713. (*free_hool)(help_buff);
  1714. ewclose(help_ew);
  1715. help_ew = 0;
  1716. break;
  1717. default:
  1718. ewevent(ew, &e, &closed);
  1719. if (closed) {
  1720. help_ew->saved = TRUE; /* Fake it */
  1721. (*free_hool)(help_buff);
  1722. ewclose(help_ew);
  1723. help_ew = 0;
  1724. }
  1725. break;
  1726. }
  1727. }
  1728. else if (ew != NULL) ewevent(ew, &e, &closed);
  1729. else wfleep();
  1730. fixmenus();
  1731. /* putc('#', stderr); */
  1732. if (!pause_set) {
  1733. if (!wpollevent(&e)) {
  1734. /* putc('<', stderr); */
  1735. return;
  1736. }
  1737. }
  1738. else wgetevent(&e);
  1739. /* fprintf(stderr, "PollEvent: type=%d win=%p data=%d\n", e.type,e.window,e.u.command); */
  1740. }
  1741. }
  1742. void flush_screen(void)
  1743. {
  1744. TEXTEDIT* tp = CSL_ew->tp;
  1745. if (stdout_n != 0) {
  1746. /* fprintf(stderr, stdout_buffer); */
  1747. ewreplace(CSL_ew, stdout_buffer);
  1748. stdout_n = 0; stdout_p = stdout_buffer;
  1749. }
  1750. if (tp->nlines > max_nlines+5) { /* Allow a five line slop */
  1751. techangefocus(tp, 0, zsubgap(tp->start[tp->nlines-max_nlines]));
  1752. tp->aim= UNDEF;
  1753. tp->focprev= FALSE;
  1754. /* ewreplace(CSL_ew, ""); */
  1755. tereplace(tp, "");
  1756. /* fprintf(stderr, "-> %d\n", tp->nlines); */
  1757. /* focus to end */
  1758. tesetfocus(tp, tp->buflen - tp->gaplen, -1);
  1759. }
  1760. wupdate(CSL_window);
  1761. wflush();
  1762. }
  1763. static clock_t prev_clock = 0;
  1764. void accept_tick(void)
  1765. {
  1766. clock_t c0 = clock();
  1767. remove_ticker();
  1768. if (c0 > prev_clock + CLOCKS_PER_SEC) {
  1769. /*
  1770. * Time spent doing all of this is counted as "overhead" or "system time"
  1771. * and not included in the times that I will report to my users...
  1772. */
  1773. if (clock_stack == &consolidated_time[0]) {
  1774. consolidated_time[0] +=
  1775. ((double)(clock_t)(c0 - base_time))/((double)CLOCKS_PER_SEC);
  1776. base_time = clock();
  1777. }
  1778. report_time((int)(100.0*consolidated_time[0]), (int)(100.0*gc_time));
  1779. }
  1780. push_clock();
  1781. wupdate(CSL_window);
  1782. poll_for_attn();
  1783. polltick_pending = NO;
  1784. ensure_screen();
  1785. add_ticker();
  1786. pop_clock();
  1787. return;
  1788. }
  1789. static char time_string[32], space_string[32];
  1790. void report_time(int32 t, int32 gct)
  1791. {
  1792. sprintf(time_string, "%d.%.2d secs", t/100, t%100);
  1793. wmenusetitem(adminmenu, MMTime, time_string);
  1794. sprintf(time_string, "+ %d.%.2d secs", gct/100, gct%100);
  1795. wmenusetitem(adminmenu, MMOTime, time_string);
  1796. }
  1797. void report_space(int gc_count, double percent)
  1798. {
  1799. sprintf(space_string, "[GC %d]:%.2f%%", gc_count, percent);
  1800. wmenusetitem(adminmenu, MMSpace, space_string);
  1801. }
  1802. void pause_for_user(void)
  1803. /*
  1804. * This is called at the end of a run so that the user gets a chance to read
  1805. * the final screen-full of output. It pops up a dialog box that will
  1806. * wait for a button push. I take the view that if output is going to a
  1807. * file then the delay is not needed, since the user can always check for
  1808. * messages there. This has the effect that non-interactive build sequences
  1809. * will often run without the pause - a good thing! Note however that this
  1810. * mean that you MUST use the close box to exit from a wimp session. Just
  1811. * "quit;" or "(stop 0)" will not do.
  1812. */
  1813. {
  1814. remove_ticker();
  1815. ensure_screen();
  1816. CSL_ew->saved = TRUE; /* Fake it */
  1817. if (spool_file != NULL) return;
  1818. /*
  1819. * Here I just loop handling events until the user hits the CLOSE box
  1820. * on my window.
  1821. */
  1822. wmessage("Leaving Reduce 3.6");
  1823. ewclose(CSL_ew);
  1824. wdone();
  1825. }
  1826. int wimpget(char *tty_buffer)
  1827. /*
  1828. * This is the main call from the body of CSL into the window manager
  1829. * to obtain input from the user. It is expected to copy some input
  1830. * characters into tty_buffer and return the number of characters
  1831. * provided. In this implementation I read the text back from the
  1832. * stdwin textedit buffer, looking rather too low.
  1833. * Any type ahead is handled in here.
  1834. */
  1835. {
  1836. TEXTEDIT* tp = CSL_ew->tp;
  1837. int i;
  1838. int n;
  1839. int lineno;
  1840. tty_nnl = 1; /* Offset from nlines */
  1841. push_clock();
  1842. remove_ticker();
  1843. if (stdout_n != 0) flush_screen();
  1844. wmenuattach(CSL_window, loadmenu);
  1845. wmenuattach(CSL_window, libmenu);
  1846. wmenuattach(CSL_window, switchmenu);
  1847. lineno = tp->nlines-1; /* Need to do this after the toend */
  1848. tty_offset = tp->foc - tp->start[lineno];
  1849. if (tty_offset<0) tty_offset += tp->gaplen;
  1850. wmenuenable(adminmenu, MMPause, NO);
  1851. if(tty_index>0) {
  1852. int i = 0;
  1853. for (; i<tty_index; i++)
  1854. if (tty_buff[i] == '\n') tty_nnl++;
  1855. tty_buff[tty_index] = '\0';
  1856. ewreplace(CSL_ew, tty_buff);
  1857. tty_index = 0;
  1858. }
  1859. event_loop();
  1860. /* fprintf(stderr, "Event loop ended\n"); */
  1861. lineno = tp->nlines-tty_nnl;
  1862. /* printf("Offset=%d Length=%d\n",tty_offset,tp->foc-tp->start[lineno]-tty_offset); */
  1863. /* for (i=0; i<tp->foc- tp->start[lineno]-tty_offset; i++) { */
  1864. /* printf("%c", *(tegettext(tp)+tp->start[lineno]+tty_offset+i)); */
  1865. /* } */
  1866. /* printf("\n"); */
  1867. memcpy(tty_buffer, tegettext(tp)+tp->start[lineno]+tty_offset,
  1868. tp->foc- tp->start[lineno]-tty_offset);
  1869. wmenudetach(CSL_window, loadmenu);
  1870. wmenudetach(CSL_window, libmenu);
  1871. wmenudetach(CSL_window, switchmenu);
  1872. wmenuenable(adminmenu, MMPause, YES);
  1873. add_ticker();
  1874. n = tp->foc- tp->start[lineno]-tty_offset;
  1875. if (n<0) {
  1876. n += tp->gaplen;
  1877. fprintf(stderr, "N correction\n");
  1878. }
  1879. tty_ready = NO;
  1880. pop_clock();
  1881. return n;
  1882. }
  1883. int char_cnt = 0;
  1884. void putc_stdout(int c)
  1885. {
  1886. *stdout_p++ = c;
  1887. *stdout_p = 0;
  1888. stdout_n++;
  1889. char_cnt++;
  1890. remove_ticker();
  1891. if (c == '\n' || stdout_n > STDOUT_BUFSIZE - LONGEST_PRINTF) {
  1892. push_clock(); flush_screen();
  1893. if (char_cnt>200) { /* Where 200 is a random number */
  1894. poll_for_attn(); char_cnt = 0;
  1895. }
  1896. pop_clock();
  1897. }
  1898. add_ticker();
  1899. }
  1900. void vfprintf_stdout(char *fmt, va_list a)
  1901. {
  1902. int n;
  1903. /*
  1904. * I have given myself LONGEST_PRINTF locations in the array for
  1905. * this vsprintf to fill in. If it overflows I am in big trouble!
  1906. */
  1907. n = vsprintf(stdout_p, fmt, a);
  1908. stdout_p += n;
  1909. stdout_n += n;
  1910. char_cnt += n;
  1911. remove_ticker();
  1912. if (stdout_n > STDOUT_BUFSIZE - LONGEST_PRINTF) {
  1913. push_clock(); flush_screen();
  1914. if (char_cnt>200) {
  1915. poll_for_attn(); char_cnt = 0;
  1916. }
  1917. pop_clock();
  1918. }
  1919. add_ticker();
  1920. }
  1921. /* end of sysxwin.c */