dosfns.c 23.1 KB
Newer Older
Richard M. Stallman's avatar
Richard M. Stallman committed
1 2
/* MS-DOS specific Lisp utilities.  Coded by Manabu Higashida, 1991.
   Major changes May-July 1993 Morten Welinder (only 10% original code left)
Paul Eggert's avatar
Paul Eggert committed
3
   Copyright (C) 1991, 1993, 1996-1998, 2001-2020 Free Software
4
   Foundation, Inc.
Richard M. Stallman's avatar
Richard M. Stallman committed
5 6 7

This file is part of GNU Emacs.

8
GNU Emacs is free software: you can redistribute it and/or modify
Richard M. Stallman's avatar
Richard M. Stallman committed
9
it under the terms of the GNU General Public License as published by
10 11
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
Richard M. Stallman's avatar
Richard M. Stallman committed
12 13 14 15 16 17 18

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
Paul Eggert's avatar
Paul Eggert committed
19
along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
20

Richard M. Stallman's avatar
Richard M. Stallman committed
21
#include <config.h>
Richard M. Stallman's avatar
Richard M. Stallman committed
22 23 24 25 26

#ifdef MSDOS
/* The entire file is within this conditional */

#include <stdio.h>
Paul Eggert's avatar
Paul Eggert committed
27
/* gettime and settime in dos.h clash with their namesakes from
28 29 30
   gnulib, so we move out of our way the prototypes in dos.h.  */
#define gettime dos_h_gettime_
#define settime dos_h_settime_
Richard M. Stallman's avatar
Richard M. Stallman committed
31
#include <dos.h>
32 33
#undef gettime
#undef settime
34

Richard M. Stallman's avatar
Richard M. Stallman committed
35
#include "lisp.h"
36
#include "character.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
37 38 39
#include "buffer.h"
#include "termchar.h"
#include "frame.h"
40
#include "termhooks.h"
Eli Zaretskii's avatar
Eli Zaretskii committed
41 42
#include "blockinput.h"
#include "window.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
43 44
#include "dosfns.h"
#include "msdos.h"
45
#include "dispextern.h"
46
#include "coding.h"
47
#include "process.h"
Eli Zaretskii's avatar
Eli Zaretskii committed
48
#include <dpmi.h>
49
#include <go32.h>
50
#include <dirent.h>
51
#include <sys/vfs.h>
52 53 54
#include <unistd.h>
#include <grp.h>
#include <crt0.h>
Richard M. Stallman's avatar
Richard M. Stallman committed
55 56

