sysdos.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. /* sysdos.c Copyright (C) 1989-99 Codemist Ltd */
  2. /*
  3. * MSDOS low-level support. This file supports Watcom C using dos4gw.
  4. * It could probably be modified fairly easily for use with other DOS
  5. * compilers.
  6. */
  7. /* Signature: 104a1b84 07-Mar-2000 */
  8. #include "machine.h"
  9. #include <stdarg.h>
  10. #include <string.h>
  11. #include <ctype.h>
  12. #include <conio.h>
  13. #include <errno.h>
  14. #include <time.h>
  15. #include <math.h>
  16. #include "tags.h"
  17. #include "externs.h"
  18. #include "read.h"
  19. #include "cslerror.h"
  20. #include "sys.h"
  21. #ifdef TIMEOUT
  22. #include "timeout.h"
  23. #endif
  24. #include <io.h>
  25. #include <dos.h>
  26. #include <sys\stat.h>
  27. #include <direct.h>
  28. #ifdef WINDOWS_NT
  29. #include <windows.h>
  30. #endif
  31. #include "filename.c"
  32. /*
  33. * This is a dummy definition of get_truename, here so that everything
  34. * will link. Both the calling convention used here and the exact
  35. * meaning and implementation may be under gentle review!
  36. */
  37. char *get_truename(char *filename, char *old, size_t n)
  38. {
  39. char *w;
  40. process_file_name(filename, old, n);
  41. if (*filename == 0)
  42. { aerror("truename");
  43. return NULL;
  44. }
  45. w = (char *)malloc(1+strlen(filename));
  46. if (w == NULL) return w;
  47. strcpy(w, filename);
  48. return w;
  49. }
  50. #include <sys\types.h>
  51. #include <direct.h>
  52. int create_directory(char *filename, char *old, size_t n)
  53. {
  54. process_file_name(filename, old, n);
  55. if (*filename == 0) return 1;
  56. #ifdef _MSC_VER
  57. return _mkdir(filename);
  58. #else
  59. return mkdir(filename);
  60. #endif
  61. }
  62. int change_directory(char *filename, char *old, size_t n)
  63. {
  64. process_file_name(filename, old, n);
  65. if (*filename == 0) return 1;
  66. #ifdef _MSC_VER
  67. if (_chdir(filename))
  68. #else
  69. if (chdir(filename))
  70. #endif
  71. { char err_buf[LONGEST_LEGAL_FILENAME+100];
  72. switch (errno)
  73. {
  74. case ENOENT:
  75. sprintf(err_buf,"The directory %s does not exist.",filename);
  76. break;
  77. default:
  78. sprintf(err_buf,"Cannot change directory to %s.",filename);
  79. break;
  80. }
  81. aerror0(err_buf);
  82. return 1;
  83. }
  84. else return 0;
  85. }
  86. int get_current_directory(char *s, int n)
  87. {
  88. #ifdef _MSC_VER
  89. char *r = _getcwd(s, n);
  90. #else
  91. char *r = getcwd(s, n);
  92. #endif
  93. if (r == NULL)
  94. { aerror0("cannot get current directory name");
  95. return 0;
  96. }
  97. else return strlen(s);
  98. }
  99. static void remove_files(char *name, int dirp, long int size)
  100. /* Remove a file, or a directory and all its contents */
  101. {
  102. #ifdef _MSC_VER
  103. if (dirp) _rmdir(name);
  104. #else
  105. if (dirp) rmdir(name);
  106. #endif
  107. else remove(name);
  108. }
  109. int delete_file(char *filename, char *old, size_t n)
  110. {
  111. process_file_name(filename, old, n);
  112. if (*filename == 0) return 1;
  113. scan_directory(filename, remove_files);
  114. return 0;
  115. }
  116. int directoryp(char *filename, char *old, size_t n)
  117. {
  118. #ifdef _MSC_VER
  119. struct _stat buf;
  120. #else
  121. struct stat buf;
  122. #endif
  123. process_file_name(filename, old, n);
  124. if (*filename == 0) return 0;
  125. #ifdef _MSC_VER
  126. _stat(filename, &buf);
  127. #else
  128. stat(filename, &buf);
  129. #endif
  130. #ifdef WINDOWS_NT
  131. return (GetFileAttributes(filename) == FILE_ATTRIBUTE_DIRECTORY);
  132. #else
  133. return S_ISDIR(buf.st_mode);
  134. #endif
  135. }
  136. int current_directory(char *s, int n)
  137. {
  138. #ifdef _MSC_VER
  139. if (_getcwd(s, n) == NULL) return 0;
  140. #else
  141. if (getcwd(s, n) == NULL) return 0;
  142. #endif
  143. else return strlen(s);
  144. }
  145. void list_directory_members(char *filename, char *old,
  146. size_t n, directory_callback *fn)
  147. {
  148. process_file_name(filename, old, n);
  149. scan_files(filename, fn);
  150. }
  151. int file_readable(char *filename, char *old, size_t n)
  152. {
  153. FILE *fp;
  154. process_file_name(filename, old, n);
  155. if (*filename == 0) return 0;
  156. /* The "correct" way to do this is via stat, but this is much simpler! */
  157. fp = fopen(filename,"r");
  158. if (fp == NULL) return 0;
  159. else
  160. { fclose(fp);
  161. return 1;
  162. }
  163. }
  164. int file_writeable(char *filename, char *old, size_t n)
  165. {
  166. FILE *fp;
  167. process_file_name(filename, old, n);
  168. if (*filename == 0) return 0;
  169. /* The "correct" way to do this is via stat, but this is much simpler! */
  170. fp = fopen(filename,"a");
  171. if (fp == NULL) return 0;
  172. else
  173. { fclose(fp);
  174. return 1;
  175. }
  176. }
  177. int rename_file(char *from_name, char *from_old, size_t from_size,
  178. char *to_name, char *to_old, size_t to_size)
  179. {
  180. process_file_name(from_name, from_old, from_size);
  181. process_file_name(to_name, to_old, to_size);
  182. if (*from_name == 0 || *to_name == 0) return 0;
  183. return rename(from_name,to_name);
  184. }
  185. #include <sys\stat.h> /* Provided with Zortech C and others */
  186. CSLbool file_exists(char *filename, char *old, size_t n, char *tt)
  187. {
  188. #ifdef _MSC_VER
  189. struct _stat statbuff;
  190. #else
  191. struct stat statbuff;
  192. #endif
  193. process_file_name(filename, old, n);
  194. if (*filename == 0) return NO;
  195. #ifdef _MSC_VER
  196. if (_stat(filename, &statbuff) != 0) return NO;
  197. #else
  198. if (stat(filename, &statbuff) != 0) return NO;
  199. #endif
  200. strcpy(tt, ctime(&(statbuff.st_mtime)));
  201. return YES;
  202. }
  203. int my_system(char *s)
  204. {
  205. int k;
  206. remove_ticker();
  207. k = system(s);
  208. add_ticker();
  209. return k;
  210. }
  211. char *my_getenv(char *s)
  212. {
  213. /*
  214. * Case fold for MSDOS
  215. */
  216. char uppercase[LONGEST_LEGAL_FILENAME];
  217. int c;
  218. char *p = uppercase;
  219. while ((c = *s++) != 0)
  220. { if (islower(c)) c = toupper(c);
  221. /*
  222. * Yes I do know that ANSI toupper does not need the islower test
  223. * first - but I have been bitten before by non-ANSI libraries.
  224. */
  225. *p++ = c;
  226. }
  227. *p = 0;
  228. s = uppercase;
  229. return getenv(s);
  230. }
  231. #ifdef WINDOWS_NT
  232. int pipes_today = 1;
  233. int win32s = 0;
  234. FILE *my_popen(char *s, char *d)
  235. {
  236. return _popen(s, d);
  237. }
  238. void my_pclose(FILE *s)
  239. {
  240. _pclose(s);
  241. }
  242. #endif
  243. /*
  244. * MSDOS does not support the idea of home directories for
  245. * users, so in case anybody still wants to use the notation "~" that
  246. * would indicate a home directory under Unix I implement something
  247. * in terms of environment variables.
  248. */
  249. int get_home_directory(char *b, int len)
  250. {
  251. char *w = my_getenv("home");
  252. if (w != NULL) strcpy(b, w);
  253. else strcpy(b, ".");
  254. return strlen(b);
  255. }
  256. int get_users_home_directory(char *b, int len)
  257. {
  258. char *w, h[LONGEST_LEGAL_FILENAME];
  259. sprintf(h, "home$%s", b);
  260. w = my_getenv(h);
  261. if (w != NULL) strcpy(b, w);
  262. else strcpy(b, ".");
  263. return strlen(b);
  264. }
  265. /*
  266. * The next bit of mess is jolly - I just want to see if stdin has been
  267. * redirected to come from a file, i.e. whether I am interactive in some
  268. * sense. This may be used to decide what to do about error reports etc.
  269. * The IDEA seems generic across most systems, but the details vary in
  270. * frustrating ways.
  271. */
  272. int batchp()
  273. {
  274. #ifdef WINDOWS_NT
  275. return 0;
  276. #else
  277. #ifdef __BORLANDC__
  278. return !isatty(fileno(stdin));
  279. #else
  280. return !isatty(stdin->_handle);
  281. #endif
  282. #endif
  283. }
  284. /*
  285. * The next procedure is responsible for establishing information about
  286. * where the main checkpoint image should be recovered from, and where
  287. * and fasl files should come from.
  288. */
  289. char *find_image_directory(int argc, char *argv[])
  290. {
  291. char image[LONGEST_LEGAL_FILENAME];
  292. char *w;
  293. /*
  294. * If the current MSDOS program is called xxx.exe, then I look
  295. * for a file xxx.img. Well to cope with having both DOS and Windows
  296. * versions around I will arrange that if the executable is called
  297. * xxxc.exe then I look for xxx.img. Ie I expect to call the command
  298. * line version cslc.exe, or r37c.exe or reducec.exe
  299. */
  300. if (argc > 0 && argv[0] != NULL)
  301. { char *pgmname = argv[0];
  302. int len = strlen(pgmname) - 4, i;
  303. /*
  304. * I expect here that argv[0] will be a fully rooted path to the
  305. * executable image, ending with the characters ".EXE". I trim off
  306. * the last 4 chars and put in ".IMG" instead. If an extension ".exe"
  307. * is not present I just append ".img".
  308. */
  309. if (pgmname[len] != '.' ||
  310. !isalpha(pgmname[len+1]) ||
  311. !isalpha(pgmname[len+2]) ||
  312. !isalpha(pgmname[len+3])) len += 4;
  313. if (tolower(pgmname[len-1]) == 'c') len--;
  314. sprintf(image, "%.*s.img", len, pgmname);
  315. i = len;
  316. while (i>0 && pgmname[i-1] != '\\') i--;
  317. len -= i;
  318. sprintf(program_name, "%.*s", len, pgmname+i);
  319. }
  320. else sprintf(image, "csl.img");
  321. /*
  322. * I copy from local vectors into malloc'd space to hand my
  323. * answer back.
  324. */
  325. w = (char *)malloc(1+strlen(image));
  326. /*
  327. * The error exit here seem unsatisfactory...
  328. */
  329. if (w == NULL)
  330. { fprintf(stderr, "\n+++ Panic - run out of space\n");
  331. exit(EXIT_FAILURE);
  332. }
  333. strcpy(w, image);
  334. return w;
  335. }
  336. clock_t prev_clock = 0;
  337. #ifdef SOFTWARE_TICKS_PER_SECOND
  338. int32 software_ticks = INITIAL_SOFTWARE_TICKS;
  339. int32 software_tick_count = 0, prev_software_tick_count = 0;
  340. #endif
  341. void accept_tick(void)
  342. {
  343. clock_t t0 = clock();
  344. #ifdef SOFTWARE_TICKS_PER_SECOND
  345. software_tick_count++;
  346. #endif
  347. if (prev_clock == 0 ||
  348. t0 > prev_clock+2*CLOCKS_PER_SEC)
  349. { ensure_screen();
  350. #ifdef SOFTWARE_TICKS_PER_SECOND
  351. if (prev_clock != 0)
  352. { double t1 = (double)(t0-prev_clock)/(double)CLOCKS_PER_SEC;
  353. double ratio =
  354. (double)(software_tick_count - prev_software_tick_count)/t1;
  355. int32 w;
  356. /*
  357. * t1 is how long since I was last here, ratio is the number of
  358. * ticks per second over that time-span.
  359. */
  360. ratio = ratio / (double)SOFTWARE_TICKS_PER_SECOND;
  361. prev_software_tick_count = software_tick_count;
  362. /*
  363. * Now ratio is the extent by which I was taking ticks too fast.
  364. * To dampen out my correction I will scale software_ticks by the
  365. * square root of this.
  366. */
  367. ratio = sqrt(ratio);
  368. w = (int)(1000.0 * ratio);
  369. /*
  370. * I clamp the correction fator so I never adjust my clock rate by
  371. * a factor of more than (about) 3.
  372. */
  373. if (w > 3000) w = 3000;
  374. else if (w < 300) w = 300;
  375. /*
  376. * Furthermore I attempt to keep software_ticks within integer range.
  377. */
  378. if (software_ticks < (0x7fffffff/3000) &&
  379. software_ticks > 50)
  380. software_ticks = (w*software_ticks)/1000;
  381. }
  382. #endif
  383. prev_clock = t0;
  384. }
  385. return;
  386. }
  387. #ifdef DOS386
  388. #ifndef OLD_ZORTECH_DOS_EXTENDER
  389. extern int _x32_memlock(void _far *, unsigned int);
  390. extern int _x32_memunlock(void _far *, unsigned int);
  391. #endif
  392. #endif
  393. #ifndef SOFTWARE_TICKS
  394. static int sometimes = 0, lockout = 0;
  395. typedef void __interrupt __far interrupt_handler(void);
  396. static interrupt_handler *original_tick_handler;
  397. /*
  398. * The next (interrupt) routine MUST be compiled with stack-checking
  399. * disabled.
  400. */
  401. static void before_tick()
  402. {
  403. }
  404. static void __interrupt deal_with_tick()
  405. {
  406. /*
  407. * The basic clock ticks arrive 18.2 per second, but if I
  408. * respond to ALL of them it seems to hit my performance
  409. * somewhat. The main issue is that the frequency with which I
  410. * accept a tick determines the latency before I respond to ^C,
  411. * so I now try to ignore 7 out of every 8 basic ticks, so polling
  412. * about twice per second.
  413. */
  414. if ((++sometimes & 0x7) == 0)
  415. { if (tick_pending == 0 && lockout == 0)
  416. { lockout = 1;
  417. if (already_in_gc) tick_on_gc_exit = YES;
  418. else
  419. { Lisp_Object nil = C_nil;
  420. CSLbool xxx = NO;
  421. if (exception_pending()) flip_exception(), xxx = YES;
  422. tick_pending = YES;
  423. saveheaplimit = heaplimit;
  424. heaplimit = fringe;
  425. savevheaplimit = vheaplimit;
  426. vheaplimit = vfringe;
  427. savecodelimit = codelimit;
  428. codelimit = codefringe;
  429. savestacklimit = stacklimit;
  430. stacklimit = stackbase;
  431. if (xxx) flip_exception();
  432. }
  433. lockout = 0;
  434. }
  435. }
  436. _chain_intr(original_tick_handler);
  437. }
  438. static void after_tick()
  439. {
  440. }
  441. #endif
  442. static CSLbool ticker_active = NO;
  443. void MS_CDECL remove_ticker(void)
  444. {
  445. if (!ticker_active) return;
  446. #ifndef SOFTWARE_TICKS
  447. _dos_setvect(0x1c, original_tick_handler);
  448. #endif
  449. ticker_active = NO;
  450. }
  451. CSLbool sigint_must_longjmp = NO;
  452. jmp_buf sigint_buf;
  453. void MS_CDECL sigint_handler(int code)
  454. {
  455. CSL_IGNORE(code);
  456. interrupt_pending = 1;
  457. signal(SIGINT, sigint_handler); /* reinstate handler */
  458. if (sigint_must_longjmp)
  459. { sigint_must_longjmp = 0;
  460. longjmp(sigint_buf, 1);
  461. }
  462. return;
  463. }
  464. void add_ticker(void)
  465. {
  466. if (ticker_active) return;
  467. #ifdef SOFTWARE_TICKS
  468. countdown = SOFTWARE_TICKS;
  469. #else
  470. /*
  471. * I take an interrupt 18.2 times per second...
  472. */
  473. original_tick_handler = _dos_getvect(0x1c);
  474. _dos_setvect(0x1c, (interrupt_handler *)deal_with_tick);
  475. #endif /* SOFTWARE_TICKS */
  476. ticker_active = YES;
  477. }
  478. void poll_for_attn()
  479. {
  480. #ifdef _MSC_VER
  481. _kbhit(); /* allows ^C to be noticed! */
  482. #else
  483. kbhit(); /* allows ^C to be noticed! */
  484. #endif
  485. }
  486. /*
  487. * The following function controls memory allocation policy
  488. */
  489. int32 ok_to_grab_memory(int32 current)
  490. {
  491. #ifdef COMMON
  492. return current;
  493. #else
  494. return 3*current + 2;
  495. #endif
  496. }
  497. #include "fileops.c"
  498. #include "scandir.c"
  499. /* end of sysdos.c */