1 /* Copyright (c) 1992, 1998 John E. Davis
2 * This file is part of JED editor library source.
3 *
4 * You may distribute this file under the terms the GNU General Public
5 * License. See the file COPYING for more information.
6 */
7 #include "config.h"
8 #include "jed-feat.h"
9
10 #include <windows.h>
11 #include <stdio.h>
12 #include <slang.h>
13
14 #include "jdmacros.h"
15
16 #include <process.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 #ifdef _MSC_VER
21 # include <direct.h>
22 #endif
23 #if defined(__BORLANDC__)
24 # include <dir.h>
25 # define _fdopen fdopen
26 #endif
27
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
31
32 #include <time.h>
33
34 #include <assert.h>
35 #include <io.h>
36 #include <errno.h>
37
38 #include <fcntl.h>
39
40 #include "display.h"
41 #include "sysdep.h"
42 #include "screen.h"
43 #include "keymap.h"
44 #include "hooks.h"
45 #include "ins.h"
46 #include "ledit.h"
47 #include "misc.h"
48 #include "cmds.h"
49 #include "sig.h"
50 #include "window.h"
51
52 #include "win32.h"
53
54 #if JED_HAS_SUBPROCESSES
55 # include "jprocess.h"
56 #endif
57
58 extern HANDLE _SLw32_Hstdin;
59
60 static int x_insert_cutbuffer(void);
61 static void x_region_2_cutbuffer(void);
62 static void x_warp_pointer(void);
63 static int msw_system(char *, int *, int *);
64
65 static SLang_Intrin_Fun_Type Jed_WinCommon_Table[] =
66 {
67 MAKE_INTRINSIC("x_warp_pointer", x_warp_pointer, VOID_TYPE, 0),
68 MAKE_INTRINSIC("x_insert_cutbuffer", x_insert_cutbuffer, INT_TYPE, 0),
69 /* Prototype: Integer x_insert_cut_buffer ();
70 * Inserts cutbuffer into the current buffer and returns the number
71 * of characters inserted.
72 */
73 MAKE_INTRINSIC("x_copy_region_to_cutbuffer", x_region_2_cutbuffer, VOID_TYPE, 0),
74 /*Prototype: Void x_copy_region_to_cutbuffer();*/
75
76 SLANG_END_TABLE
77 };
78
init_intrinsics(void)79 static int init_intrinsics (void)
80 {
81 if (-1 == SLadd_intrinsic_function ("msw_system", (FVOID_STAR) msw_system,
82 SLANG_INT_TYPE, 3, SLANG_STRING_TYPE,
83 SLANG_INT_TYPE, SLANG_INT_TYPE))
84 return -1;
85
86 if ((-1 == SLadd_intrin_fun_table (Jed_WinCommon_Table, "MSWINDOWS"))
87 || (-1 == SLdefine_for_ifdef ("MOUSE")))
88 return -1;
89
90 return 0;
91 }
92
93 int Jed_W32_Is_GUI;
94
init_tty(void)95 int init_tty(void)
96 {
97 if (-1 == jed_add_init_slang_hook (init_intrinsics))
98 return -1;
99
100 if (X_Init_Term_Hook != NULL)
101 return (*X_Init_Term_Hook) ();
102
103 Jed_W32_Is_GUI = 0;
104 if (-1 == SLang_init_tty (7, 1, 0))
105 return -1;
106
107 Input_Events[0] = _SLw32_Hstdin;
108 return 0;
109 }
110
reset_tty(void)111 void reset_tty (void)
112 {
113 if (Batch) return;
114
115 if (X_Init_Term_Hook != NULL)
116 {
117 if (X_Reset_Term_Hook != NULL) (*X_Reset_Term_Hook) ();
118 return;
119 }
120
121 SLang_reset_tty();
122 }
123
sys_System(char * command_line)124 int sys_System(char *command_line)
125 {
126 return shell_command(command_line);
127 }
128
sys_pause(int ms)129 void sys_pause (int ms)
130 {
131 Sleep(ms);
132 }
133
init_signals()134 void init_signals()
135 {
136 }
137
138
139
140 /* Delete the file NAME. returns 0 on failure, 1 on sucess
141 * Under OS/2 and DOS, unlink()[UNIX] and remove()[ANSI] are equivalent.
142 */
143
sys_delete_file(char * name)144 int sys_delete_file(char *name)
145 {
146 return(1 + remove(name));
147 }
148
149 static WIN32_FIND_DATA findata;
150 static HANDLE hsearch = INVALID_HANDLE_VALUE;
151 static char Found_Dir[JED_MAX_PATH_LEN];
152 static char Found_File[JED_MAX_PATH_LEN];
153 static int Found_FLen;
154
fixup_name(char * file)155 static void fixup_name(char *file)
156 {
157 int dir;
158 char name[JED_MAX_PATH_LEN];
159
160 strcpy (file, Found_Dir);
161
162 strcpy (name, findata.cFileName);
163 dir = (findata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
164
165 strcat(file, name);
166 if (dir) strcat(file, "\\");
167 }
168
sys_findfirst(char * thefile)169 int sys_findfirst(char *thefile)
170 {
171 char *f, the_path[JED_MAX_PATH_LEN], *file, *f1;
172 char *pat;
173
174 file = expand_filename(thefile);
175 f1 = f = extract_file(file);
176 strcpy (Found_Dir, file);
177
178 strcpy (Found_File, file);
179 Found_FLen = strlen(Found_File);
180
181 Found_Dir[(int) (f - file)] = 0;
182
183 strcpy(the_path, file);
184
185 while (*f1 && (*f1 != '*')) f1++;
186 if (! *f1)
187 {
188 while (*f && (*f != '.')) f++;
189 strcat(the_path, "*");
190 }
191 pat = the_path;
192
193 if (hsearch != INVALID_HANDLE_VALUE) FindClose (hsearch);
194 if ((INVALID_HANDLE_VALUE != (hsearch = FindFirstFile (pat, &findata))))
195 {
196 fixup_name(file);
197
198 /* stupid Windows filesystem is case-insensitive so if
199 * one searches for makefi*, it will return Makefile.in
200 * between the others, so check for wrong values and reject
201 * them */
202 if ((strncmp(file, Found_File, Found_FLen) != 0) &&
203 (!sys_findnext(file)))
204 return 0;
205
206 strcpy(thefile, file);
207 return(1);
208 }
209 else
210 return 0;
211 }
212
sys_findnext(char * file)213 int sys_findnext(char *file)
214 {
215 if (FindNextFile (hsearch, &findata))
216 {
217 fixup_name(file);
218
219 /* stupid Windows filesystem is case-insensitive so if
220 * one searches for makefi*, it will return Makefile.in
221 * between the others, so check for wrong values and reject
222 * them */
223 if (strncmp(file, Found_File, Found_FLen) == 0)
224 return 1;
225 }
226
227 FindClose (hsearch);
228 hsearch = INVALID_HANDLE_VALUE;
229 return 0;
230 }
231
232
233 /* returns 0 if file does not exist, 1 if it is not a dir, 2 if it is */
sys_chmod(char * file,int what,int * mode,short * uid,short * gid)234 int sys_chmod(char *file, int what, int *mode, short *uid, short *gid)
235 {
236 #ifdef _MSC_VER
237 struct _stat buf;
238 #else
239 struct stat buf;
240 #endif
241 char ourname[256];
242 int len;
243
244 if (what)
245 {
246 #ifdef _MSC_VER
247 _chmod(file, *mode);
248 #else
249 chmod(file, *mode);
250 #endif
251 return(0);
252 }
253
254 /* strip the trailing backslash if necessary */
255 strcpy(ourname, file);
256 len = strlen(ourname);
257 if (len>1 && ourname[len-1] == SLASH_CHAR && ourname[len-2] != ':')
258 ourname[strlen(ourname)-1] = '\0';
259
260 if (
261 #ifdef _MSC_VER
262 _stat(ourname, &buf) < 0
263 #else
264 stat(ourname, &buf) < 0
265 #endif
266 )
267 return 0;
268
269 *mode = buf.st_mode & 0777;
270
271 if (buf.st_mode & S_IFDIR) return (2);
272 return(1);
273 }
274
x_warp_pointer(void)275 static void x_warp_pointer (void)
276 {
277 }
278
279
280 static void
x_region_2_cutbuffer(void)281 x_region_2_cutbuffer (void)
282 {
283 int i, x, nbytes;
284 char *dat, *buf;
285 HGLOBAL hBuf;
286
287 dat = make_buffer_substring(&nbytes);
288 if (dat == NULL) return;
289
290 /* space for LF -> CR/LF translation(s) */
291 for (i = x = 0; i < nbytes; i++)
292 if (dat[i] == '\n') x++;
293
294 hBuf = GlobalAlloc(GHND, x + nbytes + 1); /* space for trailing nul */
295 buf = (char *) GlobalLock(hBuf);
296
297 for (i = x = 0; i < nbytes; i++)
298 {
299 if (dat[i] == '\n') buf[x++] = '\r'; /* LF -> CR/LF */
300 buf[x++] = dat[i];
301 }
302 /* since GlobalAlloc() is like calloc(), trailing nul is 'automatic' */
303
304 /* tranfer data to clipboard */
305 OpenClipboard(NULL); /* This_Window.w); */
306 EmptyClipboard();
307
308 GlobalUnlock(hBuf);
309
310 SetClipboardData(CF_TEXT, hBuf);
311 CloseClipboard();
312
313 SLfree (dat); /* discard string */
314 }
315
x_insert_cutbuffer(void)316 static int x_insert_cutbuffer (void)
317 {
318 int nbytes = 0;
319 char *dat;
320 int i, x;
321 HGLOBAL hBuf;
322 char *buf;
323
324 CHECK_READ_ONLY;
325
326 OpenClipboard(NULL);
327
328 hBuf = GetClipboardData(CF_TEXT);
329 CloseClipboard();
330
331 if (hBuf)
332 {
333 buf = (char *)GlobalLock(hBuf);
334 for(i = x = 0; buf[i] != 0; i++)
335 if (buf[i] != '\r') x++;
336
337 nbytes = x;
338 dat = SLmalloc (x + 1);
339 if (dat != NULL)
340 {
341 for(i = x = 0; buf[i] != 0; i++)
342 if (buf[i] != '\r')
343 dat[x++] = buf[i];
344
345 dat[x] = 0;
346
347 ins_chars((unsigned char *) dat, nbytes);
348 SLfree (dat);
349 }
350 GlobalUnlock(hBuf);
351 }
352
353 return nbytes;
354 }
355
msw_system(char * command_line,int * nCmdShow,int * wait)356 static int msw_system(char *command_line, int *nCmdShow, int *wait)
357 {
358 UINT retcode;
359 HCURSOR hcur, hcur_old;
360 STARTUPINFO si;
361 PROCESS_INFORMATION pi;
362
363 memset ((char *) &si, 0, sizeof (STARTUPINFO));
364 si.wShowWindow = *nCmdShow;
365 si.dwFlags = STARTF_USESHOWWINDOW;
366 si.cb = sizeof(si);
367 retcode = CreateProcess (NULL, command_line, NULL, NULL,
368 0, NORMAL_PRIORITY_CLASS, NULL,
369 NULL, &si, &pi);
370 if (!retcode)
371 {
372 msg_error ("Unable to create process");
373 return 1;
374 }
375
376 if (!*wait) return 0;
377
378 hcur = LoadCursor(NULL, IDC_WAIT);
379 hcur_old = SetCursor(hcur);
380 WaitForSingleObject(pi.hProcess, INFINITE);
381 SetCursor(hcur_old);
382 return 0;
383 }
384
385 /* popen, pclose function for Win32 -- it seems that standard ones work
386 * only for console applications.
387 */
388 # define MAX_POPEN 10
389 typedef struct
390 {
391 FILE *fp;
392 HANDLE hprocess;
393 }
394 Popen_Type;
395
396 static int Popen_Ptr = 0;
397 static Popen_Type Popen_Buf[MAX_POPEN];
398
get_helper_app(void)399 static char *get_helper_app (void)
400 {
401 char *s;
402
403 if (1 == SLang_execute_function ("_win32_get_helper_app_name"))
404 {
405 if (-1 == SLang_pop_slstring (&s))
406 return NULL;
407
408 return s;
409 }
410 msg_error ("call to _win32_get_helper_app_name failed");
411 return NULL;
412 }
413
w32_build_command(char ** argv,unsigned int num)414 char *w32_build_command (char **argv, unsigned int num)
415 {
416 unsigned int len;
417 unsigned int i;
418 char *helper;
419 char *cmd;
420
421 helper = get_helper_app ();
422 if (NULL == helper)
423 return NULL;
424 len = strlen (helper);
425 if (len) len++;
426
427 for (i = 0; i < num; i++)
428 len += 1 + strlen (argv[i]);
429
430 cmd = SLmalloc (len + 1);
431 if (cmd == NULL)
432 {
433 SLang_free_slstring (helper);
434 return NULL;
435 }
436
437 len = strlen (helper);
438 if (len)
439 {
440 strcpy (cmd, helper);
441 cmd[len] = ' ';
442 len++;
443 }
444
445 for (i = 0; i < num; i++)
446 {
447 strcpy (cmd + len, argv[i]);
448 len += strlen(argv[i]);
449 cmd[len] = ' ';
450 len++;
451 }
452 cmd[len] = 0;
453
454 SLang_free_slstring (helper);
455 return cmd;
456 }
457
w32_popen(char * cmd,char * mode)458 FILE *w32_popen(char *cmd, char *mode)
459 {
460 int fd;
461 HANDLE rd, wr, er, h, p;
462 STARTUPINFO si;
463 PROCESS_INFORMATION pi;
464 FILE *fp;
465
466 if (Popen_Ptr == MAX_POPEN)
467 {
468 msg_error("too many popens");
469 return NULL;
470 }
471
472 if (((*mode != 'r') && (*mode != 'w')) || (*(mode + 1) != 0))
473 {
474 errno = EINVAL;
475 return(NULL);
476 }
477 if (*mode == 'w')
478 {
479 msg_error ("popen mode `w' not implemented");
480 return NULL;
481 }
482
483 p = GetCurrentProcess ();
484
485 if (FALSE == CreatePipe(&rd, &wr, NULL, 0)) /* NOT inherited */
486 return NULL;
487
488 if (FALSE == DuplicateHandle (p, wr, p, &h, 0, TRUE, DUPLICATE_SAME_ACCESS))
489 {
490 CloseHandle (rd);
491 CloseHandle (wr);
492 }
493 CloseHandle (wr);
494 wr = h;
495
496 /* Get stderr handle from stdout */
497 if (FALSE == DuplicateHandle (p, wr, p, &er, 0, TRUE, DUPLICATE_SAME_ACCESS))
498 {
499 CloseHandle (rd);
500 CloseHandle (wr);
501 return NULL;
502 }
503
504 if (NULL == (cmd = w32_build_command (&cmd, 1)))
505 {
506 CloseHandle (rd);
507 CloseHandle (wr);
508 return NULL;
509 }
510
511 memset ((char *) &si, 0, sizeof (STARTUPINFO));
512 si.cb = sizeof(STARTUPINFO);
513 si.lpReserved = NULL;
514 si.lpReserved2 = NULL;
515 si.cbReserved2 = 0;
516 si.lpDesktop = NULL;
517 si.lpTitle = NULL;
518 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
519 /* si.wShowWindow = SW_MINIMIZE; */
520 si.wShowWindow = SW_HIDE;
521
522 si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
523 si.hStdOutput = wr;
524 si.hStdError = er;
525
526 if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE,
527 CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
528 {
529 jed_verror ("popen failed (cmd=%s)", cmd);
530 SLfree (cmd);
531 CloseHandle (rd);
532 CloseHandle (wr);
533 CloseHandle (er);
534 return NULL;
535 }
536 CloseHandle (wr);
537 CloseHandle (er);
538 SLfree (cmd);
539
540 fd = _open_osfhandle((long) rd, O_RDONLY|O_TEXT);
541 if ((fd < 0)
542 || (NULL == (fp = _fdopen(fd, mode))))
543 {
544 CloseHandle(pi.hProcess);
545 CloseHandle(pi.hThread);
546 if (fd < 0)
547 CloseHandle (rd);
548 else
549 _close (fd);
550 return NULL;
551 }
552 CloseHandle (pi.hThread);
553 CloseHandle (pi.hProcess);
554
555 Popen_Buf[Popen_Ptr].hprocess = pi.hProcess;
556 Popen_Buf[Popen_Ptr].fp = fp;
557 Popen_Ptr++;
558
559 return fp;
560 }
561
w32_pclose(FILE * fp)562 int w32_pclose(FILE *fp)
563 {
564 DWORD d = -1;
565 int i;
566
567 i = Popen_Ptr - 1;
568 while (i >= 0)
569 {
570 if (Popen_Buf[i].fp == fp)
571 {
572 /* send EOF */
573 fprintf(fp, "\x1a");
574 if (fclose(fp) == EOF) return -1;
575 d = 0;
576 #if 0
577 if (WaitForSingleObject(Popen_Buf[i].hprocess, 1000) == WAIT_TIMEOUT)
578 {
579 d = TerminateProcess(Popen_Buf[i].hprocess, -1);
580 }
581
582 GetExitCodeProcess(Popen_Buf[i].hprocess, &d);
583 #endif
584 i++;
585 while (i < Popen_Ptr)
586 {
587 Popen_Buf[i - 1] = Popen_Buf[i];
588 i++;
589 }
590
591 Popen_Ptr--;
592 return d;
593 }
594 i--;
595 }
596
597 return -1;
598 }
599
600