6 * $Id: dos.c,v 1.1.1.1 2001/04/29 20:35:50 karll Exp $
15 #include "tclExtdInt.h"
26 #ifdef COMPILE_BIOS_MEMSIZE
27 /* bios_memsize - return the size of memory according to the BIOS */
30 cmdbios_memsize(clientData, interp, argc, argv)
31 ClientData clientData;
39 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
43 memsize = _bios_memsize() * 1024;
45 sprintf (interp->result, "%ld", memsize);
50 /* bios_equiplist - return the equipment list according to the BIOS
52 * This is a very primitive command, probably dating back to the original
53 * PC. You can't find out much, and it's all packed into the word that's
54 * returned. If you really need this data, this code should be expanded
55 * to unpack it for you.
57 #ifdef COMPILE_BIOS_EQUIPLIST
59 cmdbios_equiplist(clientData, interp, argc, argv)
60 ClientData clientData;
66 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
70 sprintf (interp->result, "%u", _bios_equiplist());
75 /* kbhit - returns 1 if a key has been hit, else 0 */
77 cmdkbhit(clientData, interp, argc, argv)
78 ClientData clientData;
84 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
88 sprintf (interp->result, "%d", kbhit());
92 /* getkey - returns a key as an integer keycode. waits until a key
93 * has been pressed. (So use kbhit to see if one is there first, if you
94 * don't want to wait.)
97 cmdgetkey(clientData, interp, argc, argv)
98 ClientData clientData;
104 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
105 "\"", (char *) NULL);
108 sprintf (interp->result, "%d", getch());
112 /* sound frequency - start the sound playing a square wave at the specified
113 * frequency in hertz. If 0, stops the sound from playing.
116 cmdsound(clientData, interp, argc, argv)
117 ClientData clientData;
125 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
126 " frequency\"", (char *) NULL);
130 if (Tcl_GetInt(interp, argv[1], &frequency) != TCL_OK) {
134 if (frequency == 0) {
142 /* getdate - returns the current date as a list containing month, day, year */
144 cmdgetdate(clientData, interp, argc, argv)
145 ClientData clientData;
150 struct dosdate_t date;
153 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
154 "\"", (char *) NULL);
158 _dos_getdate (&date);
159 sprintf (interp->result,
168 /* setdate month day year -- set the current date to the specified
169 * month, day and year
172 cmdsetdate(clientData, interp, argc, argv)
173 ClientData clientData;
178 struct dosdate_t date;
184 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
185 " month day year", (char *) NULL);
189 if (Tcl_GetInt(interp, argv[1], &month) != TCL_OK) {
193 if (Tcl_GetInt(interp, argv[2], &day) != TCL_OK) {
197 if (Tcl_GetInt(interp, argv[3], &year) != TCL_OK) {
206 if (_dos_setdate (&date) != 0) {
207 Tcl_AppendResult(interp, "invalid date", (char *) NULL);
214 /* gettime - returns the current time as a list containing
215 * hours, minutes, and seconds
218 cmdgettime(clientData, interp, argc, argv)
219 ClientData clientData;
224 struct dostime_t time;
227 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
228 "\"", (char *) NULL);
232 _dos_gettime (&time);
233 sprintf (interp->result,
242 /* settime hour minute second -- set the current time to the specified
243 * hour, minute and second
246 cmdsettime(clientData, interp, argc, argv)
247 ClientData clientData;
252 struct dostime_t time;
258 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
259 " hour minute second", (char *) NULL);
263 if (Tcl_GetInt(interp, argv[1], &hour) != TCL_OK) {
267 if (Tcl_GetInt(interp, argv[2], &minute) != TCL_OK) {
271 if (Tcl_GetInt(interp, argv[3], &second) != TCL_OK) {
276 time.minute = minute;
277 time.second = second;
280 if (_dos_settime (&time) != 0) {
281 Tcl_AppendResult(interp, "invalid time", (char *) NULL);
289 /* convert_drive_id letter - converts a drive ID from a letter, like 'a' or
290 * 'A' to the integer dos uses, where 0 = A, 1 = B, etc.
292 * returns -1 if the ID is invalid, and sets an error message into the
293 * interpreter result buffer.
296 convert_drive_id (Tcl_Interp *interp, char *driveString)
301 driveChar = *driveString;
302 if ((driveChar == '\0') || (driveString[1] != '\0')) goto bad_drive;
303 if (isupper(driveChar)) {
304 drive = driveChar - 'A' + 1;
308 if (islower(driveChar)) {
309 drive = driveChar - 'a' + 1;
314 Tcl_AppendResult(interp, "invalid drive id", (char *) NULL);
318 /* diskfree - returns a list containing the free kbytes and the total
319 * kbytes on the specified drive letter.
321 * Currently this works under a DOS window but not on the handheld.
323 #ifdef COMPILE_DISKFREE
325 cmddiskfree(clientData, interp, argc, argv)
326 ClientData clientData;
332 struct diskfree_t diskfree;
333 int kbytesPerCluster;
338 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
339 " drive\"", (char *) NULL);
343 if ((drive = convert_drive_id (interp, argv[1])) < 0) {
347 if (_dos_getdiskfree (drive, &diskfree) != 0) {
348 Tcl_AppendResult(interp, "Couldn't get disk space: ",
349 Tcl_UnixError (interp), (char *) NULL);
353 freeClusters = diskfree.avail_clusters;
354 totalClusters = diskfree.total_clusters;
356 kbytesPerCluster = (diskfree.bytes_per_sector * diskfree.sectors_per_cluster) / 1024;
358 sprintf (interp->result,
360 (long)(freeClusters * kbytesPerCluster),
361 (long)(totalClusters * kbytesPerCluster));
367 /* cmdgetfat - returns a list containing the FAT ID byte, sectors per cluster,
368 * number of clusters, and bytes per sector.
370 #ifdef COMPILE_GETFAT
372 cmdgetfat(clientData, interp, argc, argv)
373 ClientData clientData;
379 struct fatinfo dtable;
380 int kbytesPerCluster;
385 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
386 " drive\"", (char *) NULL);
390 if ((drive = convert_drive_id (interp, argv[1])) < 0) {
394 getfat (drive, &dtable);
396 sprintf (interp->result,
407 /* cmdgetdfree - returns a list containing the available clusters, total
408 * clusters, bytes per sector, and sectors per cluster.
411 cmdgetdfree(clientData, interp, argc, argv)
412 ClientData clientData;
421 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
422 " drive\"", (char *) NULL);
426 if ((drive = convert_drive_id (interp, argv[1])) < 0) {
430 getdfree (drive, &dtable);
432 sprintf (interp->result,
442 /* drive letter - set the current drive to the specified letter */
444 cmddrive(clientData, interp, argc, argv)
445 ClientData clientData;
455 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
456 " ?driveid?\"", (char *) NULL);
461 _dos_getdrive (&drive);
462 sprintf (interp->result, "%c", drive + 'A' - 1);
466 if ((drive = convert_drive_id (interp, argv[1])) < 0) {
470 _dos_setdrive (drive, &ndrives);
471 _dos_getdrive (&newdrive);
473 if (drive != newdrive) {
474 Tcl_AppendResult(interp, "invalid drive id", (char *) NULL);
479 /* memfree - returns the amount of RAM left on the system */
481 cmdmemfree(clientData, interp, argc, argv)
482 ClientData clientData;
487 sprintf(interp->result, "%lu", farcoreleft ());
491 /* stackfree - returns the amount of stack left on the system */
493 cmdstackfree(clientData, interp, argc, argv)
494 ClientData clientData;
499 sprintf(interp->result, "%u", stackavail ());
503 #ifdef COMPILE_BIOS_SERIALCOM
504 /* bios_serialcom - does serial I/O stuff through the BIOS */
506 cmdbios_serialcom(clientData, interp, argc, argv)
507 ClientData clientData;
518 if (argc < 3 || argc > 4) {
520 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
521 " command port (data)\"", (char *) NULL);
525 if (STREQU (argv[1], "status")) {
526 command = _COM_STATUS;
527 if (argc != 3) goto argcount;
528 } else if (STREQU (argv[1], "receive")) {
529 command = _COM_RECEIVE;
530 if (argc != 3) goto argcount;
531 } else if (STREQU (argv[1], "send")) {
533 if (argc != 4) goto argcount;
535 if (Tcl_GetInt(interp, argv[2], &port) != TCL_OK) {
539 for (s = argv[3]; *s != '\0'; s++) {
540 _bios_serialcom (command, port, *s);
544 } else if (STREQU (argv[1], "init")) {
547 data = (_COM_9600|_COM_NOPARITY|_COM_CHR8|_COM_STOP1);
549 if (argc != 4) goto argcount;
553 Tcl_AppendResult(interp, "bad arg: ", argv[0],
554 " command must be one of \"init\", \"send\", \"receive\" or \"status\"", (char *) NULL);
558 if (Tcl_GetInt(interp, argv[2], &port) != TCL_OK) {
562 if (needData && Tcl_GetInt(interp, argv[3], &data) != TCL_OK) {
566 sprintf (interp->result, "%u", _bios_serialcom (command, port, data));
571 /* rawclock - returns the raw clock value in ticks */
573 cmdrawclock(clientData, interp, argc, argv)
574 ClientData clientData;
580 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
581 "\"", (char *) NULL);
584 sprintf (interp->result, "%lu", clock());
588 /* getverify - returns the operating system verify flag. If 0, writes are
589 * not being verified. If 1, they are.
591 #ifdef COMPILE_GETVERIFY
593 cmdgetverify(clientData, interp, argc, argv)
594 ClientData clientData;
600 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
601 "\"", (char *) NULL);
604 sprintf (interp->result, "%d", getverify());
609 /* wait ms - wait the specified number of milliseconds */
611 cmdwait(clientData, interp, argc, argv)
612 ClientData clientData;
620 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
621 " milliseconds\"", (char *) NULL);
625 if (Tcl_GetInt(interp, argv[1], &milliseconds) != TCL_OK) {
629 delay ((unsigned)milliseconds);
633 /* gotoxy - address the cursor to the specified x and y location */
635 cmdgotoxy(clientData, interp, argc, argv)
636 ClientData clientData;
645 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
646 " x y\"", (char *) NULL);
650 if (Tcl_GetInt(interp, argv[1], &x) != TCL_OK) {
654 if (Tcl_GetInt(interp, argv[2], &y) != TCL_OK) {
662 /* clrscr - clear the screen */
664 cmdclrscr(clientData, interp, argc, argv)
665 ClientData clientData;
674 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
675 "\"", (char *) NULL);
683 /* heapcheck - check the heap for corruption */
685 cmdheapcheck(clientData, interp, argc, argv)
686 ClientData clientData;
695 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
696 "\"", (char *) NULL);
700 switch( heapcheck () )
703 panic( "Memory heap corrupted." );
707 panic( "No memory heap." );
714 printf( "Unknown error in memory heap." );
719 /* mkdir dir - create a directory */
721 cmdmkdir(clientData, interp, argc, argv)
722 ClientData clientData;
728 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
729 " dirname\"", (char *) NULL);
733 if (mkdir (argv[1]) < 0) {
734 Tcl_AppendResult(interp, "Couldn't make directory: ", argv[1], ": ",
735 Tcl_UnixError (interp), (char *) NULL);
742 /* unlink file - delete a file */
744 cmdunlink(clientData, interp, argc, argv)
745 ClientData clientData;
751 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
752 " filename\"", (char *) NULL);
756 if (unlink (argv[1]) < 0) {
757 Tcl_AppendResult(interp, "Couldn't unlink file: ", argv[1], ": ",
758 Tcl_UnixError (interp), (char *) NULL);
766 /* execvp -- terminate the current process and execute a new one */
768 cmdexecvp(clientData, interp, argc, argv)
769 ClientData clientData;
775 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
776 " command ?args?\"", (char *) NULL);
780 if (execvp (argv[1], &argv[1]) < 0) {
781 Tcl_AppendResult(interp, "Couldn't execvp: ", argv[1], ": ",
782 Tcl_UnixError (interp), (char *) NULL);
786 /* Actually we should not ever get here. If the execvp succeeds,
823 textcolor(0-15, +128 = blink)
834 wherex - get horizontal cursor position
835 wherey - get vertical cursor position
839 /* video - do stuff to the video */
841 cmdvideo(clientData, interp, argc, argv)
842 ClientData clientData;
849 extern int _directvideo;
856 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
857 " subcommand ?options?\"", (char *) NULL);
861 if (STREQU (argv[1], "write")) {
863 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
864 " ", argv[1], " data\"", (char *) NULL);
871 if (STREQU (argv[1], "goto")) {
874 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
875 " ", argv[1], " x y\"", (char *) NULL);
879 if (Tcl_GetInt(interp, argv[2], &x) != TCL_OK) {
883 if (Tcl_GetInt(interp, argv[3], &y) != TCL_OK) {
891 if (STREQU (argv[1], "normal")) {
892 if (argc != 2) goto bad2arg;
897 if (STREQU (argv[1], "dim")) {
898 if (argc != 2) goto bad2arg;
903 if (STREQU (argv[1], "bright")) {
904 if (argc != 2) goto bad2arg;
909 else if (STREQU (argv[1], "color")) {
913 if (argc != 4) goto argcount;
916 if (Tcl_GetInt(interp, argv[2], &color) != TCL_OK) {
920 if (color < 0 || color > 15) {
921 Tcl_AppendResult(interp, "color must be between 0 & 15",
926 textcolor (color + blink);
930 if (STREQU (argv[1], "bgcolor")) {
931 if (argc != 3) goto argcount;
933 if (Tcl_GetInt(interp, argv[2], &color) != TCL_OK) {
937 if (color < 0 || color > 7) {
938 Tcl_AppendResult(interp, "bgcolor must be between 0 & 7",
943 textbackground (color + blink);
947 if (STREQU (argv[1], "clear")) {
950 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
951 " ", argv[1], "\"", (char *) NULL);
959 if (STREQU (argv[1], "direct")) {
963 sprintf (interp->result, "%d", _directvideo);
966 if (argc > 3) goto argcount;
968 if (Tcl_GetInt(interp, argv[2], &directvideo) != TCL_OK) {
971 _directvideo = directvideo;
975 Tcl_AppendResult(interp, "bad arg: ", argv[0],
976 " subcommand must be one of \"data\", \"goto\", \"clear\", \"normal\", \"dim\", \"bright\", \"color\" or \"bgcolor\"", (char *) NULL);
982 /* Tcl_InitDos - add all of the DOS functions defined in this file to the
983 * specified interpreter.
986 Tcl_InitDos (Tcl_Interp *interp)
989 #ifdef COMPILE_BIOS_MEMSIZE
990 Tcl_CreateCommand(interp, "bios_memsize", cmdbios_memsize, (ClientData) 0,
991 (Tcl_CmdDeleteProc *) NULL);
994 #ifdef COMPILE_BIOS_EQUIPLIST
995 Tcl_CreateCommand(interp, "bios_equiplist", cmdbios_equiplist,
996 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
999 #ifdef COMPILE_BIOS_SERIALCOM
1000 Tcl_CreateCommand(interp, "com", cmdbios_serialcom, (ClientData) 0,
1001 (Tcl_CmdDeleteProc *) NULL);
1004 Tcl_CreateCommand(interp, "kbhit", cmdkbhit, (ClientData) 0,
1005 (Tcl_CmdDeleteProc *) NULL);
1006 Tcl_CreateCommand(interp, "getkey", cmdgetkey, (ClientData) 0,
1007 (Tcl_CmdDeleteProc *) NULL);
1008 Tcl_CreateCommand(interp, "sound", cmdsound, (ClientData) 0,
1009 (Tcl_CmdDeleteProc *) NULL);
1010 Tcl_CreateCommand(interp, "rawclock", cmdrawclock, (ClientData) 0,
1011 (Tcl_CmdDeleteProc *) NULL);
1012 Tcl_CreateCommand(interp, "getdate", cmdgetdate, (ClientData) 0,
1013 (Tcl_CmdDeleteProc *) NULL);
1014 Tcl_CreateCommand(interp, "setdate", cmdsetdate, (ClientData) 0,
1015 (Tcl_CmdDeleteProc *) NULL);
1016 Tcl_CreateCommand(interp, "gettime", cmdgettime, (ClientData) 0,
1017 (Tcl_CmdDeleteProc *) NULL);
1018 Tcl_CreateCommand(interp, "settime", cmdsettime, (ClientData) 0,
1019 (Tcl_CmdDeleteProc *) NULL);
1021 #ifdef COMPILE_DISKFREE
1022 Tcl_CreateCommand(interp, "diskfree", cmddiskfree, (ClientData) 0,
1023 (Tcl_CmdDeleteProc *) NULL);
1026 #ifdef COMPILE_GETFAT
1027 Tcl_CreateCommand(interp, "getfat", cmdgetfat, (ClientData) 0,
1028 (Tcl_CmdDeleteProc *) NULL);
1031 Tcl_CreateCommand(interp, "getdfree", cmdgetdfree, (ClientData) 0,
1032 (Tcl_CmdDeleteProc *) NULL);
1033 Tcl_CreateCommand(interp, "drive", cmddrive, (ClientData) 0,
1034 (Tcl_CmdDeleteProc *) NULL);
1035 Tcl_CreateCommand(interp, "memfree", cmdmemfree, (ClientData) 0,
1036 (Tcl_CmdDeleteProc *) NULL);
1037 Tcl_CreateCommand(interp, "stackfree", cmdstackfree, (ClientData) 0,
1038 (Tcl_CmdDeleteProc *) NULL);
1039 Tcl_CreateCommand(interp, "wait", cmdwait, (ClientData) 0,
1040 (Tcl_CmdDeleteProc *) NULL);
1041 Tcl_CreateCommand(interp, "gotoxy", cmdgotoxy, (ClientData) 0,
1042 (Tcl_CmdDeleteProc *) NULL);
1043 Tcl_CreateCommand(interp, "cls", cmdclrscr, (ClientData) 0,
1044 (Tcl_CmdDeleteProc *) NULL);
1046 #ifdef COMPILE_GETVERIFY
1047 Tcl_CreateCommand(interp, "getverify", cmdgetverify, (ClientData) 0,
1048 (Tcl_CmdDeleteProc *) NULL);
1051 Tcl_CreateCommand(interp, "heapcheck", cmdheapcheck, (ClientData) 0,
1052 (Tcl_CmdDeleteProc *) NULL);
1053 Tcl_CreateCommand(interp, "mkdir", cmdmkdir, (ClientData) 0,
1054 (Tcl_CmdDeleteProc *) NULL);
1055 Tcl_CreateCommand(interp, "unlink", cmdunlink, (ClientData) 0,
1056 (Tcl_CmdDeleteProc *) NULL);
1057 Tcl_CreateCommand(interp, "execvp", cmdexecvp, (ClientData) 0,
1058 (Tcl_CmdDeleteProc *) NULL);
1059 Tcl_CreateCommand(interp, "video", cmdvideo, (ClientData) 0,
1060 (Tcl_CmdDeleteProc *) NULL);