Fix the %P (line number) thing in Gnus summary buffers
[emacs.git] / lib-src / ntlib.c
blob4bffc612f9bb31c773d6def1668e740f4aaa1348
1 /* Utility and Unix shadow routines for GNU Emacs support programs on NT.
3 Copyright (C) 1994, 2001-2017 Free Software Foundation, Inc.
5 Author: Geoff Voelker (voelker@cs.washington.edu)
6 Created: 10-8-94
8 This file is part of GNU Emacs.
10 GNU Emacs is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or (at
13 your option) any later version.
15 GNU Emacs is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
23 #include <windows.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <time.h>
27 #include <direct.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <errno.h>
31 #include <ctype.h>
32 #include <sys/timeb.h>
33 #include <mbstring.h>
35 #include "ntlib.h"
37 char *sys_ctime (const time_t *);
38 FILE *sys_fopen (const char *, const char *);
39 int sys_chdir (const char *);
40 int mkostemp (char *, int);
41 int sys_rename (const char *, const char *);
43 /* MinGW64 defines _TIMEZONE_DEFINED and defines 'struct timespec' in
44 its system headers. */
45 #ifndef _TIMEZONE_DEFINED
46 struct timezone
48 int tz_minuteswest; /* minutes west of Greenwich */
49 int tz_dsttime; /* type of dst correction */
51 #endif
53 void gettimeofday (struct timeval *, struct timezone *);
55 #define MAXPATHLEN _MAX_PATH
57 /* Emulate sleep...we could have done this with a define, but that
58 would necessitate including windows.h in the files that used it.
59 This is much easier. */
60 unsigned
61 sleep (unsigned seconds)
63 Sleep (seconds * 1000);
64 return 0;
67 /* Get the current working directory. */
68 char *
69 getwd (char *dir)
71 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
72 return dir;
73 return NULL;
76 static HANDLE getppid_parent;
77 static int getppid_ppid;
79 int
80 getppid (void)
82 char *ppid;
83 DWORD result;
85 ppid = getenv ("EM_PARENT_PROCESS_ID");
86 if (!ppid)
88 printf ("no pid.\n");
89 return 0;
91 else
93 getppid_ppid = atoi (ppid);
96 if (!getppid_parent)
98 getppid_parent = OpenProcess (SYNCHRONIZE, FALSE, atoi (ppid));
99 if (!getppid_parent)
101 printf ("Failed to open handle to parent process: %lu\n",
102 GetLastError ());
103 exit (1);
107 result = WaitForSingleObject (getppid_parent, 0);
108 switch (result)
110 case WAIT_TIMEOUT:
111 /* The parent is still alive. */
112 return getppid_ppid;
113 case WAIT_OBJECT_0:
114 /* The parent is gone. Return the pid of Unix init (1). */
115 return 1;
116 case WAIT_FAILED:
117 default:
118 printf ("Checking parent status failed: %lu\n", GetLastError ());
119 exit (1);
123 char *
124 getlogin (void)
126 static char user_name[256];
127 DWORD length = sizeof (user_name);
129 if (GetUserName (user_name, &length))
130 return user_name;
131 return NULL;
134 char *
135 cuserid (char * s)
137 char * name = getlogin ();
138 if (s)
139 return strcpy (s, name ? name : "");
140 return name;
143 unsigned
144 getuid (void)
146 return 0;
149 unsigned
150 geteuid (void)
152 return getuid ();
155 unsigned
156 getgid (void)
158 return 0;
161 unsigned
162 getegid (void)
164 return 0;
168 setuid (unsigned uid)
170 return 0;
174 setregid (unsigned rgid, unsigned gid)
176 return 0;
179 struct passwd *
180 getpwuid (unsigned uid)
182 return NULL;
185 char *
186 getpass (const char * prompt)
188 static char input[256];
189 HANDLE in;
190 HANDLE err;
191 DWORD count;
193 in = GetStdHandle (STD_INPUT_HANDLE);
194 err = GetStdHandle (STD_ERROR_HANDLE);
196 if (in == INVALID_HANDLE_VALUE || err == INVALID_HANDLE_VALUE)
197 return NULL;
199 if (WriteFile (err, prompt, strlen (prompt), &count, NULL))
201 int istty = (GetFileType (in) == FILE_TYPE_CHAR);
202 DWORD old_flags;
203 int rc;
205 if (istty)
207 if (GetConsoleMode (in, &old_flags))
208 SetConsoleMode (in, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
209 else
210 istty = 0;
212 rc = ReadFile (in, input, sizeof (input), &count, NULL);
213 if (count >= 2 && input[count - 2] == '\r')
214 input[count - 2] = '\0';
215 else
217 char buf[256];
218 while (ReadFile (in, buf, sizeof (buf), &count, NULL) > 0)
219 if (count >= 2 && buf[count - 2] == '\r')
220 break;
222 WriteFile (err, "\r\n", 2, &count, NULL);
223 if (istty)
224 SetConsoleMode (in, old_flags);
225 if (rc)
226 return input;
229 return NULL;
232 /* This is needed because lib/gettime.c calls gettimeofday, which MSVC
233 doesn't have. Copied from w32.c. */
234 void
235 gettimeofday (struct timeval *tv, struct timezone *tz)
237 struct _timeb tb;
238 _ftime (&tb);
240 tv->tv_sec = tb.time;
241 tv->tv_usec = tb.millitm * 1000L;
242 /* Implementation note: _ftime sometimes doesn't update the dstflag
243 according to the new timezone when the system timezone is
244 changed. We could fix that by using GetSystemTime and
245 GetTimeZoneInformation, but that doesn't seem necessary, since
246 Emacs always calls gettimeofday with the 2nd argument NULL (see
247 current_emacs_time). */
248 if (tz)
250 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
251 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
256 fchown (int fd, unsigned uid, unsigned gid)
258 return 0;
261 FILE *
262 sys_fopen (const char * path, const char * mode)
264 return fopen (path, mode);
268 sys_chdir (const char * path)
270 return _chdir (path);
273 static FILETIME utc_base_ft;
274 static long double utc_base;
275 static int init = 0;
277 static time_t
278 convert_time (FILETIME ft)
280 long double ret;
282 if (CompareFileTime (&ft, &utc_base_ft) < 0)
283 return 0;
285 ret = (long double) ft.dwHighDateTime
286 * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
287 ret -= utc_base;
288 return (time_t) (ret * 1e-7L);
291 static int
292 is_exec (const char * name)
294 char * p = strrchr (name, '.');
295 return
296 (p != NULL
297 && (stricmp (p, ".exe") == 0 ||
298 stricmp (p, ".com") == 0 ||
299 stricmp (p, ".bat") == 0 ||
300 stricmp (p, ".cmd") == 0));
303 /* FIXME? This is in configure.ac now - is this still needed? */
304 #define IS_DIRECTORY_SEP(x) ((x) == '/' || (x) == '\\')
306 /* We need this because nt/inc/sys/stat.h defines struct stat that is
307 incompatible with the MS run-time libraries. */
309 stat (const char * path, struct stat * buf)
311 WIN32_FIND_DATA wfd;
312 HANDLE fh;
313 int permission;
314 int len;
315 int rootdir = FALSE;
316 char *name = alloca (FILENAME_MAX);
318 if (!init)
320 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
321 SYSTEMTIME st;
323 st.wYear = 1970;
324 st.wMonth = 1;
325 st.wDay = 1;
326 st.wHour = 0;
327 st.wMinute = 0;
328 st.wSecond = 0;
329 st.wMilliseconds = 0;
331 SystemTimeToFileTime (&st, &utc_base_ft);
332 utc_base = (long double) utc_base_ft.dwHighDateTime
333 * 4096.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
334 init = 1;
337 if (path == NULL || buf == NULL || *path == '\0')
339 errno = EFAULT;
340 return -1;
342 if (_mbspbrk (path, "*?|<>\""))
344 errno = ENOENT;
345 return -1;
348 strcpy (name, path);
349 /* Remove trailing directory separator, unless name is the root
350 directory of a drive in which case ensure there is a trailing
351 separator. */
352 len = strlen (name);
353 rootdir = IS_DIRECTORY_SEP (name[0])
354 || (len == 3 && name[1] == ':' && IS_DIRECTORY_SEP (name[2]));
355 if (rootdir)
357 if (GetDriveType (name) < 2)
359 errno = ENOENT;
360 return -1;
362 memset (&wfd, 0, sizeof (wfd));
363 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
364 wfd.ftCreationTime = utc_base_ft;
365 wfd.ftLastAccessTime = utc_base_ft;
366 wfd.ftLastWriteTime = utc_base_ft;
367 strcpy (wfd.cFileName, name);
369 else
371 if (IS_DIRECTORY_SEP (name[len-1]))
372 name[len - 1] = 0;
374 fh = FindFirstFile (name, &wfd);
375 if (fh == INVALID_HANDLE_VALUE)
377 errno = ENOENT;
378 return -1;
380 FindClose (fh);
382 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
383 S_IFDIR : S_IFREG;
384 buf->st_nlink = 1;
385 buf->st_ino = 0;
387 if (name[0] && name[1] == ':')
388 buf->st_dev = tolower (name[0]) - 'a' + 1;
389 else
390 buf->st_dev = _getdrive ();
391 buf->st_rdev = buf->st_dev;
393 buf->st_size = wfd.nFileSizeLow;
395 /* Convert timestamps to Unix format. */
396 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
397 buf->st_atime = convert_time (wfd.ftLastAccessTime);
398 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
399 buf->st_ctime = convert_time (wfd.ftCreationTime);
400 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
402 /* determine rwx permissions */
403 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
404 permission = S_IREAD;
405 else
406 permission = S_IREAD | S_IWRITE;
408 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
409 permission |= S_IEXEC;
410 else if (is_exec (name))
411 permission |= S_IEXEC;
413 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
415 return 0;
419 lstat (const char * path, struct stat * buf)
421 return stat (path, buf);
424 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
425 when using mktemp. Copied from w32.c.
427 This is used only in update-game-score.c. It is overkill for that
428 use case, since update-game-score renames the temporary file into
429 the game score file, which isn't atomic on MS-Windows anyway, when
430 the game score already existed before running the program, which it
431 almost always does. But using a simpler implementation just to
432 make a point is uneconomical... */
435 mkostemp (char * template, int flags)
437 char * p;
438 int i, fd = -1;
439 unsigned uid = GetCurrentThreadId ();
440 int save_errno = errno;
441 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
443 errno = EINVAL;
444 if (template == NULL)
445 return -1;
447 p = template + strlen (template);
448 i = 5;
449 /* replace up to the last 5 X's with uid in decimal */
450 while (--p >= template && p[0] == 'X' && --i >= 0)
452 p[0] = '0' + uid % 10;
453 uid /= 10;
456 if (i < 0 && p[0] == 'X')
458 i = 0;
461 p[0] = first_char[i];
462 if ((fd = open (template,
463 flags | _O_CREAT | _O_EXCL | _O_RDWR,
464 S_IRUSR | S_IWUSR)) >= 0
465 || errno != EEXIST)
467 if (fd >= 0)
468 errno = save_errno;
469 return fd;
472 while (++i < sizeof (first_char));
475 /* Template is badly formed or else we can't generate a unique name. */
476 return -1;
479 /* On Windows, you cannot rename into an existing file. */
481 sys_rename (const char *from, const char *to)
483 int retval = rename (from, to);
485 if (retval < 0 && errno == EEXIST)
487 if (unlink (to) == 0)
488 retval = rename (from, to);
490 return retval;