1 /* GNUPLOT - win/winmain.c */
2 /*[
3 * Copyright 1992, 1993, 1998, 2004 Maurice Castro, Russell Lang
4 *
5 * Permission to use, copy, and distribute this software and its
6 * documentation for any purpose with or without fee is hereby granted,
7 * provided that the above copyright notice appear in all copies and
8 * that both that copyright notice and this permission notice appear
9 * in supporting documentation.
10 *
11 * Permission to modify the software is granted, but not the right to
12 * distribute the complete modified source code. Modifications are to
13 * be distributed as patches to the released version. Permission to
14 * distribute binaries produced by compiling modified sources is granted,
15 * provided you
16 * 1. distribute the corresponding source modifications from the
17 * released version in the form of a patch file along with the binaries,
18 * 2. add special version identification to distinguish your version
19 * in addition to the base release version number,
20 * 3. provide your name and address as the primary contact for the
21 * support of your modified version, and
22 * 4. retain our contact information in regard to use of the base
23 * software.
24 * Permission to distribute the released version of the source code along
25 * with corresponding source modifications in the form of a patch file is
26 * granted with same provisions 2 through 4 for binary distributions.
27 *
28 * This software is provided "as is" without express or implied warranty
29 * to the extent permitted by applicable law.
30 ]*/
31
32 /*
33 * AUTHORS
34 *
35 * Maurice Castro
36 * Russell Lang
37 *
38 */
39
40 /* This file implements the initialization code for running gnuplot */
41 /* under Microsoft Windows. */
42 /* */
43 /* The modifications to allow Gnuplot to run under Windows were made */
44 /* by Maurice Castro. (maurice@bruce.cs.monash.edu.au) 3 Jul 1992 */
45 /* and Russell Lang (rjl@monu1.cc.monash.edu.au) 30 Nov 1992 */
46 /* */
47
48 #include "syscfg.h"
49 #define STRICT
50 #include <windows.h>
51 #include <windowsx.h>
52 #include <commctrl.h>
53 #include <shlobj.h>
54 #include <shlwapi.h>
55 #include <htmlhelp.h>
56 #include <dos.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <stdarg.h>
61 #include <tchar.h>
62 #include <ctype.h>
63 #include <fcntl.h>
64 #include <io.h>
65 #include <sys/stat.h>
66 #include "alloc.h"
67 #include "plot.h"
68 #include "setshow.h"
69 #include "version.h"
70 #include "command.h"
71 #include "encoding.h"
72 #include "winmain.h"
73 #include "wtext.h"
74 #include "wcommon.h"
75 #ifdef HAVE_GDIPLUS
76 #include "wgdiplus.h"
77 #endif
78 #ifdef HAVE_D2D
79 #include "wd2d.h"
80 #endif
81 #ifdef WXWIDGETS
82 #include "wxterminal/wxt_term.h"
83 #endif
84 #ifdef HAVE_LIBCACA
85 # define TERM_PUBLIC_PROTO
86 # include "caca.trm"
87 # undef TERM_PUBLIC_PROTO
88 #endif
89
90
91 /* workaround for old header files */
92 #ifndef CSIDL_APPDATA
93 # define CSIDL_APPDATA (0x001a)
94 #endif
95
96 /* limits */
97 #define MAXSTR 255
98 #define MAXPRINTF 1024
99 /* used if vsnprintf(NULL,0,...) returns zero (MingW 3.4) */
100
101 /* globals */
102 #ifndef WGP_CONSOLE
103 TW textwin;
104 MW menuwin;
105 #endif
106 LPGW graphwin; /* current graph window */
107 LPGW listgraphs; /* list of graph windows */
108 PW pausewin;
109 LPTSTR szModuleName;
110 LPTSTR szPackageDir;
111 LPTSTR winhelpname;
112 LPTSTR szMenuName;
113 static LPTSTR szLanguageCode = NULL;
114 HWND help_window = NULL;
115
116 char *authors[]={
117 "Colin Kelley",
118 "Thomas Williams"
119 };
120
121 void WinExit(void);
122 static void WinCloseHelp(void);
123 int CALLBACK ShutDown(void);
124 #ifdef WGP_CONSOLE
125 static int ConsolePutS(const char *str);
126 static int ConsolePutCh(int ch);
127 #endif
128
129
130 static void
CheckMemory(LPTSTR str)131 CheckMemory(LPTSTR str)
132 {
133 if (str == NULL) {
134 MessageBox(NULL, TEXT("out of memory"), TEXT("gnuplot"), MB_ICONSTOP | MB_OK);
135 gp_exit(EXIT_FAILURE);
136 }
137 }
138
139
140 int
Pause(LPSTR str)141 Pause(LPSTR str)
142 {
143 int rc;
144
145 pausewin.Message = UnicodeText(str, encoding);
146 rc = PauseBox(&pausewin) == IDOK;
147 free(pausewin.Message);
148 return rc;
149 }
150
151
152 void
kill_pending_Pause_dialog(void)153 kill_pending_Pause_dialog(void)
154 {
155 if (!pausewin.bPause) /* no Pause dialog displayed */
156 return;
157 /* Pause dialog displayed, thus kill it */
158 DestroyWindow(pausewin.hWndPause);
159 pausewin.bPause = FALSE;
160 }
161
162
163 /* atexit procedure */
164 void
WinExit(void)165 WinExit(void)
166 {
167 LPGW lpgw;
168
169 /* Last chance to close Windows help, call before anything else to avoid a crash. */
170 WinCloseHelp();
171
172 /* clean-up call for printing system */
173 PrintingCleanup();
174
175 term_reset();
176
177 _fcloseall();
178
179 /* Close all graph windows */
180 for (lpgw = listgraphs; lpgw != NULL; lpgw = lpgw->next) {
181 if (GraphHasWindow(lpgw))
182 GraphClose(lpgw);
183 }
184
185 #ifndef WGP_CONSOLE
186 TextMessage(); /* process messages */
187 # ifndef __WATCOMC__
188 /* revert C++ stream redirection */
189 RedirectOutputStreams(FALSE);
190 # endif
191 #endif
192 #ifdef HAVE_GDIPLUS
193 gdiplusCleanup();
194 #endif
195 #ifdef HAVE_D2D
196 d2dCleanup();
197 #endif
198 CoUninitialize();
199 return;
200 }
201
202
203 /* call back function from Text Window WM_CLOSE */
204 int CALLBACK
ShutDown(void)205 ShutDown(void)
206 {
207 /* First chance for wgnuplot to close help system. */
208 WinCloseHelp();
209 gp_exit(EXIT_SUCCESS);
210 return 0;
211 }
212
213
214 /* This function can be used to retrieve version information from
215 * Window's Shell and common control libraries (Comctl32.dll,
216 * Shell32.dll, and Shlwapi.dll) The code was copied from the MSDN
217 * article "Shell and Common Controls Versions" */
218 DWORD
GetDllVersion(LPCTSTR lpszDllName)219 GetDllVersion(LPCTSTR lpszDllName)
220 {
221 HINSTANCE hinstDll;
222 DWORD dwVersion = 0;
223
224 /* For security purposes, LoadLibrary should be provided with a
225 fully-qualified path to the DLL. The lpszDllName variable should be
226 tested to ensure that it is a fully qualified path before it is used. */
227 hinstDll = LoadLibrary(lpszDllName);
228
229 if (hinstDll) {
230 DLLGETVERSIONPROC pDllGetVersion;
231 pDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hinstDll, "DllGetVersion");
232
233 /* Because some DLLs might not implement this function, you
234 must test for it explicitly. Depending on the particular
235 DLL, the lack of a DllGetVersion function can be a useful
236 indicator of the version. */
237 if (pDllGetVersion) {
238 DLLVERSIONINFO dvi;
239 HRESULT hr;
240
241 ZeroMemory(&dvi, sizeof(dvi));
242 dvi.cbSize = sizeof(dvi);
243 hr = (*pDllGetVersion)(&dvi);
244 if (SUCCEEDED(hr))
245 dwVersion = PACKVERSION(dvi.dwMajorVersion, dvi.dwMinorVersion);
246 }
247 FreeLibrary(hinstDll);
248 }
249 return dwVersion;
250 }
251
252
253 BOOL
IsWindowsXPorLater(void)254 IsWindowsXPorLater(void)
255 {
256 OSVERSIONINFO versionInfo;
257
258 /* get Windows version */
259 ZeroMemory(&versionInfo, sizeof(OSVERSIONINFO));
260 versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
261 GetVersionEx(&versionInfo);
262 return ((versionInfo.dwMajorVersion > 5) ||
263 ((versionInfo.dwMajorVersion == 5) && (versionInfo.dwMinorVersion >= 1)));
264 }
265
266
267 char *
appdata_directory(void)268 appdata_directory(void)
269 {
270 HMODULE hShell32;
271 FARPROC pSHGetSpecialFolderPath;
272 static char dir[MAX_PATH] = "";
273
274 if (dir[0])
275 return dir;
276
277 /* FIMXE: "ANSI" Version, no Unicode support */
278
279 /* Make sure that SHGetSpecialFolderPath is supported. */
280 hShell32 = LoadLibrary(TEXT("shell32.dll"));
281 if (hShell32) {
282 pSHGetSpecialFolderPath =
283 GetProcAddress(hShell32, "SHGetSpecialFolderPathA");
284 if (pSHGetSpecialFolderPath)
285 (*pSHGetSpecialFolderPath)(NULL, dir, CSIDL_APPDATA, FALSE);
286 FreeModule(hShell32);
287 return dir;
288 }
289
290 /* use APPDATA environment variable as fallback */
291 if (dir[0] == NUL) {
292 char *appdata = getenv("APPDATA");
293 if (appdata) {
294 strcpy(dir, appdata);
295 return dir;
296 }
297 }
298
299 return NULL;
300 }
301
302
303 /* retrieve path relative to gnuplot executable */
304 LPSTR
RelativePathToGnuplot(const char * path)305 RelativePathToGnuplot(const char * path)
306 {
307 #ifdef UNICODE
308 LPSTR ansi_dir = AnsiText(szPackageDir, encoding);
309 LPSTR rel_path = (char *) gp_realloc(ansi_dir, strlen(ansi_dir) + strlen(path) + 1, "RelativePathToGnuplot");
310 if (rel_path == NULL) {
311 free(ansi_dir);
312 return (LPSTR) path;
313 }
314 #else
315 char * rel_path = (char * ) gp_alloc(strlen(szPackageDir) + strlen(path) + 1, "RelativePathToGnuplot");
316 strcpy(rel_path, szPackageDir);
317 #endif
318 /* szPackageDir is guaranteed to have a trailing backslash */
319 strcat(rel_path, path);
320 return rel_path;
321 }
322
323
324 static void
WinCloseHelp(void)325 WinCloseHelp(void)
326 {
327 /* Due to a known bug in the HTML help system we have to
328 * call this as soon as possible before the end of the program.
329 * See e.g. http://helpware.net/FAR/far_faq.htm#HH_CLOSE_ALL
330 */
331 if (IsWindow(help_window))
332 SendMessage(help_window, WM_CLOSE, 0, 0);
333 Sleep(0);
334 }
335
336
337 static LPTSTR
GetLanguageCode(void)338 GetLanguageCode(void)
339 {
340 static TCHAR lang[6] = TEXT("");
341
342 if (lang[0] == NUL) {
343 GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVLANGNAME, lang, sizeof(lang));
344 //strcpy(lang, "JPN"); //TEST
345 /* language definition files for Japanese already use "ja" as abbreviation */
346 if (_tcscmp(lang, TEXT("JPN")) == 0)
347 lang[1] = 'A';
348 /* prefer lower case */
349 lang[0] = tolower((unsigned char)lang[0]);
350 lang[1] = tolower((unsigned char)lang[1]);
351 /* only use two character sequence */
352 lang[2] = NUL;
353 }
354
355 return lang;
356 }
357
358
359 static LPTSTR
LocalisedFile(LPCTSTR name,LPCTSTR ext,LPCTSTR defaultname)360 LocalisedFile(LPCTSTR name, LPCTSTR ext, LPCTSTR defaultname)
361 {
362 LPTSTR lang;
363 LPTSTR filename;
364
365 /* Allow user to override language detection. */
366 if (szLanguageCode)
367 lang = szLanguageCode;
368 else
369 lang = GetLanguageCode();
370
371 filename = (LPTSTR) malloc((_tcslen(szModuleName) + _tcslen(name) + _tcslen(lang) + _tcslen(ext) + 1) * sizeof(TCHAR));
372 if (filename) {
373 _tcscpy(filename, szModuleName);
374 _tcscat(filename, name);
375 _tcscat(filename, lang);
376 _tcscat(filename, ext);
377 if (!PathFileExists(filename)) {
378 _tcscpy(filename, szModuleName);
379 _tcscat(filename, defaultname);
380 }
381 }
382 return filename;
383 }
384
385
386 static void
ReadMainIni(LPTSTR file,LPTSTR section)387 ReadMainIni(LPTSTR file, LPTSTR section)
388 {
389 TCHAR profile[81] = TEXT("");
390 const TCHAR hlpext[] = TEXT(".chm");
391 const TCHAR name[] = TEXT("wgnuplot-");
392
393 /* Language code override */
394 GetPrivateProfileString(section, TEXT("Language"), TEXT(""), profile, 80, file);
395 if (profile[0] != NUL)
396 szLanguageCode = _tcsdup(profile);
397 else
398 szLanguageCode = NULL;
399
400 /* help file name */
401 GetPrivateProfileString(section, TEXT("HelpFile"), TEXT(""), profile, 80, file);
402 if (profile[0] != NUL) {
403 winhelpname = (LPTSTR) malloc((_tcslen(szModuleName) + _tcslen(profile) + 1) * sizeof(TCHAR));
404 if (winhelpname) {
405 _tcscpy(winhelpname, szModuleName);
406 _tcscat(winhelpname, profile);
407 }
408 } else {
409 /* default name is "wgnuplot-LL.chm" */
410 winhelpname = LocalisedFile(name, hlpext, TEXT(HELPFILE));
411 }
412
413 /* menu file name */
414 GetPrivateProfileString(section, TEXT("MenuFile"), TEXT(""), profile, 80, file);
415 if (profile[0] != NUL) {
416 szMenuName = (LPTSTR) malloc((_tcslen(szModuleName) + _tcslen(profile) + 1) * sizeof(TCHAR));
417 if (szMenuName) {
418 _tcscpy(szMenuName, szModuleName);
419 _tcscat(szMenuName, profile);
420 }
421 } else {
422 /* default name is "wgnuplot-LL.mnu" */
423 szMenuName = LocalisedFile(name, TEXT(".mnu"), TEXT("wgnuplot.mnu"));
424 }
425 }
426
427
428 #ifndef WGP_CONSOLE
429 int WINAPI
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpszCmdLine,int nCmdShow)430 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
431 #else
432 int
433 main(int argc, char **argv)
434 #endif
435 {
436 LPTSTR tail;
437 #ifdef WGP_CONSOLE
438 HINSTANCE hInstance = GetModuleHandle(NULL), hPrevInstance = NULL;
439 #else
440 int i;
441 #endif
442
443 #ifndef WGP_CONSOLE
444 # if defined( __MINGW32__) && !defined(_W64)
445 # define argc _argc
446 # define argv _argv
447 # else /* MSVC, WATCOM, MINGW-W64 */
448 # define argc __argc
449 # define argv __argv
450 # endif
451 #endif /* WGP_CONSOLE */
452
453 szModuleName = (LPTSTR) malloc((MAXSTR + 1) * sizeof(TCHAR));
454 CheckMemory(szModuleName);
455
456 /* get path to gnuplot executable */
457 GetModuleFileName(hInstance, szModuleName, MAXSTR);
458 if ((tail = _tcsrchr(szModuleName, '\\')) != NULL) {
459 tail++;
460 *tail = 0;
461 }
462 szModuleName = (LPTSTR) realloc(szModuleName, (_tcslen(szModuleName) + 1) * sizeof(TCHAR));
463 CheckMemory(szModuleName);
464
465 if (_tcslen(szModuleName) >= 5 && _tcsnicmp(&szModuleName[_tcslen(szModuleName)-5], TEXT("\\bin\\"), 5) == 0) {
466 size_t len = _tcslen(szModuleName) - 4;
467 szPackageDir = (LPTSTR) malloc((len + 1) * sizeof(TCHAR));
468 CheckMemory(szPackageDir);
469 _tcsncpy(szPackageDir, szModuleName, len);
470 szPackageDir[len] = NUL;
471 } else {
472 szPackageDir = szModuleName;
473 }
474
475 #ifndef WGP_CONSOLE
476 textwin.hInstance = hInstance;
477 textwin.hPrevInstance = hPrevInstance;
478 textwin.nCmdShow = nCmdShow;
479 textwin.Title = L"gnuplot";
480 #endif
481
482 /* create structure of first graph window */
483 graphwin = (LPGW) calloc(1, sizeof(GW));
484 listgraphs = graphwin;
485
486 /* locate ini file */
487 {
488 char * inifile;
489 #ifdef UNICODE
490 LPWSTR winifile;
491 #endif
492 get_user_env(); /* this hasn't been called yet */
493 inifile = gp_strdup("~\\wgnuplot.ini");
494 gp_expand_tilde(&inifile);
495
496 /* if tilde expansion fails use current directory as
497 default - that was the previous default behaviour */
498 if (inifile[0] == '~') {
499 free(inifile);
500 inifile = "wgnuplot.ini";
501 }
502 #ifdef UNICODE
503 graphwin->IniFile = winifile = UnicodeText(inifile, S_ENC_DEFAULT);
504 #else
505 graphwin->IniFile = inifile;
506 #endif
507 #ifndef WGP_CONSOLE
508 textwin.IniFile = graphwin->IniFile;
509 #endif
510 ReadMainIni(graphwin->IniFile, TEXT("WGNUPLOT"));
511 }
512
513 #ifndef WGP_CONSOLE
514 textwin.IniSection = TEXT("WGNUPLOT");
515 textwin.DragPre = L"load '";
516 textwin.DragPost = L"'\n";
517 textwin.lpmw = &menuwin;
518 textwin.ScreenSize.x = 80;
519 textwin.ScreenSize.y = 80;
520 textwin.KeyBufSize = 2048;
521 textwin.CursorFlag = 1; /* scroll to cursor after \n & \r */
522 textwin.shutdown = MakeProcInstance((FARPROC)ShutDown, hInstance);
523 textwin.AboutText = (LPTSTR) malloc(1024 * sizeof(TCHAR));
524 CheckMemory(textwin.AboutText);
525 wsprintf(textwin.AboutText,
526 TEXT("Version %hs patchlevel %hs\n") \
527 TEXT("last modified %hs\n") \
528 TEXT("%hs\n%hs, %hs and many others\n") \
529 TEXT("gnuplot home: http://www.gnuplot.info\n"),
530 gnuplot_version, gnuplot_patchlevel,
531 gnuplot_date,
532 gnuplot_copyright, authors[1], authors[0]);
533 textwin.AboutText = (LPTSTR) realloc(textwin.AboutText, (_tcslen(textwin.AboutText) + 1) * sizeof(TCHAR));
534 CheckMemory(textwin.AboutText);
535
536 menuwin.szMenuName = szMenuName;
537 #endif
538
539 pausewin.hInstance = hInstance;
540 pausewin.hPrevInstance = hPrevInstance;
541 pausewin.Title = L"gnuplot pause";
542
543 graphwin->hInstance = hInstance;
544 graphwin->hPrevInstance = hPrevInstance;
545 #ifdef WGP_CONSOLE
546 graphwin->lptw = NULL;
547 #else
548 graphwin->lptw = &textwin;
549 #endif
550
551 /* COM Initialization */
552 if (!SUCCEEDED(CoInitialize(NULL))) {
553 // FIXME: Need to abort
554 }
555
556 /* init common controls */
557 {
558 INITCOMMONCONTROLSEX initCtrls;
559 initCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX);
560 initCtrls.dwICC = ICC_WIN95_CLASSES;
561 InitCommonControlsEx(&initCtrls);
562 }
563
564 #ifndef WGP_CONSOLE
565 if (TextInit(&textwin))
566 gp_exit(EXIT_FAILURE);
567 textwin.hIcon = LoadIcon(hInstance, TEXT("TEXTICON"));
568 SetClassLongPtr(textwin.hWndParent, GCLP_HICON, (LONG_PTR)textwin.hIcon);
569
570 /* Note: we want to know whether this is an interactive session so that we can
571 * decide whether or not to write status information to stderr. The old test
572 * for this was to see if (argc > 1) but the addition of optional command line
573 * switches broke this. What we really wanted to know was whether any of the
574 * command line arguments are file names or an explicit in-line "-e command".
575 * (This is a copy of a code snippet from plot.c)
576 */
577 for (i = 1; i < argc; i++) {
578 if (!_stricmp(argv[i], "/noend"))
579 continue;
580 if ((argv[i][0] != '-') || (argv[i][1] == 'e')) {
581 interactive = FALSE;
582 break;
583 }
584 }
585 if (interactive)
586 ShowWindow(textwin.hWndParent, textwin.nCmdShow);
587 if (IsIconic(textwin.hWndParent)) { /* update icon */
588 RECT rect;
589 GetClientRect(textwin.hWndParent, (LPRECT) &rect);
590 InvalidateRect(textwin.hWndParent, (LPRECT) &rect, 1);
591 UpdateWindow(textwin.hWndParent);
592 }
593 # ifndef __WATCOMC__
594 /* Finally, also redirect C++ standard output streams. */
595 RedirectOutputStreams(TRUE);
596 # endif
597 #else /* !WGP_CONSOLE */
598 # ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
599 # define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
600 # endif
601 {
602 /* Enable Windows 10 Console Virtual Terminal Sequences */
603 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
604 DWORD mode;
605 GetConsoleMode(handle, &mode);
606 SetConsoleMode(handle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
607 }
608
609 // set console mode handler to catch "abort" signals
610 SetConsoleCtrlHandler(ConsoleHandler, TRUE);
611 #endif
612
613 gp_atexit(WinExit);
614
615 if (!_isatty(_fileno(stdin)))
616 _setmode(_fileno(stdin), O_BINARY);
617
618 gnu_main(argc, argv);
619
620 /* First chance to close help system for console gnuplot,
621 second for wgnuplot */
622 WinCloseHelp();
623 gp_exit_cleanup();
624 return 0;
625 }
626
627
628 void
MultiByteAccumulate(BYTE ch,LPWSTR wstr,int * count)629 MultiByteAccumulate(BYTE ch, LPWSTR wstr, int * count)
630 {
631 static char mbstr[4] = "";
632 static int mbwait = 0;
633 static int mbcount = 0;
634
635 *count = 0;
636
637 /* try to re-sync on control characters */
638 /* works for utf8 and sjis */
639 if (ch < 32) {
640 mbwait = mbcount = 0;
641 mbstr[0] = NUL;
642 }
643
644 if (encoding == S_ENC_UTF8) { /* combine UTF8 byte sequences */
645 if (mbwait == 0) {
646 /* first byte */
647 mbcount = 0;
648 mbstr[mbcount] = ch;
649 if ((ch & 0xE0) == 0xC0) {
650 // expect one more byte
651 mbwait = 1;
652 } else if ((ch & 0xF0) == 0xE0) {
653 // expect two more bytes
654 mbwait = 2;
655 } else if ((ch & 0xF8) == 0xF0) {
656 // expect three more bytes
657 mbwait = 3;
658 }
659 } else {
660 /* subsequent byte */
661 /*assert((ch & 0xC0) == 0x80);*/
662 if ((ch & 0xC0) == 0x80) {
663 mbcount++;
664 mbwait--;
665 } else {
666 /* invalid sequence */
667 mbcount = 0;
668 mbwait = 0;
669 }
670 mbstr[mbcount] = ch;
671 }
672 if (mbwait == 0) {
673 *count = MultiByteToWideChar(CP_UTF8, 0, mbstr, mbcount + 1, wstr, 2);
674 }
675 } else if (encoding == S_ENC_SJIS) { /* combine S-JIS sequences */
676 if (mbwait == 0) {
677 /* first or single byte */
678 mbcount = 0;
679 mbstr[mbcount] = ch;
680 if (is_sjis_lead_byte(ch)) {
681 /* first byte */
682 mbwait = 1;
683 }
684 } else {
685 if ((ch >= 0x40) && (ch <= 0xfc)) {
686 /* valid */
687 mbcount++;
688 } else {
689 /* invalid */
690 mbcount = 0;
691 }
692 mbwait = 0; /* max. double byte sequences */
693 mbstr[mbcount] = ch;
694 }
695 if (mbwait == 0) {
696 *count = MultiByteToWideChar(932, 0, mbstr, mbcount + 1, wstr, 2);
697 }
698 } else {
699 mbcount = 0;
700 mbwait = 0;
701 mbstr[0] = (char) ch;
702 *count = MultiByteToWideChar(WinGetCodepage(encoding), 0, mbstr, mbcount + 1, wstr, 2);
703 }
704 }
705
706
707 /* replacement stdio routines that use
708 * - Text Window for stdin/stdout (wgnuplot)
709 * - Unicode console APIs to handle encodings (console gnuplot)
710 * WARNING: Do not write to stdout/stderr with functions not listed
711 * in win/wtext.h
712 */
713
714 #undef kbhit
715 #undef getche
716 #undef getch
717 #undef putch
718
719 #undef fgetc
720 #undef getchar
721 #undef getc
722 #undef fgets
723 #undef gets
724
725 #undef fputc
726 #undef putchar
727 #undef putc
728 #undef fputs
729 #undef puts
730
731 #undef fprintf
732 #undef printf
733 #undef vprintf
734 #undef vfprintf
735
736 #undef fwrite
737 #undef fread
738
739 #ifndef WGP_CONSOLE
740 # define TEXTMESSAGE TextMessage()
741 # define GETCH() TextGetChE(&textwin)
742 # define PUTS(s) TextPutS(&textwin, (char*) s)
743 # define PUTCH(c) TextPutCh(&textwin, (BYTE) c)
744 # define isterm(f) (f==stdin || f==stdout || f==stderr)
745 #else
746 # define TEXTMESSAGE
747 # define GETCH() ConsoleReadCh()
748 # define PUTS(s) ConsolePutS(s)
749 # define PUTCH(c) ConsolePutCh(c)
750 # define isterm(f) _isatty(_fileno(f))
751 #endif
752
753 int
MyPutCh(int ch)754 MyPutCh(int ch)
755 {
756 return PUTCH(ch);
757 }
758
759 #ifndef WGP_CONSOLE
760 int
MyKBHit(void)761 MyKBHit(void)
762 {
763 return TextKBHit(&textwin);
764 }
765
766 int
MyGetCh(void)767 MyGetCh(void)
768 {
769 return TextGetCh(&textwin);
770 }
771
772 int
MyGetChE(void)773 MyGetChE(void)
774 {
775 return TextGetChE(&textwin);
776 }
777 #endif
778
779
780 int
MyFGetC(FILE * file)781 MyFGetC(FILE *file)
782 {
783 if (isterm(file))
784 return GETCH();
785 return fgetc(file);
786 }
787
788 char *
MyGetS(char * str)789 MyGetS(char *str)
790 {
791 MyFGetS(str, 80, stdin);
792 if (strlen(str) > 0 && str[strlen(str) - 1] == '\n')
793 str[strlen(str) - 1] = '\0';
794 return str;
795 }
796
797 char *
MyFGetS(char * str,unsigned int size,FILE * file)798 MyFGetS(char *str, unsigned int size, FILE *file)
799 {
800 if (isterm(file)) {
801 #ifndef WGP_CONSOLE
802 char * p = TextGetS(&textwin, str, size);
803 if (p != NULL)
804 return str;
805 return NULL;
806 #else
807 unsigned int i;
808 int c;
809
810 c = ConsoleGetch();
811 if (c == EOF)
812 return NULL;
813
814 for (i = 1; i < size - 1; i++) {
815 c = ConsoleGetch();
816 if (str[i] == EOF)
817 break;
818 str[i] = c;
819 if (str[i] == '\n')
820 break;
821 }
822 str[i] = NUL;
823 return str;
824 #endif
825 }
826 return fgets(str,size,file);
827 }
828
829 int
MyFPutC(int ch,FILE * file)830 MyFPutC(int ch, FILE *file)
831 {
832 if (isterm(file)) {
833 PUTCH(ch);
834 TEXTMESSAGE;
835 return ch;
836 }
837 return fputc(ch,file);
838 }
839
840 int
MyFPutS(const char * str,FILE * file)841 MyFPutS(const char *str, FILE *file)
842 {
843 if (isterm(file)) {
844 PUTS(str);
845 TEXTMESSAGE;
846 return (*str);
847 }
848 return fputs(str,file);
849 }
850
851 int
MyPutS(const char * str)852 MyPutS(const char *str)
853 {
854 PUTS(str);
855 PUTCH('\n');
856 TEXTMESSAGE;
857 return 0;
858 }
859
860 int
MyFPrintF(FILE * file,const char * fmt,...)861 MyFPrintF(FILE *file, const char *fmt, ...)
862 {
863 int count;
864 va_list args;
865
866 va_start(args, fmt);
867 if (isterm(file)) {
868 char *buf;
869
870 count = vsnprintf(NULL, 0, fmt, args) + 1;
871 if (count == 0)
872 count = MAXPRINTF;
873 va_end(args);
874 va_start(args, fmt);
875 buf = (char *) malloc(count * sizeof(char));
876 count = vsnprintf(buf, count, fmt, args);
877 PUTS(buf);
878 free(buf);
879 } else {
880 count = vfprintf(file, fmt, args);
881 }
882 va_end(args);
883 return count;
884 }
885
886 int
MyVFPrintF(FILE * file,const char * fmt,va_list args)887 MyVFPrintF(FILE *file, const char *fmt, va_list args)
888 {
889 int count;
890
891 if (isterm(file)) {
892 char *buf;
893 va_list args_copied;
894
895 va_copy(args_copied, args);
896 count = vsnprintf(NULL, 0U, fmt, args) + 1;
897 if (count == 0)
898 count = MAXPRINTF;
899 va_end(args_copied);
900 buf = (char *) malloc(count * sizeof(char));
901 count = vsnprintf(buf, count, fmt, args);
902 PUTS(buf);
903 free(buf);
904 } else {
905 count = vfprintf(file, fmt, args);
906 }
907 return count;
908 }
909
910 int
MyPrintF(const char * fmt,...)911 MyPrintF(const char *fmt, ...)
912 {
913 int count;
914 char *buf;
915 va_list args;
916
917 va_start(args, fmt);
918 count = vsnprintf(NULL, 0, fmt, args) + 1;
919 if (count == 0)
920 count = MAXPRINTF;
921 va_end(args);
922 va_start(args, fmt);
923 buf = (char *) malloc(count * sizeof(char));
924 count = vsnprintf(buf, count, fmt, args);
925 PUTS(buf);
926 free(buf);
927 va_end(args);
928 return count;
929 }
930
931 size_t
MyFWrite(const void * ptr,size_t size,size_t n,FILE * file)932 MyFWrite(const void *ptr, size_t size, size_t n, FILE *file)
933 {
934 if (isterm(file)) {
935 size_t i;
936 for (i = 0; i < n; i++)
937 PUTCH(((BYTE *)ptr)[i]);
938 TEXTMESSAGE;
939 return n;
940 }
941 return fwrite(ptr, size, n, file);
942 }
943
944 size_t
MyFRead(void * ptr,size_t size,size_t n,FILE * file)945 MyFRead(void *ptr, size_t size, size_t n, FILE *file)
946 {
947 if (isterm(file)) {
948 size_t i;
949
950 for (i = 0; i < n; i++)
951 ((BYTE *)ptr)[i] = GETCH();
952 TEXTMESSAGE;
953 return n;
954 }
955 return fread(ptr, size, n, file);
956 }
957
958
959 #ifdef USE_FAKEPIPES
960
961 static char pipe_type = NUL;
962 static char * pipe_filename = NULL;
963 static char * pipe_command = NULL;
964
965 FILE *
fake_popen(const char * command,const char * type)966 fake_popen(const char * command, const char * type)
967 {
968 FILE * f = NULL;
969 char tmppath[MAX_PATH];
970 char tmpfile[MAX_PATH];
971 DWORD ret;
972
973 if (type == NULL)
974 return NULL;
975
976 pipe_type = NUL;
977 if (pipe_filename != NULL)
978 free(pipe_filename);
979
980 /* Random temp file name in %TEMP% */
981 ret = GetTempPathA(sizeof(tmppath), tmppath);
982 if ((ret == 0) || (ret > sizeof(tmppath)))
983 return NULL;
984 ret = GetTempFileNameA(tmppath, "gpp", 0, tmpfile);
985 if (ret == 0)
986 return NULL;
987 pipe_filename = gp_strdup(tmpfile);
988
989 if (*type == 'r') {
990 char * cmd;
991 int rc;
992 LPWSTR wcmd;
993 pipe_type = *type;
994 /* Execute command with redirection of stdout to temporary file. */
995 #ifndef HAVE_BROKEN_WSYSTEM
996 cmd = (char *) malloc(strlen(command) + strlen(pipe_filename) + 5);
997 sprintf(cmd, "%s > %s", command, pipe_filename);
998 wcmd = UnicodeText(cmd, encoding);
999 rc = _wsystem(wcmd);
1000 free(wcmd);
1001 #else
1002 cmd = (char *) malloc(strlen(command) + strlen(pipe_filename) + 15);
1003 sprintf(cmd, "cmd /c %s > %s", command, pipe_filename);
1004 rc = system(cmd);
1005 #endif
1006 free(cmd);
1007 /* Now open temporary file. */
1008 /* system() returns 1 if the command could not be executed. */
1009 if (rc != 1) {
1010 f = fopen(pipe_filename, "r");
1011 } else {
1012 remove(pipe_filename);
1013 free(pipe_filename);
1014 pipe_filename = NULL;
1015 errno = EINVAL;
1016 }
1017 } else if (*type == 'w') {
1018 pipe_type = *type;
1019 /* Write output to temporary file and handle the rest in fake_pclose. */
1020 if (type[1] == 'b')
1021 int_error(NO_CARET, "Could not execute pipe '%s'. Writing to binary pipes is not supported.", command);
1022 else
1023 f = fopen(pipe_filename, "w");
1024 pipe_command = gp_strdup(command);
1025 }
1026
1027 return f;
1028 }
1029
1030
1031 int
fake_pclose(FILE * stream)1032 fake_pclose(FILE *stream)
1033 {
1034 int rc = 0;
1035 if (!stream)
1036 return ECHILD;
1037
1038 /* Close temporary file */
1039 fclose(stream);
1040
1041 /* Finally, execute command with redirected stdin. */
1042 if (pipe_type == 'w') {
1043 char * cmd;
1044 LPWSTR wcmd;
1045
1046 #ifndef HAVE_BROKEN_WSYSTEM
1047 cmd = (char *) gp_alloc(strlen(pipe_command) + strlen(pipe_filename) + 10, "fake_pclose");
1048 /* FIXME: this won't work for binary data. We need a proper `cat` replacement. */
1049 sprintf(cmd, "type %s | %s", pipe_filename, pipe_command);
1050 wcmd = UnicodeText(cmd, encoding);
1051 rc = _wsystem(wcmd);
1052 free(wcmd);
1053 #else
1054 cmd = (char *) gp_alloc(strlen(pipe_command) + strlen(pipe_filename) + 20, "fake_pclose");
1055 sprintf(cmd, "cmd/c type %s | %s", pipe_filename, pipe_command);
1056 rc = system(cmd);
1057 #endif
1058 free(cmd);
1059 }
1060
1061 /* Delete temp file again. */
1062 if (pipe_filename) {
1063 remove(pipe_filename);
1064 errno = 0;
1065 free(pipe_filename);
1066 pipe_filename = NULL;
1067 }
1068
1069 if (pipe_command) {
1070 /* system() returns 255 if the command could not be executed.
1071 The real popen would have returned an error already. */
1072 if (rc == 255)
1073 int_error(NO_CARET, "Could not execute pipe '%s'.", pipe_command);
1074 free(pipe_command);
1075 }
1076
1077 return rc;
1078 }
1079 #endif
1080
1081
1082 #ifdef WGP_CONSOLE
1083
1084 int
ConsoleGetch(void)1085 ConsoleGetch(void)
1086 {
1087 int fd = _fileno(stdin);
1088 HANDLE h;
1089 DWORD waitResult;
1090
1091 h = (HANDLE)_get_osfhandle(fd);
1092 if (h == INVALID_HANDLE_VALUE)
1093 fprintf(stderr, "ERROR: Invalid stdin handle value!\n");
1094
1095 do {
1096 waitResult = MsgWaitForMultipleObjects(1, &h, FALSE, INFINITE, QS_ALLINPUT);
1097 if (waitResult == WAIT_OBJECT_0) {
1098 if (_isatty(fd)) {
1099 DWORD c = ConsoleReadCh();
1100 if (c != NUL)
1101 return c;
1102 } else {
1103 unsigned char c;
1104 if (fread(&c, 1, 1, stdin) == 1)
1105 return c;
1106 else
1107 return EOF;
1108 }
1109 } else if (waitResult == WAIT_OBJECT_0+1) {
1110 WinMessageLoop();
1111 if (ctrlc_flag)
1112 return '\r';
1113 } else
1114 break;
1115 } while (1);
1116
1117 return '\r';
1118 }
1119
1120 #endif /* WGP_CONSOLE */
1121
1122
1123 int
ConsoleReadCh(void)1124 ConsoleReadCh(void)
1125 {
1126 const int max_input = 8;
1127 static char console_input[8];
1128 static int first_input_char = 0;
1129 static int last_input_char = 0;
1130 INPUT_RECORD rec;
1131 DWORD recRead;
1132 HANDLE h;
1133
1134 if (first_input_char != last_input_char) {
1135 int c = console_input[first_input_char];
1136 first_input_char++;
1137 first_input_char %= max_input;
1138 return c;
1139 }
1140
1141 h = GetStdHandle(STD_INPUT_HANDLE);
1142 if (h == NULL)
1143 return NUL;
1144
1145 ReadConsoleInputW(h, &rec, 1, &recRead);
1146 /* FIXME: We should handle rec.Event.KeyEvent.wRepeatCount > 1, too. */
1147 if (recRead == 1 && rec.EventType == KEY_EVENT && rec.Event.KeyEvent.bKeyDown &&
1148 (rec.Event.KeyEvent.wVirtualKeyCode < VK_SHIFT ||
1149 rec.Event.KeyEvent.wVirtualKeyCode > VK_MENU)) {
1150 if (rec.Event.KeyEvent.uChar.UnicodeChar) {
1151 if ((rec.Event.KeyEvent.dwControlKeyState == SHIFT_PRESSED) && (rec.Event.KeyEvent.wVirtualKeyCode == VK_TAB)) {
1152 return 034; /* remap Shift-Tab */
1153 } else {
1154 int i, count;
1155 char mbchar[8];
1156 count = WideCharToMultiByte(WinGetCodepage(encoding), 0,
1157 &rec.Event.KeyEvent.uChar.UnicodeChar, 1,
1158 mbchar, sizeof(mbchar),
1159 NULL, NULL);
1160 for (i = 1; i < count; i++) {
1161 console_input[last_input_char] = mbchar[i];
1162 last_input_char++;
1163 last_input_char %= max_input;
1164 }
1165 return mbchar[0];
1166 }
1167 } else {
1168 switch (rec.Event.KeyEvent.wVirtualKeyCode) {
1169 case VK_UP: return 020;
1170 case VK_DOWN: return 016;
1171 case VK_LEFT: return 002;
1172 case VK_RIGHT: return 006;
1173 case VK_HOME: return 001;
1174 case VK_END: return 005;
1175 case VK_DELETE: return 0117;
1176 }
1177 }
1178 }
1179
1180 /* Error reading event or, key up or, one of the following event records:
1181 MOUSE_EVENT_RECORD, WINDOW_BUFFER_SIZE_RECORD, MENU_EVENT_RECORD, FOCUS_EVENT_RECORD */
1182 return NUL;
1183 }
1184
1185 #ifdef WGP_CONSOLE
1186
1187 static int
ConsolePutS(const char * str)1188 ConsolePutS(const char *str)
1189 {
1190 LPWSTR wstr = UnicodeText(str, encoding);
1191 // Use standard file IO instead of Console API
1192 // to enable word-wrapping on Windows 10 and
1193 // allow for redirection of stdout/stderr.
1194 //HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
1195 //WriteConsoleW(h, wstr, wcslen(wstr), NULL, NULL);
1196 fputws(wstr, stdout);
1197 free(wstr);
1198 return 0;
1199 }
1200
1201
1202 static int
ConsolePutCh(int ch)1203 ConsolePutCh(int ch)
1204 {
1205 WCHAR w[4];
1206 int count;
1207
1208 MultiByteAccumulate(ch, w, &count);
1209 if (count > 0) {
1210 // Use standard file IO instead of Console API
1211 // to enable word-wrapping on Windows 10.
1212 //HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
1213 //WriteConsoleW(h, w, count, NULL, NULL);
1214 w[count] = 0;
1215 fputws(w, stdout);
1216 }
1217 return ch;
1218 }
1219 #endif
1220
1221
1222 /* This is called by the system to signal various events.
1223 Note that it is executed in a separate thread. */
1224 BOOL WINAPI
ConsoleHandler(DWORD dwType)1225 ConsoleHandler(DWORD dwType)
1226 {
1227 switch (dwType) {
1228 case CTRL_CLOSE_EVENT:
1229 case CTRL_LOGOFF_EVENT:
1230 case CTRL_SHUTDOWN_EVENT: {
1231 #ifdef WGP_CONSOLE
1232 HANDLE h;
1233 INPUT_RECORD rec;
1234 DWORD written;
1235 #endif
1236
1237 // NOTE: returning from this handler terminates the application.
1238 // Instead, we signal the main thread to clean up and exit and
1239 // then idle by sleeping.
1240 #ifndef WGP_CONSOLE
1241 // close the main window to exit gnuplot
1242 PostMessage(textwin.hWndParent, WM_CLOSE, 0, 0);
1243 #else
1244 terminate_flag = TRUE;
1245 // send ^D to main thread input queue
1246 h = GetStdHandle(STD_INPUT_HANDLE);
1247 ZeroMemory(&rec, sizeof(rec));
1248 rec.EventType = KEY_EVENT;
1249 rec.Event.KeyEvent.bKeyDown = TRUE;
1250 rec.Event.KeyEvent.wRepeatCount = 1;
1251 rec.Event.KeyEvent.uChar.AsciiChar = 004;
1252 WriteConsoleInput(h, &rec, 1, &written);
1253 #endif
1254 // give the main thread time to exit
1255 Sleep(10000);
1256 return TRUE;
1257 }
1258 default:
1259 break;
1260 }
1261 return FALSE;
1262 }
1263
1264
1265 /* public interface to printer routines : Windows PRN emulation
1266 * (formerly in win.trm)
1267 */
1268
1269 #define MAX_PRT_LEN 256
1270 static char win_prntmp[MAX_PRT_LEN+1];
1271
1272 FILE *
open_printer(void)1273 open_printer(void)
1274 {
1275 char *temp;
1276
1277 if ((temp = getenv("TEMP")) == NULL)
1278 *win_prntmp = '\0';
1279 else {
1280 safe_strncpy(win_prntmp, temp, MAX_PRT_LEN);
1281 /* stop X's in path being converted by _mktemp */
1282 for (temp = win_prntmp; *temp != NUL; temp++)
1283 *temp = tolower((unsigned char)*temp);
1284 if ((strlen(win_prntmp) > 0) && (win_prntmp[strlen(win_prntmp) - 1] != '\\'))
1285 strcat(win_prntmp, "\\");
1286 }
1287 strncat(win_prntmp, "_gptmp", MAX_PRT_LEN - strlen(win_prntmp));
1288 strncat(win_prntmp, "XXXXXX", MAX_PRT_LEN - strlen(win_prntmp));
1289 _mktemp(win_prntmp);
1290 return fopen(win_prntmp, "wb");
1291 }
1292
1293
1294 void
close_printer(FILE * outfile)1295 close_printer(FILE *outfile)
1296 {
1297 LPTSTR fname;
1298 HWND hwnd;
1299 TCHAR title[100];
1300
1301 #ifdef UNICODE
1302 fname = UnicodeText(win_prntmp, S_ENC_DEFAULT);
1303 #else
1304 fname = win_prntmp;
1305 #endif
1306 fclose(outfile);
1307
1308 #ifndef WGP_CONSOLE
1309 hwnd = textwin.hWndParent;
1310 #else
1311 hwnd = GetDesktopWindow();
1312 #endif
1313 if (term->name != NULL)
1314 wsprintf(title, TEXT("gnuplot graph (%hs)"), term->name);
1315 else
1316 _tcscpy(title, TEXT("gnuplot graph"));
1317 DumpPrinter(hwnd, title, fname);
1318
1319 #ifdef UNICODE
1320 free(fname);
1321 #endif
1322 }
1323
1324
1325 void
screen_dump(void)1326 screen_dump(void)
1327 {
1328 if (term == NULL) {
1329 int_error(c_token, "");
1330 }
1331 if (strcmp(term->name, "windows") == 0)
1332 GraphPrint(graphwin);
1333 #ifdef WXWIDGETS
1334 else if (strcmp(term->name, "wxt") == 0)
1335 wxt_screen_dump();
1336 #endif
1337 #ifdef QTTERM
1338 //else if (strcmp(term->name, "qt") == 0)
1339 #endif
1340 else
1341 int_error(c_token, "screendump not supported for terminal `%s`", term->name);
1342 }
1343
1344
1345 void
win_raise_terminal_window(int id)1346 win_raise_terminal_window(int id)
1347 {
1348 LPGW lpgw = listgraphs;
1349 while ((lpgw != NULL) && (lpgw->Id != id))
1350 lpgw = lpgw->next;
1351 if (lpgw != NULL) {
1352 if (IsIconic(lpgw->hWndGraph))
1353 ShowWindow(lpgw->hWndGraph, SW_SHOWNORMAL);
1354 BringWindowToTop(lpgw->hWndGraph);
1355 }
1356 }
1357
1358
1359 void
win_raise_terminal_group(void)1360 win_raise_terminal_group(void)
1361 {
1362 LPGW lpgw = listgraphs;
1363 while (lpgw != NULL) {
1364 if (IsIconic(lpgw->hWndGraph))
1365 ShowWindow(lpgw->hWndGraph, SW_SHOWNORMAL);
1366 BringWindowToTop(lpgw->hWndGraph);
1367 lpgw = lpgw->next;
1368 }
1369 }
1370
1371
1372 void
win_lower_terminal_window(int id)1373 win_lower_terminal_window(int id)
1374 {
1375 LPGW lpgw = listgraphs;
1376 while ((lpgw != NULL) && (lpgw->Id != id))
1377 lpgw = lpgw->next;
1378 if (lpgw != NULL)
1379 SetWindowPos(lpgw->hWndGraph, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
1380 }
1381
1382
1383 void
win_lower_terminal_group(void)1384 win_lower_terminal_group(void)
1385 {
1386 LPGW lpgw = listgraphs;
1387 while (lpgw != NULL) {
1388 SetWindowPos(lpgw->hWndGraph, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
1389 lpgw = lpgw->next;
1390 }
1391 }
1392
1393
1394 /* returns true if there are any graph windows open (win terminal) */
1395 static TBOOLEAN
WinWindowOpened(void)1396 WinWindowOpened(void)
1397 {
1398 LPGW lpgw;
1399
1400 lpgw = listgraphs;
1401 while (lpgw != NULL) {
1402 if (GraphHasWindow(lpgw))
1403 return TRUE;
1404 lpgw = lpgw->next;
1405 }
1406 return FALSE;
1407 }
1408
1409
1410 /* returns true if there are any graph windows open (wxt/caca/win terminals) */
1411 /* Note: This routine is used to handle "persist". Do not test for qt windows here
1412 since they run in a separate process */
1413 TBOOLEAN
WinAnyWindowOpen(void)1414 WinAnyWindowOpen(void)
1415 {
1416 TBOOLEAN window_opened = WinWindowOpened();
1417 #ifdef WXWIDGETS
1418 window_opened |= wxt_window_opened();
1419 #endif
1420 #ifdef HAVE_LIBCACA
1421 window_opened |= CACA_window_opened();
1422 #endif
1423 return window_opened;
1424 }
1425
1426
1427 #ifndef WGP_CONSOLE
1428 void
WinPersistTextClose(void)1429 WinPersistTextClose(void)
1430 {
1431 if (!WinAnyWindowOpen() &&
1432 (textwin.hWndParent != NULL) && !IsWindowVisible(textwin.hWndParent))
1433 PostMessage(textwin.hWndParent, WM_CLOSE, 0, 0);
1434 }
1435 #endif
1436
1437
1438 void
WinMessageLoop(void)1439 WinMessageLoop(void)
1440 {
1441 MSG msg;
1442
1443 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1444 /* HBB 19990505: Petzold says we should check this: */
1445 if (msg.message == WM_QUIT)
1446 return;
1447 TranslateMessage(&msg);
1448 DispatchMessage(&msg);
1449 }
1450 }
1451
1452
1453 #ifndef WGP_CONSOLE
1454 void
WinOpenConsole(void)1455 WinOpenConsole(void)
1456 {
1457 /* Try to attach to an existing console window. */
1458 if (AttachConsole(ATTACH_PARENT_PROCESS) == 0) {
1459 if (GetLastError() != ERROR_ACCESS_DENIED) {
1460 /* Open new console if we are are not attached to one already.
1461 Note that closing this console window will end wgnuplot, too. */
1462 AllocConsole();
1463 }
1464 }
1465 SetConsoleCtrlHandler(ConsoleHandler, TRUE);
1466 }
1467 #endif
1468
1469
1470 void
WinRaiseConsole(void)1471 WinRaiseConsole(void)
1472 {
1473 HWND console = NULL;
1474 #ifndef WGP_CONSOLE
1475 console = textwin.hWndParent;
1476 if (pausewin.bPause && IsWindow(pausewin.hWndPause))
1477 console = pausewin.hWndPause;
1478 #else
1479 console = GetConsoleWindow();
1480 #endif
1481 if (console != NULL) {
1482 if (IsIconic(console))
1483 ShowWindow(console, SW_SHOWNORMAL);
1484 BringWindowToTop(console);
1485 }
1486 }
1487
1488
1489 /* WinGetCodepage:
1490 Map gnuplot's internal character encoding to Windows codepage codes.
1491 */
1492 UINT
WinGetCodepage(enum set_encoding_id encoding)1493 WinGetCodepage(enum set_encoding_id encoding)
1494 {
1495 UINT codepage;
1496
1497 /* For a list of code page identifiers see
1498 http://msdn.microsoft.com/en-us/library/dd317756%28v=vs.85%29.aspx
1499 */
1500 switch (encoding) {
1501 case S_ENC_DEFAULT: codepage = CP_ACP; break;
1502 case S_ENC_ISO8859_1: codepage = 28591; break;
1503 case S_ENC_ISO8859_2: codepage = 28592; break;
1504 case S_ENC_ISO8859_9: codepage = 28599; break;
1505 case S_ENC_ISO8859_15: codepage = 28605; break;
1506 case S_ENC_CP437: codepage = 437; break;
1507 case S_ENC_CP850: codepage = 850; break;
1508 case S_ENC_CP852: codepage = 852; break;
1509 case S_ENC_CP950: codepage = 950; break;
1510 case S_ENC_CP1250: codepage = 1250; break;
1511 case S_ENC_CP1251: codepage = 1251; break;
1512 case S_ENC_CP1252: codepage = 1252; break;
1513 case S_ENC_CP1254: codepage = 1254; break;
1514 case S_ENC_KOI8_R: codepage = 20866; break;
1515 case S_ENC_KOI8_U: codepage = 21866; break;
1516 case S_ENC_SJIS: codepage = 932; break;
1517 case S_ENC_UTF8: codepage = CP_UTF8; break;
1518 default: {
1519 /* unknown encoding, fall back to default "ANSI" codepage */
1520 codepage = CP_ACP;
1521 FPRINTF((stderr, "unknown encoding: %i\n", encoding));
1522 }
1523 }
1524 return codepage;
1525 }
1526
1527
1528 LPWSTR
UnicodeText(LPCSTR str,enum set_encoding_id encoding)1529 UnicodeText(LPCSTR str, enum set_encoding_id encoding)
1530 {
1531 LPWSTR strw = NULL;
1532 UINT codepage = WinGetCodepage(encoding);
1533 int length;
1534
1535 /* sanity check */
1536 if (str == NULL)
1537 return NULL;
1538
1539 /* get length of converted string */
1540 length = MultiByteToWideChar(codepage, 0, str, -1, NULL, 0);
1541 strw = (LPWSTR) malloc(sizeof(WCHAR) * length);
1542
1543 /* convert string to UTF-16 */
1544 length = MultiByteToWideChar(codepage, 0, str, -1, strw, length);
1545
1546 return strw;
1547 }
1548
1549
1550 LPSTR
AnsiText(LPCWSTR strw,enum set_encoding_id encoding)1551 AnsiText(LPCWSTR strw, enum set_encoding_id encoding)
1552 {
1553 LPSTR str = NULL;
1554 UINT codepage = WinGetCodepage(encoding);
1555 int length;
1556
1557 /* get length of converted string */
1558 length = WideCharToMultiByte(codepage, 0, strw, -1, NULL, 0, NULL, 0);
1559 str = (LPSTR) malloc(sizeof(char) * length);
1560
1561 /* convert string to "Ansi" */
1562 length = WideCharToMultiByte(codepage, 0, strw, -1, str, length, NULL, 0);
1563
1564 return str;
1565 }
1566
1567
1568 FILE *
win_fopen(const char * filename,const char * mode)1569 win_fopen(const char *filename, const char *mode)
1570 {
1571 FILE * file;
1572 LPWSTR wfilename = UnicodeText(filename, encoding);
1573 LPWSTR wmode = UnicodeText(mode, encoding);
1574 file = _wfopen(wfilename, wmode);
1575 free(wfilename);
1576 free(wmode);
1577 return file;
1578 }
1579
1580
1581 #ifndef USE_FAKEPIPES
1582 FILE *
win_popen(const char * filename,const char * mode)1583 win_popen(const char *filename, const char *mode)
1584 {
1585 FILE * file;
1586 LPWSTR wfilename = UnicodeText(filename, encoding);
1587 LPWSTR wmode = UnicodeText(mode, encoding);
1588 file = _wpopen(wfilename, wmode);
1589 free(wfilename);
1590 free(wmode);
1591 return file;
1592 }
1593 #endif
1594
1595
1596 UINT
GetDPI(void)1597 GetDPI(void)
1598 {
1599 HDC hdc_screen = GetDC(NULL);
1600 if (hdc_screen) {
1601 UINT dpi = GetDeviceCaps(hdc_screen, LOGPIXELSX);
1602 ReleaseDC(NULL, hdc_screen);
1603 return dpi;
1604 } else {
1605 return 96;
1606 }
1607 }
1608