DEFUN ("int86", Fint86, Sint86, 2, 2, 0,
57
       doc: /* Call specific MS-DOS interrupt number INTERRUPT with REGISTERS.
58 59 60 61 62
Return the updated REGISTER vector.

INTERRUPT should be an integer in the range 0 to 255.
REGISTERS should be a vector produced by `make-register' and
`set-register-value'.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
63
  (Lisp_Object interrupt, Lisp_Object registers)
Richard M. Stallman's avatar
Richard M. Stallman committed
64 65 66 67 68
{
  register int i;
  int no;
  union REGS inregs, outregs;

69
  CHECK_FIXNUM (interrupt);
Tom Tromey's avatar
Tom Tromey committed
70
  no = (unsigned long) XFIXNUM (interrupt);
71
  CHECK_VECTOR (registers);
72
  if (no < 0 || no > 0xff || ASIZE (registers) != 8)
Richard M. Stallman's avatar
Richard M. Stallman committed
73 74
    return Qnil;
  for (i = 0; i < 8; i++)
Paul Eggert's avatar
Paul Eggert committed
75
    CHECK_FIXNUM (AREF (registers, i));
Richard M. Stallman's avatar
Richard M. Stallman committed
76

Paul Eggert's avatar
Paul Eggert committed
77 78 79 80 81 82 83 84
  inregs.x.ax    = (unsigned long) XFIXNUM (AREF (registers, 0));
  inregs.x.bx    = (unsigned long) XFIXNUM (AREF (registers, 1));
  inregs.x.cx    = (unsigned long) XFIXNUM (AREF (registers, 2));
  inregs.x.dx    = (unsigned long) XFIXNUM (AREF (registers, 3));
  inregs.x.si    = (unsigned long) XFIXNUM (AREF (registers, 4));
  inregs.x.di    = (unsigned long) XFIXNUM (AREF (registers, 5));
  inregs.x.cflag = (unsigned long) XFIXNUM (AREF (registers, 6));
  inregs.x.flags = (unsigned long) XFIXNUM (AREF (registers, 7));
Richard M. Stallman's avatar
Richard M. Stallman committed
85 86 87

  int86 (no, &inregs, &outregs);

88 89 90 91 92 93 94 95
  ASET (registers, 0, make_fixnum (outregs.x.ax));
  ASET (registers, 1, make_fixnum (outregs.x.bx));
  ASET (registers, 2, make_fixnum (outregs.x.cx));
  ASET (registers, 3, make_fixnum (outregs.x.dx));
  ASET (registers, 4, make_fixnum (outregs.x.si));
  ASET (registers, 5, make_fixnum (outregs.x.di));
  ASET (registers, 6, make_fixnum (outregs.x.cflag));
  ASET (registers, 7, make_fixnum (outregs.x.flags));
Richard M. Stallman's avatar
Richard M. Stallman committed
96

97
  return registers;
Richard M. Stallman's avatar
Richard M. Stallman committed
98 99
}

100
DEFUN ("msdos-memget", Fdos_memget, Sdos_memget, 2, 2, 0,
101 102
       doc: /* Read DOS memory at offset ADDRESS into VECTOR.
Return the updated VECTOR.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
103
  (Lisp_Object address, Lisp_Object vector)
104 105 106 107 108
{
  register int i;
  int offs, len;
  char *buf;

109
  CHECK_FIXNUM (address);
Tom Tromey's avatar
Tom Tromey committed
110
  offs = (unsigned long) XFIXNUM (address);
111
  CHECK_VECTOR (vector);
112
  len = ASIZE (vector);
113
  if (len < 1 || len > 2048 || offs < 0 || offs > 0xfffff - len)
114 115 116
    return Qnil;
  buf = alloca (len);
  dosmemget (offs, len, buf);
Eli Zaretskii's avatar
Eli Zaretskii committed
117

118
  for (i = 0; i < len; i++)
119
    ASET (vector, i, make_fixnum (buf[i]));
120

121
  return vector;
122 123 124
}

DEFUN ("msdos-memput", Fdos_memput, Sdos_memput, 2, 2, 0,
125
       doc: /* Write DOS memory at offset ADDRESS from VECTOR.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
126
  (Lisp_Object address, Lisp_Object vector)
127 128 129 130 131
{
  register int i;
  int offs, len;
  char *buf;

132
  CHECK_FIXNUM (address);
Tom Tromey's avatar
Tom Tromey committed
133
  offs = (unsigned long) XFIXNUM (address);
134
  CHECK_VECTOR (vector);
135
  len = ASIZE (vector);
136
  if (len < 1 || len > 2048 || offs < 0 || offs > 0xfffff - len)
137 138 139 140 141
    return Qnil;
  buf = alloca (len);

  for (i = 0; i < len; i++)
    {
Paul Eggert's avatar
Paul Eggert committed
142 143
      CHECK_FIXNUM (AREF (vector, i));
      buf[i] = (unsigned char) XFIXNUM (AREF (vector, i)) & 0xFF;
144 145 146 147 148 149 150
    }

  dosmemput (buf, len, offs);
  return Qt;
}

DEFUN ("msdos-set-keyboard", Fmsdos_set_keyboard, Smsdos_set_keyboard, 1, 2, 0,
151 152 153 154
       doc: /* Set keyboard layout according to COUNTRY-CODE.
If the optional argument ALLKEYS is non-nil, the keyboard is mapped for
all keys; otherwise it is only used when the ALT key is pressed.
The current keyboard layout is available in dos-keyboard-code.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
155
  (Lisp_Object country_code, Lisp_Object allkeys)
156
{
157
  CHECK_FIXNUM (country_code);
Tom Tromey's avatar
Tom Tromey committed
158
  if (!dos_set_keyboard (XFIXNUM (country_code), !NILP (allkeys)))
159 160 161 162
    return Qnil;
  return Qt;
}

Morten Welinder's avatar
Morten Welinder committed
163 164 165 166
#ifndef HAVE_X_WINDOWS
/* Later we might want to control the mouse interface with this function,
   e.g., with respect to non-80 column screen modes.  */

167 168
DEFUN ("msdos-mouse-p", Fmsdos_mouse_p, Smsdos_mouse_p, 0, 0, 0,
       doc: /* Report whether a mouse is present.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
169
  (void)
Morten Welinder's avatar
Morten Welinder committed
170 171 172 173 174 175 176 177
{
  if (have_mouse)
    return Qt;
  else
    return Qnil;
}
#endif

178
DEFUN ("msdos-mouse-init", Fmsdos_mouse_init, Smsdos_mouse_init, 0, 0, "",
179
       doc: /* Initialize and enable mouse if available.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
180
  (void)
181
{
182 183 184 185 186 187
  if (have_mouse)
    {
      have_mouse = 1;
      mouse_init ();
      return Qt;
    }
188 189 190 191
  return Qnil;
}

DEFUN ("msdos-mouse-enable", Fmsdos_mouse_enable, Smsdos_mouse_enable, 0, 0, "",
192
       doc: /* Enable mouse if available.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
193
  (void)
194 195 196
{
  if (have_mouse)
    {
197 198
      have_mouse = 1;
      mouse_on ();
199 200 201 202 203
    }
  return have_mouse ? Qt : Qnil;
}

DEFUN ("msdos-mouse-disable", Fmsdos_mouse_disable, Smsdos_mouse_disable, 0, 0, "",
204
       doc: /* Disable mouse if available.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
205
  (void)
206 207 208 209 210 211
{
  mouse_off ();
  if (have_mouse) have_mouse = -1;
  return Qnil;
}

212
DEFUN ("insert-startup-screen", Finsert_startup_screen, Sinsert_startup_screen, 0, 0, "",
213
       doc: /* Insert copy of screen contents prior to starting Emacs.
214
Return nil if startup screen is not available.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
215
  (void)
216 217
{
  char *s;
Eli Zaretskii's avatar
Eli Zaretskii committed
218 219
  int rows, cols, i, j;

220 221
  if (!dos_get_saved_screen (&s, &rows, &cols))
    return Qnil;
Eli Zaretskii's avatar
Eli Zaretskii committed
222

223 224 225 226
  for (i = 0; i < rows; i++)
    {
      for (j = 0; j < cols; j++)
	{
227
	  insert_char (*s);
228 229
	  s += 2;
	}
230
      insert_char ('\n');
231 232 233 234
    }

  return Qt;
}
Morten Welinder's avatar
Morten Welinder committed
235

236
unsigned char dos_country_info[DOS_COUNTRY_INFO];
237 238 239 240 241 242 243 244 245 246 247 248 249 250
static unsigned char usa_country_info[DOS_COUNTRY_INFO] = {
  0, 0,				/* date format */
  '$', 0, 0, 0, 0,		/* currency string */
  ',', 0,			/* thousands separator */
  '.', 0,			/* decimal separator */
  '/', 0,			/* date separator */
  ':', 0,			/* time separator */
  0,				/* currency format */
  2,				/* digits after decimal in currency */
  0,				/* time format */
  0, 0, 0, 0,			/* address of case map routine, GPF if used */
  ' ', 0,			/* data-list separator (?) */
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0	/* reserved */
};
251

Eli Zaretskii's avatar
Eli Zaretskii committed
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
#ifndef HAVE_X_WINDOWS
static unsigned dos_windows_version;
char parent_vm_title[50];	/* Ralf Brown says 30 is enough */
int w95_set_virtual_machine_title (const char *);

void
restore_parent_vm_title (void)
{
  if (NILP (Vdos_windows_version))
    return;
  if ((dos_windows_version & 0xff) >= 4 && parent_vm_title[0])
    w95_set_virtual_machine_title (parent_vm_title);
  delay (50);
}
#endif /* !HAVE_X_WINDOWS */
Eli Zaretskii's avatar
Eli Zaretskii committed
267

Richard M. Stallman's avatar
Richard M. Stallman committed
268
void
269
init_dosfns (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
270 271 272
{
  union REGS regs;
  _go32_dpmi_registers dpmiregs;
273
  unsigned long xbuf = _go32_info_block.linear_address_of_transfer_buffer;
Richard M. Stallman's avatar
Richard M. Stallman committed
274

Morten Welinder's avatar
Morten Welinder committed
275
#ifndef SYSTEM_MALLOC
276 277
  extern void get_lim_data (void);

Richard M. Stallman's avatar
Richard M. Stallman committed
278
  get_lim_data (); /* why the hell isn't this called elsewhere? */
Morten Welinder's avatar
Morten Welinder committed
279
#endif
Richard M. Stallman's avatar
Richard M. Stallman committed
280 281 282

  regs.x.ax = 0x3000;
  intdos (&regs, &regs);
283
  Vdos_version = Fcons (make_fixnum (regs.h.al), make_fixnum (regs.h.ah));
Richard M. Stallman's avatar
Richard M. Stallman committed
284

285 286
  /* Obtain the country code via DPMI, use DJGPP transfer buffer.  */
  dpmiregs.x.ax = 0x3800;
287
  dpmiregs.x.ds = xbuf >> 4;
288 289 290 291 292 293 294 295
  dpmiregs.x.dx = 0;
  dpmiregs.x.ss = dpmiregs.x.sp = dpmiregs.x.flags = 0;
  _go32_dpmi_simulate_int (0x21, &dpmiregs);
  if (dpmiregs.x.flags & 1)
    {
      dos_country_code = 1;	/* assume USA if 213800 failed */
      memcpy (dos_country_info, usa_country_info, DOS_COUNTRY_INFO);
    }
Richard M. Stallman's avatar
Richard M. Stallman committed
296 297 298
  else
    {
      dos_country_code = dpmiregs.x.bx;
299
      dosmemget (xbuf, DOS_COUNTRY_INFO, dos_country_info);
Richard M. Stallman's avatar
Richard M. Stallman committed
300
    }
301

302
  dos_set_keyboard (dos_country_code, 0);
Richard M. Stallman's avatar
Richard M. Stallman committed
303 304 305 306 307

  regs.x.ax = 0x6601;
  intdos (&regs, &regs);
  if (regs.x.cflag)
    /* Estimate code page from country code */
Eli Zaretskii's avatar
Eli Zaretskii committed
308
    switch (dos_country_code)
Richard M. Stallman's avatar
Richard M. Stallman committed
309 310 311 312 313 314 315 316 317 318 319
      {
      case 45: /* Denmark */
      case 47: /* Norway */
	dos_codepage = 865;
	break;
      default:
	/* US */
	dos_codepage = 437;
      }
  else
    dos_codepage = regs.x.bx & 0xffff;
320

Eli Zaretskii's avatar
Eli Zaretskii committed
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
#ifndef HAVE_X_WINDOWS
  parent_vm_title[0] = '\0';

  /* If we are running from DOS box on MS-Windows, get Windows version.  */
  dpmiregs.x.ax = 0x1600;	/* enhanced mode installation check */
  dpmiregs.x.ss = dpmiregs.x.sp = dpmiregs.x.flags = 0;
  _go32_dpmi_simulate_int (0x2f, &dpmiregs);
  /* We only support Windows-specific features when we run on Windows 9X
     or on Windows 3.X/enhanced mode.

     Int 2Fh/AX=1600h returns:

     AL = 00:  no Windows at all;
     AL = 01:  Windows/386 2.x;
     AL = 80h: Windows 3.x in mode other than enhanced;
     AL = FFh: Windows/386 2.x

     We also check AH > 0 (Windows 3.1 or later), in case AL tricks us.  */
  if (dpmiregs.h.al > 2 && dpmiregs.h.al != 0x80 && dpmiregs.h.al != 0xff
      && (dpmiregs.h.al > 3 || dpmiregs.h.ah > 0))
    {
      dos_windows_version = dpmiregs.x.ax;
      Vdos_windows_version =
344
	Fcons (make_fixnum (dpmiregs.h.al), make_fixnum (dpmiregs.h.ah));
Eli Zaretskii's avatar
Eli Zaretskii committed
345 346 347 348 349 350 351 352

      /* Save the current title of this virtual machine, so we can restore
	 it before exiting.  Otherwise, Windows 95 will continue to use
	 the title we set even after we are history, stupido...  */
      if (dpmiregs.h.al >= 4)
	{
	  dpmiregs.x.ax = 0x168e;
	  dpmiregs.x.dx = 3;	/* get VM title */
Juanma Barranquero's avatar
Juanma Barranquero committed
353
	  dpmiregs.x.cx = sizeof (parent_vm_title) - 1;
Eli Zaretskii's avatar
Eli Zaretskii committed
354 355 356 357 358
	  dpmiregs.x.es = __tb >> 4;
	  dpmiregs.x.di = __tb & 15;
	  dpmiregs.x.sp = dpmiregs.x.ss = dpmiregs.x.flags = 0;
	  _go32_dpmi_simulate_int (0x2f, &dpmiregs);
	  if (dpmiregs.x.ax == 1)
Juanma Barranquero's avatar
Juanma Barranquero committed
359
	    dosmemget (__tb, sizeof (parent_vm_title), parent_vm_title);
Eli Zaretskii's avatar
Eli Zaretskii committed
360 361 362 363 364 365 366 367 368
	}
    }
  else
    {
      dos_windows_version = 0;
      Vdos_windows_version = Qnil;
    }
#endif /* !HAVE_X_WINDOWS */

369 370 371 372
  /* Without this, we never see hidden files.
     Don't OR it with the previous value, so the value recorded at dump
     time, possibly with `preserve-case' flags set, won't get through.  */
  __opendir_flags = __OPENDIR_FIND_HIDDEN;
Richard M. Stallman's avatar
Richard M. Stallman committed
373 374
}

Eli Zaretskii's avatar
Eli Zaretskii committed
375
#ifndef HAVE_X_WINDOWS
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390

/* Emulation of some X window features from xfns.c and xfaces.c.  */

/* Standard VGA colors, in the order of their standard numbering
   in the default VGA palette.  */
static char *vga_colors[16] = {
  "black", "blue", "green", "cyan", "red", "magenta", "brown",
  "lightgray", "darkgray", "lightblue", "lightgreen", "lightcyan",
  "lightred", "lightmagenta", "yellow", "white"
};

/* Given a color name, return its index, or -1 if not found.  Note
   that this only performs case-insensitive comparison against the
   standard names.  For anything more sophisticated, like matching
   "gray" with "grey" or translating X color names into their MSDOS
391 392
   equivalents, call the Lisp function Qtty_color_desc (defined
   on lisp/term/tty-colors.el).  */
393 394 395 396 397
int
msdos_stdcolor_idx (const char *name)
{
  int i;

398
  for (i = 0; i < ARRAYELTS (vga_colors); i++)
399
    if (xstrcasecmp (name, vga_colors[i]) == 0)
400 401
      return i;

402
  return
Eli Zaretskii's avatar
Eli Zaretskii committed
403 404
    strcmp (name, unspecified_fg) == 0 ? FACE_TTY_DEFAULT_FG_COLOR
    : strcmp (name, unspecified_bg) == 0 ? FACE_TTY_DEFAULT_BG_COLOR
405
    : FACE_TTY_DEFAULT_COLOR;
406 407 408
}

/* Given a color index, return its standard name.  */
409
Lisp_Object
410 411
msdos_stdcolor_name (int idx)
{
Eli Zaretskii's avatar
Eli Zaretskii committed
412 413 414 415
  if (idx == FACE_TTY_DEFAULT_FG_COLOR)
    return build_string (unspecified_fg);
  else if (idx == FACE_TTY_DEFAULT_BG_COLOR)
    return build_string (unspecified_bg);
416
  else if (idx >= 0 && idx < ARRAYELTS (vga_colors))
Eli Zaretskii's avatar
Eli Zaretskii committed
417 418 419
    return build_string (vga_colors[idx]);
  else
    return Qunspecified;	/* meaning the default */
420 421
}

Eli Zaretskii's avatar
Eli Zaretskii committed
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
/* Support for features that are available when we run in a DOS box
   on MS-Windows.  */
int
ms_windows_version (void)
{
  return dos_windows_version;
}

/* Set the title of the current virtual machine, to appear on
   the caption bar of that machine's window.  */

int
w95_set_virtual_machine_title (const char *title_string)
{
  /* Only Windows 9X (version 4 and higher) support this function.  */
  if (!NILP (Vdos_windows_version)
      && (dos_windows_version & 0xff) >= 4)
    {
      _go32_dpmi_registers regs;
      dosmemput (title_string, strlen (title_string) + 1, __tb);
      regs.x.ax = 0x168e;
      regs.x.dx = 1;
      regs.x.es = __tb >> 4;
      regs.x.di = __tb & 15;
      regs.x.sp = regs.x.ss = regs.x.flags = 0;
      _go32_dpmi_simulate_int (0x2f, &regs);
      return regs.x.ax == 1;
    }
  return 0;
}

/* Change the title of frame F to NAME.
   If NAME is nil, use the frame name as the title.

   If Emacs is not run from a DOS box on Windows 9X, this only
   sets the name in the frame struct, but has no other effects.  */

void
460
x_set_title (struct frame *f, Lisp_Object name)
Eli Zaretskii's avatar
Eli Zaretskii committed
461 462
{
  /* Don't change the title if it's already NAME.  */
463
  if (EQ (name, f->title))
Eli Zaretskii's avatar
Eli Zaretskii committed
464 465
    return;

466
  update_mode_lines = 13;
Eli Zaretskii's avatar
Eli Zaretskii committed
467

468
  fset_title (f, name);
Eli Zaretskii's avatar
Eli Zaretskii committed
469 470

  if (NILP (name))
471
    name = f->name;
Eli Zaretskii's avatar
Eli Zaretskii committed
472 473 474

  if (FRAME_MSDOS_P (f))
    {
475
      block_input ();
476
      w95_set_virtual_machine_title (SDATA (name));
477
      unblock_input ();
Eli Zaretskii's avatar
Eli Zaretskii committed
478 479 480 481
    }
}
#endif /* !HAVE_X_WINDOWS */

482
DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
483
       doc: /* SKIP: real doc in fileio.c.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
484
  (Lisp_Object filename)
485 486 487 488
{
  struct statfs stfs;
  Lisp_Object encoded, value;

489
  CHECK_STRING (filename);
490 491 492
  filename = Fexpand_file_name (filename, Qnil);
  encoded = ENCODE_FILE (filename);

493
  if (statfs (SDATA (encoded), &stfs))
494 495 496 497 498 499 500 501 502
    value = Qnil;
  else
    value = list3 (make_float ((double) stfs.f_bsize * stfs.f_blocks),
		   make_float ((double) stfs.f_bsize * stfs.f_bfree),
		   make_float ((double) stfs.f_bsize * stfs.f_bavail));

  return value;
}

503 504 505 506 507
/* System depended enumeration of and access to system processes a-la
   ps(1).  Here, we only return info about the running Emacs process.
   (There are no other processes on DOS, right?)  */

Lisp_Object
508
list_system_processes (void)
509 510 511
{
  Lisp_Object proclist = Qnil;

512
  proclist = Fcons (INT_TO_INTEGER (getpid ()), proclist);
513 514 515 516 517 518 519 520 521 522

  return proclist;
}

Lisp_Object
system_process_attributes (Lisp_Object pid)
{
  int proc_id;
  Lisp_Object attrs = Qnil;

523 524
  CHECK_NUMBER (pid);
  proc_id = XFLOATINT (pid);
525 526 527 528 529 530 531 532 533 534 535 536

  if (proc_id == getpid ())
    {
      EMACS_INT uid, gid;
      char *usr;
      struct group *gr;
      char cmd[FILENAME_MAX];
      char *cmdline = NULL, *p, *q;
      size_t cmdline_size = 0;
      int i;
      Lisp_Object cmd_str, decoded_cmd, tem;
      double pmem;
537
#ifndef SYSTEM_MALLOC
538
      extern unsigned long ret_lim_data ();
539
#endif
540 541

      uid = getuid ();
542
      attrs = Fcons (Fcons (Qeuid, INT_TO_INTEGER (uid)), attrs);
543 544 545 546
      usr = getlogin ();
      if (usr)
	attrs = Fcons (Fcons (Quser, build_string (usr)), attrs);
      gid = getgid ();
547
      attrs = Fcons (Fcons (Qegid, INT_TO_INTEGER (gid)), attrs);
548 549 550 551 552
      gr = getgrgid (gid);
      if (gr)
	attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs);
      strcpy (cmd, basename (__crt0_argv[0]));
      /* Command name is encoded in locale-coding-system; decode it.  */
553
      cmd_str = build_unibyte_string (cmd);
554 555 556 557
      decoded_cmd = code_convert_string_norecord (cmd_str,
						  Vlocale_coding_system, 0);
      attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
      /* Pretend we have 0 as PPID.  */
558
      attrs = Fcons (Fcons (Qppid, make_fixnum (0)), attrs);
559 560 561 562 563
      attrs = Fcons (Fcons (Qpgrp, pid), attrs);
      attrs = Fcons (Fcons (Qttname, build_string ("/dev/tty")), attrs);
      /* We are never idle!  */
      tem = Fget_internal_run_time ();
      attrs = Fcons (Fcons (Qtime, tem), attrs);
564
      attrs = Fcons (Fcons (Qthcount, make_fixnum (1)), attrs);
565 566 567 568
      attrs = Fcons (Fcons (Qstart,
			    Fsymbol_value (intern ("before-init-time"))),
		     attrs);
      attrs = Fcons (Fcons (Qvsize,
569
			    INT_TO_INTEGER ((unsigned long) sbrk (0) / 1024)),
570 571
		     attrs);
      attrs = Fcons (Fcons (Qetime, tem), attrs);
572 573 574
#ifndef SYSTEM_MALLOC
      /* ret_lim_data is on vm-limit.c, which is not compiled in under
	 SYSTEM_MALLOC.  */
575 576
      pmem = (double)((unsigned long) sbrk (0)) / ret_lim_data () * 100.0;
      if (pmem > 100)
577
#endif
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
	pmem = 100;
      attrs = Fcons (Fcons (Qpmem, make_float (pmem)), attrs);
      /* Pass 1: Count how much storage we need.  */
      for (i = 0; i < __crt0_argc; i++)
	{
	  cmdline_size += strlen (__crt0_argv[i]) + 1; /* +1 for blank delim */
	  if (strpbrk (__crt0_argv[i], " \t\n\r\v\f"))
	    {
	      cmdline_size += 2;
	      for (p = __crt0_argv[i]; *p; p++)
		{
		  if (*p == '"')
		    cmdline_size++;
		}
	    }
	}
      /* Pass 2: Allocate storage and concatenate argv[].  */
      cmdline = xmalloc (cmdline_size + 1);
      for (i = 0, q = cmdline; i < __crt0_argc; i++)
	{
	  if (strpbrk (__crt0_argv[i], " \t\n\r\v\f"))
	    {
	      *q++ = '"';
	      for (p = __crt0_argv[i]; *p; p++)
		{
		  if (*p == '\"')
		    *q++ = '\\';
		  *q++ = *p;
		}
	      *q++ = '"';
	    }
	  else
	    {
	      strcpy (q, __crt0_argv[i]);
	      q += strlen (__crt0_argv[i]);
	    }
	  *q++ = ' ';
	}
      /* Remove the trailing blank.  */
      if (q > cmdline)
	q[-1] = '\0';

      /* Command line is encoded in locale-coding-system; decode it.  */
621
      cmd_str = build_unibyte_string (cmdline);
622 623 624 625 626 627 628 629
      decoded_cmd = code_convert_string_norecord (cmd_str,
						  Vlocale_coding_system, 0);
      xfree (cmdline);
      attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs);
    }

  return attrs;
}
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671

