syscwin.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978
  1. /* syscwin.c Copyright (C) 1989-96 Codemist Ltd */
  2. /*
  3. * Windows 95 and NT support, using MFC via the "cwin" package.
  4. * Should also be OK for Windows 3.x if "win32s" is used.
  5. */
  6. /* Signature: 0da77977 07-Mar-2000 */
  7. #include <stdarg.h>
  8. #include <string.h>
  9. #include <ctype.h>
  10. #include <time.h>
  11. #include <math.h>
  12. #ifdef __cplusplus
  13. #include <afxwin.h>
  14. #else
  15. #include <windows.h>
  16. #endif
  17. #include "machine.h"
  18. #include "tags.h"
  19. #include "externs.h"
  20. #include "read.h"
  21. #include "cslerror.h"
  22. #include "sys.h"
  23. #ifdef TIMEOUT
  24. #include "timeout.h"
  25. #endif
  26. #ifdef __WATCOMC__
  27. #include <float.h>
  28. #endif
  29. #include <errno.h>
  30. #include <io.h>
  31. #include <dos.h>
  32. #include <direct.h>
  33. #include <sys\stat.h>
  34. #ifdef _MSC_VER
  35. #define strdup(x) _strdup(x)
  36. #endif
  37. #ifndef SOFTWARE_TICKS
  38. void CALLBACK deal_with_tick(UINT idevent, UINT x1, DWORD x2, DWORD x3, DWORD x4)
  39. /*
  40. * A timer arranges to call me back kere about 5 times per second.
  41. * Since this call is not synchronised with anything else all I do is
  42. * set flags that will be looked at by other bits of code.
  43. */
  44. {
  45. if (tick_pending == 0)
  46. {
  47. if (already_in_gc) tick_on_gc_exit = YES;
  48. else
  49. { Lisp_Object nil = C_nil;
  50. CSLbool xxx = NO;
  51. if (exception_pending()) flip_exception(), xxx = YES;
  52. tick_pending = YES;
  53. saveheaplimit = heaplimit;
  54. heaplimit = fringe;
  55. savevheaplimit = vheaplimit;
  56. vheaplimit = vfringe;
  57. savecodelimit = codelimit;
  58. codelimit = codefringe;
  59. savestacklimit = stacklimit;
  60. stacklimit = stackbase;
  61. if (xxx) flip_exception();
  62. }
  63. }
  64. }
  65. #endif
  66. static CSLbool ticker_active = NO;
  67. void add_ticker(void)
  68. {
  69. if (ticker_active) return;
  70. #ifdef SOFTWARE_TICKS
  71. countdown = SOFTWARE_TICKS;
  72. #else
  73. /*
  74. * I take an interrupt 5 times per second...
  75. */
  76. // my_timer = SetTimer(my_window, (UINT)1, (UINT)200,
  77. // (TIMERPROC)deal_with_tick);
  78. timeBeginPeriod(200);
  79. my_timer = timeSetEvent(200, 200, (LPTIMECALLBACK)deal_with_tick,
  80. 0, TIME_PERIODIC);
  81. if (my_timer == 0)
  82. { alert_box("Failed to start up the timer");
  83. ticker_active = NO; /* Actually a shambles */
  84. }
  85. else
  86. #endif
  87. ticker_active = YES;
  88. }
  89. void MS_CDECL remove_ticker(void)
  90. {
  91. if (!ticker_active) return;
  92. #ifndef SOFTWARE_TICKS
  93. // KillTimer(my_window, my_timer);
  94. timeKillEvent(my_timer);
  95. timeEndPeriod(200);
  96. #endif
  97. ticker_active = NO;
  98. }
  99. /*
  100. * void poll_for_attn()
  101. * {
  102. * kbhit(); // causes ^C to be noticed!
  103. * }
  104. */
  105. static clock_t prev_clock = 0;
  106. #ifdef INITIAL_SOFTWARE_TICKS
  107. int32 software_ticks = INITIAL_SOFTWARE_TICKS;
  108. int32 software_tick_count = 0, prev_software_tick_count = 0;
  109. #endif
  110. void accept_tick(void)
  111. {
  112. /*
  113. * This is where I can put things that need to be done regularly. At
  114. * In particular I can poll the window manager here.
  115. */
  116. /*
  117. * Around once per 2 seconds I update the clock display on the menu bar -
  118. * the intent of this is to give a bit of feedback to the user that
  119. * things are happening. NOTE WELL: I tune all this in terms of CPU time
  120. * (measured with clock()) rather than wall-clock time (time()). On
  121. * a multi-tasking system this means that a Lisp task running at low
  122. * priority in the background will hardly poll at all, and one that is
  123. * suspended (if such a possibility can arise) will not do a lot. But
  124. * I HOPE that CPU time is not consumed while one is suspended awaiting
  125. * keyboard input, and so that sort of delay should not cause messups
  126. * in my "learning" of the correct poll rate.
  127. */
  128. clock_t t0 = clock();
  129. #ifdef SOFTWARE_TICKS_PER_SECOND
  130. software_tick_count++;
  131. #endif
  132. if (prev_clock == 0 || t0 > prev_clock + 2*CLOCKS_PER_SEC)
  133. { long int t, gct;
  134. Lisp_Object nil;
  135. ensure_screen(); nil = C_nil;
  136. if (exception_pending()) return;
  137. #ifdef SOFTWARE_TICKS_PER_SECOND
  138. if (prev_clock != 0)
  139. { double t1 = (double)(t0-prev_clock)/(double)CLOCKS_PER_SEC;
  140. double ratio =
  141. (double)(software_tick_count - prev_software_tick_count)/t1;
  142. int32 w;
  143. /*
  144. * t1 is how long since I was last here, ratio is the number of
  145. * ticks per second over that time-span.
  146. */
  147. ratio = ratio / (double)SOFTWARE_TICKS_PER_SECOND;
  148. prev_software_tick_count = software_tick_count;
  149. /*
  150. * Now ratio is the extent by which I was taking ticks too fast.
  151. * To dampen out my correction I will scale software_ticks by the
  152. * square root of this.
  153. */
  154. ratio = sqrt(ratio);
  155. w = (int)(1000.0 * ratio);
  156. /*
  157. * I clamp the correction fator so I never adjust my clock rate by
  158. * a factor of more than (about) 3.
  159. */
  160. if (w > 3000) w = 3000;
  161. else if (w < 300) w = 300;
  162. /*
  163. * Furthermore I attempt to keep software_ticks within integer range.
  164. */
  165. if (software_ticks < (0x7fffffff/3000) &&
  166. software_ticks > 50)
  167. software_ticks = (w*software_ticks)/1000;
  168. }
  169. #endif
  170. t0 = clock();
  171. if (clock_stack == &consolidated_time[0])
  172. { consolidated_time[0] +=
  173. (double)(t0 - base_time)/(double)CLOCKS_PER_SEC;
  174. base_time = t0;
  175. }
  176. t = (long int)(100.0 * consolidated_time[0]);
  177. gct = (long int)(100.0 * gc_time);
  178. report_time(t, gct);
  179. prev_clock = t0;
  180. }
  181. cwin_poll_window_manager();
  182. if (cwin_interrupt_pending != 0)
  183. { Lisp_Object nil = C_nil;
  184. interrupt_pending = YES;
  185. if (exception_pending()) nil = (Lisp_Object)((int32)nil ^ 1);
  186. miscflags |= HEADLINE_FLAG | MESSAGES_FLAG;
  187. cwin_interrupt_pending = 0;
  188. }
  189. }
  190. void putc_stdout(int c)
  191. {
  192. if (alternative_stdout != NULL) putc(c, alternative_stdout);
  193. else cwin_putchar(c);
  194. }
  195. void pause_for_user()
  196. {
  197. }
  198. int pipes_today = 0;
  199. int win32s = 0;
  200. void flush_screen()
  201. {
  202. cwin_ensure_screen();
  203. }
  204. void start_up_window_manager(int use_wimp)
  205. {
  206. int32 n = GetVersion();
  207. switch (n & 0xc0000000)
  208. {
  209. case 0: win32s = 0; /* NT */
  210. pipes_today = 1;
  211. break;
  212. case 0x80000000:
  213. default:
  214. win32s = 1; /* win32s */
  215. pipes_today = 0;
  216. break;
  217. case 0xc0000000:
  218. win32s = 2; /* Windows 95 */
  219. pipes_today = 1;
  220. break;
  221. }
  222. }
  223. int wimpget(char *buf)
  224. {
  225. int c, n=0;
  226. Lisp_Object nil;
  227. ensure_screen(); nil = C_nil;
  228. if (exception_pending()) return 0;
  229. while (n < 255)
  230. { c = cwin_getchar();
  231. nil = C_nil;
  232. if (exception_pending() || c == EOF) return 0;
  233. c = c & 0xff;
  234. buf[n++] = c;
  235. if (c == '\n') break;
  236. };
  237. return n;
  238. }
  239. /*
  240. * Slightly optional jollies re GC statistics...
  241. */
  242. static char time_string[32], space_string[32];
  243. void report_time(int32 t, int32 gct)
  244. {
  245. sprintf(time_string, "%ld.%.2ld+%ld.%.2ld secs ",
  246. t/100L, t%100L, gct/100L, gct%100L);
  247. if ((window_heading & 1) == 0) cwin_report_left(time_string);
  248. }
  249. void report_space(int n, double percent)
  250. {
  251. sprintf(space_string, "[GC %d]:%.2f%%", n, percent);
  252. if ((window_heading & 4) == 0) cwin_report_right(space_string);
  253. }
  254. /*
  255. * End of the worst of the window-manager aware code
  256. */
  257. #undef exit
  258. #define exit(a) my_exit(a)
  259. #include "fileops.c"
  260. #include "scandir.c"
  261. /*
  262. * To the extent that I believe that versions of Windows that support long
  263. * file names are now readily available, and that compatibility with older
  264. * systems is ridiculous, I disable the conversion to 8+3 format shown
  265. * here. The particular bit of sample code that convinced me was attempting
  266. * to create files with names like xxx.html where each file contained the
  267. * names of other files in the set. And truncation to xxx.htm meant that the
  268. * cross-references failed. Ugh.
  269. */
  270. #ifdef EIGHT_PLUS_THREE
  271. /*
  272. * Windows 95 can support long file names, but Windows 3.x and DOS do not.
  273. * This is in fact a potential cause of big mess. What I do here is to
  274. * truncate all file-names to 8+3 format. The effect will be that if files
  275. * have been set up for use with Windows 3.x they will still work, and files
  276. * created by and used ONLY by this system will be OK. But if a Windows-95
  277. * utility is used to create a file with a long name then I will not be able
  278. * to use that name to access it. Users beware!
  279. */
  280. static void eight_plus_three(char *s)
  281. {
  282. int c, i=0;
  283. char *p=s;
  284. while ((c=*p++)!=0 && c!='.' && c!='\\' && c!=':') i++;
  285. if (c==':') return;
  286. if (i>8)
  287. { char *q=s+8;
  288. p--;
  289. while ((*q++=*p++)!=0);
  290. p=s+9;
  291. }
  292. if (c!='.') return;
  293. i=0;
  294. s=p;
  295. while ((c=*p++)!=0 && c!='\\') i++;
  296. if (i>3)
  297. { char *q=s+3;
  298. p--;
  299. while ((*q++=*p++)!=0);
  300. }
  301. }
  302. #endif
  303. #include "filename.c"
  304. int change_directory(char *filename, char *old, size_t n)
  305. {
  306. process_file_name(filename, old, n);
  307. if (*filename == 0) return 1;
  308. #ifdef _MSC_VER
  309. if (_chdir(filename))
  310. #else
  311. if (chdir(filename))
  312. #endif
  313. { char err_buf[LONGEST_LEGAL_FILENAME+100];
  314. switch (errno)
  315. {
  316. case ENOENT:
  317. sprintf(err_buf,"The directory %s does not exist.",filename);
  318. break;
  319. default:
  320. sprintf(err_buf,"Cannot change directory to %s.",filename);
  321. break;
  322. }
  323. aerror0(err_buf);
  324. return 1;
  325. }
  326. else return 0;
  327. }
  328. int create_directory(char *filename, char *old, size_t n)
  329. {
  330. process_file_name(filename, old, n);
  331. if (*filename == 0) return 1;
  332. #ifdef _MSC_VER
  333. return _mkdir(filename);
  334. #else
  335. return mkdir(filename);
  336. #endif
  337. }
  338. CSLbool file_exists(char *filename, char *old, size_t n, char *tt)
  339. {
  340. #ifdef _MSC_VER
  341. struct _stat statbuff;
  342. #else
  343. struct stat statbuff;
  344. #endif
  345. process_file_name(filename, old, n);
  346. if (*filename == 0) return NO;
  347. #ifdef _MSC_VER
  348. if (_stat(filename, &statbuff) != 0) return NO;
  349. #else
  350. if (stat(filename, &statbuff) != 0) return NO;
  351. #endif
  352. strcpy(tt, ctime(&(statbuff.st_mtime)));
  353. return YES;
  354. }
  355. static void remove_files(char *name, int dirp, long int size)
  356. /*
  357. * Remove a file, or a directory and all its contents. This function
  358. * can still misbehave if you do not have write access to all the files
  359. * involved.
  360. */
  361. {
  362. size = size;
  363. switch (dirp)
  364. {
  365. case SCAN_ENDDIR:
  366. #ifdef _MSC_VER
  367. _rmdir(name); return;
  368. #else
  369. rmdir(name); return;
  370. #endif
  371. case SCAN_FILE:
  372. remove(name); return;
  373. }
  374. }
  375. int delete_file(char *filename, char *old, size_t n)
  376. {
  377. process_file_name(filename, old, n);
  378. if (*filename == 0) return 1;
  379. scan_directory(filename, remove_files);
  380. return 0;
  381. }
  382. int directoryp(char *filename, char *old, size_t n)
  383. {
  384. process_file_name(filename, old, n);
  385. if (*filename == 0) return 0;
  386. return (GetFileAttributes(filename) == FILE_ATTRIBUTE_DIRECTORY);
  387. }
  388. extern char *get_truename(char *filename, char *old, size_t n)
  389. {
  390. #ifdef _MSC_VER
  391. struct _stat buf;
  392. #else
  393. struct stat buf;
  394. #endif
  395. char *temp, *fn, *dir, *pwd;
  396. process_file_name(filename, old, n);
  397. if (*filename == 0) aerror("truename");
  398. /* Find out whether we have a file or a directory. Be careful in case
  399. * the first two characters define a drive.
  400. */
  401. if (0 /* strlen(filename) > 2 && *(filename+1) == ':' */)
  402. {
  403. /*
  404. * Again beware the fact that aerror0 does not change the flow of control.
  405. */
  406. #ifdef _MSC_VER
  407. if (_stat(filename+2,&buf) == -1) aerror0("truename: cannot stat file");
  408. #else
  409. if (stat(filename+2,&buf) == -1) aerror0("truename: cannot stat file");
  410. #endif
  411. }
  412. else
  413. {
  414. #ifdef _MSC_VER
  415. if (_stat(filename,&buf) == -1) aerror0("truename: cannot stat file");
  416. #else
  417. if (stat(filename,&buf) == -1) aerror0("truename: cannot stat file");
  418. #endif
  419. }
  420. /* Store current directory */
  421. #ifdef _MSC_VER
  422. if ((pwd = (char *)_getcwd((char *)NULL, LONGEST_LEGAL_FILENAME)) == NULL)
  423. #else
  424. if ((pwd = (char *)getcwd((char *)NULL, LONGEST_LEGAL_FILENAME)) == NULL)
  425. #endif
  426. aerror0("truename: cannot get current working directory");
  427. if ((buf.st_mode & S_IFMT) == S_IFDIR)
  428. { /* We have a directory */
  429. char *dir = (char*) malloc(LONGEST_LEGAL_FILENAME);
  430. #ifdef _MSC_VER
  431. if (_chdir(filename) != 0)
  432. aerror0("truename: cannot change directory");
  433. if (_getcwd(dir ,LONGEST_LEGAL_FILENAME) == NULL)
  434. aerror0("truename: cannot get current working directory");
  435. if (_chdir(pwd) != 0)
  436. aerror0("truename: cannot change directory");
  437. #else
  438. if (chdir(filename) != 0)
  439. aerror0("truename: cannot change directory");
  440. if (getcwd(dir ,LONGEST_LEGAL_FILENAME) == NULL)
  441. aerror0("truename: cannot get current working directory");
  442. if (chdir(pwd) != 0)
  443. aerror0("truename: cannot change directory");
  444. #endif
  445. free(pwd);
  446. /*
  447. * This is an axiom-specific hack --- it expects that truname
  448. * preserves trailing directory characters.
  449. */
  450. if (old[n-1] == '\\' || old[n-1] == '/' && dir[strlen(dir)-1] != '\\')
  451. { n = strlen(dir);
  452. dir[n] = '\\';
  453. dir[n+1] = '\0';
  454. }
  455. return dir;
  456. }
  457. else
  458. { /* Assume we have some kind of file */
  459. temp = strrchr(filename,'\\');
  460. if (temp)
  461. { /* Found a directory component */
  462. fn = strdup(temp);
  463. *temp = '\0';
  464. /* fn is now "\file" and filename is the directory */
  465. #ifdef _MSC_VER
  466. if (_chdir(filename) != 0)
  467. aerror0("truename: cannot change directory");
  468. if ((temp = (char *)_getcwd((char *)NULL,LONGEST_LEGAL_FILENAME)) == NULL)
  469. aerror0("truename: cannot get current working directory");
  470. if (_chdir(pwd) != 0)
  471. aerror0("truename: cannot change directory");
  472. #else
  473. if (chdir(filename) != 0)
  474. aerror0("truename: cannot change directory");
  475. if ((temp = (char *)getcwd((char *)NULL,LONGEST_LEGAL_FILENAME)) == NULL)
  476. aerror0("truename: cannot get current working directory");
  477. if (chdir(pwd) != 0)
  478. aerror0("truename: cannot change directory");
  479. #endif
  480. dir = (char *)malloc((strlen(temp) + strlen(fn) + 1)*sizeof(char));
  481. strcpy(dir,temp);
  482. free(temp);
  483. strcat(dir, fn);
  484. free(pwd);
  485. free(fn);
  486. return dir;
  487. }
  488. else
  489. { dir = (char *)malloc((strlen(pwd) + strlen(filename) + 2)*sizeof(char));
  490. strcpy(dir, pwd);
  491. strcat(dir, "\\");
  492. strcat(dir,filename);
  493. free(pwd);
  494. return dir;
  495. }
  496. }
  497. }
  498. int get_current_directory(char *s, int n)
  499. {
  500. int n1 = GetCurrentDirectory(n, s);
  501. if (n1 == 0)
  502. { aerror0("cannot get current directory name");
  503. return 0;
  504. }
  505. else if (n1 >= n)
  506. { aerror("the pathname of the current directory is too long");
  507. return 0;
  508. }
  509. else return n1;
  510. }
  511. #ifdef NAG_VERSION
  512. #define MAX_NUMBER_OF_FILES 2048
  513. int list_directory_members(char *filename, char *old, char **filelist[],
  514. size_t n)
  515. { WIN32_FIND_DATA fileData;
  516. HANDLE fileHandle;
  517. int32 number_of_entries = 1;
  518. char **files;
  519. process_file_name(filename, old, n);
  520. if (*filename == 0) strcpy(filename,"*.*");
  521. else if (filename[strlen(filename)-1] != '\\')
  522. filename=strcat(filename,"\\*.*");
  523. else filename=strcat(filename,"*.*");
  524. fileHandle = FindFirstFile(filename,&fileData);
  525. if (fileHandle == INVALID_HANDLE_VALUE) return 0;
  526. /*
  527. * The fixed allocation size here seems unsatisfactory, but I will leave it
  528. * like that for the moment because altering things to behave better would
  529. * probably involve redesigning the interface to this function.
  530. */
  531. files=(char **)malloc(MAX_NUMBER_OF_FILES*sizeof(char *));
  532. files[0]=strdup(fileData.cFileName);
  533. while(FindNextFile(fileHandle,&fileData))
  534. { files[number_of_entries] = strdup(fileData.cFileName);
  535. number_of_entries++;
  536. }
  537. FindClose(fileHandle);
  538. *filelist = files;
  539. return number_of_entries;
  540. }
  541. #else
  542. void list_directory_members(char *filename, char *old,
  543. size_t n, directory_callback *fn)
  544. {
  545. process_file_name(filename, old, n);
  546. scan_files(filename, fn);
  547. }
  548. #endif
  549. /*
  550. * The following few lines are an attempt to provide compatibility
  551. * between Watcom C 11.0 and Microsoft Visual C++ version 5... Both provide
  552. * a stat() function but they use different names for the bits that
  553. * can be used to test if files are readable or writable.
  554. */
  555. #ifndef S_IRUSR
  556. #define S_IRUSR _S_IREAD
  557. #endif
  558. #ifndef S_IWUSR
  559. #define S_IWUSR _S_IWRITE
  560. #endif
  561. int file_readable(char *filename, char *old, size_t n)
  562. {
  563. #ifdef _MSC_VER
  564. struct _stat buf;
  565. #else
  566. struct stat buf;
  567. #endif
  568. process_file_name(filename, old, n);
  569. if (*filename == 0) return 0;
  570. #ifdef _MSC_VER
  571. if (_stat(filename,&buf) == -1)
  572. #else
  573. if (stat(filename,&buf) == -1)
  574. #endif
  575. return 0; /* File probably does not exist */
  576. else
  577. return (buf.st_mode & S_IRUSR);
  578. }
  579. int file_writeable(char *filename, char *old, size_t n)
  580. {
  581. #ifdef _MSC_VER
  582. struct _stat buf;
  583. #else
  584. struct stat buf;
  585. #endif
  586. process_file_name(filename, old, n);
  587. if (*filename == 0) return 0;
  588. #ifdef _MSC_VER
  589. if (_stat(filename,&buf) == -1)
  590. #else
  591. if (stat(filename,&buf) == -1)
  592. #endif
  593. return 0; /* Should we check to see if the directory is writeable? */
  594. else
  595. return (buf.st_mode & S_IWUSR);
  596. }
  597. int rename_file(char *from_name, char *from_old, size_t from_size,
  598. char *to_name, char *to_old, size_t to_size)
  599. {
  600. process_file_name(from_name, from_old, from_size);
  601. process_file_name(to_name, to_old, to_size);
  602. if (*from_name == 0 || *to_name == 0) return 0;
  603. return rename(from_name,to_name);
  604. }
  605. /*
  606. * It appears to me that "system" as provided by the Windows NT SDK
  607. * libraries is a real mess. This is perhaps because executing a
  608. * command might want to generate terminal output, so when one invokes
  609. * "system" it first pops up a console window running the command
  610. * interpreter, then loads the thing you wanted executed, and then
  611. * closes everything down - probably before you have had any real
  612. * chance to observe any output that was generated. I might therefore
  613. * want to invent a version of my own... as in here using CreateProcess.
  614. * The issues about Win32 vs Win32s incompatibilities here are HORRID.
  615. */
  616. int my_system(char *s)
  617. {
  618. #ifdef __WATCOMC__
  619. int i = system(s);
  620. _fpreset();
  621. return i;
  622. #else
  623. STARTUPINFO ss;
  624. PROCESS_INFORMATION pp;
  625. memset(&ss, 0, sizeof(STARTUPINFO));
  626. ss.cb = sizeof(STARTUPINFO);
  627. if (!CreateProcess(NULL, s, NULL, NULL, FALSE, 0, NULL, NULL, &ss, &pp))
  628. return 0;
  629. CloseHandle(pp.hProcess);
  630. CloseHandle(pp.hThread);
  631. return 1;
  632. #endif
  633. }
  634. HWND gnuplot_handle = 0;
  635. BOOL CALLBACK find_text(HWND h, LPARAM x)
  636. {
  637. char buffer[24];
  638. GetClassName(h, buffer, 20);
  639. if (strcmp(buffer, "wgnuplot_text") != 0) return TRUE;
  640. gnuplot_handle = h;
  641. return FALSE;
  642. }
  643. FILE *my_popen(char *command, char *direction)
  644. {
  645. /*
  646. * Here I take a pretty shameless direction and spot the special case of
  647. * opening an output pipe to gnuplot... and hook in a behind-the-scenes
  648. * way.
  649. */
  650. int i = 0, j;
  651. for (;;)
  652. { char *name = "gnuplot";
  653. j = i;
  654. while (*name && tolower(command[j++]) == *name) name++;
  655. if (*name == 0)
  656. { HWND parent;
  657. #ifdef OLD_API
  658. if (WinExec(command, SW_SHOWNORMAL) <= 32) return 0;
  659. #else
  660. /*
  661. * Win32 would rather I used the following long-winded version, which provides
  662. * a pile of generality that is irrelevant here!
  663. */
  664. STARTUPINFO startup;
  665. PROCESS_INFORMATION process;
  666. clock_t t0, t1;
  667. memset(&startup, 0, sizeof(STARTUPINFO));
  668. startup.cb = sizeof(startup);
  669. startup.lpReserved = NULL;
  670. startup.lpDesktop = NULL;
  671. startup.lpTitle = NULL;
  672. startup.dwFlags = STARTF_USESHOWWINDOW;
  673. startup.wShowWindow = SW_SHOWNORMAL;
  674. startup.cbReserved2 = 0;
  675. startup.lpReserved2 = NULL;
  676. if (!CreateProcess(NULL, command, NULL, NULL, FALSE,
  677. 0, NULL, NULL, &startup, &process)) return 0;
  678. #endif
  679. gnuplot_handle = 0;
  680. t0 = clock();
  681. for (i=0; i<25; i++) /* Give it 5 seconds to appear */
  682. { parent = FindWindow((LPSTR)"wgnuplot_parent",
  683. (LPSTR)"gnuplot");
  684. if (parent != 0) break;
  685. t0 += CLOCKS_PER_SEC/5;
  686. while ((t1 = clock()) < t0) cwin_poll_window_manager();
  687. t0 = t1;
  688. }
  689. if (parent != 0)
  690. { for (i=0; i<10; i++) /* 2 more seconds for the child */
  691. { EnumChildWindows(parent, find_text, 0);
  692. if (gnuplot_handle != 0) break;
  693. t0 += CLOCKS_PER_SEC/5;
  694. while ((t1 = clock()) < t0) cwin_poll_window_manager();
  695. t0 = t1;
  696. }
  697. }
  698. return (FILE *)-1; // special handle for the gnuplot pipe
  699. }
  700. i++;
  701. if (command[i] == 0) break;
  702. }
  703. #ifdef __WATCOMC__
  704. CSL_IGNORE(command); CSL_IGNORE(direction);
  705. return 0;
  706. #else
  707. return _popen(command, direction);
  708. #endif
  709. }
  710. int my_pipe_putc(int c, FILE *f)
  711. {
  712. if (f == (FILE *)(-1))
  713. { if (gnuplot_handle == 0) return EOF;
  714. if (c == '\n') c = '\r';
  715. SendMessage(gnuplot_handle, WM_CHAR, c, 1L);
  716. return c;
  717. }
  718. else return putc(c, f);
  719. }
  720. int my_pipe_flush(FILE *f)
  721. {
  722. if (f != (FILE *)(-1)) return fflush(f);
  723. return 0;
  724. }
  725. void my_pclose(FILE *stream)
  726. {
  727. if (stream == (FILE *)(-1))
  728. { SendMessage(gnuplot_handle, WM_CHAR, 'q', 1L);
  729. SendMessage(gnuplot_handle, WM_CHAR, 'u', 1L);
  730. SendMessage(gnuplot_handle, WM_CHAR, 'i', 1L);
  731. SendMessage(gnuplot_handle, WM_CHAR, 't', 1L);
  732. SendMessage(gnuplot_handle, WM_CHAR, '\r', 1L);
  733. return;
  734. }
  735. #ifdef __WATCOMC__
  736. CSL_IGNORE(stream);
  737. #else
  738. _pclose(stream);
  739. #endif
  740. }
  741. char *my_getenv(char *s)
  742. {
  743. /*
  744. * Case fold for MSDOS
  745. */
  746. char uppercase[LONGEST_LEGAL_FILENAME];
  747. int c;
  748. char *p = uppercase;
  749. while ((c = *s++) != 0) *p++ = toupper(c);
  750. *p = 0;
  751. s = uppercase;
  752. return getenv(s);
  753. }
  754. /*
  755. * MSDOS does not support the idea of home directories for
  756. * users, so in case anybody still wants to use the notation "~" that
  757. * would indicate a home directory under Unix I implement something
  758. * in terms of environment variables.
  759. */
  760. int get_home_directory(char *b, int len)
  761. {
  762. /*
  763. * Worry about "len" here...
  764. */
  765. char *w = my_getenv("home");
  766. if (w != NULL) strcpy(b, w);
  767. else strcpy(b, ".");
  768. return strlen(b);
  769. }
  770. int get_users_home_directory(char *b, int len)
  771. {
  772. /*
  773. * Worry about "len" here...
  774. */
  775. char *w, h[LONGEST_LEGAL_FILENAME];
  776. sprintf(h, "home$%s", b);
  777. w = my_getenv(h);
  778. if (w != NULL) strcpy(b, w);
  779. else strcpy(b, ".");
  780. return strlen(b);
  781. }
  782. /*
  783. * The next bit of mess is jolly - I just want to see if stdin has been
  784. * redirected to come from a file, i.e. whether I am interactive in some
  785. * sense. This may be used to decide what to do about error reports etc.
  786. * The IDEA seems generic across most systems, but the details vary in
  787. * frustrating ways.
  788. */
  789. int batchp()
  790. {
  791. return 0; /* !isatty(stdin->_file); */
  792. }
  793. /*
  794. * The next procedure is responsible for establishing information about
  795. * where the main checkpoint image should be recovered from, and where
  796. * and fasl files should come from.
  797. */
  798. char *find_image_directory(int argc, char *argv[])
  799. {
  800. char *w;
  801. int i = strlen(cwin_full_program_name), j;
  802. strcpy(program_name, programName);
  803. CSL_IGNORE(argc); CSL_IGNORE(argv);
  804. /*
  805. * If the current program is called c:\aaa\xxx.exe, then I look
  806. * for a file c:\aaa\xxx.img
  807. */
  808. w = (char *)malloc(i+1);
  809. if (w == NULL)
  810. { fprintf(stderr, "\n+++ Panic - run out of space\n");
  811. my_exit(EXIT_FAILURE);
  812. }
  813. strcpy(w, cwin_full_program_name);
  814. /*
  815. * Windows file-names are not case-sensitive when you search, but
  816. * I think names look neater in lower case so I force things here.
  817. */
  818. for (j=i-4; j>=0; j--)
  819. { if (w[j] == '\\' || w[j] == '/') break;
  820. w[j] = tolower(w[j]);
  821. }
  822. w[i-3] = 'i';
  823. w[i-2] = 'm';
  824. w[i-1] = 'g';
  825. return w;
  826. }
  827. CSLbool sigint_must_longjmp = NO;
  828. jmp_buf sigint_buf;
  829. void MS_CDECL sigint_handler(int code)
  830. {
  831. CSL_IGNORE(code);
  832. interrupt_pending = 1;
  833. if (sigint_must_longjmp)
  834. { sigint_must_longjmp = 0;
  835. longjmp(sigint_buf, 1);
  836. }
  837. return;
  838. }
  839. /*
  840. * The following function controls memory allocation policy
  841. */
  842. int32 ok_to_grab_memory(int32 current)
  843. {
  844. MEMORYSTATUS w;
  845. memset(&w, 0, sizeof(w));
  846. w.dwLength = sizeof(w);
  847. GlobalMemoryStatus(&w);
  848. #ifdef NOT_CONFIDENT_ENOUGH_HIDE_THIS_TRASH
  849. term_printf("memStats %d %d %d %d %d %d %d %d\n",
  850. w.dwLength,
  851. w.dwMemoryLoad,
  852. w.dwTotalPhys, w.dwAvailPhys,
  853. w.dwTotalPageFile, w.dwAvailPageFile,
  854. w.dwTotalVirtual, w.dwAvailVirtual);
  855. #endif
  856. if (w.dwTotalPhys == 0)
  857. {
  858. #ifdef COMMON
  859. return current;
  860. #else
  861. return 3*current + 2;
  862. #endif
  863. }
  864. else
  865. /*
  866. * Here we seem to be running under win32 (not win32s) and can measure how
  867. * much memory is currently available for this process. I will grab space
  868. * until win32 is using all the physical memory there is. After that I will
  869. * tend to grow much more cautiously.
  870. */
  871. { int32 freemem = w.dwAvailPhys / CSL_PAGE_SIZE;
  872. if (freemem == 0) return current / 2 + 1;
  873. if (freemem > 3*current + 2) freemem = 3*current + 2;
  874. return freemem;
  875. }
  876. }
  877. /* end of syscwin.c */