Rationalize the use of c-new-BEG and c-new-END in CC Mode.
[emacs.git] / lib-src / ntlib.c
blob2ace218f8231330b54d351f4de04ac9dcf4a5a88
1 /* Utility and Unix shadow routines for GNU Emacs support programs on NT.
3 Copyright (C) 1994, 2001-2016 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: %d\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: %d\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 /* Place a wrapper around the MSVC version of ctime. It returns NULL
262 on network directories, so we handle that case here.
263 (Ulrich Leodolter, 1/11/95). */
264 char *
265 sys_ctime (const time_t *t)
267 char *str = (char *) ctime (t);
268 return (str ? str : "Sun Jan 01 00:00:00 1970");
271 FILE *
272 sys_fopen (const char * path, const char * mode)
274 return fopen (path, mode);
278 sys_chdir (const char * path)
280 return _chdir (path);
283 static FILETIME utc_base_ft;
284 static long double utc_base;
285 static int init = 0;
287 static time_t
288 convert_time (FILETIME ft)
290 long double ret;
292 if (CompareFileTime (&ft, &utc_base_ft) < 0)
293 return 0;
295 ret = (long double) ft.dwHighDateTime
296 * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
297 ret -= utc_base;
298 return (time_t) (ret * 1e-7L);
301 static int
302 is_exec (const char * name)
304 char * p = strrchr (name, '.');
305 return
306 (p != NULL
307 && (stricmp (p, ".exe") == 0 ||
308 stricmp (p, ".com") == 0 ||
309 stricmp (p, ".bat") == 0 ||
310 stricmp (p, ".cmd") == 0));
313 /* FIXME? This is in configure.ac now - is this still needed? */
314 #define IS_DIRECTORY_SEP(x) ((x) == '/' || (x) == '\\')
316 /* We need this because nt/inc/sys/stat.h defines struct stat that is
317 incompatible with the MS run-time libraries. */
319 stat (const char * path, struct stat * buf)
321 WIN32_FIND_DATA wfd;
322 HANDLE fh;
323 int permission;
324 int len;
325 int rootdir = FALSE;
326 char *name = alloca (FILENAME_MAX);
328 if (!init)
330 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
331 SYSTEMTIME st;
333 st.wYear = 1970;
334 st.wMonth = 1;
335 st.wDay = 1;
336 st.wHour = 0;
337 st.wMinute = 0;
338 st.wSecond = 0;
339 st.wMilliseconds = 0;
341 SystemTimeToFileTime (&st, &utc_base_ft);
342 utc_base = (long double) utc_base_ft.dwHighDateTime
343 * 4096.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
344 init = 1;
347 if (path == NULL || buf == NULL || *path == '\0')
349 errno = EFAULT;
350 return -1;
352 if (_mbspbrk (path, "*?|<>\""))
354 errno = ENOENT;
355 return -1;
358 strcpy (name, path);
359 /* Remove trailing directory separator, unless name is the root
360 directory of a drive in which case ensure there is a trailing
361 separator. */
362 len = strlen (name);
363 rootdir = IS_DIRECTORY_SEP (name[0])
364 || (len == 3 && name[1] == ':' && IS_DIRECTORY_SEP (name[2]));
365 if (rootdir)
367 if (GetDriveType (name) < 2)
369 errno = ENOENT;
370 return -1;
372 memset (&wfd, 0, sizeof (wfd));
373 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
374 wfd.ftCreationTime = utc_base_ft;
375 wfd.ftLastAccessTime = utc_base_ft;
376 wfd.ftLastWriteTime = utc_base_ft;
377 strcpy (wfd.cFileName, name);
379 else
381 if (IS_DIRECTORY_SEP (name[len-1]))
382 name[len - 1] = 0;
384 fh = FindFirstFile (name, &wfd);
385 if (fh == INVALID_HANDLE_VALUE)
387 errno = ENOENT;
388 return -1;
390 FindClose (fh);
392 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
393 S_IFDIR : S_IFREG;
394 buf->st_nlink = 1;
395 buf->st_ino = 0;
397 if (name[0] && name[1] == ':')
398 buf->st_dev = tolower (name[0]) - 'a' + 1;
399 else
400 buf->st_dev = _getdrive ();
401 buf->st_rdev = buf->st_dev;
403 buf->st_size = wfd.nFileSizeLow;
405 /* Convert timestamps to Unix format. */
406 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
407 buf->st_atime = convert_time (wfd.ftLastAccessTime);
408 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
409 buf->st_ctime = convert_time (wfd.ftCreationTime);
410 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
412 /* determine rwx permissions */
413 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
414 permission = S_IREAD;
415 else
416 permission = S_IREAD | S_IWRITE;
418 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
419 permission |= S_IEXEC;
420 else if (is_exec (name))
421 permission |= S_IEXEC;
423 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
425 return 0;
429 lstat (const char * path, struct stat * buf)
431 return stat (path, buf);
434 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
435 when using mktemp. Copied from w32.c.
437 This is used only in update-game-score.c. It is overkill for that
438 use case, since update-game-score renames the temporary file into
439 the game score file, which isn't atomic on MS-Windows anyway, when
440 the game score already existed before running the program, which it
441 almost always does. But using a simpler implementation just to
442 make a point is uneconomical... */
445 mkostemp (char * template, int flags)
447 char * p;
448 int i, fd = -1;
449 unsigned uid = GetCurrentThreadId ();
450 int save_errno = errno;
451 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
453 errno = EINVAL;
454 if (template == NULL)
455 return -1;
457 p = template + strlen (template);
458 i = 5;
459 /* replace up to the last 5 X's with uid in decimal */
460 while (--p >= template && p[0] == 'X' && --i >= 0)
462 p[0] = '0' + uid % 10;
463 uid /= 10;
466 if (i < 0 && p[0] == 'X')
468 i = 0;
471 p[0] = first_char[i];
472 if ((fd = open (template,
473 flags | _O_CREAT | _O_EXCL | _O_RDWR,
474 S_IRUSR | S_IWUSR)) >= 0
475 || errno != EEXIST)
477 if (fd >= 0)
478 errno = save_errno;
479 return fd;
482 while (++i < sizeof (first_char));
485 /* Template is badly formed or else we can't generate a unique name. */
486 return -1;
489 /* On Windows, you cannot rename into an existing file. */
491 sys_rename (const char *from, const char *to)
493 int retval = rename (from, to);
495 if (retval < 0 && errno == EEXIST)
497 if (unlink (to) == 0)
498 retval = rename (from, to);
500 return retval;