/* Support for memory-info.  */
int
dos_memory_info (unsigned long *totalram, unsigned long *freeram,
		 unsigned long *totalswap, unsigned long *freeswap)
{
  _go32_dpmi_meminfo info;
  unsigned long mem1, mem2, freemem;

  _go32_dpmi_get_free_memory_information (&info);
  /* DPMI server of Windows NT and its descendants reports in
     info.available_memory a much lower amount that is really
     available, which causes bogus "past 95% of memory limit"
     warnings.  Try to overcome that via circumstantial evidence.  */
  mem1 = info.available_memory;
  mem2 = info.available_physical_pages;
  /* DPMI Spec: "Fields that are unavailable will hold -1."  */
  if ((long)mem1 == -1L)
    mem1 = 0;
  if ((long)mem2 == -1L)
    mem2 = 0;
  else
    mem2 *= 4096;
  /* Surely, the available memory is at least what we have physically
     available, right?  */
  if (mem1 >= mem2)
    freemem = mem1;
  else
    freemem = mem2;
  *freeram = freemem;
  *totalswap =
    ((long)info.max_pages_in_paging_file == -1L)
    ? 0
    : info.max_pages_in_paging_file * 4096;
  *totalram =
    ((long)info.total_physical_pages == -1L)
    ? (freemem + (unsigned long)sbrk (0) + *totalswap)
    : info.total_physical_pages * 4096;
  *freeswap = 0;
  return 0;
}

