syscwin.c 32 KB

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