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