672

Eli Zaretskii's avatar
Eli Zaretskii committed
673 674 675
void
dos_cleanup (void)
{
676 677
  struct tty_display_info *tty;

Eli Zaretskii's avatar
Eli Zaretskii committed
678 679 680
#ifndef HAVE_X_WINDOWS
  restore_parent_vm_title ();
#endif
681 682
  /* Make sure the termscript file is committed, in case we are
     crashing and some vital info was written there.  */
683
  if (FRAMEP (selected_frame))
684
    {
685 686 687 688 689 690 691 692 693 694 695 696
      struct frame *sf = XFRAME (selected_frame);

      if (FRAME_LIVE_P (sf)
	  && (FRAME_MSDOS_P (sf) || FRAME_TERMCAP_P (sf)))
	{
	  tty = CURTTY ();
	  if (tty->termscript)
	    {
	      fflush (tty->termscript);
	      fsync (fileno (tty->termscript));
	    }
	}
697
    }
Eli Zaretskii's avatar
Eli Zaretskii committed
698 699
}

Richard M. Stallman's avatar
Richard M. Stallman committed
700 701 702
/*
 *	Define everything
 */
703 704
void
syms_of_dosfns (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
705 706
{
  defsubr (&Sint86);
707 708
  defsubr (&Sdos_memget);
  defsubr (&Sdos_memput);
709 710
  defsubr (&Smsdos_mouse_init);
  defsubr (&Smsdos_mouse_enable);
711 712
  defsubr (&Smsdos_set_keyboard);
  defsubr (&Sinsert_startup_screen);
713
  defsubr (&Smsdos_mouse_disable);
714
  defsubr (&Sfile_system_info);
Morten Welinder's avatar
Morten Welinder committed
715 716 717
#ifndef HAVE_X_WINDOWS
  defsubr (&Smsdos_mouse_p);
#endif
Richard M. Stallman's avatar
Richard M. Stallman committed
718

719
  DEFVAR_INT ("dos-country-code", dos_country_code,
720 721
	      doc: /* The country code returned by Dos when Emacs was started.
Usually this is the international telephone prefix.  */);
Richard M. Stallman's avatar
Richard M. Stallman committed
722

723
  DEFVAR_INT ("dos-codepage", dos_codepage,
724 725 726 727 728 729 730 731 732 733
	      doc: /* The codepage active when Emacs was started.
The following are known:
	437	United States
	850	Multilingual (Latin I)
	852	Slavic (Latin II)
	857	Turkish
	860	Portugal
	861	Iceland
	863	Canada (French)
	865	Norway/Denmark  */);
Richard M. Stallman's avatar
Richard M. Stallman committed
734

735
  DEFVAR_INT ("dos-timezone-offset", dos_timezone_offset,
736 737
	      doc: /* The current timezone offset to UTC in minutes.
Implicitly modified when the TZ variable is changed.  */);
Eli Zaretskii's avatar
Eli Zaretskii committed
738

739
  DEFVAR_LISP ("dos-version", Vdos_version,
740
	       doc: /* The (MAJOR . MINOR) Dos version (subject to modification with setver).  */);
741

Eli Zaretskii's avatar
Eli Zaretskii committed
742
#ifndef HAVE_X_WINDOWS
743
  DEFVAR_LISP ("dos-windows-version", Vdos_windows_version,
744
	       doc: /* The (MAJOR . MINOR) Windows version for DOS session on MS-Windows.  */);
Eli Zaretskii's avatar
Eli Zaretskii committed
745 746
#endif

747
  DEFVAR_LISP ("dos-display-scancodes", Vdos_display_scancodes,
748
	       doc: /* Whether DOS raw keyboard events are displayed as you type.
749 750 751 752
When non-nil, the keyboard scan-codes are displayed at the bottom right
corner of the display (typically at the end of the mode line).
The output format is: scan code:char code*modifiers.  */);

753
  Vdos_display_scancodes = Qnil;
Eli Zaretskii's avatar
Eli Zaretskii committed
754

755
  DEFVAR_INT ("dos-hyper-key", dos_hyper_key,
756
	      doc: /* If set to 1, use right ALT key as hyper key.
757
If set to 2, use right CTRL key as hyper key.  */);
758
  dos_hyper_key = 0;
Eli Zaretskii's avatar
Eli Zaretskii committed
759

760
  DEFVAR_INT ("dos-super-key", dos_super_key,
761
	      doc: /* If set to 1, use right ALT key as super key.
762
If set to 2, use right CTRL key as super key.  */);
763
  dos_super_key = 0;
Eli Zaretskii's avatar
Eli Zaretskii committed
764

765
  DEFVAR_INT ("dos-keypad-mode", dos_keypad_mode,
766
	      doc: /* Controls what key code is returned by a key in the numeric keypad.
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
The `numlock ON' action is only taken if no modifier keys are pressed.
The value is an integer constructed by adding the following bits together:

  0x00	Digit key returns digit    (if numlock ON)
  0x01	Digit key returns kp-digit (if numlock ON)
  0x02	Digit key returns M-digit  (if numlock ON)
  0x03	Digit key returns edit key (if numlock ON)

  0x00	Grey key returns char      (if numlock ON)
  0x04	Grey key returns kp-key    (if numlock ON)

  0x00	Digit key returns digit    (if numlock OFF)
  0x10	Digit key returns kp-digit (if numlock OFF)
  0x20	Digit key returns M-digit  (if numlock OFF)
  0x30	Digit key returns edit key (if numlock OFF)

  0x00	Grey key returns char      (if numlock OFF)
  0x40	Grey key returns kp-key    (if numlock OFF)

  0x200	ALT-0..ALT-9 in top-row produces shifted codes.  */);
787
  dos_keypad_mode = 0x75;
Eli Zaretskii's avatar
Eli Zaretskii committed
788

789
  DEFVAR_INT ("dos-keyboard-layout", dos_keyboard_layout,
790 791
	      doc: /* Contains the country code for the current keyboard layout.
Use msdos-set-keyboard to select another keyboard layout.  */);
792
  dos_keyboard_layout = 1;	/* US */
Eli Zaretskii's avatar
Eli Zaretskii committed
793

794
  DEFVAR_INT ("dos-decimal-point", dos_decimal_point,
795 796 797 798
	      doc: /* The character to produce when kp-decimal key is pressed.
If non-zero, this variable contains the character to be returned when the
decimal point key in the numeric keypad is pressed when Num Lock is on.
If zero, the decimal point key returns the country code specific value.  */);
799
  dos_decimal_point = 0;
Richard M. Stallman's avatar
Richard M. Stallman committed
800 801
}
#endif /* MSDOS */