1 /*
2  _________
3 /         \ tinyfiledialogs.c v2.7.2 [November 23, 2016] zlib licence
4 |tiny file| Unique code file of "tiny file dialogs" created [November 9, 2014]
5 | dialogs | Copyright (c) 2014 - 2016 Guillaume Vareille http://ysengrin.com
6 \____  ___/ http://tinyfiledialogs.sourceforge.net
7      \|
8                                 git://git.code.sf.net/p/tinyfiledialogs/code
9 	 _____________________________________________________
10 	 |                                                      |
11 	 | direct CONTACT:  mailto:tinyfiledialogs@ysengrin.com |
12 	 |______________________________________________________|
13 
14 A big thank you to Don Heyse http://ldglite.sf.net for
15                    his code contributions, bug corrections & thorough testing!
16 
17 Please
18 	1) let me know
19 	- if you are including tiny file dialogs,
20 	  I'll be happy to add your link to the list of projects using it.
21 	- If you are using it on different hardware / OS / compiler.
22 	2) Be the first to leave a review on Sourceforge. Thanks.
23 
24 tiny file dialogs (cross-platform C C++)
25 InputBox PasswordBox MessageBox ColorPicker
26 OpenFileDialog SaveFileDialog SelectFolderDialog
27 Native dialog library for WINDOWS MAC OSX GTK+ QT CONSOLE & more
28 
29 A single C file (add it to your C or C++ project) with 6 boxes:
30 - message / question
31 - input / password
32 - save file
33 - open file & multiple files
34 - select folder
35 - color picker.
36 
37 Complements OpenGL GLFW GLUT GLUI VTK SFML SDL Ogre Unity ION
38 CEGUI MathGL CPW GLOW IMGUI GLT NGL STB & GUI less programs
39 
40 NO INIT
41 NO MAIN LOOP
42 
43 The dialogs can be forced into console mode
44 
45 Windows (XP to 10) [ASCII + MBCS + UTF-8 + UTF-16]
46 - native code & some vbs create the graphic dialogs
47 - enhanced console mode can use dialog.exe from
48 http://andrear.altervista.org/home/cdialog.php
49 - basic console input
50 
51 Unix (command line call attempts) [ASCII + UTF-8]
52 - applescript
53 - zenity / matedialog
54 - kdialog
55 - Xdialog
56 - python2 tkinter
57 - dialog (opens a console if needed)
58 - basic console input
59 The same executable can run across desktops & distributions
60 
61 tested with C & C++ compilers
62 on VisualStudio MinGW Mac Linux Bsd Solaris Minix Raspbian C# fortran (iso_c)
63 using Gnome Kde Enlightenment Mate Cinnamon Unity
64 Lxde Lxqt Xfce WindowMaker IceWm Cde Jds OpenBox
65 
66 bindings for LUA and C# dll
67 
68 - License -
69 
70 This software is provided 'as-is', without any express or implied
71 warranty.  In no event will the authors be held liable for any damages
72 arising from the use of this software.
73 
74 Permission is granted to anyone to use this software for any purpose,
75 including commercial applications, and to alter it and redistribute it
76 freely, subject to the following restrictions:
77 
78 1. The origin of this software must not be misrepresented; you must not
79 claim that you wrote the original software.  If you use this software
80 in a product, an acknowledgment in the product documentation would be
81 appreciated but is not required.
82 2. Altered source versions must be plainly marked as such, and must not be
83 misrepresented as being the original software.
84 3. This notice may not be removed or altered from any source distribution.
85 */
86 
87 #include <stdio.h>
88 #include <stdlib.h>
89 #include <string.h>
90 #include <ctype.h>
91 #include <sys/stat.h>
92 
93 #include "tinyfiledialogs.h"
94 /* #define TINYFD_NOLIB */
95 
96 #ifdef _WIN32
97  #ifndef _WIN32_WINNT
98   #define _WIN32_WINNT 0x0500
99  #endif
100  #ifndef TINYFD_NOLIB
101   #include <Windows.h>
102   #include <Shlobj.h>
103  #endif
104  #include <conio.h>
105  /*#include <io.h>*/
106  #define SLASH "\\"
107  int tinyfd_winUtf8 = 0 ; /* on windows string char can be 0:MBSC or 1:UTF-8 */
108 #else
109  #include <limits.h>
110  #include <unistd.h>
111  #include <dirent.h> /* on old systems try <sys/dir.h> instead */
112  #include <termios.h>
113  #include <sys/utsname.h>
114  #define SLASH "/"
115 #endif /* _WIN32 */
116 
117 #define MAX_PATH_OR_CMD 1024 /* _MAX_PATH or MAX_PATH */
118 #define MAX_MULTIPLE_FILES 32
119 
120 char tinyfd_version [8] = "2.7.2";
121 
122 #if defined(TINYFD_NOLIB) && defined(_WIN32)
123 int tinyfd_forceConsole = 1 ;
124 #else
125 int tinyfd_forceConsole = 0 ; /* 0 (default) or 1 */
126 #endif
127 /* for unix & windows: 0 (graphic mode) or 1 (console mode).
128 0: try to use a graphic solution, if it fails then it uses console mode.
129 1: forces all dialogs into console mode even when the X server is present,
130   if the package dialog (and a console is present) or dialog.exe is installed.
131   on windows it only make sense for console applications */
132 
133 char tinyfd_response[1024];
134 /* if you pass "tinyfd_query" as aTitle,
135 the functions will not display the dialogs
136 but and return 0 for console mode, 1 for graphic mode.
137 tinyfd_response is then filled with the retain solution.
138 possible values for tinyfd_response are (all lowercase)
139 for the graphic mode:
140   windows applescript zenity zenity3 matedialog kdialog
141   xdialog tkinter gdialog gxmessage xmessage
142 for the console mode:
143   dialog whiptail basicinput */
144 
145 #if defined(TINYFD_NOLIB) && defined(_WIN32)
146 static int gWarningDisplayed = 1 ;
147 #else
148 static int gWarningDisplayed = 0 ;
149 #endif
150 
151 static char gTitle[]="missing software! (so we switch to basic console input)";
152 
153 static char gAsciiArt[] ="\
154  ___________\n\
155 /           \\ \n\
156 | tiny file |\n\
157 |  dialogs  |\n\
158 \\_____  ____/\n\
159       \\|";
160 
161 #ifdef _WIN32
162 static char gMessageWin[] = "tiny file dialogs on Windows needs:\n\t\
163 							a graphic display\nor\tdialog.exe (enhanced console mode)\
164 							\nor\ta console for basic input";
165 #else
166 static char gMessageUnix[] = "tiny file dialogs on UNIX needs:\n\tapplescript\
167 \nor\tzenity / matedialog\
168 \nor\tkdialog\
169 \nor\tXdialog\
170 \nor\tpython 2 with tkinter\
171 \nor\tdialog (opens a console if needed)\
172 \nor\twhiptail, gdialog, gxmessage or xmessage\
173 \nor\tit will use/open a console for basic input";
174 #endif
175 
176 #ifdef _MSC_VER
177 #pragma warning(push)
178 #pragma warning(disable:4996) /* allows usage of strncpy, strcpy, strcat, sprintf, fopen */
179 #pragma warning(disable:4100) /* allows usage of strncpy, strcpy, strcat, sprintf, fopen */
180 #pragma warning(disable:4706) /* allows usage of strncpy, strcpy, strcat, sprintf, fopen */
181 #pragma warning(disable:4244 4267)
182 #endif
183 
getPathWithoutFinalSlash(char * const aoDestination,char const * const aSource)184 static char * getPathWithoutFinalSlash(
185 	char * const aoDestination, /* make sure it is allocated, use _MAX_PATH */
186 	char const * const aSource) /* aoDestination and aSource can be the same */
187 {
188 	char const * lTmp ;
189 	if ( aSource )
190 	{
191 		lTmp = strrchr(aSource, '/');
192 		if (!lTmp)
193 		{
194 			lTmp = strrchr(aSource, '\\');
195 		}
196 		if (lTmp)
197 		{
198 			strncpy(aoDestination, aSource, lTmp - aSource );
199 			aoDestination[lTmp - aSource] = '\0';
200 		}
201 		else
202 		{
203 			* aoDestination = '\0';
204 		}
205 	}
206 	else
207 	{
208 		* aoDestination = '\0';
209 	}
210 	return aoDestination;
211 }
212 
213 
getLastName(char * const aoDestination,char const * const aSource)214 static char * getLastName(
215 	char * const aoDestination, /* make sure it is allocated */
216 	char const * const aSource)
217 {
218 	/* copy the last name after '/' or '\' */
219 	char const * lTmp ;
220 	if ( aSource )
221 	{
222 		lTmp = strrchr(aSource, '/');
223 		if (!lTmp)
224 		{
225 			lTmp = strrchr(aSource, '\\');
226 		}
227 		if (lTmp)
228 		{
229 			strcpy(aoDestination, lTmp + 1);
230 		}
231 		else
232 		{
233 			strcpy(aoDestination, aSource);
234 		}
235 	}
236 	else
237 	{
238 		* aoDestination = '\0';
239 	}
240 	return aoDestination;
241 }
242 
243 
ensureFinalSlash(char * const aioString)244 static void ensureFinalSlash ( char * const aioString )
245 {
246 	if ( aioString && strlen ( aioString ) )
247 	{
248 		char * lastcar = aioString + strlen ( aioString ) - 1 ;
249 		if ( strncmp ( lastcar , SLASH , 1 ) )
250 		{
251 			strcat ( lastcar , SLASH ) ;
252 		}
253 	}
254 }
255 
256 
Hex2RGB(char const aHexRGB[8],unsigned char aoResultRGB[3])257 static void Hex2RGB( char const aHexRGB [8] ,
258 					 unsigned char aoResultRGB [3] )
259 {
260 	char lColorChannel [8] ;
261 	if ( aoResultRGB )
262 	{
263 		if ( aHexRGB )
264 		{
265 			strcpy(lColorChannel, aHexRGB ) ;
266 			aoResultRGB[2] = (unsigned char)strtoul(lColorChannel+5,NULL,16);
267 			lColorChannel[5] = '\0';
268 			aoResultRGB[1] = (unsigned char)strtoul(lColorChannel+3,NULL,16);
269 			lColorChannel[3] = '\0';
270 			aoResultRGB[0] = (unsigned char)strtoul(lColorChannel+1,NULL,16);
271 /* printf("%d %d %d\n", aoResultRGB[0], aoResultRGB[1], aoResultRGB[2]); */
272 		}
273 		else
274 		{
275 			aoResultRGB[0]=0;
276 			aoResultRGB[1]=0;
277 			aoResultRGB[2]=0;
278 		}
279 	}
280 }
281 
RGB2Hex(unsigned char const aRGB[3],char aoResultHexRGB[8])282 static void RGB2Hex( unsigned char const aRGB [3] ,
283 					 char aoResultHexRGB [8] )
284 {
285 	if ( aoResultHexRGB )
286 	{
287 		if ( aRGB )
288 		{
289 #if defined(__GNUC__) && defined(_WIN32)
290 			sprintf(aoResultHexRGB, "#%02hx%02hx%02hx",
291 #else
292 			sprintf(aoResultHexRGB, "#%02hhx%02hhx%02hhx",
293 #endif
294 				aRGB[0], aRGB[1], aRGB[2]);
295 			/* printf("aoResultHexRGB %s\n", aoResultHexRGB); */
296 		}
297 		else
298 		{
299 			aoResultHexRGB[0]=0;
300 			aoResultHexRGB[1]=0;
301 			aoResultHexRGB[2]=0;
302 		}
303 	}
304 }
305 
306 
replaceSubStr(char const * const aSource,char const * const aOldSubStr,char const * const aNewSubStr,char * const aoDestination)307 static void replaceSubStr ( char const * const aSource ,
308 						    char const * const aOldSubStr ,
309 						    char const * const aNewSubStr ,
310 						    char * const aoDestination )
311 {
312 	char const * pOccurence ;
313 	char const * p ;
314 	char const * lNewSubStr = "" ;
315 	int lOldSubLen = strlen ( aOldSubStr ) ;
316 
317 	if ( ! aSource )
318 	{
319 		* aoDestination = '\0' ;
320 		return ;
321 	}
322 	if ( ! aOldSubStr )
323 	{
324 		strcpy ( aoDestination , aSource ) ;
325 		return ;
326 	}
327 	if ( aNewSubStr )
328 	{
329 		lNewSubStr = aNewSubStr ;
330 	}
331 	p = aSource ;
332 	* aoDestination = '\0' ;
333 	while ( ( pOccurence = strstr ( p , aOldSubStr ) ) != NULL )
334 	{
335 		strncat ( aoDestination , p , pOccurence - p ) ;
336 		strcat ( aoDestination , lNewSubStr ) ;
337 		p = pOccurence + lOldSubLen ;
338 	}
339 	strcat ( aoDestination , p ) ;
340 }
341 
342 
filenameValid(char const * const aFileNameWithoutPath)343 static int filenameValid( char const * const aFileNameWithoutPath )
344 {
345 	if ( ! aFileNameWithoutPath
346 	  || ! strlen(aFileNameWithoutPath)
347 	  || strpbrk(aFileNameWithoutPath , "\\/:*?\"<>|") )
348 	{
349 		return 0 ;
350 	}
351 	return 1 ;
352 }
353 
354 
fileExists(char const * const aFilePathAndName)355 static int fileExists( char const * const aFilePathAndName )
356 {
357 	FILE * lIn ;
358 	if ( ! aFilePathAndName || ! strlen(aFilePathAndName) )
359 	{
360 		return 0 ;
361 	}
362 	lIn = fopen( aFilePathAndName , "r" ) ;
363 	if ( ! lIn )
364 	{
365 		return 0 ;
366 	}
367 	fclose ( lIn ) ;
368 	return 1 ;
369 }
370 
371 
372 /* source and destination can be the same or ovelap*/
ensureFilesExist(char * const aDestination,char const * const aSourcePathsAndNames)373 static char const * ensureFilesExist( char * const aDestination ,
374 							 		  char const * const aSourcePathsAndNames)
375 {
376 	char * lDestination = aDestination ;
377 	char const * p ;
378 	char const * p2 ;
379 	int lLen ;
380 
381 	if ( ! aSourcePathsAndNames )
382 	{
383 		return NULL ;
384 	}
385 	lLen = strlen( aSourcePathsAndNames ) ;
386 	if ( ! lLen )
387 	{
388 		return NULL ;
389 	}
390 
391 	p = aSourcePathsAndNames ;
392 	while ( (p2 = strchr(p, '|')) != NULL )
393 	{
394 		lLen = p2-p ;
395 		memmove(lDestination,p,lLen);
396 		lDestination[lLen] = '\0';
397 		if ( fileExists ( lDestination ) )
398 		{
399 			lDestination += lLen ;
400 			* lDestination = '|';
401 			lDestination ++ ;
402 		}
403 		p = p2 + 1 ;
404 	}
405 	if ( fileExists ( p ) )
406 	{
407 		lLen = strlen(p) ;
408 		memmove(lDestination,p,lLen);
409 		lDestination[lLen] = '\0';
410 	}
411 	else
412 	{
413 		* (lDestination-1) = '\0';
414 	}
415 	return aDestination ;
416 }
417 
418 
wipefile(char const * const aFilename)419 static void wipefile(char const * const aFilename)
420 {
421 	int i;
422 	struct stat st;
423 	FILE * lIn;
424 
425 	if (stat(aFilename, &st) == 0)
426 	{
427 		if ((lIn = fopen(aFilename, "w")))
428 		{
429 			for (i = 0; i < st.st_size; i++)
430 			{
431 				fputc('A', lIn);
432 			}
433 		}
434 		fclose(lIn);
435 	}
436 }
437 
438 #ifdef _WIN32
439 
replaceChr(char * const aString,char const aOldChr,char const aNewChr)440 static int replaceChr ( char * const aString ,
441 						char const aOldChr ,
442 						char const aNewChr )
443 {
444 	char * p ;
445 	int lRes = 0 ;
446 
447 	if ( ! aString )
448 	{
449 		return 0 ;
450 	}
451 
452 	if ( aOldChr == aNewChr )
453 	{
454 		return 0 ;
455 	}
456 
457 	p = aString ;
458 	while ( (p = strchr ( p , aOldChr )) )
459 	{
460 		* p = aNewChr ;
461 		p ++ ;
462 		lRes = 1 ;
463 	}
464 	return lRes ;
465 }
466 
467 
dirExists(char const * const aDirPath)468 static int dirExists ( char const * const aDirPath )
469 {
470 	struct stat lInfo;
471 	if ( ! aDirPath || ! strlen ( aDirPath ) )
472 		return 0 ;
473 	if ( stat ( aDirPath , & lInfo ) != 0 )
474 		return 0 ;
475 	else if ( lInfo.st_mode & S_IFDIR )
476 		return 1 ;
477 	else
478 		return 0 ;
479 }
480 
481 #ifndef TINYFD_NOLIB
482 
getPathWithoutFinalSlashW(wchar_t * const aoDestination,wchar_t const * const aSource)483 static wchar_t * getPathWithoutFinalSlashW(
484 	wchar_t * const aoDestination, /* make sure it is allocated, use _MAX_PATH */
485 	wchar_t const * const aSource) /* aoDestination and aSource can be the same */
486 {
487 	wchar_t const * lTmp;
488 	if (aSource)
489 	{
490 		lTmp = wcsrchr(aSource, L'/');
491 		if (!lTmp)
492 		{
493 			lTmp = wcsrchr(aSource, L'\\');
494 		}
495 		if (lTmp)
496 		{
497 			wcsncpy(aoDestination, aSource, lTmp - aSource);
498 			aoDestination[lTmp - aSource] = L'\0';
499 		}
500 		else
501 		{
502 			*aoDestination = L'\0';
503 		}
504 	}
505 	else
506 	{
507 		*aoDestination = L'\0';
508 	}
509 	return aoDestination;
510 }
511 
512 
getLastNameW(wchar_t * const aoDestination,wchar_t const * const aSource)513 static wchar_t * getLastNameW(
514 	wchar_t * const aoDestination, /* make sure it is allocated */
515 	wchar_t const * const aSource)
516 {
517 	/* copy the last name after '/' or '\' */
518 	wchar_t const * lTmp;
519 	if (aSource)
520 	{
521 		lTmp = wcsrchr(aSource, L'/');
522 		if (!lTmp)
523 		{
524 			lTmp = wcsrchr(aSource, L'\\');
525 		}
526 		if (lTmp)
527 		{
528 			wcscpy(aoDestination, lTmp + 1);
529 		}
530 		else
531 		{
532 			wcscpy(aoDestination, aSource);
533 		}
534 	}
535 	else
536 	{
537 		*aoDestination = L'\0';
538 	}
539 	return aoDestination;
540 }
541 
542 
Hex2RGBW(wchar_t const aHexRGB[8],unsigned char aoResultRGB[3])543 static void Hex2RGBW(wchar_t const aHexRGB[8],
544 	unsigned char aoResultRGB[3])
545 {
546 	wchar_t lColorChannel[8];
547 	if (aoResultRGB)
548 	{
549 		if (aHexRGB)
550 		{
551 			wcscpy(lColorChannel, aHexRGB);
552 			aoResultRGB[2] = (unsigned char)wcstoul(lColorChannel + 5, NULL, 16);
553 			lColorChannel[5] = '\0';
554 			aoResultRGB[1] = (unsigned char)wcstoul(lColorChannel + 3, NULL, 16);
555 			lColorChannel[3] = '\0';
556 			aoResultRGB[0] = (unsigned char)wcstoul(lColorChannel + 1, NULL, 16);
557 			/* printf("%d %d %d\n", aoResultRGB[0], aoResultRGB[1], aoResultRGB[2]); */
558 		}
559 		else
560 		{
561 			aoResultRGB[0] = 0;
562 			aoResultRGB[1] = 0;
563 			aoResultRGB[2] = 0;
564 		}
565 	}
566 }
567 
568 
RGB2HexW(unsigned char const aRGB[3],wchar_t aoResultHexRGB[8])569 static void RGB2HexW(
570 	unsigned char const aRGB[3],
571 	wchar_t aoResultHexRGB[8])
572 {
573 	if (aoResultHexRGB)
574 	{
575 		if (aRGB)
576 		{
577 #if defined(__GNUC__) && __GNUC__ < 5
578 swprintf(aoResultHexRGB, L"#%02hhx%02hhx%02hhx", aRGB[0], aRGB[1], aRGB[2]);
579 #else
580 swprintf(aoResultHexRGB, 8, L"#%02hhx%02hhx%02hhx", aRGB[0], aRGB[1], aRGB[2]);
581 #endif
582 		 /* wprintf(L"aoResultHexRGB %s\n", aoResultHexRGB); */
583 		}
584 		else
585 		{
586 			aoResultHexRGB[0] = 0;
587 			aoResultHexRGB[1] = 0;
588 			aoResultHexRGB[2] = 0;
589 		}
590 	}
591 }
592 
593 
594 #if !defined(WC_ERR_INVALID_CHARS)
595 /* undefined prior to Vista, so not yet in MINGW header file */
596 #define WC_ERR_INVALID_CHARS 0x00000080
597 #endif
598 
599 
sizeUtf16(char const * const aUtf8string)600 static int sizeUtf16(char const * const aUtf8string)
601 {
602 	return MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
603 					aUtf8string, -1, NULL, 0);
604 }
605 
606 
sizeUtf8(wchar_t const * const aUtf16string)607 static int sizeUtf8(wchar_t const * const aUtf16string)
608 {
609 	return WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
610 		aUtf16string, -1, NULL, 0, NULL, NULL);
611 }
612 
613 
utf8to16(char const * const aUtf8string)614 static wchar_t * utf8to16(char const * const aUtf8string)
615 {
616 	wchar_t * lUtf16string ;
617 	int lSize = sizeUtf16(aUtf8string);
618 	lUtf16string = (wchar_t *) malloc( lSize * sizeof(wchar_t) );
619 	lSize = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
620 					aUtf8string, -1, lUtf16string, lSize);
621 	if (lSize == 0)
622 	{
623 		free(lUtf16string);
624 		return NULL;
625 	}
626 	return lUtf16string;
627 }
628 
629 
utf16to8(wchar_t const * const aUtf16string)630 static char * utf16to8(wchar_t const * const aUtf16string)
631 {
632 	char * lUtf8string ;
633 	int lSize = sizeUtf8(aUtf16string);
634 	lUtf8string = (char *) malloc( lSize );
635 	lSize = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
636 		aUtf16string, -1, lUtf8string, lSize, NULL, NULL);
637 	if (lSize == 0)
638 	{
639 		free(lUtf8string);
640 		return NULL;
641 	}
642 	return lUtf8string;
643 }
644 
645 
runSilentA(char const * const aString)646 static void runSilentA(char const * const aString)
647 {
648 	STARTUPINFOA StartupInfo;
649 	PROCESS_INFORMATION ProcessInfo;
650 	char * lArgs;
651 	char * pEnvCMD = NULL;
652 	char * pDefaultCMD = "CMD.EXE";
653 	ULONG rc;
654 	int lStringLen = 0;
655 
656 	memset(&StartupInfo, 0, sizeof(StartupInfo));
657 	StartupInfo.cb = sizeof(STARTUPINFOA);
658 	StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
659 	StartupInfo.wShowWindow = SW_HIDE;
660 
661 	if ( aString )
662 	{
663 		lStringLen = strlen(aString);
664 	}
665 	lArgs = (char *) malloc( MAX_PATH_OR_CMD + lStringLen );
666 
667 	pEnvCMD = getenv("COMSPEC");
668 
669 	if (pEnvCMD){
670 
671 		strcpy(lArgs, pEnvCMD);
672 	}
673 	else{
674 		strcpy(lArgs, pDefaultCMD);
675 	}
676 
677 	/* c to execute then terminate the command window */
678 	strcat(lArgs, " /c ");
679 
680 	/* application and parameters to run from the command window */
681 	strcat(lArgs, aString);
682 
683 	if (!CreateProcessA(NULL, lArgs, NULL, NULL, FALSE,
684 		CREATE_NEW_CONSOLE, NULL, NULL,
685 		&StartupInfo, &ProcessInfo))
686 	{
687 		free(lArgs);
688 		return; /* GetLastError(); */
689 	}
690 
691 	WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
692 	if (!GetExitCodeProcess(ProcessInfo.hProcess, &rc))
693 		rc = 0;
694 
695 	CloseHandle(ProcessInfo.hThread);
696 	CloseHandle(ProcessInfo.hProcess);
697 
698 	free(lArgs);
699 	return; /* rc */
700 }
701 
702 
runSilentW(wchar_t const * const aString)703 static void runSilentW(wchar_t const * const aString)
704 {
705 	STARTUPINFOW StartupInfo;
706 	PROCESS_INFORMATION ProcessInfo;
707 	ULONG rc;
708 	wchar_t * lArgs;
709 	wchar_t * pEnvCMD;
710 	wchar_t * pDefaultCMD = L"CMD.EXE";
711 	int lStringLen = 0;
712 
713 	memset(&StartupInfo, 0, sizeof(StartupInfo));
714 	StartupInfo.cb = sizeof(STARTUPINFOW);
715 	StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
716 	StartupInfo.wShowWindow = SW_HIDE;
717 
718 	if ( aString )
719 	{
720 		lStringLen = wcslen(aString);
721 	}
722 	lArgs = (wchar_t *) malloc( (MAX_PATH_OR_CMD + lStringLen) * sizeof(wchar_t) );
723 
724 	pEnvCMD = utf8to16( getenv("COMSPEC") );
725 	if (pEnvCMD)
726 	{
727 		wcscpy(lArgs, pEnvCMD);
728 		free(pEnvCMD);
729 	}
730 	else
731 	{
732 		wcscpy(lArgs, pDefaultCMD);
733 	}
734 
735 	/* c to execute then terminate the command window */
736 	wcscat(lArgs, L" /c ");
737 
738 	/* application and parameters to run from the command window */
739 	wcscat(lArgs, aString);
740 
741 	if (!CreateProcessW(NULL, lArgs, NULL, NULL, FALSE,
742 				CREATE_NEW_CONSOLE, NULL, NULL,
743 				&StartupInfo, &ProcessInfo))
744 	{
745 		free(lArgs);
746 		return; /* GetLastError(); */
747 	}
748 
749 	WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
750 	if (!GetExitCodeProcess(ProcessInfo.hProcess, &rc))
751 	{
752 		rc = 0;
753 	}
754 
755 	CloseHandle(ProcessInfo.hThread);
756 	CloseHandle(ProcessInfo.hProcess);
757 
758 	free(lArgs);
759 	return; /* rc */
760 }
761 
762 
tinyfd_messageBoxW(wchar_t const * const aTitle,wchar_t const * const aMessage,wchar_t const * const aDialogType,wchar_t const * const aIconType,int const aDefaultButton)763 int tinyfd_messageBoxW(
764 	wchar_t const * const aTitle, /* NULL or "" */
765 	wchar_t const * const aMessage, /* NULL or ""  may contain \n and \t */
766 	wchar_t const * const aDialogType, /* "ok" "okcancel" "yesno" */
767 	wchar_t const * const aIconType, /* "info" "warning" "error" "question" */
768 	int const aDefaultButton) /* 0 for cancel/no , 1 for ok/yes */
769 {
770 	int lBoxReturnValue;
771 	UINT aCode;
772 
773 	if (aIconType && !wcscmp(L"warning", aIconType))
774 	{
775 		aCode = MB_ICONWARNING;
776 	}
777 	else if (aIconType && !wcscmp(L"error", aIconType))
778 	{
779 		aCode = MB_ICONERROR;
780 	}
781 	else if (aIconType && !wcscmp(L"question", aIconType))
782 	{
783 		aCode = MB_ICONQUESTION;
784 	}
785 	else
786 	{
787 		aCode = MB_ICONINFORMATION;
788 	}
789 
790 	if (aDialogType && !wcscmp(L"okcancel", aDialogType))
791 	{
792 		aCode += MB_OKCANCEL;
793 		if (!aDefaultButton)
794 		{
795 			aCode += MB_DEFBUTTON2;
796 		}
797 	}
798 	else if (aDialogType && !wcscmp(L"yesno", aDialogType))
799 	{
800 		aCode += MB_YESNO;
801 		if (!aDefaultButton)
802 		{
803 			aCode += MB_DEFBUTTON2;
804 		}
805 	}
806 	else
807 	{
808 		aCode += MB_OK;
809 	}
810 
811 	lBoxReturnValue = MessageBoxW(NULL, aMessage, aTitle, aCode);
812 	if (((aDialogType
813 		&& wcscmp(L"okcancel", aDialogType)
814 		&& wcscmp(L"yesno", aDialogType)))
815 		|| (lBoxReturnValue == IDOK)
816 		|| (lBoxReturnValue == IDYES))
817 	{
818 		return 1;
819 	}
820 	else
821 	{
822 		return 0;
823 	}
824 }
825 
826 
messageBoxWinGui8(char const * const aTitle,char const * const aMessage,char const * const aDialogType,char const * const aIconType,int const aDefaultButton)827 static int messageBoxWinGui8(
828 	char const * const aTitle, /* NULL or "" */
829 	char const * const aMessage, /* NULL or ""  may contain \n and \t */
830 	char const * const aDialogType, /* "ok" "okcancel" "yesno" */
831 	char const * const aIconType, /* "info" "warning" "error" "question" */
832 	int const aDefaultButton) /* 0 for cancel/no , 1 for ok/yes */
833 {
834 	int lIntRetVal;
835 	wchar_t * lTitle;
836 	wchar_t * lMessage;
837 	wchar_t * lDialogType;
838 	wchar_t * lIconType;
839 
840 	lTitle = utf8to16(aTitle);
841 	lMessage = utf8to16(aMessage);
842 	lDialogType = utf8to16(aDialogType);
843 	lIconType = utf8to16(aIconType);
844 
845 	lIntRetVal = tinyfd_messageBoxW(lTitle, lMessage,
846 								lDialogType, lIconType, aDefaultButton );
847 
848 	free(lTitle);
849 	free(lMessage);
850 	free(lDialogType);
851 	free(lIconType);
852 
853 	return lIntRetVal ;
854 }
855 
856 
inputBoxWinGui(char * const aoBuff,char const * const aTitle,char const * const aMessage,char const * const aDefaultInput)857 static char const * inputBoxWinGui(
858 	char * const aoBuff ,
859 	char const * const aTitle , /* NULL or "" */
860 	char const * const aMessage , /* NULL or "" may NOT contain \n nor \t */
861 	char const * const aDefaultInput ) /* "" , if NULL it's a passwordBox */
862 {
863 	char * lDialogString;
864 	FILE * lIn;
865 	int lResult;
866 	int lTitleLen;
867 	int lMessageLen;
868 	wchar_t * lDialogStringW;
869 
870 	lTitleLen =  aTitle ? strlen(aTitle) : 0 ;
871 	lMessageLen =  aMessage ? strlen(aMessage) : 0 ;
872 	lDialogString = (char *)malloc(3 * MAX_PATH_OR_CMD + lTitleLen + lMessageLen);
873 
874 	if (aDefaultInput)
875 	{
876 		sprintf(lDialogString, "%s\\AppData\\Local\\Temp\\tinyfd.vbs",
877 			getenv("USERPROFILE"));
878 	}
879 	else
880 	{
881 		sprintf(lDialogString, "%s\\AppData\\Local\\Temp\\tinyfd.hta",
882 			getenv("USERPROFILE"));
883 	}
884 	lIn = fopen(lDialogString, "w");
885 	if (!lIn)
886 	{
887 		free(lDialogString);
888 		return NULL;
889 	}
890 
891 	if ( aDefaultInput )
892 	{
893 		strcpy(lDialogString, "Dim result:result=InputBox(\"");
894 		if (aMessage && strlen(aMessage))
895 		{
896 			strcat(lDialogString, aMessage);
897 		}
898 		strcat(lDialogString, "\",\"");
899 		if (aTitle && strlen(aTitle))
900 		{
901 			strcat(lDialogString, aTitle);
902 		}
903 		strcat(lDialogString, "\",\"");
904 		if (aDefaultInput && strlen(aDefaultInput))
905 		{
906 			strcat(lDialogString, aDefaultInput);
907 		}
908 		strcat(lDialogString, "\"):If IsEmpty(result) then:WScript.Echo 0");
909 		strcat(lDialogString, ":Else: WScript.Echo \"1\" & result : End If");
910 	}
911 	else
912 	{
913 		sprintf(lDialogString, "\n\
914 <html>\n\
915 <head>\n\
916 <title>%s</title>\n\
917 <HTA:APPLICATION\n\
918 ID = 'tinyfdHTA'\n\
919 APPLICATIONNAME = 'tinyfd_inputBox'\n\
920 MINIMIZEBUTTON = 'no'\n\
921 MAXIMIZEBUTTON = 'no'\n\
922 BORDER = 'dialog'\n\
923 SCROLL = 'no'\n\
924 SINGLEINSTANCE = 'yes'\n\
925 WINDOWSTATE = 'hidden'>\n\
926 \n\
927 <script language = 'VBScript'>\n\
928 \n\
929 intWidth = Screen.Width/4\n\
930 intHeight = Screen.Height/6\n\
931 ResizeTo intWidth, intHeight\n\
932 MoveTo((Screen.Width/2)-(intWidth/2)),((Screen.Height/2)-(intHeight/2))\n\
933 result = 0\n\
934 \n\
935 Sub Window_onLoad\n\
936 txt_input.Focus\n\
937 End Sub\n\
938 \n\
939 Sub Window_onUnload\n\
940 Set objFSO = CreateObject(\"Scripting.FileSystemObject\")\n\
941 Set oShell = CreateObject(\"WScript.Shell\")\n\
942 strHomeFolder = oShell.ExpandEnvironmentStrings(\"%%USERPROFILE%%\")\n\
943 Set objFile = objFSO.CreateTextFile(strHomeFolder & \"\\AppData\\Local\\Temp\\tinyfd.txt\",True)\n\
944 If result = 1 Then\n\
945 objFile.Write 1 & txt_input.Value\n\
946 Else\n\
947 objFile.Write 0\n\
948 End If\n\
949 objFile.Close\n\
950 End Sub\n\
951 \n\
952 Sub Run_ProgramOK\n\
953 result = 1\n\
954 window.Close\n\
955 End Sub\n\
956 \n\
957 Sub Run_ProgramCancel\n\
958 window.Close\n\
959 End Sub\n\
960 \n\
961 Sub Default_Buttons\n\
962 If Window.Event.KeyCode = 13 Then\n\
963 btn_OK.Click\n\
964 ElseIf Window.Event.KeyCode = 27 Then\n\
965 btn_Cancel.Click\n\
966 End If\n\
967 End Sub\n\
968 \n\
969 </script>\n\
970 </head>\n\
971 <body style = 'background-color:#EEEEEE' onkeypress = 'vbs:Default_Buttons' align = 'top'>\n\
972 <table width = '100%%' height = '80%%' align = 'center' border = '0'>\n\
973 <tr border = '0'>\n\
974 <td align = 'left' valign = 'middle' style='Font-Family:Arial'>\n\
975 %s\n\
976 </td>\n\
977 <td align = 'right' valign = 'middle' style = 'margin-top: 0em'>\n\
978 <table  align = 'right' style = 'margin-right: 0em;'>\n\
979 <tr align = 'right' style = 'margin-top: 5em;'>\n\
980 <input type = 'button' value = 'OK' name = 'btn_OK' onClick = 'vbs:Run_ProgramOK' style = 'width: 5em; margin-top: 2em;'><br>\n\
981 <input type = 'button' value = 'Cancel' name = 'btn_Cancel' onClick = 'vbs:Run_ProgramCancel' style = 'width: 5em;'><br><br>\n\
982 </tr>\n\
983 </table>\n\
984 </td>\n\
985 </tr>\n\
986 </table>\n\
987 <table width = '100%%' height = '100%%' align = 'center' border = '0'>\n\
988 <tr>\n\
989 <td align = 'left' valign = 'top'>\n\
990 <input type = 'password' id = 'txt_input'\n\
991 name = 'txt_input' value = '' style = 'float:left;width:100%%' ><BR>\n\
992 </td>\n\
993 </tr>\n\
994 </table>\n\
995 </body>\n\
996 </html>\n\
997 "		, aTitle ? aTitle : "", aMessage ? aMessage : "") ;
998 	}
999 	fputs(lDialogString, lIn);
1000 	fclose(lIn);
1001 
1002 	strcpy(lDialogString, "");
1003 
1004 	if (aDefaultInput)
1005 	{
1006 		strcat(lDialogString, "cscript.exe ");
1007 		strcat(lDialogString, "//Nologo ");
1008 		strcat(lDialogString,"%USERPROFILE%\\AppData\\Local\\Temp\\tinyfd.vbs");
1009 		strcat(lDialogString, " > %USERPROFILE%\\AppData\\Local\\Temp\\tinyfd.txt");
1010 	}
1011 	else
1012 	{
1013 		strcat(lDialogString,
1014 			"mshta.exe %USERPROFILE%\\AppData\\Local\\Temp\\tinyfd.hta");
1015 	}
1016 
1017 	/* printf ( "lDialogString: %s\n" , lDialogString ) ; */
1018 
1019 	if (tinyfd_winUtf8)
1020 	{
1021 		lDialogStringW = utf8to16(lDialogString);
1022 		runSilentW(lDialogStringW);
1023 		free(lDialogStringW);
1024 	}
1025 	else
1026 	{
1027 		runSilentA(lDialogString);
1028 	}
1029 
1030 	/*
1031 	if (!(lIn = _popen(lDialogString, "r")))
1032 	{
1033 		free(lDialogString);
1034 		return NULL;
1035 	}
1036 	while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL)
1037 	{
1038 	}
1039 	_pclose(lIn);
1040 	if (aoBuff[strlen(aoBuff) - 1] == '\n')
1041 	{
1042 		aoBuff[strlen(aoBuff) - 1] = '\0';
1043 	}
1044 	*/
1045 
1046 	if (aDefaultInput)
1047 	{
1048 		sprintf(lDialogString, "%s\\AppData\\Local\\Temp\\tinyfd.txt",
1049 			getenv("USERPROFILE"));
1050 		if (!(lIn = fopen(lDialogString, "r")))
1051 		{
1052 			remove(lDialogString);
1053 			free(lDialogString);
1054 			return NULL;
1055 		}
1056 		while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL)
1057 		{}
1058 		fclose(lIn);
1059 		remove(lDialogString);
1060 
1061 		sprintf(lDialogString, "%s\\AppData\\Local\\Temp\\tinyfd.vbs",
1062 			getenv("USERPROFILE"));
1063 	}
1064 	else
1065 	{
1066 		sprintf(lDialogString, "%s\\AppData\\Local\\Temp\\tinyfd.txt",
1067 			getenv("USERPROFILE"));
1068 		if (!(lIn = fopen(lDialogString, "r")))
1069 		{
1070 			remove(lDialogString);
1071 			free(lDialogString);
1072 			return NULL;
1073 		}
1074 		while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL)
1075 		{}
1076 		fclose(lIn);
1077 
1078 		wipefile(lDialogString);
1079 		remove(lDialogString);
1080 		sprintf(lDialogString, "%s\\AppData\\Local\\Temp\\tinyfd.hta",
1081 			getenv("USERPROFILE"));
1082 	}
1083 	remove(lDialogString);
1084 	free(lDialogString);
1085 	/* printf ( "aoBuff: %s\n" , aoBuff ) ; */
1086 	lResult = strncmp(aoBuff, "1", 1) ? 0 : 1;
1087 	/* printf ( "lResult: %d \n" , lResult ) ; */
1088 	if (!lResult)
1089 	{
1090 		return NULL ;
1091 	}
1092 	/* printf ( "aoBuff+1: %s\n" , aoBuff+1 ) ; */
1093 	return aoBuff + 1;
1094 }
1095 
1096 
tinyfd_saveFileDialogW(wchar_t const * const aTitle,wchar_t const * const aDefaultPathAndFile,int const aNumOfFilterPatterns,wchar_t const * const * const aFilterPatterns,wchar_t const * const aSingleFilterDescription)1097 wchar_t const * tinyfd_saveFileDialogW(
1098 	wchar_t const * const aTitle, /* NULL or "" */
1099 	wchar_t const * const aDefaultPathAndFile, /* NULL or "" */
1100 	int const aNumOfFilterPatterns, /* 0 */
1101 	wchar_t const * const * const aFilterPatterns, /* NULL or {"*.jpg","*.png"} */
1102 	wchar_t const * const aSingleFilterDescription) /* NULL or "image files" */
1103 {
1104 	static wchar_t lBuff[MAX_PATH_OR_CMD];
1105 	wchar_t lDirname[MAX_PATH_OR_CMD];
1106 	wchar_t lDialogString[MAX_PATH_OR_CMD];
1107 	wchar_t lFilterPatterns[MAX_PATH_OR_CMD] = L"";
1108 	wchar_t * p;
1109 	wchar_t * lRetval;
1110 	int i;
1111 	HRESULT lHResult;
1112 	OPENFILENAMEW ofn = {0};
1113 
1114 	lHResult = CoInitializeEx(NULL, 0);
1115 
1116 	getPathWithoutFinalSlashW(lDirname, aDefaultPathAndFile);
1117 	getLastNameW(lBuff, aDefaultPathAndFile);
1118 
1119 	if (aNumOfFilterPatterns > 0)
1120 	{
1121 		if (aSingleFilterDescription && wcslen(aSingleFilterDescription))
1122 		{
1123 			wcscpy(lFilterPatterns, aSingleFilterDescription);
1124 			wcscat(lFilterPatterns, L"\n");
1125 		}
1126 		wcscat(lFilterPatterns, aFilterPatterns[0]);
1127 		for (i = 1; i < aNumOfFilterPatterns; i++)
1128 		{
1129 			wcscat(lFilterPatterns, L";");
1130 			wcscat(lFilterPatterns, aFilterPatterns[i]);
1131 		}
1132 		wcscat(lFilterPatterns, L"\n");
1133 		if (!(aSingleFilterDescription && wcslen(aSingleFilterDescription)))
1134 		{
1135 			wcscpy(lDialogString, lFilterPatterns);
1136 			wcscat(lFilterPatterns, lDialogString);
1137 		}
1138 		wcscat(lFilterPatterns, L"All Files\n*.*\n");
1139 		p = lFilterPatterns;
1140 		while ((p = wcschr(p, L'\n')) != NULL)
1141 		{
1142 			*p = L'\0';
1143 			p++;
1144 		}
1145 	}
1146 
1147 	ofn.lStructSize = sizeof(OPENFILENAMEW);
1148 	ofn.hwndOwner = 0;
1149 	ofn.hInstance = 0;
1150 	ofn.lpstrFilter = lFilterPatterns && wcslen(lFilterPatterns) ? lFilterPatterns : NULL;
1151 	ofn.lpstrCustomFilter = NULL;
1152 	ofn.nMaxCustFilter = 0;
1153 	ofn.nFilterIndex = 1;
1154 	ofn.lpstrFile = lBuff;
1155 
1156 	ofn.nMaxFile = MAX_PATH_OR_CMD;
1157 	ofn.lpstrFileTitle = NULL;
1158 	ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT;
1159 	ofn.lpstrInitialDir = lDirname && wcslen(lDirname) ? lDirname : NULL;
1160 	ofn.lpstrTitle = aTitle && wcslen(aTitle) ? aTitle : NULL;
1161 	ofn.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR;
1162 	ofn.nFileOffset = 0;
1163 	ofn.nFileExtension = 0;
1164 	ofn.lpstrDefExt = NULL;
1165 	ofn.lCustData = 0L;
1166 	ofn.lpfnHook = NULL;
1167 	ofn.lpTemplateName = NULL;
1168 
1169 	if (GetSaveFileNameW(&ofn) == 0)
1170 	{
1171 		lRetval = NULL;
1172 	}
1173 	else
1174 	{
1175 		lRetval = lBuff;
1176 	}
1177 
1178 	if (lHResult == S_OK || lHResult == S_FALSE)
1179 	{
1180 		CoUninitialize();
1181 	}
1182 	return lRetval;
1183 }
1184 
1185 
saveFileDialogWinGui8(char * const aoBuff,char const * const aTitle,char const * const aDefaultPathAndFile,int const aNumOfFilterPatterns,char const * const * const aFilterPatterns,char const * const aSingleFilterDescription)1186 static char const * saveFileDialogWinGui8(
1187 	char * const aoBuff,
1188 	char const * const aTitle, /* NULL or "" */
1189 	char const * const aDefaultPathAndFile, /* NULL or "" */
1190 	int const aNumOfFilterPatterns, /* 0 */
1191 	char const * const * const aFilterPatterns, /* NULL or {"*.jpg","*.png"} */
1192 	char const * const aSingleFilterDescription) /* NULL or "image files" */
1193 {
1194 	wchar_t * lTitle;
1195 	wchar_t * lDefaultPathAndFile;
1196 	wchar_t * lSingleFilterDescription;
1197 	wchar_t * * lFilterPatterns;
1198 	wchar_t const * lTmpWChar;
1199 	char * lTmpChar;
1200 	int i ;
1201 
1202 	lFilterPatterns = (wchar_t **) malloc(aNumOfFilterPatterns*sizeof(wchar_t *));
1203 	for (i = 0; i < aNumOfFilterPatterns; i++)
1204 	{
1205 		lFilterPatterns[i]  = utf8to16(aFilterPatterns[i]);
1206 	}
1207 
1208 	lTitle = utf8to16(aTitle);
1209 	lDefaultPathAndFile = utf8to16(aDefaultPathAndFile);
1210 	lSingleFilterDescription = utf8to16(aSingleFilterDescription);
1211 
1212 	lTmpWChar = tinyfd_saveFileDialogW(
1213 					lTitle,
1214 					lDefaultPathAndFile,
1215 					aNumOfFilterPatterns,
1216 					(wchar_t const** ) /*stupid cast for gcc*/
1217 					lFilterPatterns,
1218 					lSingleFilterDescription);
1219 
1220 	free(lTitle);
1221 	free(lDefaultPathAndFile);
1222 	free(lSingleFilterDescription);
1223 	for (i = 0; i < aNumOfFilterPatterns; i++)
1224 	{
1225 		free(lFilterPatterns[i]);
1226 	}
1227 	free(lFilterPatterns);
1228 
1229 	if (!lTmpWChar)
1230 	{
1231 		return NULL;
1232 	}
1233 
1234 	lTmpChar = utf16to8(lTmpWChar);
1235 	strcpy(aoBuff, lTmpChar);
1236 	free(lTmpChar);
1237 
1238 	return aoBuff;
1239 }
1240 
1241 
tinyfd_openFileDialogW(wchar_t const * const aTitle,wchar_t const * const aDefaultPathAndFile,int const aNumOfFilterPatterns,wchar_t const * const * const aFilterPatterns,wchar_t const * const aSingleFilterDescription,int const aAllowMultipleSelects)1242 wchar_t const * tinyfd_openFileDialogW(
1243 	wchar_t const * const aTitle, /*  NULL or "" */
1244 	wchar_t const * const aDefaultPathAndFile, /*  NULL or "" */
1245 	int const aNumOfFilterPatterns, /* 0 */
1246 	wchar_t const * const * const aFilterPatterns, /* NULL or {"*.jpg","*.png"} */
1247 	wchar_t const * const aSingleFilterDescription, /* NULL or "image files" */
1248 	int const aAllowMultipleSelects) /* 0 or 1 */
1249 {
1250 	static wchar_t lBuff[MAX_MULTIPLE_FILES*MAX_PATH_OR_CMD];
1251 
1252 	size_t lLengths[MAX_MULTIPLE_FILES];
1253 	wchar_t lDirname[MAX_PATH_OR_CMD];
1254 	wchar_t lFilterPatterns[MAX_PATH_OR_CMD] = L"";
1255 	wchar_t lDialogString[MAX_PATH_OR_CMD];
1256 	wchar_t * lPointers[MAX_MULTIPLE_FILES];
1257 	wchar_t * lRetval, * p;
1258 	int i, j;
1259 	size_t lBuffLen;
1260 	HRESULT lHResult;
1261 	OPENFILENAMEW ofn = { 0 };
1262 
1263 	lHResult = CoInitializeEx(NULL, 0);
1264 
1265 	getPathWithoutFinalSlashW(lDirname, aDefaultPathAndFile);
1266 	getLastNameW(lBuff, aDefaultPathAndFile);
1267 
1268 	if (aNumOfFilterPatterns > 0)
1269 	{
1270 		if (aSingleFilterDescription && wcslen(aSingleFilterDescription))
1271 		{
1272 			wcscpy(lFilterPatterns, aSingleFilterDescription);
1273 			wcscat(lFilterPatterns, L"\n");
1274 		}
1275 		wcscat(lFilterPatterns, aFilterPatterns[0]);
1276 		for (i = 1; i < aNumOfFilterPatterns; i++)
1277 		{
1278 			wcscat(lFilterPatterns, L";");
1279 			wcscat(lFilterPatterns, aFilterPatterns[i]);
1280 		}
1281 		wcscat(lFilterPatterns, L"\n");
1282 		if (!(aSingleFilterDescription && wcslen(aSingleFilterDescription)))
1283 		{
1284 			wcscpy(lDialogString, lFilterPatterns);
1285 			wcscat(lFilterPatterns, lDialogString);
1286 		}
1287 		wcscat(lFilterPatterns, L"All Files\n*.*\n");
1288 		p = lFilterPatterns;
1289 		while ((p = wcschr(p, L'\n')) != NULL)
1290 		{
1291 			*p = L'\0';
1292 			p++;
1293 		}
1294 	}
1295 
1296 	ofn.lStructSize = sizeof(OPENFILENAME);
1297 	ofn.hwndOwner = 0;
1298 	ofn.hInstance = 0;
1299 	ofn.lpstrFilter = lFilterPatterns && wcslen(lFilterPatterns) ? lFilterPatterns : NULL;
1300 	ofn.lpstrCustomFilter = NULL;
1301 	ofn.nMaxCustFilter = 0;
1302 	ofn.nFilterIndex = 1;
1303 	ofn.lpstrFile = lBuff;
1304 	ofn.nMaxFile = MAX_PATH_OR_CMD;
1305 	ofn.lpstrFileTitle = NULL;
1306 	ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT;
1307 	ofn.lpstrInitialDir = lDirname && wcslen(lDirname) ? lDirname : NULL;
1308 	ofn.lpstrTitle = aTitle && wcslen(aTitle) ? aTitle : NULL;
1309 	ofn.Flags = OFN_EXPLORER | OFN_NOCHANGEDIR;
1310 	ofn.nFileOffset = 0;
1311 	ofn.nFileExtension = 0;
1312 	ofn.lpstrDefExt = NULL;
1313 	ofn.lCustData = 0L;
1314 	ofn.lpfnHook = NULL;
1315 	ofn.lpTemplateName = NULL;
1316 
1317 	if (aAllowMultipleSelects)
1318 	{
1319 		ofn.Flags |= OFN_ALLOWMULTISELECT;
1320 	}
1321 
1322 	if (GetOpenFileNameW(&ofn) == 0)
1323 	{
1324 		lRetval = NULL;
1325 	}
1326 	else
1327 	{
1328 		lBuffLen = wcslen(lBuff);
1329 		lPointers[0] = lBuff + lBuffLen + 1;
1330 		if (!aAllowMultipleSelects || (lPointers[0][0] == L'\0'))
1331 		{
1332 			lRetval = lBuff;
1333 		}
1334 		else
1335 		{
1336 			i = 0;
1337 			do
1338 			{
1339 				lLengths[i] = wcslen(lPointers[i]);
1340 				lPointers[i + 1] = lPointers[i] + lLengths[i] + 1;
1341 				i++;
1342 			} while (lPointers[i][0] != L'\0');
1343 			i--;
1344 			p = lBuff + MAX_MULTIPLE_FILES*MAX_PATH_OR_CMD - 1;
1345 			*p = L'\0';
1346 			for (j = i; j >= 0; j--)
1347 			{
1348 				p -= lLengths[j];
1349 				memmove(p, lPointers[j], lLengths[j]*sizeof(wchar_t));
1350 				p--;
1351 				*p = L'\\';
1352 				p -= lBuffLen;
1353 				memmove(p, lBuff, lBuffLen*sizeof(wchar_t));
1354 				p--;
1355 				*p = L'|';
1356 			}
1357 			p++;
1358 			lRetval = p;
1359 		}
1360 	}
1361 
1362 	if (lHResult == S_OK || lHResult == S_FALSE)
1363 	{
1364 		CoUninitialize();
1365 	}
1366 	return lRetval;
1367 }
1368 
1369 
openFileDialogWinGui8(char * const aoBuff,char const * const aTitle,char const * const aDefaultPathAndFile,int const aNumOfFilterPatterns,char const * const * const aFilterPatterns,char const * const aSingleFilterDescription,int const aAllowMultipleSelects)1370 static char const * openFileDialogWinGui8(
1371 	char * const aoBuff,
1372 	char const * const aTitle, /*  NULL or "" */
1373 	char const * const aDefaultPathAndFile, /*  NULL or "" */
1374 	int const aNumOfFilterPatterns, /* 0 */
1375 	char const * const * const aFilterPatterns, /* NULL or {"*.jpg","*.png"} */
1376 	char const * const aSingleFilterDescription, /* NULL or "image files" */
1377 	int const aAllowMultipleSelects) /* 0 or 1 */
1378 {
1379 	wchar_t * lTitle;
1380 	wchar_t * lDefaultPathAndFile;
1381 	wchar_t * lSingleFilterDescription;
1382 	wchar_t * * lFilterPatterns;
1383 	wchar_t const * lTmpWChar;
1384 	char * lTmpChar;
1385 	int i;
1386 
1387 	lFilterPatterns = (wchar_t * *) malloc(aNumOfFilterPatterns*sizeof(wchar_t *));
1388 	for (i = 0; i < aNumOfFilterPatterns; i++)
1389 	{
1390 		lFilterPatterns[i] = utf8to16(aFilterPatterns[i]);
1391 	}
1392 
1393 	lTitle = utf8to16(aTitle);
1394 	lDefaultPathAndFile = utf8to16(aDefaultPathAndFile);
1395 	lSingleFilterDescription = utf8to16(aSingleFilterDescription);
1396 
1397 	lTmpWChar = tinyfd_openFileDialogW(
1398 		lTitle,
1399 		lDefaultPathAndFile,
1400 		aNumOfFilterPatterns,
1401 		(wchar_t const**) /*stupid cast for gcc*/
1402 		lFilterPatterns,
1403 		lSingleFilterDescription,
1404 		aAllowMultipleSelects);
1405 
1406 	free(lTitle);
1407 	free(lDefaultPathAndFile);
1408 	free(lSingleFilterDescription);
1409 	for (i = 0; i < aNumOfFilterPatterns; i++)
1410 	{
1411 		free(lFilterPatterns[i]);
1412 	}
1413 	free(lFilterPatterns);
1414 
1415 	if (!lTmpWChar)
1416 	{
1417 		return NULL;
1418 	}
1419 
1420 	lTmpChar = utf16to8(lTmpWChar);
1421 	strcpy(aoBuff, lTmpChar);
1422 	free(lTmpChar);
1423 
1424 	return aoBuff;
1425 }
1426 
1427 
tinyfd_selectFolderDialogW(wchar_t const * const aTitle,wchar_t const * const aDefaultPath)1428 wchar_t const * tinyfd_selectFolderDialogW(
1429 	wchar_t const * const aTitle, /*  NULL or "" */
1430 	wchar_t const * const aDefaultPath) /* NULL or "" */
1431 {
1432 	static wchar_t lBuff[MAX_PATH_OR_CMD];
1433 
1434 	BROWSEINFOW bInfo;
1435 	LPITEMIDLIST lpItem;
1436 	HRESULT lHResult;
1437 
1438 	lHResult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1439 
1440 	/* we can't use aDefaultPath */
1441 	bInfo.hwndOwner = 0;
1442 	bInfo.pidlRoot = NULL;
1443 	bInfo.pszDisplayName = lBuff;
1444 	bInfo.lpszTitle = aTitle && wcslen(aTitle) ? aTitle : NULL;
1445 	bInfo.ulFlags = BIF_USENEWUI;
1446 	bInfo.lpfn = NULL;
1447 	bInfo.lParam = 0;
1448 	bInfo.iImage = -1;
1449 
1450 	lpItem = SHBrowseForFolderW(&bInfo);
1451 	if (lpItem)
1452 	{
1453 		SHGetPathFromIDListW(lpItem, lBuff);
1454 	}
1455 
1456 	if (lHResult == S_OK || lHResult == S_FALSE)
1457 	{
1458 		CoUninitialize();
1459 	}
1460 	return lBuff;
1461 }
1462 
1463 
selectFolderDialogWinGui8(char * const aoBuff,char const * const aTitle,char const * const aDefaultPath)1464 static char const * selectFolderDialogWinGui8 (
1465 	char * const aoBuff ,
1466 	char const * const aTitle , /*  NULL or "" */
1467 	char const * const aDefaultPath ) /* NULL or "" */
1468 {
1469 	wchar_t * lTitle;
1470 	wchar_t * lDefaultPath;
1471 	wchar_t const * lTmpWChar;
1472 	char * lTmpChar;
1473 
1474 	lTitle = utf8to16(aTitle);
1475 	lDefaultPath = utf8to16(aDefaultPath);
1476 
1477 	lTmpWChar = tinyfd_selectFolderDialogW(
1478 		lTitle,
1479 		lDefaultPath);
1480 
1481 	free(lTitle);
1482 	free(lDefaultPath);
1483 	if (!lTmpWChar)
1484 	{
1485 		return NULL;
1486 	}
1487 
1488 	lTmpChar = utf16to8(lTmpWChar);
1489 	strcpy(aoBuff, lTmpChar);
1490 	free(lTmpChar);
1491 
1492 	return aoBuff;
1493 }
1494 
1495 
tinyfd_colorChooserW(wchar_t const * const aTitle,wchar_t const * const aDefaultHexRGB,unsigned char const aDefaultRGB[3],unsigned char aoResultRGB[3])1496 wchar_t const * tinyfd_colorChooserW(
1497 	wchar_t const * const aTitle, /* NULL or "" */
1498 	wchar_t const * const aDefaultHexRGB, /* NULL or "#FF0000"*/
1499 	unsigned char const aDefaultRGB[3], /* { 0 , 255 , 255 } */
1500 	unsigned char aoResultRGB[3]) /* { 0 , 0 , 0 } */
1501 {
1502 	static wchar_t lResultHexRGB[8];
1503 	CHOOSECOLORW cc;
1504 	COLORREF crCustColors[16];
1505 	unsigned char lDefaultRGB[3];
1506 	int lRet;
1507 
1508 	/*
1509 	HRESULT lHResult;
1510 	lHResult = CoInitializeEx(NULL, 0);
1511 	*/
1512 
1513 	if (aDefaultHexRGB)
1514 	{
1515 		Hex2RGBW(aDefaultHexRGB, lDefaultRGB);
1516 	}
1517 	else
1518 	{
1519 		lDefaultRGB[0] = aDefaultRGB[0];
1520 		lDefaultRGB[1] = aDefaultRGB[1];
1521 		lDefaultRGB[2] = aDefaultRGB[2];
1522 	}
1523 
1524 	/* we can't use aTitle */
1525 	cc.lStructSize = sizeof(CHOOSECOLOR);
1526 	cc.hwndOwner = NULL;
1527 	cc.hInstance = NULL;
1528 	cc.rgbResult = RGB(lDefaultRGB[0], lDefaultRGB[1], lDefaultRGB[2]);
1529 	cc.lpCustColors = crCustColors;
1530 	cc.Flags = CC_RGBINIT | CC_FULLOPEN;
1531 	cc.lCustData = 0;
1532 	cc.lpfnHook = NULL;
1533 	cc.lpTemplateName = NULL;
1534 
1535 	lRet = ChooseColorW(&cc);
1536 
1537 	if (!lRet)
1538 	{
1539 		return NULL;
1540 	}
1541 
1542 	aoResultRGB[0] = GetRValue(cc.rgbResult);
1543 	aoResultRGB[1] = GetGValue(cc.rgbResult);
1544 	aoResultRGB[2] = GetBValue(cc.rgbResult);
1545 
1546 	RGB2HexW(aoResultRGB, lResultHexRGB);
1547 
1548 	/*
1549 	if (lHResult == S_OK || lHResult == S_FALSE)
1550 	{
1551 		CoUninitialize();
1552 	}
1553 	*/
1554 
1555 	return lResultHexRGB;
1556 }
1557 
1558 
colorChooserWinGui8(char const * const aTitle,char const * const aDefaultHexRGB,unsigned char const aDefaultRGB[3],unsigned char aoResultRGB[3])1559 static char const * colorChooserWinGui8(
1560 	char const * const aTitle, /* NULL or "" */
1561 	char const * const aDefaultHexRGB, /* NULL or "#FF0000"*/
1562 	unsigned char const aDefaultRGB[3], /* { 0 , 255 , 255 } */
1563 	unsigned char aoResultRGB[3]) /* { 0 , 0 , 0 } */
1564 {
1565 	static char lResultHexRGB[8];
1566 
1567 	wchar_t * lTitle;
1568 	wchar_t * lDefaultHexRGB;
1569 	wchar_t const * lTmpWChar;
1570 	char * lTmpChar;
1571 
1572 	lTitle = utf8to16(aTitle);
1573 	lDefaultHexRGB = utf8to16(aDefaultHexRGB);
1574 
1575 	lTmpWChar = tinyfd_colorChooserW(
1576 		lTitle,
1577 		lDefaultHexRGB,
1578 		aDefaultRGB,
1579 		aoResultRGB );
1580 
1581 	free(lTitle);
1582 	free(lDefaultHexRGB);
1583 	if (!lTmpWChar)
1584 	{
1585 		return NULL;
1586 	}
1587 
1588 	lTmpChar = utf16to8(lTmpWChar);
1589 	strcpy(lResultHexRGB, lTmpChar);
1590 	free(lTmpChar);
1591 
1592 	return lResultHexRGB;
1593 }
1594 
1595 
messageBoxWinGuiA(char const * const aTitle,char const * const aMessage,char const * const aDialogType,char const * const aIconType,int const aDefaultButton)1596 static int messageBoxWinGuiA (
1597     char const * const aTitle , /* NULL or "" */
1598     char const * const aMessage , /* NULL or ""  may contain \n and \t */
1599     char const * const aDialogType , /* "ok" "okcancel" "yesno" */
1600     char const * const aIconType , /* "info" "warning" "error" "question" */
1601     int const aDefaultButton ) /* 0 for cancel/no , 1 for ok/yes */
1602 {
1603 	int lBoxReturnValue;
1604     UINT aCode ;
1605 
1606 	if ( aIconType && ! strcmp( "warning" , aIconType ) )
1607 	{
1608 		aCode = MB_ICONWARNING ;
1609 	}
1610 	else if ( aIconType && ! strcmp("error", aIconType))
1611 	{
1612 		aCode = MB_ICONERROR ;
1613 	}
1614 	else if ( aIconType && ! strcmp("question", aIconType))
1615 	{
1616 		aCode = MB_ICONQUESTION ;
1617 	}
1618 	else
1619 	{
1620 		aCode = MB_ICONINFORMATION ;
1621 	}
1622 
1623 	if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) )
1624 	{
1625 		aCode += MB_OKCANCEL ;
1626 		if ( ! aDefaultButton )
1627 		{
1628 			aCode += MB_DEFBUTTON2 ;
1629 		}
1630 	}
1631 	else if ( aDialogType && ! strcmp( "yesno" , aDialogType ) )
1632 	{
1633 		aCode += MB_YESNO ;
1634 		if ( ! aDefaultButton )
1635 		{
1636 			aCode += MB_DEFBUTTON2 ;
1637 		}
1638 	}
1639 	else
1640 	{
1641 		aCode += MB_OK ;
1642 	}
1643 
1644 	lBoxReturnValue = MessageBoxA(NULL, aMessage, aTitle, aCode);
1645 	if ( ( ( aDialogType
1646 		  && strcmp("okcancel", aDialogType)
1647 		  && strcmp("yesno", aDialogType) ) )
1648 		|| (lBoxReturnValue == IDOK)
1649 		|| (lBoxReturnValue == IDYES) )
1650 	{
1651 		return 1 ;
1652 	}
1653 	else
1654 	{
1655 		return 0 ;
1656 	}
1657 }
1658 
1659 
saveFileDialogWinGuiA(char * const aoBuff,char const * const aTitle,char const * const aDefaultPathAndFile,int const aNumOfFilterPatterns,char const * const * const aFilterPatterns,char const * const aSingleFilterDescription)1660 static char const * saveFileDialogWinGuiA (
1661 	char * const aoBuff ,
1662     char const * const aTitle , /* NULL or "" */
1663     char const * const aDefaultPathAndFile , /* NULL or "" */
1664     int const aNumOfFilterPatterns , /* 0 */
1665     char const * const * const aFilterPatterns , /* NULL or {"*.jpg","*.png"} */
1666     char const * const aSingleFilterDescription ) /* NULL or "image files" */
1667 {
1668 	char lDirname [MAX_PATH_OR_CMD] ;
1669 	char lDialogString[MAX_PATH_OR_CMD];
1670 	char lFilterPatterns[MAX_PATH_OR_CMD] = "";
1671 	int i ;
1672 	char * p;
1673 	char * lRetval;
1674 	HRESULT lHResult;
1675 	OPENFILENAMEA ofn = { 0 };
1676 
1677 	lHResult = CoInitializeEx(NULL,0);
1678 
1679 	getPathWithoutFinalSlash(lDirname, aDefaultPathAndFile);
1680 	getLastName(aoBuff, aDefaultPathAndFile);
1681 
1682 	if (aNumOfFilterPatterns > 0)
1683 	{
1684 		if ( aSingleFilterDescription && strlen(aSingleFilterDescription) )
1685 		{
1686 			strcpy(lFilterPatterns, aSingleFilterDescription);
1687 			strcat(lFilterPatterns, "\n");
1688 		}
1689 		strcat(lFilterPatterns, aFilterPatterns[0]);
1690 		for (i = 1; i < aNumOfFilterPatterns; i++)
1691 		{
1692 			strcat(lFilterPatterns, ";");
1693 			strcat(lFilterPatterns, aFilterPatterns[i]);
1694 		}
1695 		strcat(lFilterPatterns, "\n");
1696 		if ( ! (aSingleFilterDescription && strlen(aSingleFilterDescription) ) )
1697 		{
1698 			strcpy(lDialogString, lFilterPatterns);
1699 			strcat(lFilterPatterns, lDialogString);
1700 		}
1701 		strcat(lFilterPatterns, "All Files\n*.*\n");
1702 		p = lFilterPatterns;
1703 		while ((p = strchr(p, '\n')) != NULL)
1704 		{
1705 			*p = '\0';
1706 			p ++ ;
1707 		}
1708 	}
1709 
1710 	ofn.lStructSize     = sizeof(OPENFILENAME) ;
1711 	ofn.hwndOwner       = 0 ;
1712 	ofn.hInstance       = 0 ;
1713 	ofn.lpstrFilter		= lFilterPatterns && strlen(lFilterPatterns) ? lFilterPatterns : NULL;
1714 	ofn.lpstrCustomFilter = NULL ;
1715 	ofn.nMaxCustFilter  = 0 ;
1716 	ofn.nFilterIndex    = 1 ;
1717 	ofn.lpstrFile		= aoBuff;
1718 
1719 	ofn.nMaxFile        = MAX_PATH_OR_CMD ;
1720 	ofn.lpstrFileTitle  = NULL ;
1721 	ofn.nMaxFileTitle   = _MAX_FNAME + _MAX_EXT ;
1722 	ofn.lpstrInitialDir = lDirname && strlen(lDirname) ? lDirname : NULL;
1723 	ofn.lpstrTitle		= aTitle && strlen(aTitle) ? aTitle : NULL;
1724 	ofn.Flags           = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR ;
1725 	ofn.nFileOffset     = 0 ;
1726 	ofn.nFileExtension  = 0 ;
1727 	ofn.lpstrDefExt     = NULL ;
1728 	ofn.lCustData       = 0L ;
1729 	ofn.lpfnHook        = NULL ;
1730 	ofn.lpTemplateName  = NULL ;
1731 
1732 	if ( GetSaveFileNameA ( & ofn ) == 0 )
1733 	{
1734 		lRetval = NULL ;
1735 	}
1736 	else
1737 	{
1738 		lRetval = aoBuff ;
1739 	}
1740 
1741 	if (lHResult==S_OK || lHResult==S_FALSE)
1742 	{
1743 		CoUninitialize();
1744 	}
1745 	return lRetval ;
1746 }
1747 
1748 
openFileDialogWinGuiA(char * const aoBuff,char const * const aTitle,char const * const aDefaultPathAndFile,int const aNumOfFilterPatterns,char const * const * const aFilterPatterns,char const * const aSingleFilterDescription,int const aAllowMultipleSelects)1749 static char const * openFileDialogWinGuiA (
1750 	char * const aoBuff ,
1751     char const * const aTitle , /*  NULL or "" */
1752     char const * const aDefaultPathAndFile , /*  NULL or "" */
1753     int const aNumOfFilterPatterns , /* 0 */
1754     char const * const * const aFilterPatterns , /* NULL or {"*.jpg","*.png"} */
1755     char const * const aSingleFilterDescription , /* NULL or "image files" */
1756     int const aAllowMultipleSelects ) /* 0 or 1 */
1757 {
1758 	char lDirname [MAX_PATH_OR_CMD] ;
1759 	char lFilterPatterns[MAX_PATH_OR_CMD] = "";
1760 	char lDialogString[MAX_PATH_OR_CMD] ;
1761 	char * lPointers[MAX_MULTIPLE_FILES];
1762 	size_t lLengths[MAX_MULTIPLE_FILES];
1763 	int i , j ;
1764 	char * p;
1765 	size_t lBuffLen ;
1766 	char * lRetval;
1767 	HRESULT lHResult;
1768 	OPENFILENAMEA ofn = {0};
1769 
1770 	lHResult = CoInitializeEx(NULL,0);
1771 
1772 	getPathWithoutFinalSlash(lDirname, aDefaultPathAndFile);
1773 	getLastName(aoBuff, aDefaultPathAndFile);
1774 
1775 	if (aNumOfFilterPatterns > 0)
1776 	{
1777 		if ( aSingleFilterDescription && strlen(aSingleFilterDescription) )
1778 		{
1779 			strcpy(lFilterPatterns, aSingleFilterDescription);
1780 			strcat(lFilterPatterns, "\n");
1781 		}
1782 		strcat(lFilterPatterns, aFilterPatterns[0]);
1783 		for (i = 1; i < aNumOfFilterPatterns; i++)
1784 		{
1785 			strcat(lFilterPatterns, ";");
1786 			strcat(lFilterPatterns, aFilterPatterns[i]);
1787 		}
1788 		strcat(lFilterPatterns, "\n");
1789 		if ( ! (aSingleFilterDescription && strlen(aSingleFilterDescription) ) )
1790 		{
1791 			strcpy(lDialogString, lFilterPatterns);
1792 			strcat(lFilterPatterns, lDialogString);
1793 		}
1794 		strcat(lFilterPatterns, "All Files\n*.*\n");
1795 		p = lFilterPatterns;
1796 		while ((p = strchr(p, '\n')) != NULL)
1797 		{
1798 			*p = '\0';
1799 			p ++ ;
1800 		}
1801 	}
1802 
1803 	ofn.lStructSize     = sizeof ( OPENFILENAME ) ;
1804 	ofn.hwndOwner       = 0 ;
1805 	ofn.hInstance       = 0 ;
1806 	ofn.lpstrFilter		= lFilterPatterns && strlen(lFilterPatterns) ? lFilterPatterns : NULL;
1807 	ofn.lpstrCustomFilter = NULL ;
1808 	ofn.nMaxCustFilter  = 0 ;
1809 	ofn.nFilterIndex    = 1 ;
1810 	ofn.lpstrFile		= aoBuff ;
1811 	ofn.nMaxFile        = MAX_PATH_OR_CMD ;
1812 	ofn.lpstrFileTitle  = NULL ;
1813 	ofn.nMaxFileTitle   = _MAX_FNAME + _MAX_EXT ;
1814 	ofn.lpstrInitialDir = lDirname && strlen(lDirname) ? lDirname : NULL;
1815 	ofn.lpstrTitle		= aTitle && strlen(aTitle) ? aTitle : NULL;
1816 	ofn.Flags			= OFN_EXPLORER  | OFN_NOCHANGEDIR ;
1817 	ofn.nFileOffset     = 0 ;
1818 	ofn.nFileExtension  = 0 ;
1819 	ofn.lpstrDefExt     = NULL ;
1820 	ofn.lCustData       = 0L ;
1821 	ofn.lpfnHook        = NULL ;
1822 	ofn.lpTemplateName  = NULL ;
1823 
1824 	if ( aAllowMultipleSelects )
1825 	{
1826 		ofn.Flags |= OFN_ALLOWMULTISELECT;
1827 	}
1828 
1829 	if ( GetOpenFileNameA ( & ofn ) == 0 )
1830 	{
1831 		lRetval = NULL ;
1832 	}
1833 	else
1834 	{
1835 		lBuffLen = strlen(aoBuff) ;
1836 		lPointers[0] = aoBuff + lBuffLen + 1 ;
1837 		if ( !aAllowMultipleSelects || (lPointers[0][0] == '\0')  )
1838 		{
1839 			lRetval = aoBuff ;
1840 		}
1841 		else
1842 		{
1843 			i = 0 ;
1844 			do
1845 			{
1846 				lLengths[i] = strlen(lPointers[i]);
1847 				lPointers[i+1] = lPointers[i] + lLengths[i] + 1 ;
1848 				i ++ ;
1849 			}
1850 			while ( lPointers[i][0] != '\0' );
1851 			i--;
1852 			p = aoBuff + MAX_MULTIPLE_FILES*MAX_PATH_OR_CMD - 1 ;
1853 			* p = '\0';
1854 			for ( j = i ; j >=0 ; j-- )
1855 			{
1856 				p -= lLengths[j];
1857 				memmove(p, lPointers[j], lLengths[j]);
1858 				p--;
1859 				*p = '\\';
1860 				p -= lBuffLen ;
1861 				memmove(p, aoBuff, lBuffLen);
1862 				p--;
1863 				*p = '|';
1864 			}
1865 			p++;
1866 			lRetval = p ;
1867 		}
1868 	}
1869 
1870 	if (lHResult==S_OK || lHResult==S_FALSE)
1871 	{
1872 		CoUninitialize();
1873 	}
1874 	return lRetval;
1875 }
1876 
1877 
selectFolderDialogWinGuiA(char * const aoBuff,char const * const aTitle,char const * const aDefaultPath)1878 static char const * selectFolderDialogWinGuiA (
1879 	char * const aoBuff ,
1880 	char const * const aTitle , /*  NULL or "" */
1881 	char const * const aDefaultPath ) /* NULL or "" */
1882 {
1883 	BROWSEINFOA bInfo ;
1884 	LPITEMIDLIST lpItem ;
1885 	HRESULT lHResult;
1886 
1887 	lHResult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1888 
1889 	/* we can't use aDefaultPath */
1890 	bInfo.hwndOwner = 0 ;
1891 	bInfo.pidlRoot = NULL ;
1892 	bInfo.pszDisplayName = aoBuff ;
1893 	bInfo.lpszTitle = aTitle && strlen(aTitle) ? aTitle : NULL;
1894 	bInfo.ulFlags = BIF_USENEWUI;
1895 	bInfo.lpfn = NULL ;
1896 	bInfo.lParam = 0 ;
1897 	bInfo.iImage = -1 ;
1898 
1899 	lpItem = SHBrowseForFolderA ( & bInfo ) ;
1900 	if ( lpItem )
1901 	{
1902 		SHGetPathFromIDListA ( lpItem , aoBuff ) ;
1903 	}
1904 
1905 	if (lHResult==S_OK || lHResult==S_FALSE)
1906 	{
1907 		CoUninitialize();
1908 	}
1909 	return aoBuff ;
1910 }
1911 
1912 
colorChooserWinGuiA(char const * const aTitle,char const * const aDefaultHexRGB,unsigned char const aDefaultRGB[3],unsigned char aoResultRGB[3])1913 static char const * colorChooserWinGuiA(
1914 	char const * const aTitle, /* NULL or "" */
1915 	char const * const aDefaultHexRGB, /* NULL or "#FF0000"*/
1916 	unsigned char const aDefaultRGB[3], /* { 0 , 255 , 255 } */
1917 	unsigned char aoResultRGB[3]) /* { 0 , 0 , 0 } */
1918 {
1919 	static char lResultHexRGB[8];
1920 
1921 	CHOOSECOLORA cc;
1922 	COLORREF crCustColors[16];
1923 	unsigned char lDefaultRGB[3];
1924 	int lRet;
1925 
1926 	if ( aDefaultHexRGB )
1927 	{
1928 		Hex2RGB(aDefaultHexRGB, lDefaultRGB);
1929 	}
1930 	else
1931 	{
1932 		lDefaultRGB[0]=aDefaultRGB[0];
1933 		lDefaultRGB[1]=aDefaultRGB[1];
1934 		lDefaultRGB[2]=aDefaultRGB[2];
1935 	}
1936 
1937 	/* we can't use aTitle */
1938 	cc.lStructSize = sizeof ( CHOOSECOLOR ) ;
1939 	cc.hwndOwner = NULL ;
1940 	cc.hInstance = NULL ;
1941 	cc.rgbResult = RGB(lDefaultRGB[0], lDefaultRGB[1], lDefaultRGB[2]);
1942 	cc.lpCustColors = crCustColors;
1943 	cc.Flags = CC_RGBINIT | CC_FULLOPEN;
1944 	cc.lCustData = 0;
1945 	cc.lpfnHook = NULL;
1946 	cc.lpTemplateName = NULL;
1947 
1948 	lRet = ChooseColorA(&cc);
1949 
1950 	if ( ! lRet )
1951 	{
1952 		return NULL;
1953 	}
1954 
1955 	aoResultRGB[0] = GetRValue(cc.rgbResult);
1956 	aoResultRGB[1] = GetGValue(cc.rgbResult);
1957 	aoResultRGB[2] = GetBValue(cc.rgbResult);
1958 
1959 	RGB2Hex(aoResultRGB, lResultHexRGB);
1960 
1961 	return lResultHexRGB;
1962 }
1963 
1964 #endif /* TINYFD_NOLIB */
1965 
dialogPresent()1966 static int dialogPresent ( )
1967 {
1968 	static int lDialogPresent = -1 ;
1969 	char lBuff [MAX_PATH_OR_CMD] ;
1970 	FILE * lIn ;
1971 	char const * lString = "dialog.exe";
1972 	if ( lDialogPresent < 0 )
1973 	{
1974 		if (!(lIn = _popen("where dialog.exe","r")))
1975 		{
1976 			lDialogPresent = 0 ;
1977 			return 0 ;
1978 		}
1979 		while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL )
1980 		{}
1981 		_pclose ( lIn ) ;
1982 		if ( lBuff[strlen ( lBuff ) -1] == '\n' )
1983 		{
1984 			lBuff[strlen ( lBuff ) -1] = '\0' ;
1985 		}
1986 		if ( strcmp(lBuff+strlen(lBuff)-strlen(lString),lString) )
1987 		{
1988 			lDialogPresent = 0 ;
1989 		}
1990 		else
1991 		{
1992 			lDialogPresent = 1 ;
1993 		}
1994 	}
1995 	return lDialogPresent ;
1996 }
1997 
1998 
messageBoxWinConsole(char const * const aTitle,char const * const aMessage,char const * const aDialogType,char const * const aIconType,int const aDefaultButton)1999 static int messageBoxWinConsole (
2000     char const * const aTitle , /* NULL or "" */
2001     char const * const aMessage , /* NULL or ""  may contain \n and \t */
2002     char const * const aDialogType , /* "ok" "okcancel" "yesno" */
2003     char const * const aIconType , /* "info" "warning" "error" "question" */
2004     int const aDefaultButton ) /* 0 for cancel/no , 1 for ok/yes */
2005 {
2006 	char lDialogString[MAX_PATH_OR_CMD];
2007 	char lDialogFile[MAX_PATH_OR_CMD];
2008 	FILE * lIn;
2009 	char lBuff [MAX_PATH_OR_CMD] = "";
2010 
2011 	strcpy ( lDialogString , "dialog " ) ;
2012 	if ( aTitle && strlen(aTitle) )
2013 	{
2014 		strcat(lDialogString, "--title \"") ;
2015 		strcat(lDialogString, aTitle) ;
2016 		strcat(lDialogString, "\" ") ;
2017 	}
2018 
2019 	if ( aDialogType && ( !strcmp( "okcancel" , aDialogType ) || !strcmp( "yesno" , aDialogType ) ) )
2020 	{
2021 		strcat(lDialogString, "--backtitle \"") ;
2022 		strcat(lDialogString, "tab -> move focus") ;
2023 		strcat(lDialogString, "\" ") ;
2024 	}
2025 
2026 	if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) )
2027 	{
2028 		if ( ! aDefaultButton )
2029 		{
2030 			strcat ( lDialogString , "--defaultno " ) ;
2031 		}
2032 		strcat ( lDialogString ,
2033 				"--yes-label \"Ok\" --no-label \"Cancel\" --yesno " ) ;
2034 	}
2035 	else if ( aDialogType && ! strcmp( "yesno" , aDialogType ) )
2036 	{
2037 		if ( ! aDefaultButton )
2038 		{
2039 			strcat ( lDialogString , "--defaultno " ) ;
2040 		}
2041 		strcat ( lDialogString , "--yesno " ) ;
2042 	}
2043 	else
2044 	{
2045 		strcat ( lDialogString , "--msgbox " ) ;
2046 	}
2047 
2048 	strcat ( lDialogString , "\"" ) ;
2049 	if ( aMessage && strlen(aMessage) )
2050 	{
2051 		replaceSubStr ( aMessage , "\n" , "\\n" , lBuff ) ;
2052 		strcat(lDialogString, lBuff) ;
2053 		lBuff[0]='\0';
2054 	}
2055 
2056 	strcat(lDialogString, "\" 10 60");
2057 	strcat(lDialogString, " && echo 1 > ");
2058 
2059 	strcpy(lDialogFile, getenv("USERPROFILE"));
2060 	strcat(lDialogFile, "\\AppData\\Local\\Temp\\tinyfd.txt");
2061 	strcat(lDialogString, lDialogFile);
2062 
2063 	/* printf ( "lDialogString: %s\n" , lDialogString ) ; */
2064 	system ( lDialogString ) ;
2065 
2066 	if (!(lIn = fopen(lDialogFile, "r")))
2067 	{
2068 		remove(lDialogFile);
2069 		return 0 ;
2070 	}
2071 	while (fgets(lBuff, sizeof(lBuff), lIn) != NULL)
2072 	{}
2073 	fclose(lIn);
2074 	remove(lDialogFile);
2075     if ( lBuff[strlen ( lBuff ) -1] == '\n' )
2076     {
2077     	lBuff[strlen ( lBuff ) -1] = '\0' ;
2078     }
2079 	/* printf ( "lBuff: %s\n" , lBuff ) ; */
2080 	if ( ! strlen(lBuff) )
2081 	{
2082 		return 0;
2083 	}
2084 	return 1;
2085 }
2086 
2087 
inputBoxWinConsole(char * const aoBuff,char const * const aTitle,char const * const aMessage,char const * const aDefaultInput)2088 static char const * inputBoxWinConsole(
2089 	char * const aoBuff ,
2090 	char const * const aTitle , /* NULL or "" */
2091 	char const * const aMessage , /* NULL or "" may NOT contain \n nor \t */
2092 	char const * const aDefaultInput ) /* "" , if NULL it's a passwordBox */
2093 {
2094 	char lDialogString[MAX_PATH_OR_CMD];
2095 	char lDialogFile[MAX_PATH_OR_CMD];
2096 	FILE * lIn;
2097 	int lResult;
2098 
2099 	strcpy(lDialogFile, getenv("USERPROFILE"));
2100 	strcat(lDialogFile, "\\AppData\\Local\\Temp\\tinyfd.txt");
2101 	strcpy(lDialogString , "echo|set /p=1 >" ) ;
2102 	strcat(lDialogString, lDialogFile);
2103 	strcat( lDialogString , " & " ) ;
2104 
2105 	strcat ( lDialogString , "dialog " ) ;
2106 	if ( aTitle && strlen(aTitle) )
2107 	{
2108 		strcat(lDialogString, "--title \"") ;
2109 		strcat(lDialogString, aTitle) ;
2110 		strcat(lDialogString, "\" ") ;
2111 	}
2112 
2113 	strcat(lDialogString, "--backtitle \"") ;
2114 	strcat(lDialogString, "tab -> move focus") ;
2115 	strcat(lDialogString, "\" ") ;
2116 
2117 	if ( ! aDefaultInput )
2118 	{
2119 		strcat ( lDialogString , "--passwordbox" ) ;
2120 	}
2121 	else
2122 	{
2123 		strcat ( lDialogString , "--inputbox" ) ;
2124 	}
2125 	strcat ( lDialogString , " \"" ) ;
2126 	if ( aMessage && strlen(aMessage) )
2127 	{
2128 		strcat(lDialogString, aMessage) ;
2129 	}
2130 	strcat(lDialogString,"\" 10 60 ") ;
2131 	if ( aDefaultInput && strlen(aDefaultInput) )
2132 	{
2133 		strcat(lDialogString, "\"") ;
2134 		strcat(lDialogString, aDefaultInput) ;
2135 		strcat(lDialogString, "\" ") ;
2136 	}
2137 
2138 	strcat(lDialogString, "2>>");
2139 	strcpy(lDialogFile, getenv("USERPROFILE"));
2140 	strcat(lDialogFile, "\\AppData\\Local\\Temp\\tinyfd.txt");
2141 	strcat(lDialogString, lDialogFile);
2142 	strcat(lDialogString, " || echo 0 > ");
2143 	strcat(lDialogString, lDialogFile);
2144 
2145 	/* printf ( "lDialogString: %s\n" , lDialogString ) ; */
2146 	system ( lDialogString ) ;
2147 
2148 	if (!(lIn = fopen(lDialogFile, "r")))
2149 	{
2150 		remove(lDialogFile);
2151 		return 0 ;
2152 	}
2153 	while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL)
2154 	{}
2155 	fclose(lIn);
2156 
2157 	wipefile(lDialogFile);
2158 	remove(lDialogFile);
2159     if ( aoBuff[strlen ( aoBuff ) -1] == '\n' )
2160     {
2161     	aoBuff[strlen ( aoBuff ) -1] = '\0' ;
2162     }
2163 	/* printf ( "aoBuff: %s\n" , aoBuff ) ; */
2164 
2165 	/* printf ( "aoBuff: %s len: %lu \n" , aoBuff , strlen(aoBuff) ) ; */
2166     lResult =  strncmp ( aoBuff , "1" , 1) ? 0 : 1 ;
2167 	/* printf ( "lResult: %d \n" , lResult ) ; */
2168     if ( ! lResult )
2169     {
2170 		return NULL ;
2171 	}
2172 	/* printf ( "aoBuff+1: %s\n" , aoBuff+1 ) ; */
2173 	return aoBuff+3 ;
2174 }
2175 
2176 
saveFileDialogWinConsole(char * const aoBuff,char const * const aTitle,char const * const aDefaultPathAndFile)2177 static char const * saveFileDialogWinConsole (
2178 	char * const aoBuff ,
2179 	char const * const aTitle , /* NULL or "" */
2180 	char const * const aDefaultPathAndFile ) /* NULL or "" */
2181 {
2182 	char lDialogString[MAX_PATH_OR_CMD];
2183 	char lPathAndFile[MAX_PATH_OR_CMD] = "";
2184 	FILE * lIn;
2185 
2186 	strcpy ( lDialogString , "dialog " ) ;
2187  	if ( aTitle && strlen(aTitle) )
2188 	{
2189 		strcat(lDialogString, "--title \"") ;
2190 		strcat(lDialogString, aTitle) ;
2191 		strcat(lDialogString, "\" ") ;
2192 	}
2193 
2194 	strcat(lDialogString, "--backtitle \"") ;
2195 	strcat(lDialogString,
2196 		"tab -> focus | spacebar -> select | / -> populate | enter -> ok input line") ;
2197 	strcat(lDialogString, "\" ") ;
2198 
2199 	strcat ( lDialogString , "--fselect \"" ) ;
2200 	if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) )
2201 	{
2202 		/* dialog.exe uses unix separators even on windows */
2203 		strcpy(lPathAndFile, aDefaultPathAndFile);
2204 		replaceChr ( lPathAndFile , '\\' , '/' ) ;
2205 	}
2206 
2207 	/* dialog.exe needs at least one separator */
2208 	if ( ! strchr(lPathAndFile, '/') )
2209 	{
2210 		strcat(lDialogString, "./") ;
2211 	}
2212 	strcat(lDialogString, lPathAndFile) ;
2213 	strcat(lDialogString, "\" 0 60 2>");
2214 	strcpy(lPathAndFile, getenv("USERPROFILE"));
2215 	strcat(lPathAndFile, "\\AppData\\Local\\Temp\\tinyfd.txt");
2216 	strcat(lDialogString, lPathAndFile);
2217 
2218 	/* printf ( "lDialogString: %s\n" , lDialogString ) ; */
2219 	system ( lDialogString ) ;
2220 
2221 	if (!(lIn = fopen(lPathAndFile, "r")))
2222 	{
2223 		remove(lPathAndFile);
2224 		return NULL;
2225 	}
2226 	while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL)
2227 	{}
2228 	fclose(lIn);
2229 	remove(lPathAndFile);
2230 	replaceChr ( aoBuff , '/' , '\\' ) ;
2231 	/* printf ( "aoBuff: %s\n" , aoBuff ) ; */
2232 	getLastName(lDialogString,aoBuff);
2233 	if ( ! strlen(lDialogString) )
2234 	{
2235 		return NULL;
2236 	}
2237 	return aoBuff;
2238 }
2239 
2240 
openFileDialogWinConsole(char * const aoBuff,char const * const aTitle,char const * const aDefaultPathAndFile,int const aAllowMultipleSelects)2241 static char const * openFileDialogWinConsole (
2242 	char * const aoBuff ,
2243 	char const * const aTitle , /*  NULL or "" */
2244 	char const * const aDefaultPathAndFile , /*  NULL or "" */
2245 	int const aAllowMultipleSelects ) /* 0 or 1 */
2246 {
2247 	char lFilterPatterns[MAX_PATH_OR_CMD] = "";
2248 	char lDialogString[MAX_PATH_OR_CMD] ;
2249 	FILE * lIn;
2250 
2251 	strcpy ( lDialogString , "dialog " ) ;
2252  	if ( aTitle && strlen(aTitle) )
2253 	{
2254 		strcat(lDialogString, "--title \"") ;
2255 		strcat(lDialogString, aTitle) ;
2256 		strcat(lDialogString, "\" ") ;
2257 	}
2258 
2259 	strcat(lDialogString, "--backtitle \"") ;
2260 	strcat(lDialogString,
2261 		"tab -> focus | spacebar -> select | / -> populate | enter -> ok input line") ;
2262 	strcat(lDialogString, "\" ") ;
2263 
2264 	strcat ( lDialogString , "--fselect \"" ) ;
2265 	if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) )
2266 	{
2267 		/* dialog.exe uses unix separators even on windows */
2268 		strcpy(lFilterPatterns, aDefaultPathAndFile);
2269 		replaceChr ( lFilterPatterns , '\\' , '/' ) ;
2270 	}
2271 
2272 	/* dialog.exe needs at least one separator */
2273 	if ( ! strchr(lFilterPatterns, '/') )
2274 	{
2275 		strcat(lDialogString, "./") ;
2276 	}
2277 	strcat(lDialogString, lFilterPatterns) ;
2278 	strcat(lDialogString, "\" 0 60 2>");
2279 	strcpy(lFilterPatterns, getenv("USERPROFILE"));
2280 	strcat(lFilterPatterns, "\\AppData\\Local\\Temp\\tinyfd.txt");
2281 	strcat(lDialogString, lFilterPatterns);
2282 
2283 	/* printf ( "lDialogString: %s\n" , lDialogString ) ; */
2284 	system ( lDialogString ) ;
2285 
2286 	if (!(lIn = fopen(lFilterPatterns, "r")))
2287 	{
2288 		remove(lFilterPatterns);
2289 		return NULL;
2290 	}
2291 	while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL)
2292 	{}
2293 	fclose(lIn);
2294 	remove(lFilterPatterns);
2295 	replaceChr ( aoBuff , '/' , '\\' ) ;
2296 	/* printf ( "aoBuff: %s\n" , aoBuff ) ; */
2297 	return aoBuff;
2298 }
2299 
2300 
selectFolderDialogWinConsole(char * const aoBuff,char const * const aTitle,char const * const aDefaultPath)2301 static char const * selectFolderDialogWinConsole (
2302 	char * const aoBuff ,
2303 	char const * const aTitle , /*  NULL or "" */
2304 	char const * const aDefaultPath ) /* NULL or "" */
2305 {
2306 	char lDialogString [MAX_PATH_OR_CMD] ;
2307 	char lString [MAX_PATH_OR_CMD] ;
2308 	FILE * lIn ;
2309 
2310 	strcpy ( lDialogString , "dialog " ) ;
2311  	if ( aTitle && strlen(aTitle) )
2312 	{
2313 		strcat(lDialogString, "--title \"") ;
2314 		strcat(lDialogString, aTitle) ;
2315 		strcat(lDialogString, "\" ") ;
2316 	}
2317 
2318 	strcat(lDialogString, "--backtitle \"") ;
2319 	strcat(lDialogString,
2320 		"tab -> focus | spacebar -> select | / -> populate | enter -> ok input line") ;
2321 	strcat(lDialogString, "\" ") ;
2322 
2323 	strcat ( lDialogString , "--dselect \"" ) ;
2324 	if ( aDefaultPath && strlen(aDefaultPath) )
2325 	{
2326 		/* dialog.exe uses unix separators even on windows */
2327 		strcpy(lString, aDefaultPath) ;
2328 		ensureFinalSlash(lString);
2329 		replaceChr ( lString , '\\' , '/' ) ;
2330 		strcat(lDialogString, lString) ;
2331 	}
2332 	else
2333 	{
2334 		/* dialog.exe needs at least one separator */
2335 		strcat(lDialogString, "./") ;
2336 	}
2337 	strcat(lDialogString, "\" 0 60 2>");
2338 	strcpy(lString, getenv("USERPROFILE"));
2339 	strcat(lString, "\\AppData\\Local\\Temp\\tinyfd.txt");
2340 	strcat(lDialogString, lString);
2341 
2342 	/* printf ( "lDialogString: %s\n" , lDialogString ) ; */
2343 	system ( lDialogString ) ;
2344 
2345 	if (!(lIn = fopen(lString, "r")))
2346 	{
2347 		remove(lString);
2348 		return NULL;
2349 	}
2350 	while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL)
2351 	{}
2352 	fclose(lIn);
2353 	remove(lString);
2354 	replaceChr ( aoBuff , '/' , '\\' ) ;
2355 	/* printf ( "aoBuff: %s\n" , aoBuff ) ; */
2356 	return aoBuff;
2357 }
2358 
2359 
2360 /* returns 0 for cancel/no , 1 for ok/yes */
tinyfd_messageBox(char const * const aTitle,char const * const aMessage,char const * const aDialogType,char const * const aIconType,int const aDefaultButton)2361 int tinyfd_messageBox (
2362 	char const * const aTitle , /* NULL or "" */
2363 	char const * const aMessage , /* NULL or ""  may contain \n and \t */
2364 	char const * const aDialogType , /* "ok" "okcancel" "yesno" */
2365 	char const * const aIconType , /* "info" "warning" "error" "question" */
2366 	int const aDefaultButton ) /* 0 for cancel/no , 1 for ok/yes */
2367 {
2368 	char lChar ;
2369 
2370 #ifndef TINYFD_NOLIB
2371 	if ((!tinyfd_forceConsole || !(GetConsoleWindow() || dialogPresent()))
2372 		&& (!getenv("SSH_CLIENT") || getenv("DISPLAY")))
2373 	{
2374 		if (aTitle&&!strcmp(aTitle, "tinyfd_query")){ strcpy(tinyfd_response, "windows"); return 1; }
2375 		if (tinyfd_winUtf8)
2376 		{
2377 			return messageBoxWinGui8(
2378 				aTitle, aMessage, aDialogType, aIconType, aDefaultButton);
2379 		}
2380 		else
2381 		{
2382 			return messageBoxWinGuiA(
2383 				aTitle, aMessage, aDialogType, aIconType, aDefaultButton);
2384 		}
2385 	}
2386 	else
2387 #endif /* TINYFD_NOLIB */
2388 	if ( dialogPresent() )
2389 	{
2390 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return 0;}
2391 		return messageBoxWinConsole(
2392 					aTitle,aMessage,aDialogType,aIconType,aDefaultButton);
2393 	}
2394 	else
2395 	{
2396 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return 0;}
2397 		if (!gWarningDisplayed && !tinyfd_forceConsole )
2398 		{
2399 			gWarningDisplayed = 1;
2400 			printf("\n\n%s", gAsciiArt);
2401 			printf("\n%s\n", gTitle);
2402 			printf("%s\n\n\n", gMessageWin);
2403 		}
2404  		if ( aTitle && strlen(aTitle) )
2405 		{
2406 			printf ("%s\n\n", aTitle);
2407 		}
2408 		if ( aDialogType && !strcmp("yesno",aDialogType) )
2409 		{
2410 			do
2411 			{
2412 				if ( aMessage && strlen(aMessage) )
2413 				{
2414 					printf("%s\n",aMessage);
2415 				}
2416 				printf("y/n: ");
2417 				lChar = (char) tolower ( _getch() ) ;
2418 				printf("\n\n");
2419 			}
2420 			while ( lChar != 'y' && lChar != 'n' ) ;
2421 			return lChar == 'y' ? 1 : 0 ;
2422 		}
2423 		else if ( aDialogType && !strcmp("okcancel",aDialogType) )
2424 		{
2425 			do
2426 			{
2427 				if ( aMessage && strlen(aMessage) )
2428 				{
2429 					printf("%s\n",aMessage);
2430 				}
2431 				printf("[O]kay/[C]ancel: ");
2432 				lChar = (char) tolower ( _getch() ) ;
2433 				printf("\n\n");
2434 			}
2435 			while ( lChar != 'o' && lChar != 'c' ) ;
2436 			return lChar == 'o' ? 1 : 0 ;
2437 		}
2438 		else
2439 		{
2440 			if ( aMessage && strlen(aMessage) )
2441 			{
2442 				printf("%s\n\n",aMessage);
2443 			}
2444 			printf("press enter to continue ");
2445 			lChar = (char) _getch() ;
2446 			printf("\n\n");
2447 			return 1 ;
2448 		}
2449 	}
2450 }
2451 
2452 
2453 /* returns NULL on cancel */
tinyfd_inputBox(char const * const aTitle,char const * const aMessage,char const * const aDefaultInput)2454 char const * tinyfd_inputBox(
2455 	char const * const aTitle , /* NULL or "" */
2456 	char const * const aMessage , /* NULL or "" may NOT contain \n nor \t */
2457 	char const * const aDefaultInput ) /* "" , if NULL it's a passwordBox */
2458 {
2459 	static char lBuff [MAX_PATH_OR_CMD] ;
2460 	char * lEOF;
2461 
2462 #ifndef TINYFD_NOLIB
2463 	DWORD mode = 0;
2464 	HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
2465 
2466 	if ((!tinyfd_forceConsole || !(
2467 		GetConsoleWindow() ||
2468 		dialogPresent()))
2469 		&& ( !getenv("SSH_CLIENT") || getenv("DISPLAY") ) )
2470 	{
2471 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"windows");return (char const *)1;}
2472 		lBuff[0]='\0';
2473 		return inputBoxWinGui(lBuff,aTitle,aMessage,aDefaultInput);
2474 	}
2475 	else
2476 #endif /* TINYFD_NOLIB */
2477 	if ( dialogPresent() )
2478 	{
2479 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;}
2480 		lBuff[0]='\0';
2481 		return inputBoxWinConsole(lBuff,aTitle,aMessage,aDefaultInput);
2482 	}
2483 	else
2484 	{
2485       if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return (char const *)0;}
2486       lBuff[0]='\0';
2487       if (!gWarningDisplayed && !tinyfd_forceConsole)
2488       {
2489           gWarningDisplayed = 1 ;
2490           printf("\n\n%s", gAsciiArt);
2491           printf("\n%s\n", gTitle);
2492           printf("%s\n\n\n", gMessageWin);
2493       }
2494       if ( aTitle && strlen(aTitle) )
2495       {
2496           printf ("%s\n\n", aTitle);
2497       }
2498       if ( aMessage && strlen(aMessage) )
2499       {
2500           printf("%s\n",aMessage);
2501       }
2502       printf("(ctrl-Z + enter to cancel): ");
2503 #ifndef TINYFD_NOLIB
2504       if ( ! aDefaultInput )
2505       {
2506           GetConsoleMode(hStdin,&mode);
2507           SetConsoleMode(hStdin,mode & (~ENABLE_ECHO_INPUT) );
2508       }
2509 #endif /* TINYFD_NOLIB */
2510       lEOF = fgets(lBuff, MAX_PATH_OR_CMD, stdin);
2511       if ( ! lEOF )
2512       {
2513           return NULL;
2514       }
2515 #ifndef TINYFD_NOLIB
2516       if ( ! aDefaultInput )
2517       {
2518           SetConsoleMode(hStdin,mode);
2519           printf ("\n");
2520       }
2521 #endif /* TINYFD_NOLIB */
2522       printf ("\n");
2523       if ( strchr(lBuff,27) )
2524       {
2525           return NULL ;
2526       }
2527       if ( lBuff[strlen ( lBuff ) -1] == '\n' )
2528       {
2529           lBuff[strlen ( lBuff ) -1] = '\0' ;
2530       }
2531       return lBuff ;
2532   }
2533 }
2534 
2535 
tinyfd_saveFileDialog(char const * const aTitle,char const * const aDefaultPathAndFile,int const aNumOfFilterPatterns,char const * const * const aFilterPatterns,char const * const aSingleFilterDescription)2536 char const * tinyfd_saveFileDialog (
2537 	char const * const aTitle , /* NULL or "" */
2538 	char const * const aDefaultPathAndFile , /* NULL or "" */
2539 	int const aNumOfFilterPatterns , /* 0 */
2540 	char const * const * const aFilterPatterns , /* NULL or {"*.jpg","*.png"} */
2541 	char const * const aSingleFilterDescription ) /* NULL or "image files" */
2542 {
2543 	static char lBuff [MAX_PATH_OR_CMD] ;
2544 	char lString[MAX_PATH_OR_CMD] ;
2545 	char const * p ;
2546 	lBuff[0]='\0';
2547 #ifndef TINYFD_NOLIB
2548 	if ( ( !tinyfd_forceConsole || !( GetConsoleWindow() || dialogPresent() ) )
2549 	  && ( !getenv("SSH_CLIENT") || getenv("DISPLAY") ) )
2550 	{
2551 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"windows");return (char const *)1;}
2552 		if (tinyfd_winUtf8)
2553 		{
2554 			p = saveFileDialogWinGui8(lBuff,
2555 				aTitle, aDefaultPathAndFile, aNumOfFilterPatterns, aFilterPatterns, aSingleFilterDescription);
2556 		}
2557 		else
2558 		{
2559 			p = saveFileDialogWinGuiA(lBuff,
2560 				aTitle, aDefaultPathAndFile, aNumOfFilterPatterns, aFilterPatterns, aSingleFilterDescription);
2561 		}
2562 	}
2563 	else
2564 #endif /* TINYFD_NOLIB */
2565 	if ( dialogPresent() )
2566 	{
2567 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;}
2568 		p = saveFileDialogWinConsole(lBuff,aTitle,aDefaultPathAndFile);
2569 	}
2570 	else
2571 	{
2572 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return (char const *)0;}
2573 		p = tinyfd_inputBox(aTitle, "Save file","");
2574 	}
2575 
2576 	if ( ! p || ! strlen ( p )  )
2577 	{
2578 		return NULL;
2579 	}
2580 	getPathWithoutFinalSlash ( lString , p ) ;
2581 	if ( strlen ( lString ) && ! dirExists ( lString ) )
2582 	{
2583 		return NULL ;
2584 	}
2585 	getLastName(lString,p);
2586 	if ( ! filenameValid(lString) )
2587 	{
2588 		return NULL;
2589 	}
2590 	return p ;
2591 }
2592 
2593 
2594 /* in case of multiple files, the separator is | */
tinyfd_openFileDialog(char const * const aTitle,char const * const aDefaultPathAndFile,int const aNumOfFilterPatterns,char const * const * const aFilterPatterns,char const * const aSingleFilterDescription,int const aAllowMultipleSelects)2595 char const * tinyfd_openFileDialog (
2596     char const * const aTitle , /*  NULL or "" */
2597     char const * const aDefaultPathAndFile , /*  NULL or "" */
2598     int const aNumOfFilterPatterns , /* 0 */
2599     char const * const * const aFilterPatterns , /* NULL or {"*.jpg","*.png"} */
2600     char const * const aSingleFilterDescription , /* NULL or "image files" */
2601     int const aAllowMultipleSelects ) /* 0 or 1 */
2602 {
2603 	static char lBuff[MAX_MULTIPLE_FILES*MAX_PATH_OR_CMD];
2604 	char const * p ;
2605 #ifndef TINYFD_NOLIB
2606 	if ( ( !tinyfd_forceConsole || !( GetConsoleWindow() || dialogPresent() ) )
2607 	  && ( !getenv("SSH_CLIENT") || getenv("DISPLAY") ) )
2608 	{
2609 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"windows");return (char const *)1;}
2610 		if (tinyfd_winUtf8)
2611 		{
2612 			p = openFileDialogWinGui8(lBuff,
2613 				aTitle, aDefaultPathAndFile, aNumOfFilterPatterns,
2614 				aFilterPatterns, aSingleFilterDescription, aAllowMultipleSelects);
2615 		}
2616 		else
2617 		{
2618 			p = openFileDialogWinGuiA(lBuff,
2619 				aTitle, aDefaultPathAndFile, aNumOfFilterPatterns,
2620 				aFilterPatterns, aSingleFilterDescription, aAllowMultipleSelects);
2621 		}
2622 	}
2623 	else
2624 #endif /* TINYFD_NOLIB */
2625 	if ( dialogPresent() )
2626 	{
2627 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;}
2628 		p = openFileDialogWinConsole(lBuff,
2629 				aTitle,aDefaultPathAndFile,aAllowMultipleSelects);
2630 	}
2631 	else
2632 	{
2633 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return (char const *)0;}
2634 		p = tinyfd_inputBox(aTitle, "Open file","");
2635 	}
2636 
2637 	if ( ! p || ! strlen ( p )  )
2638 	{
2639 		return NULL;
2640 	}
2641 	if ( aAllowMultipleSelects && strchr(p, '|') )
2642 	{
2643 		p = ensureFilesExist( lBuff , p ) ;
2644 	}
2645 	else if ( ! fileExists (p) )
2646 	{
2647 		return NULL ;
2648 	}
2649 	/* printf ( "lBuff3: %s\n" , p ) ; */
2650 	return p ;
2651 }
2652 
2653 
tinyfd_selectFolderDialog(char const * const aTitle,char const * const aDefaultPath)2654 char const * tinyfd_selectFolderDialog (
2655 	char const * const aTitle , /*  NULL or "" */
2656 	char const * const aDefaultPath ) /* NULL or "" */
2657 {
2658     static char lBuff [MAX_PATH_OR_CMD] ;
2659 	char const * p ;
2660 #ifndef TINYFD_NOLIB
2661 	if ( ( !tinyfd_forceConsole || !( GetConsoleWindow() || dialogPresent() ) )
2662 	  && ( !getenv("SSH_CLIENT") || getenv("DISPLAY") ) )
2663 	{
2664 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"windows");return (char const *)1;}
2665 		if (tinyfd_winUtf8)
2666 		{
2667 			p = selectFolderDialogWinGui8(lBuff, aTitle, aDefaultPath);
2668 		}
2669 		else
2670 		{
2671 			p = selectFolderDialogWinGuiA(lBuff, aTitle, aDefaultPath);
2672 		}
2673 	}
2674 	else
2675 #endif /* TINYFD_NOLIB */
2676 	if ( dialogPresent() )
2677 	{
2678 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;}
2679 		p = selectFolderDialogWinConsole(lBuff,aTitle,aDefaultPath);
2680 	}
2681 	else
2682 	{
2683 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return (char const *)0;}
2684 		p = tinyfd_inputBox(aTitle, "Select folder","");
2685 	}
2686 
2687 	if ( ! p || ! strlen ( p ) || ! dirExists ( p ) )
2688 	{
2689 		return NULL ;
2690 	}
2691 	return p ;
2692 }
2693 
2694 
2695 /* returns the hexcolor as a string "#FF0000" */
2696 /* aoResultRGB also contains the result */
2697 /* aDefaultRGB is used only if aDefaultHexRGB is NULL */
2698 /* aDefaultRGB and aoResultRGB can be the same array */
tinyfd_colorChooser(char const * const aTitle,char const * const aDefaultHexRGB,unsigned char const aDefaultRGB[3],unsigned char aoResultRGB[3])2699 char const * tinyfd_colorChooser(
2700 	char const * const aTitle, /* NULL or "" */
2701 	char const * const aDefaultHexRGB, /* NULL or "#FF0000"*/
2702 	unsigned char const aDefaultRGB[3], /* { 0 , 255 , 255 } */
2703 	unsigned char aoResultRGB[3]) /* { 0 , 0 , 0 } */
2704 {
2705 	char lDefaultHexRGB[8];
2706 	char * lpDefaultHexRGB;
2707 	int i;
2708 	char const * p ;
2709 
2710 #ifndef TINYFD_NOLIB
2711 	if ( (!tinyfd_forceConsole || !( GetConsoleWindow() || dialogPresent()) )
2712 	  && (!getenv("SSH_CLIENT") || getenv("DISPLAY")) )
2713 	{
2714 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"windows");return (char const *)1;}
2715 		if (tinyfd_winUtf8)
2716 		{
2717 			return colorChooserWinGui8(
2718 				aTitle, aDefaultHexRGB, aDefaultRGB, aoResultRGB);
2719 		}
2720 		else
2721 		{
2722 			return colorChooserWinGuiA(
2723 				aTitle, aDefaultHexRGB, aDefaultRGB, aoResultRGB);
2724 		}
2725 	}
2726 	else
2727 #endif /* TINYFD_NOLIB */
2728 	if ( aDefaultHexRGB )
2729 	{
2730 		lpDefaultHexRGB = (char *) aDefaultHexRGB ;
2731 	}
2732 	else
2733 	{
2734 		RGB2Hex( aDefaultRGB , lDefaultHexRGB ) ;
2735 		lpDefaultHexRGB = (char *) lDefaultHexRGB ;
2736 	}
2737 	p = tinyfd_inputBox(aTitle,
2738 			"Enter hex rgb color (i.e. #f5ca20)",lpDefaultHexRGB);
2739 	if (aTitle&&!strcmp(aTitle,"tinyfd_query")) return p;
2740 
2741 	if ( !p || (strlen(p) != 7) || (p[0] != '#') )
2742 	{
2743 		return NULL ;
2744 	}
2745 	for ( i = 1 ; i < 7 ; i ++ )
2746 	{
2747 		if ( ! isxdigit( p[i] ) )
2748 		{
2749 			return NULL ;
2750 		}
2751 	}
2752 	Hex2RGB(p,aoResultRGB);
2753 	return p ;
2754 }
2755 
2756 #else /* unix */
2757 
2758 static char gPython2Name[16];
2759 
isDarwin()2760 static int isDarwin ( )
2761 {
2762 	static int lsIsDarwin = -1 ;
2763 	struct utsname lUtsname ;
2764 	if ( lsIsDarwin < 0 )
2765 	{
2766 		lsIsDarwin = !uname(&lUtsname) && !strcmp(lUtsname.sysname,"Darwin") ;
2767 	}
2768 	return lsIsDarwin ;
2769 }
2770 
2771 
dirExists(char const * const aDirPath)2772 static int dirExists ( char const * const aDirPath )
2773 {
2774 	DIR * lDir ;
2775 	if ( ! aDirPath || ! strlen ( aDirPath ) )
2776 		return 0 ;
2777 	lDir = opendir ( aDirPath ) ;
2778 	if ( ! lDir )
2779 	{
2780 		return 0 ;
2781 	}
2782 	closedir ( lDir ) ;
2783 	return 1 ;
2784 }
2785 
2786 
detectPresence(char const * const aExecutable)2787 static int detectPresence ( char const * const aExecutable )
2788 {
2789 	char lBuff [MAX_PATH_OR_CMD] ;
2790 	char lTestedString [MAX_PATH_OR_CMD] = "which " ;
2791 	FILE * lIn ;
2792 
2793     strcat ( lTestedString , aExecutable ) ;
2794     lIn = popen ( lTestedString , "r" ) ;
2795     if ( ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL )
2796         && ( ! strchr ( lBuff , ':' ) ) )
2797     {	/* present */
2798     	pclose ( lIn ) ;
2799     	return 1 ;
2800     }
2801     else
2802     {
2803     	pclose ( lIn ) ;
2804     	return 0 ;
2805     }
2806 }
2807 
2808 
tryCommand(char const * const aCommand)2809 static int tryCommand ( char const * const aCommand )
2810 {
2811 	char lBuff [MAX_PATH_OR_CMD] ;
2812 	FILE * lIn ;
2813 
2814 	lIn = popen ( aCommand , "r" ) ;
2815 	if ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) == NULL )
2816 	{	/* present */
2817 		pclose ( lIn ) ;
2818 		return 1 ;
2819 	}
2820 	else
2821 	{
2822 		pclose ( lIn ) ;
2823 		return 0 ;
2824 	}
2825 
2826 }
2827 
2828 
terminalName()2829 static char const * terminalName ( )
2830 {
2831 	static char lTerminalName[64] = "*" ;
2832 	if ( lTerminalName[0] == '*' )
2833 	{
2834 		if ( isDarwin() )
2835 		{
2836 			if ( strcpy(lTerminalName , "/opt/X11/bin/xterm" )
2837 		      && detectPresence ( lTerminalName ) )
2838 			{
2839 				strcat(lTerminalName , " -e bash -c " ) ;
2840 			}
2841 			else
2842 			{
2843 				strcpy(lTerminalName , "" ) ;
2844 			}
2845 		}
2846 		else if ( strcpy(lTerminalName,"terminator") /*good*/
2847 			  && detectPresence(lTerminalName) )
2848 		{
2849 			strcat(lTerminalName , " -x bash -c " ) ;
2850 		}
2851 		else if ( strcpy(lTerminalName,"lxterminal") /*good*/
2852 			  && detectPresence(lTerminalName) )
2853 		{
2854 			strcat(lTerminalName , " -e bash -c " ) ;
2855 		}
2856 		else if ( strcpy(lTerminalName,"mate-terminal") /*good*/
2857 			  && detectPresence(lTerminalName) )
2858 		{
2859 			strcat(lTerminalName , " -x bash -c " ) ;
2860 		}
2861 		else if ( strcpy(lTerminalName,"konsole")
2862 			  && detectPresence(lTerminalName) )
2863 		{
2864 			strcat(lTerminalName , " -e bash -c " ) ;
2865 		}
2866 		else if ( strcpy(lTerminalName,"rxvt") /*good*/
2867 			  && detectPresence(lTerminalName) )
2868 		{
2869 			strcat(lTerminalName , " -e bash -c " ) ;
2870 		}
2871 		else if ( strcpy(lTerminalName,"urxvt") /*good*/
2872 			  && detectPresence(lTerminalName) )
2873 		{
2874 			strcat(lTerminalName , " -e bash -c " ) ;
2875 		}
2876 		else if ( strcpy(lTerminalName,"mrxvt") /*good*/
2877 			  && detectPresence(lTerminalName) )
2878 		{
2879 			strcat(lTerminalName , " -e bash -c " ) ;
2880 		}
2881 		else if ( strcpy(lTerminalName,"evilvte") /*good*/
2882 			  && detectPresence(lTerminalName) )
2883 		{
2884 			strcat(lTerminalName , " -e bash -c " ) ;
2885 		}
2886 		else if ( strcpy(lTerminalName,"termit") /*good*/
2887 			  && detectPresence(lTerminalName) )
2888 		{
2889 			strcat(lTerminalName , " -e bash -c " ) ;
2890 		}
2891 		else if ( strcpy(lTerminalName,"kterm") /*good*/
2892 			  && detectPresence(lTerminalName) )
2893 		{
2894 			strcat(lTerminalName , " -e bash -c " ) ;
2895 		}
2896 		else if ( strcpy(lTerminalName,"roxterm") /*good*/
2897 			  && detectPresence(lTerminalName) )
2898 		{
2899 			strcat(lTerminalName , " -e bash -c " ) ;
2900 		}
2901 		else if ( strcpy(lTerminalName,"xterm") /*good small*/
2902 			&& detectPresence(lTerminalName) )
2903 		{
2904 			strcat(lTerminalName , " -e bash -c " ) ;
2905 		}
2906 		else if ( strcpy(lTerminalName,"lxterm") /*good small*/
2907 			  && detectPresence(lTerminalName) )
2908 		{
2909 			strcat(lTerminalName , " -e bash -c " ) ;
2910 		}
2911 		else if ( strcpy(lTerminalName,"xvt") /*good B&W*/
2912 			  && detectPresence(lTerminalName) )
2913 		{
2914 			strcat(lTerminalName , " -e bash -c " ) ;
2915 		}
2916 		else if ( strcpy(lTerminalName,"pterm") /*good only letters*/
2917 			  && detectPresence(lTerminalName) )
2918 		{
2919 			strcat(lTerminalName , " -e bash -c " ) ;
2920 		}
2921 		else if ( strcpy(lTerminalName,"x-terminal-emulator") /*alias*/
2922 			  && detectPresence(lTerminalName) )
2923 		{
2924 			strcat(lTerminalName , " -e bash -c " ) ;
2925 		}
2926 		else if ( strcpy(lTerminalName,"$TERM") /*alias*/
2927 			  && detectPresence(lTerminalName) )
2928 		{
2929 			strcat(lTerminalName , " -x bash -c " ) ;
2930 		}
2931 		else
2932 		{
2933 			strcpy(lTerminalName , "" ) ;
2934 		}
2935 		/* bad: koi8rxterm xfce4-terminal gnome-terminal guake tilda
2936 				vala-terminal Eterm aterm Terminal terminology sakura lilyterm*/
2937 	}
2938 	if ( strlen(lTerminalName) )
2939 	{
2940 		return lTerminalName ;
2941 	}
2942 	else
2943 	{
2944 		return NULL ;
2945 	}
2946 }
2947 
2948 
dialogName()2949 static char const * dialogName ( )
2950 {
2951 	static char lDialogName[64] = "*" ;
2952 	if ( lDialogName[0] == '*' )
2953 	{
2954 		if ( isDarwin() && strcpy(lDialogName , "/opt/local/bin/dialog" )
2955 			&& detectPresence ( lDialogName ) )
2956 		{}
2957 		else if ( strcpy(lDialogName , "dialog" )
2958 			&& detectPresence ( lDialogName ) )
2959 		{}
2960 		else
2961 		{
2962 			strcpy(lDialogName , "" ) ;
2963 		}
2964 	}
2965 	if ( strlen(lDialogName) && ( isatty(1) || terminalName() ) )
2966 	{
2967 		return lDialogName ;
2968 	}
2969 	else
2970 	{
2971 		return NULL ;
2972 	}
2973 }
2974 
2975 
whiptailPresent()2976 static int whiptailPresent ( )
2977 {
2978 	static int lWhiptailPresent = -1 ;
2979 	if ( lWhiptailPresent < 0 )
2980 	{
2981 		lWhiptailPresent = detectPresence ( "whiptail" ) ;
2982 	}
2983 	return lWhiptailPresent && ( isatty(1) || terminalName() ) ;
2984 }
2985 
2986 
graphicMode()2987 static int graphicMode()
2988 {
2989 	return !( tinyfd_forceConsole && (isatty(1) || terminalName()) )
2990 		&& ( getenv("DISPLAY") || (isDarwin() && !(getenv("SSH_TTY") ) ) ) ;
2991 }
2992 
2993 
xmessagePresent()2994 static int xmessagePresent ( )
2995 {
2996 	static int lXmessagePresent = -1 ;
2997 	if ( lXmessagePresent < 0 )
2998 	{
2999 		lXmessagePresent = detectPresence("xmessage");/*if not tty,not on osxpath*/
3000 	}
3001 	return lXmessagePresent && graphicMode ( ) ;
3002 }
3003 
3004 
gxmessagePresent()3005 static int gxmessagePresent ( )
3006 {
3007     static int lGxmessagePresent = -1 ;
3008     if ( lGxmessagePresent < 0 )
3009     {
3010         lGxmessagePresent = detectPresence("gxmessage") ;
3011     }
3012     return lGxmessagePresent && graphicMode ( ) ;
3013 }
3014 
3015 
notifysendPresent()3016 static int notifysendPresent ( )
3017 {
3018     static int lNotifysendPresent = -1 ;
3019     if ( lNotifysendPresent < 0 )
3020     {
3021         lNotifysendPresent = detectPresence("notify-send") ;
3022     }
3023     return lNotifysendPresent && graphicMode ( ) ;
3024 }
3025 
3026 
xdialogPresent()3027 static int xdialogPresent ( )
3028 {
3029     static int lXdialogPresent = -1 ;
3030     if ( lXdialogPresent < 0 )
3031     {
3032         lXdialogPresent = detectPresence("Xdialog") ;
3033     }
3034     return lXdialogPresent && graphicMode ( ) ;
3035 }
3036 
3037 
gdialogPresent()3038 static int gdialogPresent ( )
3039 {
3040     static int lGdialoglPresent = -1 ;
3041     if ( lGdialoglPresent < 0 )
3042     {
3043         lGdialoglPresent = detectPresence ( "gdialog" ) ;
3044     }
3045     return lGdialoglPresent && graphicMode ( ) ;
3046 }
3047 
3048 
osascriptPresent()3049 static int osascriptPresent ( )
3050 {
3051     static int lOsascriptPresent = -1 ;
3052     if ( lOsascriptPresent < 0 )
3053     {
3054         lOsascriptPresent = detectPresence ( "osascript" ) ;
3055     }
3056 	return lOsascriptPresent && graphicMode ( ) ;
3057 }
3058 
3059 
kdialogPresent()3060 static int kdialogPresent ( )
3061 {
3062 	static int lKdialogPresent = -1 ;
3063 	if ( lKdialogPresent < 0 )
3064 	{
3065 		lKdialogPresent = detectPresence("kdialog") ;
3066 	}
3067 	return lKdialogPresent && graphicMode ( ) ;
3068 }
3069 
3070 
matedialogPresent()3071 static int matedialogPresent ( )
3072 {
3073 	static int lMatedialogPresent = -1 ;
3074 	if ( lMatedialogPresent < 0 )
3075 	{
3076 		lMatedialogPresent = detectPresence("matedialog") ;
3077 	}
3078 	return lMatedialogPresent && graphicMode ( ) ;
3079 }
3080 
3081 
zenityPresent()3082 static int zenityPresent ( )
3083 {
3084 	static int lZenityPresent = -1 ;
3085 	if ( lZenityPresent < 0 )
3086 	{
3087 		lZenityPresent = detectPresence("zenity") ;
3088 	}
3089 	return lZenityPresent && graphicMode ( ) ;
3090 }
3091 
3092 
osx9orBetter()3093 static int osx9orBetter ( )
3094 {
3095 	static int lOsx9orBetter = -1 ;
3096 	char lBuff [MAX_PATH_OR_CMD] ;
3097 	FILE * lIn ;
3098 	int V,v;
3099 
3100 	if ( lOsx9orBetter < 0 )
3101 	{
3102 		lOsx9orBetter = 0 ;
3103 		lIn = popen ( "osascript -e 'set osver to system version of (system info)'" , "r" ) ;
3104 		if ( ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL )
3105 			&& ( 2 == sscanf(lBuff, "%d.%d", &V, &v) ) )
3106 		{
3107 			V = V * 100 + v;
3108 			if ( V >= 1009 )
3109 			{
3110 				lOsx9orBetter = 1 ;
3111 			}
3112 		}
3113 		pclose ( lIn ) ;
3114 		/* printf ("Osx10 = %d, %d = <%s>\n", lOsx9orBetter, V, lBuff) ; */
3115 	}
3116 	return lOsx9orBetter ;
3117 }
3118 
3119 
zenity3Present()3120 static int zenity3Present ( )
3121 {
3122 	static int lZenity3Present = -1 ;
3123 	char lBuff [MAX_PATH_OR_CMD] ;
3124 	FILE * lIn ;
3125 
3126 	if ( lZenity3Present < 0 )
3127 	{
3128 		lZenity3Present = 0 ;
3129 		if ( zenityPresent() )
3130 		{
3131 			lIn = popen ( "zenity --version" , "r" ) ;
3132 			if ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL )
3133 			{
3134 				if ( atoi(lBuff) >= 3 )
3135 				{
3136 					lZenity3Present = 1 ;
3137 				}
3138 				else if ( ( atoi(lBuff) == 2 ) && ( atoi(strtok(lBuff,".")+2 ) >= 32 ) )
3139 				{
3140 					lZenity3Present = 1 ;
3141 				}
3142 			}
3143 			pclose ( lIn ) ;
3144 		}
3145 	}
3146 	return lZenity3Present && graphicMode ( ) ;
3147 }
3148 
3149 
tkinter2Present()3150 static int tkinter2Present ( )
3151 {
3152     static int lTkinter2Present = -1 ;
3153 	char lPythonCommand[256];
3154 	char lPythonParams[256] =
3155 "-c \"try:\n\timport Tkinter;\nexcept:\n\tprint(0);\"";
3156 	int i;
3157 
3158 	if ( lTkinter2Present < 0 )
3159 	{
3160 		strcpy(gPython2Name , "python" ) ;
3161 		sprintf ( lPythonCommand , "%s %s" , gPython2Name , lPythonParams ) ;
3162 		lTkinter2Present = tryCommand(lPythonCommand);
3163 		if ( ! lTkinter2Present )
3164 		{
3165 			strcpy(gPython2Name , "python2" ) ;
3166 			if ( detectPresence(gPython2Name) )
3167 			{
3168 		sprintf ( lPythonCommand , "%s %s" , gPython2Name , lPythonParams ) ;
3169 				lTkinter2Present = tryCommand(lPythonCommand);
3170 			}
3171 			else
3172 			{
3173 				for ( i = 9 ; i >= 0 ; i -- )
3174 				{
3175 					sprintf ( gPython2Name , "python2.%d" , i ) ;
3176 					if ( detectPresence(gPython2Name) )
3177 					{
3178 		sprintf ( lPythonCommand , "%s %s" , gPython2Name , lPythonParams ) ;
3179 						lTkinter2Present = tryCommand(lPythonCommand);
3180 						break ;
3181 					}
3182 				}
3183 			}
3184 		}
3185 	}
3186 	/* printf ("gPython2Name %s\n", gPython2Name) ; */
3187 	return lTkinter2Present && graphicMode ( ) ;
3188 }
3189 
3190 
3191 /* returns 0 for cancel/no , 1 for ok/yes */
tinyfd_messageBox(char const * const aTitle,char const * const aMessage,char const * const aDialogType,char const * const aIconType,int const aDefaultButton)3192 int tinyfd_messageBox (
3193 	char const * const aTitle , /* NULL or "" */
3194 	char const * const aMessage , /* NULL or ""  may contain \n and \t */
3195 	char const * const aDialogType , /* "ok" "okcancel" "yesno"*/
3196 	char const * const aIconType , /* "info" "warning" "error" "question" */
3197 	int const aDefaultButton ) /* 0 for cancel/no , 1 for ok/yes */
3198 {
3199 	char lBuff [MAX_PATH_OR_CMD] ;
3200 	char * lDialogString = NULL ;
3201 	char * lpDialogString;
3202 	FILE * lIn ;
3203 	int lWasGraphicDialog = 0 ;
3204 	int lWasXterm = 0 ;
3205 	int lResult ;
3206 	char lChar ;
3207 	struct termios infoOri;
3208 	struct termios info;
3209 	int lTitleLen ;
3210 	int lMessageLen ;
3211 
3212 	lBuff[0]='\0';
3213 
3214 	lTitleLen =  aTitle ? strlen(aTitle) : 0 ;
3215 	lMessageLen =  aMessage ? strlen(aMessage) : 0 ;
3216 	if ( !aTitle || strcmp(aTitle,"tinyfd_query") )
3217 	{
3218 		lDialogString = (char *) malloc( MAX_PATH_OR_CMD + lTitleLen + lMessageLen );
3219 	}
3220 
3221 	if ( osascriptPresent ( ) )
3222 	{
3223 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"applescript");return 1;}
3224 
3225 		strcpy ( lDialogString , "osascript ");
3226 		if ( ! osx9orBetter() ) strcat ( lDialogString , " -e 'tell application \"System Events\"' -e 'Activate'");
3227 		strcat ( lDialogString , " -e 'try' -e 'display dialog \"") ;
3228 		if ( aMessage && strlen(aMessage) )
3229 		{
3230 			strcat(lDialogString, aMessage) ;
3231 		}
3232 		strcat(lDialogString, "\" ") ;
3233 		if ( aTitle && strlen(aTitle) )
3234 		{
3235 			strcat(lDialogString, "with title \"") ;
3236 			strcat(lDialogString, aTitle) ;
3237 			strcat(lDialogString, "\" ") ;
3238 		}
3239 		strcat(lDialogString, "with icon ") ;
3240 		if ( aIconType && ! strcmp( "error" , aIconType ) )
3241 		{
3242 			strcat(lDialogString, "stop " ) ;
3243 		}
3244 		else if ( aIconType && ! strcmp( "warning" , aIconType ) )
3245 		{
3246 			strcat(lDialogString, "caution " ) ;
3247 		}
3248 		else /* question or info */
3249 		{
3250 			strcat(lDialogString, "note " ) ;
3251 		}
3252 		if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) )
3253 		{
3254 			if ( ! aDefaultButton )
3255 			{
3256 				strcat ( lDialogString ,"default button \"Cancel\" " ) ;
3257 			}
3258 		}
3259 		else if ( aDialogType && ! strcmp( "yesno" , aDialogType ) )
3260 		{
3261 			strcat ( lDialogString ,"buttons {\"No\", \"Yes\"} " ) ;
3262 			if (aDefaultButton)
3263 			{
3264 				strcat ( lDialogString ,"default button \"Yes\" " ) ;
3265 			}
3266 			else
3267 			{
3268 				strcat ( lDialogString ,"default button \"No\" " ) ;
3269 			}
3270 			strcat ( lDialogString ,"cancel button \"No\"" ) ;
3271 		}
3272 		else
3273 		{
3274 			strcat ( lDialogString ,"buttons {\"OK\"} " ) ;
3275 			strcat ( lDialogString ,"default button \"OK\" " ) ;
3276 		}
3277 		strcat ( lDialogString, "' ") ;
3278 		strcat ( lDialogString, "-e '1' " );
3279 		strcat ( lDialogString, "-e 'on error number -128' " ) ;
3280 		strcat ( lDialogString, "-e '0' " );
3281 		strcat ( lDialogString, "-e 'end try'") ;
3282 		if ( ! osx9orBetter() ) strcat ( lDialogString, " -e 'end tell'") ;
3283 	}
3284 	else if ( zenityPresent() || matedialogPresent() )
3285 	{
3286 		if ( zenityPresent() )
3287 		{
3288 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity");return 1;}
3289 		  strcpy ( lDialogString , "zenity --" ) ;
3290 		}
3291 		else
3292 		{
3293 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"matedialog");return 1;}
3294 			strcpy ( lDialogString , "matedialog --" ) ;
3295 		}
3296 
3297 		if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) )
3298 		{
3299 				strcat ( lDialogString ,
3300 						"question --ok-label=Ok --cancel-label=Cancel" ) ;
3301 		}
3302 		else if ( aDialogType && ! strcmp( "yesno" , aDialogType ) )
3303 		{
3304 				strcat ( lDialogString , "question" ) ;
3305 		}
3306 		else if ( aIconType && ! strcmp( "error" , aIconType ) )
3307 		{
3308 		    strcat ( lDialogString , "error" ) ;
3309 		}
3310 		else if ( aIconType && ! strcmp( "warning" , aIconType ) )
3311 		{
3312 		    strcat ( lDialogString , "warning" ) ;
3313 		}
3314 		else
3315 		{
3316 		    strcat ( lDialogString , "info" ) ;
3317 		}
3318 		if ( aTitle && strlen(aTitle) )
3319 		{
3320 			strcat(lDialogString, " --title=\"") ;
3321 			strcat(lDialogString, aTitle) ;
3322 			strcat(lDialogString, "\"") ;
3323 		}
3324 		if ( aMessage && strlen(aMessage) )
3325 		{
3326 			strcat(lDialogString, " --text=\"") ;
3327 			strcat(lDialogString, aMessage) ;
3328 			strcat(lDialogString, "\"") ;
3329 		}
3330 		if ( zenity3Present ( ) )
3331 		{
3332 			strcat ( lDialogString , " --icon-name=dialog-" ) ;
3333 			if ( aIconType && (! strcmp( "question" , aIconType )
3334 			  || ! strcmp( "error" , aIconType )
3335 			  || ! strcmp( "warning" , aIconType ) ) )
3336 			{
3337 				strcat ( lDialogString , aIconType ) ;
3338 			}
3339 			else
3340 			{
3341 				strcat ( lDialogString , "information" ) ;
3342 			}
3343 		}
3344 		strcat ( lDialogString , ";if [ $? = 0 ];then echo 1;else echo 0;fi");
3345 	}
3346 	else if ( kdialogPresent() )
3347 	{
3348 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"kdialog");return 1;}
3349 
3350 		strcpy ( lDialogString , "kdialog --" ) ;
3351 		if ( aDialogType && ( ! strcmp( "okcancel" , aDialogType )
3352 		  || ! strcmp( "yesno" , aDialogType ) ) )
3353 		{
3354 			if ( aIconType && ( ! strcmp( "warning" , aIconType )
3355 			  || ! strcmp( "error" , aIconType ) ) )
3356 			{
3357 				strcat ( lDialogString , "warning" ) ;
3358 			}
3359 			strcat ( lDialogString , "yesno" ) ;
3360 		}
3361 		else if ( aIconType && ! strcmp( "error" , aIconType ) )
3362 		{
3363 			strcat ( lDialogString , "error" ) ;
3364 		}
3365 		else if ( aIconType && ! strcmp( "warning" , aIconType ) )
3366 		{
3367 			strcat ( lDialogString , "sorry" ) ;
3368 		}
3369 		else
3370 		{
3371 			strcat ( lDialogString , "msgbox" ) ;
3372 		}
3373 		strcat ( lDialogString , " \"" ) ;
3374 		if ( aMessage )
3375 		{
3376 			strcat ( lDialogString , aMessage ) ;
3377 		}
3378 		strcat ( lDialogString , "\"" ) ;
3379 		if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) )
3380 		{
3381 			strcat ( lDialogString ,
3382 				" --yes-label Ok --no-label Cancel" ) ;
3383 		}
3384 		if ( aTitle && strlen(aTitle) )
3385 		{
3386 			strcat(lDialogString, " --title \"") ;
3387 			strcat(lDialogString, aTitle) ;
3388 			strcat(lDialogString, "\"") ;
3389 		}
3390 		strcat ( lDialogString , ";if [ $? = 0 ];then echo 1;else echo 0;fi");
3391 	}
3392 	else if ( ! xdialogPresent() && tkinter2Present ( ) )
3393 	{
3394 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"tkinter");return 1;}
3395 
3396 		strcpy ( lDialogString , gPython2Name ) ;
3397 		if ( ! isatty ( 1 ) && isDarwin ( ) )
3398 		{
3399 		 	strcat ( lDialogString , " -i" ) ;  /* for osx without console */
3400 		}
3401 
3402 		strcat ( lDialogString ,
3403 " -c \"import Tkinter,tkMessageBox;root=Tkinter.Tk();root.withdraw();");
3404 
3405 		if ( isDarwin ( ) )
3406 		{
3407 			strcat ( lDialogString ,
3408 "import os;os.system('''/usr/bin/osascript -e 'tell app \\\"Finder\\\" to set \
3409 frontmost of process \\\"Python\\\" to true' ''');");
3410 		}
3411 
3412 		strcat ( lDialogString ,"res=tkMessageBox." ) ;
3413     if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) )
3414     {
3415       strcat ( lDialogString , "askokcancel(" ) ;
3416       if ( aDefaultButton )
3417 			{
3418 				strcat ( lDialogString , "default=tkMessageBox.OK," ) ;
3419 			}
3420 			else
3421 			{
3422 				strcat ( lDialogString , "default=tkMessageBox.CANCEL," ) ;
3423 			}
3424     }
3425     else if ( aDialogType && ! strcmp( "yesno" , aDialogType ) )
3426     {
3427       strcat ( lDialogString , "askyesno(" ) ;
3428       if ( aDefaultButton )
3429 			{
3430 				strcat ( lDialogString , "default=tkMessageBox.YES," ) ;
3431 			}
3432 			else
3433 			{
3434 				strcat ( lDialogString , "default=tkMessageBox.NO," ) ;
3435 			}
3436     }
3437     else
3438     {
3439 			strcat ( lDialogString , "showinfo(" ) ;
3440     }
3441     strcat ( lDialogString , "icon='" ) ;
3442     if ( aIconType && (! strcmp( "question" , aIconType )
3443       || ! strcmp( "error" , aIconType )
3444       || ! strcmp( "warning" , aIconType ) ) )
3445     {
3446 			strcat ( lDialogString , aIconType ) ;
3447     }
3448     else
3449     {
3450 			strcat ( lDialogString , "info" ) ;
3451     }
3452 		strcat(lDialogString, "',") ;
3453     if ( aTitle && strlen(aTitle) )
3454     {
3455 			strcat(lDialogString, "title='") ;
3456 			strcat(lDialogString, aTitle) ;
3457 			strcat(lDialogString, "',") ;
3458     }
3459 		if ( aMessage && strlen(aMessage) )
3460 		{
3461 			strcat(lDialogString, "message='") ;
3462 			lpDialogString = lDialogString + strlen(lDialogString);
3463 			replaceSubStr ( aMessage , "\n" , "\\n" , lpDialogString ) ;
3464 			strcat(lDialogString, "'") ;
3465 		}
3466 		strcat(lDialogString, ");\n\
3467 if res==False :\n\tprint 0\n\
3468 else :\n\tprint 1\n\"" ) ;
3469     }
3470 	else if (!xdialogPresent() && !gdialogPresent() && gxmessagePresent() )
3471 	{
3472 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"gxmessage");return 1;}
3473 
3474 		strcpy ( lDialogString , "gxmessage");
3475 
3476 		if ( aDialogType && ! strcmp("okcancel" , aDialogType) )
3477 		{
3478 			strcat ( lDialogString , " -buttons Ok:1,Cancel:0");
3479 		}
3480 		else if ( aDialogType && ! strcmp("yesno" , aDialogType) )
3481 		{
3482 			strcat ( lDialogString , " -buttons Yes:1,No:0");
3483 		}
3484 
3485 		strcat ( lDialogString , " -center \"");
3486 		if ( aMessage && strlen(aMessage) )
3487 		{
3488 			strcat ( lDialogString , aMessage ) ;
3489 		}
3490 		strcat(lDialogString, "\"" ) ;
3491 		if ( aTitle && strlen(aTitle) )
3492 		{
3493 			strcat ( lDialogString , " -title  \"");
3494 			strcat ( lDialogString , aTitle ) ;
3495 			strcat ( lDialogString, "\"" ) ;
3496 		}
3497 		strcat ( lDialogString , " ; echo $? ");
3498 	}
3499 	else if (!xdialogPresent() && !gdialogPresent() && notifysendPresent()
3500 			 && strcmp("okcancel" , aDialogType)
3501 			 && strcmp("yesno" , aDialogType) )
3502 	{
3503 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"notify");return 1;}
3504 
3505 		strcpy ( lDialogString , "notify-send \"" ) ;
3506 		if ( aTitle && strlen(aTitle) )
3507 		{
3508 			strcat(lDialogString, aTitle) ;
3509 			strcat ( lDialogString , " | " ) ;
3510 		}
3511 		if ( aMessage && strlen(aMessage) )
3512 		{
3513 			strcat(lDialogString, aMessage) ;
3514 		}
3515 		strcat ( lDialogString , "\"" ) ;
3516 	}
3517 	else if (!xdialogPresent() && !gdialogPresent() && xmessagePresent()
3518 		&& strcmp("okcancel" , aDialogType)
3519 		&& strcmp("yesno" , aDialogType) )
3520 	{
3521 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xmessage");return 1;}
3522 
3523 		strcpy ( lDialogString , "xmessage -center \"");
3524 		if ( aTitle && strlen(aTitle) )
3525 		{
3526 			strcat(lDialogString, aTitle) ;
3527 			strcat(lDialogString, "\n\n" ) ;
3528 		}
3529 		if ( aMessage && strlen(aMessage) )
3530 		{
3531 			strcat(lDialogString, aMessage) ;
3532 		}
3533 		strcat(lDialogString, "\"" ) ;
3534 	}
3535 	else if ( xdialogPresent() || gdialogPresent()
3536 		   || dialogName() || whiptailPresent() )
3537 	{
3538 		if ( xdialogPresent ( ) )
3539 		{
3540 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xdialog");return 1;}
3541 			lWasGraphicDialog = 1 ;
3542 			strcpy ( lDialogString , "(Xdialog " ) ;
3543 		}
3544 		else if ( gdialogPresent ( ) )
3545 		{
3546 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"gdialog");return 1;}
3547 			lWasGraphicDialog = 1 ;
3548 			strcpy ( lDialogString , "(gdialog " ) ;
3549 		}
3550 		else if ( dialogName ( ) )
3551 		{
3552 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return 0;}
3553 			if ( isatty ( 1 ) )
3554 			{
3555 				strcpy ( lDialogString , "(dialog " ) ;
3556 			}
3557 			else
3558 			{
3559 				lWasXterm = 1 ;
3560 				strcpy ( lDialogString , terminalName() ) ;
3561 				strcat ( lDialogString , "'(" ) ;
3562 				strcat ( lDialogString , dialogName() ) ;
3563 				strcat ( lDialogString , " " ) ;
3564 			}
3565 		}
3566 		else if ( isatty ( 1 ) )
3567 		{
3568 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"whiptail");return 0;}
3569 			strcpy ( lDialogString , "(whiptail " ) ;
3570 		}
3571 		else
3572 		{
3573 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"whiptail");return 0;}
3574 			lWasXterm = 1 ;
3575 			strcpy ( lDialogString , terminalName() ) ;
3576 			strcat ( lDialogString , "'(whiptail " ) ;
3577 		}
3578 
3579  		if ( aTitle && strlen(aTitle) )
3580 		{
3581 			strcat(lDialogString, "--title \"") ;
3582 			strcat(lDialogString, aTitle) ;
3583 			strcat(lDialogString, "\" ") ;
3584 		}
3585 
3586 		if ( !xdialogPresent() && !gdialogPresent() )
3587 		{
3588 			if ( aDialogType && ( !strcmp( "okcancel" , aDialogType ) || !strcmp( "yesno" , aDialogType ) ) )
3589 			{
3590 				strcat(lDialogString, "--backtitle \"") ;
3591 				strcat(lDialogString, "tab -> move focus") ;
3592 				strcat(lDialogString, "\" ") ;
3593 			}
3594 		}
3595 
3596 		if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) )
3597 		{
3598 			if ( ! aDefaultButton )
3599 			{
3600 				strcat ( lDialogString , "--defaultno " ) ;
3601 			}
3602 			strcat ( lDialogString ,
3603 					"--yes-label \"Ok\" --no-label \"Cancel\" --yesno " ) ;
3604 		}
3605 		else if ( aDialogType && ! strcmp( "yesno" , aDialogType ) )
3606 		{
3607 			if ( ! aDefaultButton )
3608 			{
3609 				strcat ( lDialogString , "--defaultno " ) ;
3610 			}
3611 			strcat ( lDialogString , "--yesno " ) ;
3612 		}
3613 		else
3614 		{
3615 			strcat ( lDialogString , "--msgbox " ) ;
3616 
3617 		}
3618 		strcat ( lDialogString , "\"" ) ;
3619 		if ( aMessage && strlen(aMessage) )
3620 		{
3621 			strcat(lDialogString, aMessage) ;
3622 		}
3623 
3624 		if ( lWasGraphicDialog )
3625 		{
3626 			strcat(lDialogString,
3627 				   "\" 10 60 ) 2>&1;if [ $? = 0 ];then echo 1;else echo 0;fi");
3628 		}
3629 		else
3630 		{
3631 			strcat(lDialogString, "\" 10 60 >/dev/tty) 2>&1;if [ $? = 0 ];");
3632 			if ( lWasXterm )
3633 			{
3634 				strcat ( lDialogString ,
3635 					"then\n\techo 1\nelse\n\techo 0\nfi >/tmp/tinyfd.txt';\
3636 cat /tmp/tinyfd.txt;rm /tmp/tinyfd.txt");
3637 			}
3638 			else
3639 			{
3640 			   strcat(lDialogString,
3641 					  "then echo 1;else echo 0;fi;clear >/dev/tty");
3642 			}
3643 		}
3644 	}
3645 	else if ( ! isatty ( 1 ) && terminalName() )
3646 	{
3647 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return 0;}
3648 		strcpy ( lDialogString , terminalName() ) ;
3649 		strcat ( lDialogString , "'" ) ;
3650 		if ( !gWarningDisplayed && !tinyfd_forceConsole)
3651 		{
3652 			gWarningDisplayed = 1 ;
3653 			strcat ( lDialogString , "echo \"" ) ;
3654 			strcat ( lDialogString, gAsciiArt) ;
3655 			strcat ( lDialogString , " \";" ) ;
3656 			strcat ( lDialogString , "echo \"" ) ;
3657 			strcat ( lDialogString, gTitle) ;
3658 			strcat ( lDialogString , "\";" ) ;
3659 			strcat ( lDialogString , "echo \"" ) ;
3660 			strcat ( lDialogString, gMessageUnix) ;
3661 			strcat ( lDialogString , "\";echo;echo;" ) ;
3662 		}
3663 		if ( aTitle && strlen(aTitle) )
3664 		{
3665 			strcat ( lDialogString , "echo \"" ) ;
3666 			strcat ( lDialogString, aTitle) ;
3667 			strcat ( lDialogString , "\";echo;" ) ;
3668 		}
3669 		if ( aMessage && strlen(aMessage) )
3670 		{
3671 			strcat ( lDialogString , "echo \"" ) ;
3672 			strcat ( lDialogString, aMessage) ;
3673 			strcat ( lDialogString , "\"; " ) ;
3674 		}
3675 		if ( aDialogType && !strcmp("yesno",aDialogType) )
3676 		{
3677 			strcat ( lDialogString , "echo -n \"y/n: \"; " ) ;
3678 			strcat ( lDialogString , "stty raw -echo;" ) ;
3679 			strcat ( lDialogString ,
3680 				"answer=$( while ! head -c 1 | grep -i [ny];do true ;done);");
3681 			strcat ( lDialogString ,
3682 				"if echo \"$answer\" | grep -iq \"^y\";then\n");
3683 			strcat ( lDialogString , "\techo 1\nelse\n\techo 0\nfi" ) ;
3684 		}
3685 		else if ( aDialogType && !strcmp("okcancel",aDialogType) )
3686 		{
3687 			strcat ( lDialogString , "echo -n \"[O]kay/[C]ancel: \"; " ) ;
3688 			strcat ( lDialogString , "stty raw -echo;" ) ;
3689 			strcat ( lDialogString ,
3690 				"answer=$( while ! head -c 1 | grep -i [oc];do true ;done);");
3691 			strcat ( lDialogString ,
3692 				"if echo \"$answer\" | grep -iq \"^o\";then\n");
3693 			strcat ( lDialogString , "\techo 1\nelse\n\techo 0\nfi" ) ;
3694 		}
3695 		else
3696 		{
3697 			strcat(lDialogString , "echo -n \"press enter to continue \"; ");
3698 			strcat ( lDialogString , "stty raw -echo;" ) ;
3699 			strcat ( lDialogString ,
3700 				"answer=$( while ! head -c 1;do true ;done);echo 1");
3701 		}
3702 		strcat ( lDialogString ,
3703 			" >/tmp/tinyfd.txt';cat /tmp/tinyfd.txt;rm /tmp/tinyfd.txt");
3704 	}
3705 	else
3706 	{
3707 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return 0;}
3708 		if ( !gWarningDisplayed && !tinyfd_forceConsole)
3709 		{
3710 			gWarningDisplayed = 1 ;
3711 			printf("\n\n%s", gAsciiArt);
3712 			printf ("\n%s\n", gTitle);
3713 			printf ("%s\n\n\n", gMessageUnix);
3714 		}
3715  		if ( aTitle && strlen(aTitle) )
3716 		{
3717 			printf ("%s\n\n", aTitle);
3718 		}
3719 
3720 		tcgetattr(0, &infoOri);
3721 		tcgetattr(0, &info);
3722 		info.c_lflag &= ~ICANON;
3723 		info.c_cc[VMIN] = 1;
3724 		info.c_cc[VTIME] = 0;
3725 		tcsetattr(0, TCSANOW, &info);
3726 		if ( aDialogType && !strcmp("yesno",aDialogType) )
3727 		{
3728 			do
3729 			{
3730 				if ( aMessage && strlen(aMessage) )
3731 				{
3732 					printf("%s\n",aMessage);
3733 				}
3734 				printf("y/n: "); fflush(stdout);
3735 				lChar = tolower ( getchar() ) ;
3736 				printf("\n\n");
3737 			}
3738 			while ( lChar != 'y' && lChar != 'n' );
3739 			lResult = lChar == 'y' ? 1 : 0 ;
3740 		}
3741 		else if ( aDialogType && !strcmp("okcancel",aDialogType) )
3742 		{
3743 			do
3744 			{
3745 				if ( aMessage && strlen(aMessage) )
3746 				{
3747 					printf("%s\n",aMessage);
3748 				}
3749 				printf("[O]kay/[C]ancel: "); fflush(stdout);
3750 				lChar = tolower ( getchar() ) ;
3751 				printf("\n\n");
3752 			}
3753 			while ( lChar != 'o' && lChar != 'c' );
3754 			lResult = lChar == 'o' ? 1 : 0 ;
3755 		}
3756 		else
3757 		{
3758 			if ( aMessage && strlen(aMessage) )
3759 			{
3760 				printf("%s\n\n",aMessage);
3761 			}
3762 			printf("press enter to continue "); fflush(stdout);
3763 			getchar() ;
3764 			printf("\n\n");
3765 			lResult = 1 ;
3766 		}
3767 		tcsetattr(0, TCSANOW, &infoOri);
3768 		free(lDialogString);
3769 		return lResult ;
3770 	}
3771 
3772 	/* printf ( "lDialogString: %s\n" , lDialogString ) ; */
3773 	if ( ! ( lIn = popen ( lDialogString , "r" ) ) )
3774 	{
3775 		free(lDialogString);
3776 		return 0 ;
3777 	}
3778 	while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL )
3779 	{}
3780 
3781 	pclose ( lIn ) ;
3782 
3783 	/* printf ( "lBuff: %s len: %lu \n" , lBuff , strlen(lBuff) ) ; */
3784 	if ( lBuff[strlen ( lBuff ) -1] == '\n' )
3785 	{
3786 		lBuff[strlen ( lBuff ) -1] = '\0' ;
3787 	}
3788 	/* printf ( "lBuff1: %s len: %lu \n" , lBuff , strlen(lBuff) ) ; */
3789 
3790 	lResult =  strcmp ( lBuff , "1" ) ? 0 : 1 ;
3791 	/* printf ( "lResult: %d\n" , lResult ) ; */
3792 	free(lDialogString);
3793 	return lResult ;
3794 }
3795 
3796 
3797 /* returns NULL on cancel */
tinyfd_inputBox(char const * const aTitle,char const * const aMessage,char const * const aDefaultInput)3798 char const * tinyfd_inputBox(
3799 	char const * const aTitle , /* NULL or "" */
3800 	char const * const aMessage , /* NULL or "" may NOT contain \n nor \t */
3801 	char const * const aDefaultInput ) /* "" , if NULL it's a passwordBox */
3802 {
3803 	static char lBuff[MAX_PATH_OR_CMD];
3804 	char * lDialogString = NULL;
3805 	char * lpDialogString;
3806 	FILE * lIn ;
3807 	int lResult ;
3808 	int lWasGdialog = 0 ;
3809 	int lWasGraphicDialog = 0 ;
3810 	int lWasXterm = 0 ;
3811 	int lWasBasicXterm = 0 ;
3812 	struct termios oldt ;
3813 	struct termios newt ;
3814 	char * lEOF;
3815 	int lTitleLen ;
3816 	int lMessageLen ;
3817 
3818 	lBuff[0]='\0';
3819 
3820 	lTitleLen =  aTitle ? strlen(aTitle) : 0 ;
3821 	lMessageLen =  aMessage ? strlen(aMessage) : 0 ;
3822 	if ( !aTitle || strcmp(aTitle,"tinyfd_query") )
3823 	{
3824 		lDialogString = (char *) malloc( MAX_PATH_OR_CMD + lTitleLen + lMessageLen );
3825 	}
3826 
3827 	if ( osascriptPresent ( ) )
3828 	{
3829 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"applescript");return (char const *)1;}
3830 		strcpy ( lDialogString , "osascript ");
3831 		if ( ! osx9orBetter() ) strcat ( lDialogString , " -e 'tell application \"System Events\"' -e 'Activate'");
3832 		strcat ( lDialogString , " -e 'try' -e 'display dialog \"") ;
3833 		if ( aMessage && strlen(aMessage) )
3834 		{
3835 			strcat(lDialogString, aMessage) ;
3836 		}
3837 		strcat(lDialogString, "\" ") ;
3838 		strcat(lDialogString, "default answer \"") ;
3839 		if ( aDefaultInput && strlen(aDefaultInput) )
3840 		{
3841 			strcat(lDialogString, aDefaultInput) ;
3842 		}
3843 		strcat(lDialogString, "\" ") ;
3844 		if ( ! aDefaultInput )
3845 		{
3846 			strcat(lDialogString, "hidden answer true ") ;
3847 		}
3848 		if ( aTitle && strlen(aTitle) )
3849 		{
3850 			strcat(lDialogString, "with title \"") ;
3851 			strcat(lDialogString, aTitle) ;
3852 			strcat(lDialogString, "\" ") ;
3853 		}
3854 		strcat(lDialogString, "with icon note' ") ;
3855 		strcat(lDialogString, "-e '\"1\" & text returned of result' " );
3856 		strcat(lDialogString, "-e 'on error number -128' " ) ;
3857 		strcat(lDialogString, "-e '0' " );
3858 		strcat(lDialogString, "-e 'end try'") ;
3859 		if ( ! osx9orBetter() ) strcat(lDialogString, " -e 'end tell'") ;
3860 	}
3861 	else if ( zenityPresent() || matedialogPresent() )
3862 	{
3863 		if ( zenityPresent() )
3864 		{
3865 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity");return (char const *)1;}
3866       strcpy ( lDialogString ,  "szAnswer=$(zenity --entry" ) ;
3867 		}
3868 		else
3869 		{
3870 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"matedialog");return (char const *)1;}
3871 			strcpy ( lDialogString ,  "szAnswer=$(matedialog --entry" ) ;
3872 		}
3873 
3874 		if ( aTitle && strlen(aTitle) )
3875 		{
3876 			strcat(lDialogString, " --title=\"") ;
3877 			strcat(lDialogString, aTitle) ;
3878 			strcat(lDialogString, "\"") ;
3879 		}
3880 		if ( aMessage && strlen(aMessage) )
3881 		{
3882 			strcat(lDialogString, " --text=\"") ;
3883 			strcat(lDialogString, aMessage) ;
3884 			strcat(lDialogString, "\"") ;
3885 		}
3886 		if ( aDefaultInput && strlen(aDefaultInput) )
3887 		{
3888 			strcat(lDialogString, " --entry-text=\"") ;
3889 			strcat(lDialogString, aDefaultInput) ;
3890 			strcat(lDialogString, "\"") ;
3891 		}
3892 		else
3893 		{
3894 			strcat(lDialogString, " --hide-text") ;
3895 		}
3896 		strcat ( lDialogString ,
3897 				");if [ $? = 0 ];then echo 1$szAnswer;else echo 0$szAnswer;fi");
3898 	}
3899 	else if ( kdialogPresent() )
3900 	{
3901 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"kdialog");return (char const *)1;}
3902 		strcpy ( lDialogString , "szAnswer=$(kdialog" ) ;
3903 		if ( ! aDefaultInput )
3904 		{
3905 			strcat(lDialogString, " --password ") ;
3906 		}
3907 		else
3908 		{
3909 			strcat(lDialogString, " --inputbox ") ;
3910 
3911 		}
3912 		strcat(lDialogString, "\"") ;
3913 		if ( aMessage && strlen(aMessage) )
3914 		{
3915 			strcat(lDialogString, aMessage ) ;
3916 		}
3917 		strcat(lDialogString , "\" \"" ) ;
3918 		if ( aDefaultInput && strlen(aDefaultInput) )
3919 		{
3920 			strcat(lDialogString, aDefaultInput ) ;
3921 		}
3922 		strcat(lDialogString , "\"" ) ;
3923 		if ( aTitle && strlen(aTitle) )
3924 		{
3925 			strcat(lDialogString, " --title \"") ;
3926 			strcat(lDialogString, aTitle) ;
3927 			strcat(lDialogString, "\"") ;
3928 		}
3929 		strcat ( lDialogString ,
3930 				");if [ $? = 0 ];then echo 1$szAnswer;else echo 0$szAnswer;fi");
3931 	}
3932 	else if ( ! xdialogPresent() && tkinter2Present ( ) )
3933 	{
3934 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"tkinter");return (char const *)1;}
3935 		strcpy ( lDialogString , gPython2Name ) ;
3936 		if ( ! isatty ( 1 ) && isDarwin ( ) )
3937 		{
3938         	strcat ( lDialogString , " -i" ) ;  /* for osx without console */
3939 		}
3940 
3941 		strcat ( lDialogString ,
3942 " -c \"import Tkinter,tkSimpleDialog;root=Tkinter.Tk();root.withdraw();");
3943 
3944 		if ( isDarwin ( ) )
3945 		{
3946 			strcat ( lDialogString ,
3947 "import os;os.system('''/usr/bin/osascript -e 'tell app \\\"Finder\\\" to set \
3948 frontmost of process \\\"Python\\\" to true' ''');");
3949 		}
3950 
3951 		strcat ( lDialogString ,"res=tkSimpleDialog.askstring(" ) ;
3952 		if ( aTitle && strlen(aTitle) )
3953 		{
3954 			strcat(lDialogString, "title='") ;
3955 			strcat(lDialogString, aTitle) ;
3956 			strcat(lDialogString, "',") ;
3957 		}
3958 		if ( aMessage && strlen(aMessage) )
3959 		{
3960 
3961 			strcat(lDialogString, "prompt='") ;
3962 			lpDialogString = lDialogString + strlen(lDialogString);
3963 			replaceSubStr ( aMessage , "\n" , "\\n" , lpDialogString ) ;
3964 			strcat(lDialogString, "',") ;
3965 		}
3966 		if ( aDefaultInput )
3967 		{
3968 			if ( strlen(aDefaultInput) )
3969 			{
3970 				strcat(lDialogString, "initialvalue='") ;
3971 				strcat(lDialogString, aDefaultInput) ;
3972 				strcat(lDialogString, "',") ;
3973 			}
3974 		}
3975 		else
3976 		{
3977 			strcat(lDialogString, "show='*'") ;
3978 		}
3979 		strcat(lDialogString, ");\nif res is None :\n\tprint 0");
3980 		strcat(lDialogString, "\nelse :\n\tprint '1'+res\n\"" ) ;
3981 	}
3982 	else if (!xdialogPresent() && !gdialogPresent() && gxmessagePresent() )
3983 	{
3984 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"gxmessage");return (char const *)1;}
3985 		strcpy ( lDialogString , "szAnswer=$(gxmessage -buttons Ok:1,Cancel:0 -center \"");
3986 
3987 		if ( aMessage && strlen(aMessage) )
3988 		{
3989 			strcat ( lDialogString , aMessage ) ;
3990 		}
3991 		strcat(lDialogString, "\"" ) ;
3992 		if ( aTitle && strlen(aTitle) )
3993 		{
3994 			strcat ( lDialogString , " -title  \"");
3995 			strcat ( lDialogString , aTitle ) ;
3996 			strcat(lDialogString, "\" " ) ;
3997 		}
3998 		strcat(lDialogString, " -entrytext \"" ) ;
3999 		if ( aDefaultInput && strlen(aDefaultInput) )
4000 		{
4001 			strcat ( lDialogString , aDefaultInput ) ;
4002 		}
4003 		strcat(lDialogString, "\"" ) ;
4004 		strcat ( lDialogString , ");echo $?$szAnswer");
4005 	}
4006 	else if ( xdialogPresent() || gdialogPresent()
4007 		   || dialogName() || whiptailPresent() )
4008 	{
4009 		if ( xdialogPresent ( ) )
4010 		{
4011 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xdialog");return (char const *)1;}
4012 			lWasGraphicDialog = 1 ;
4013 			strcpy ( lDialogString , "(Xdialog " ) ;
4014 		}
4015 		else if ( gdialogPresent ( ) )
4016 		{
4017 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"gdialog");return (char const *)1;}
4018 			lWasGraphicDialog = 1 ;
4019 			lWasGdialog = 1 ;
4020 			strcpy ( lDialogString , "(gdialog " ) ;
4021 		}
4022 		else if ( dialogName ( ) )
4023 		{
4024 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;}
4025 			if ( isatty ( 1 ) )
4026 			{
4027 				strcpy ( lDialogString , "(dialog " ) ;
4028 			}
4029 			else
4030 			{
4031 				lWasXterm = 1 ;
4032 				strcpy ( lDialogString , terminalName() ) ;
4033 				strcat ( lDialogString , "'(" ) ;
4034 				strcat ( lDialogString , dialogName() ) ;
4035 				strcat ( lDialogString , " " ) ;
4036 			}
4037 		}
4038 		else if ( isatty ( 1 ) )
4039 		{
4040 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"whiptail");return (char const *)0;}
4041 			strcpy ( lDialogString , "(whiptail " ) ;
4042 		}
4043 		else
4044 		{
4045 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"whiptail");return (char const *)0;}
4046 			lWasXterm = 1 ;
4047 			strcpy ( lDialogString , terminalName() ) ;
4048 			strcat ( lDialogString , "'(whiptail " ) ;
4049 		}
4050 
4051 		if ( aTitle && strlen(aTitle) )
4052 		{
4053 			strcat(lDialogString, "--title \"") ;
4054 			strcat(lDialogString, aTitle) ;
4055 			strcat(lDialogString, "\" ") ;
4056 		}
4057 
4058 		if ( !xdialogPresent() && !gdialogPresent() )
4059 		{
4060 			strcat(lDialogString, "--backtitle \"") ;
4061 			strcat(lDialogString, "tab -> move focus") ;
4062 			strcat(lDialogString, "\" ") ;
4063 		}
4064 
4065 		if ( aDefaultInput || lWasGdialog )
4066 		{
4067 			strcat ( lDialogString , "--inputbox" ) ;
4068 		}
4069 		else
4070 		{
4071 			strcat ( lDialogString , "--passwordbox" ) ;
4072 		}
4073 		strcat ( lDialogString , " \"" ) ;
4074 		if ( aMessage && strlen(aMessage) )
4075 		{
4076 			strcat(lDialogString, aMessage) ;
4077 		}
4078 		strcat(lDialogString,"\" 10 60 ") ;
4079 		if ( aDefaultInput && strlen(aDefaultInput) )
4080 		{
4081 			strcat(lDialogString, "\"") ;
4082 			strcat(lDialogString, aDefaultInput) ;
4083 			strcat(lDialogString, "\" ") ;
4084 		}
4085 		if ( lWasGraphicDialog )
4086 		{
4087 			strcat(lDialogString,") 2>/tmp/tinyfd.txt;\
4088 	if [ $? = 0 ];then tinyfdBool=1;else tinyfdBool=0;fi;\
4089 	tinyfdRes=$(cat /tmp/tinyfd.txt);echo $tinyfdBool$tinyfdRes") ;
4090 		}
4091 		else
4092 		{
4093 			strcat(lDialogString,">/dev/tty ) 2>/tmp/tinyfd.txt;\
4094 	if [ $? = 0 ];then tinyfdBool=1;else tinyfdBool=0;fi;\
4095 	tinyfdRes=$(cat /tmp/tinyfd.txt);echo $tinyfdBool$tinyfdRes") ;
4096 
4097 			if ( lWasXterm )
4098 			{
4099 		strcat(lDialogString," >/tmp/tinyfd0.txt';cat /tmp/tinyfd0.txt");
4100 			}
4101 			else
4102 			{
4103 				strcat(lDialogString, "; clear >/dev/tty") ;
4104 			}
4105 		}
4106 	}
4107 	else if ( ! isatty ( 1 ) && terminalName() )
4108 	{
4109 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return (char const *)0;}
4110 		lWasBasicXterm = 1 ;
4111 		strcpy ( lDialogString , terminalName() ) ;
4112 		strcat ( lDialogString , "'" ) ;
4113 		if ( !gWarningDisplayed && !tinyfd_forceConsole)
4114 		{
4115 			gWarningDisplayed = 1 ;
4116 			strcat ( lDialogString , "echo \"" ) ;
4117 			strcat ( lDialogString, gAsciiArt) ;
4118 			strcat ( lDialogString , "\";" ) ;
4119 			strcat ( lDialogString , "echo \"" ) ;
4120 			strcat ( lDialogString, gTitle) ;
4121 			strcat ( lDialogString , "\";" ) ;
4122 			strcat ( lDialogString , "echo \"" ) ;
4123 			strcat ( lDialogString, gMessageUnix) ;
4124 			strcat ( lDialogString , "\";echo;echo;" ) ;
4125 		}
4126 		if ( aTitle && strlen(aTitle) && !tinyfd_forceConsole)
4127 		{
4128 			strcat ( lDialogString , "echo \"" ) ;
4129 			strcat ( lDialogString, aTitle) ;
4130 			strcat ( lDialogString , "\";echo;" ) ;
4131 		}
4132 
4133 		strcat ( lDialogString , "echo \"" ) ;
4134 		if ( aMessage && strlen(aMessage) )
4135 		{
4136 			strcat ( lDialogString, aMessage) ;
4137 		}
4138 		strcat ( lDialogString , "\";read " ) ;
4139 		if ( ! aDefaultInput )
4140 		{
4141 			strcat ( lDialogString , "-s " ) ;
4142 		}
4143 		strcat ( lDialogString , "-p \"" ) ;
4144 		strcat ( lDialogString , "(esc+enter to cancel): \" ANSWER " ) ;
4145 		strcat ( lDialogString , ";echo 1$ANSWER >/tmp/tinyfd.txt';" ) ;
4146 		strcat ( lDialogString , "cat -v /tmp/tinyfd.txt");
4147 	}
4148 	else
4149 	{
4150 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return (char const *)0;}
4151 		if ( !gWarningDisplayed && !tinyfd_forceConsole)
4152 		{
4153 			gWarningDisplayed = 1 ;
4154 			printf ("\n\n%s", gAsciiArt);
4155 			printf ("\n%s\n", gTitle);
4156 			printf ("%s\n\n\n", gMessageUnix);
4157 		}
4158 		if ( aTitle && strlen(aTitle) )
4159 		{
4160 			printf ("%s\n\n", aTitle);
4161 		}
4162 		if ( aMessage && strlen(aMessage) )
4163 		{
4164 			printf("%s\n",aMessage);
4165 		}
4166 		printf("(esc+enter to cancel): "); fflush(stdout);
4167 		if ( ! aDefaultInput )
4168 		{
4169 			tcgetattr(STDIN_FILENO, & oldt) ;
4170 			newt = oldt ;
4171 			newt.c_lflag &= ~ECHO ;
4172 			tcsetattr(STDIN_FILENO, TCSANOW, & newt);
4173 		}
4174 
4175 		lEOF = fgets(lBuff, MAX_PATH_OR_CMD, stdin);
4176 		/* printf("lbuff<%c><%d>\n",lBuff[0],lBuff[0]); */
4177 		if ( ! lEOF  || (lBuff[0] == '\0') )
4178 		{
4179 			free(lDialogString);
4180 			return NULL;
4181 		}
4182 
4183 		if ( lBuff[0] == '\n' )
4184 		{
4185 			lEOF = fgets(lBuff, MAX_PATH_OR_CMD, stdin);
4186 			/* printf("lbuff<%c><%d>\n",lBuff[0],lBuff[0]); */
4187 			if ( ! lEOF  || (lBuff[0] == '\0') )
4188 			{
4189 				free(lDialogString);
4190 				return NULL;
4191 			}
4192 		}
4193 
4194 		if ( ! aDefaultInput )
4195 		{
4196 			tcsetattr(STDIN_FILENO, TCSANOW, & oldt);
4197 			printf ("\n");
4198 		}
4199 		printf ("\n");
4200 		if ( strchr(lBuff,27) )
4201 		{
4202 			free(lDialogString);
4203 			return NULL ;
4204 		}
4205 		if ( lBuff[strlen ( lBuff ) -1] == '\n' )
4206 		{
4207 			lBuff[strlen ( lBuff ) -1] = '\0' ;
4208 		}
4209 		free(lDialogString);
4210 		return lBuff ;
4211 	}
4212 
4213 	/* printf ( "lDialogString: %s\n" , lDialogString ) ; */
4214 	lIn = popen ( lDialogString , "r" );
4215 	if ( ! lIn  )
4216 	{
4217 		if ( fileExists("/tmp/tinyfd.txt") )
4218 		{
4219 			wipefile("/tmp/tinyfd.txt");
4220 			remove("/tmp/tinyfd.txt");
4221 		}
4222 		if ( fileExists("/tmp/tinyfd0.txt") )
4223 		{
4224 			wipefile("/tmp/tinyfd0.txt");
4225 			remove("/tmp/tinyfd0.txt");
4226 		}
4227 		free(lDialogString);
4228 		return NULL ;
4229 	}
4230 	while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL )
4231 	{}
4232 
4233 	pclose ( lIn ) ;
4234 
4235 	if ( fileExists("/tmp/tinyfd.txt") )
4236 	{
4237 		wipefile("/tmp/tinyfd.txt");
4238 		remove("/tmp/tinyfd.txt");
4239 	}
4240 	if ( fileExists("/tmp/tinyfd0.txt") )
4241 	{
4242 		wipefile("/tmp/tinyfd0.txt");
4243 		remove("/tmp/tinyfd0.txt");
4244 	}
4245 
4246 	/* printf ( "len Buff: %lu\n" , strlen(lBuff) ) ; */
4247 	/* printf ( "lBuff0: %s\n" , lBuff ) ; */
4248 	if ( lBuff[strlen ( lBuff ) -1] == '\n' )
4249 	{
4250 		lBuff[strlen ( lBuff ) -1] = '\0' ;
4251 	}
4252 	/* printf ( "lBuff1: %s len: %lu \n" , lBuff , strlen(lBuff) ) ; */
4253 	if ( lWasBasicXterm )
4254 	{
4255 		if ( strstr(lBuff,"^[") ) /* esc was pressed */
4256 		{
4257 			free(lDialogString);
4258 			return NULL ;
4259 		}
4260 	}
4261 
4262 	lResult =  strncmp ( lBuff , "1" , 1) ? 0 : 1 ;
4263 	/* printf ( "lResult: %d \n" , lResult ) ; */
4264 	if ( ! lResult )
4265 	{
4266 		free(lDialogString);
4267 		return NULL ;
4268 	}
4269 	/* printf ( "lBuff+1: %s\n" , lBuff+1 ) ; */
4270 	free(lDialogString);
4271 
4272 	return lBuff+1 ;
4273 }
4274 
4275 
tinyfd_saveFileDialog(char const * const aTitle,char const * const aDefaultPathAndFile,int const aNumOfFilterPatterns,char const * const * const aFilterPatterns,char const * const aSingleFilterDescription)4276 char const * tinyfd_saveFileDialog (
4277     char const * const aTitle , /* NULL or "" */
4278     char const * const aDefaultPathAndFile , /* NULL or "" */
4279     int const aNumOfFilterPatterns , /* 0 */
4280     char const * const * const aFilterPatterns , /* NULL or {"*.jpg","*.png"} */
4281     char const * const aSingleFilterDescription ) /* NULL or "image files" */
4282 {
4283 
4284 	static char lBuff [MAX_PATH_OR_CMD] ;
4285 	char lDialogString [MAX_PATH_OR_CMD] ;
4286 	char lString [MAX_PATH_OR_CMD] ;
4287 	int i ;
4288 	int lWasGraphicDialog = 0 ;
4289 	int lWasXterm = 0 ;
4290 	char const * p ;
4291 	FILE * lIn ;
4292 	lBuff[0]='\0';
4293 
4294 	if ( osascriptPresent ( ) )
4295 	{
4296 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"applescript");return (char const *)1;}
4297 		strcpy ( lDialogString , "osascript ");
4298 		if ( ! osx9orBetter() ) strcat ( lDialogString , " -e 'tell application \"Finder\"' -e 'Activate'");
4299 		strcat ( lDialogString , " -e 'try' -e 'POSIX path of ( choose file name " );
4300 		if ( aTitle && strlen(aTitle) )
4301 		{
4302 			strcat(lDialogString, "with prompt \"") ;
4303 			strcat(lDialogString, aTitle) ;
4304 			strcat(lDialogString, "\" ") ;
4305 		}
4306 		getPathWithoutFinalSlash ( lString , aDefaultPathAndFile ) ;
4307 		if ( strlen(lString) )
4308 		{
4309 			strcat(lDialogString, "default location \"") ;
4310 			strcat(lDialogString, lString ) ;
4311 			strcat(lDialogString , "\" " ) ;
4312 		}
4313 		getLastName ( lString , aDefaultPathAndFile ) ;
4314 		if ( strlen(lString) )
4315 		{
4316 			strcat(lDialogString, "default name \"") ;
4317 			strcat(lDialogString, lString ) ;
4318 			strcat(lDialogString , "\" " ) ;
4319 		}
4320 		strcat ( lDialogString , ")' " ) ;
4321 		strcat(lDialogString, "-e 'on error number -128' " ) ;
4322 		strcat(lDialogString, "-e 'end try'") ;
4323 		if ( ! osx9orBetter() ) strcat ( lDialogString, " -e 'end tell'") ;
4324 	}
4325   else if ( zenityPresent() || matedialogPresent() )
4326   {
4327 		if ( zenityPresent() )
4328 		{
4329 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity");return (char const *)1;}
4330       strcpy ( lDialogString , "zenity" ) ;
4331 		}
4332 		else
4333 		{
4334 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"matedialog");return (char const *)1;}
4335 			strcpy ( lDialogString , "matedialog" ) ;
4336 
4337 		}
4338 		strcat(lDialogString, " --file-selection --save --confirm-overwrite" ) ;
4339 
4340 		if ( aTitle && strlen(aTitle) )
4341 		{
4342 			strcat(lDialogString, " --title=\"") ;
4343 			strcat(lDialogString, aTitle) ;
4344 			strcat(lDialogString, "\"") ;
4345 		}
4346 		if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) )
4347 		{
4348 			strcat(lDialogString, " --filename=\"") ;
4349 			strcat(lDialogString, aDefaultPathAndFile) ;
4350 			strcat(lDialogString, "\"") ;
4351 		}
4352 		if ( aNumOfFilterPatterns > 0 )
4353 		{
4354 			strcat ( lDialogString , " --file-filter='" ) ;
4355 			if ( aSingleFilterDescription && strlen(aSingleFilterDescription) )
4356 			{
4357 				strcat ( lDialogString , aSingleFilterDescription ) ;
4358 				strcat ( lDialogString , " | " ) ;
4359 			}
4360 			for ( i = 0 ; i < aNumOfFilterPatterns ; i ++ )
4361 			{
4362 				strcat ( lDialogString , aFilterPatterns [i] ) ;
4363 				strcat ( lDialogString , " " ) ;
4364 			}
4365 			strcat ( lDialogString , "' --file-filter='All files | *'" ) ;
4366 		}
4367   }
4368   else if ( kdialogPresent() )
4369   {
4370 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"kdialog");return (char const *)1;}
4371 		strcpy ( lDialogString , "kdialog --getsavefilename" ) ;
4372     if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) )
4373     {
4374 			strcat(lDialogString, " \"") ;
4375 			strcat(lDialogString, aDefaultPathAndFile ) ;
4376 			strcat(lDialogString , "\"" ) ;
4377 		}
4378 		else
4379 		{
4380 			strcat(lDialogString, " :" ) ;
4381 		}
4382     if ( aNumOfFilterPatterns > 0 )
4383     {
4384 		strcat(lDialogString , " \"" ) ;
4385 		for ( i = 0 ; i < aNumOfFilterPatterns ; i ++ )
4386 		{
4387 			strcat ( lDialogString , aFilterPatterns [i] ) ;
4388 			strcat ( lDialogString , " " ) ;
4389 		}
4390 		if ( aSingleFilterDescription && strlen(aSingleFilterDescription) )
4391 		{
4392 			strcat ( lDialogString , " | " ) ;
4393 			strcat ( lDialogString , aSingleFilterDescription ) ;
4394 		}
4395 		strcat ( lDialogString , "\"" ) ;
4396     }
4397     if ( aTitle && strlen(aTitle) )
4398     {
4399 			strcat(lDialogString, " --title \"") ;
4400 			strcat(lDialogString, aTitle) ;
4401 			strcat(lDialogString, "\"") ;
4402     }
4403   }
4404   else if ( ! xdialogPresent() && tkinter2Present ( ) )
4405   {
4406 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"tkinter");return (char const *)1;}
4407 		strcpy ( lDialogString , gPython2Name ) ;
4408 		if ( ! isatty ( 1 ) && isDarwin ( ))
4409 		{
4410         	strcat ( lDialogString , " -i" ) ;  /* for osx without console */
4411 		}
4412 	    strcat ( lDialogString ,
4413 " -c \"import Tkinter,tkFileDialog;root=Tkinter.Tk();root.withdraw();");
4414 
4415     	if ( isDarwin ( ) )
4416     	{
4417 			strcat ( lDialogString ,
4418 "import os;os.system('''/usr/bin/osascript -e 'tell app \\\"Finder\\\" to set\
4419  frontmost of process \\\"Python\\\" to true' ''');");
4420 		}
4421 
4422 		strcat ( lDialogString , "print tkFileDialog.asksaveasfilename(");
4423 		if ( aTitle && strlen(aTitle) )
4424 		{
4425 			strcat(lDialogString, "title='") ;
4426 			strcat(lDialogString, aTitle) ;
4427 			strcat(lDialogString, "',") ;
4428 		}
4429 	    if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) )
4430 	    {
4431 			getPathWithoutFinalSlash ( lString , aDefaultPathAndFile ) ;
4432 			if ( strlen(lString) )
4433 			{
4434 				strcat(lDialogString, "initialdir='") ;
4435 				strcat(lDialogString, lString ) ;
4436 				strcat(lDialogString , "'," ) ;
4437 			}
4438 			getLastName ( lString , aDefaultPathAndFile ) ;
4439 			if ( strlen(lString) )
4440 			{
4441 				strcat(lDialogString, "initialfile='") ;
4442 				strcat(lDialogString, lString ) ;
4443 				strcat(lDialogString , "'," ) ;
4444 			}
4445 		}
4446 	    if ( ( aNumOfFilterPatterns > 1 )
4447 		  || ( (aNumOfFilterPatterns == 1) /* test because poor osx behaviour */
4448 			&& ( aFilterPatterns[0][strlen(aFilterPatterns[0])-1] != '*' ) ) )
4449 	    {
4450 			strcat(lDialogString , "filetypes=(" ) ;
4451 			strcat ( lDialogString , "('" ) ;
4452 			if ( aSingleFilterDescription && strlen(aSingleFilterDescription) )
4453 			{
4454 				strcat ( lDialogString , aSingleFilterDescription ) ;
4455 			}
4456 			strcat ( lDialogString , "',(" ) ;
4457 			for ( i = 0 ; i < aNumOfFilterPatterns ; i ++ )
4458 			{
4459 				strcat ( lDialogString , "'" ) ;
4460 				strcat ( lDialogString , aFilterPatterns [i] ) ;
4461 				strcat ( lDialogString , "'," ) ;
4462 			}
4463 			strcat ( lDialogString , "))," ) ;
4464 			strcat ( lDialogString , "('All files','*'))" ) ;
4465 	    }
4466 		strcat ( lDialogString , ")\"" ) ;
4467 	}
4468 	else if ( xdialogPresent() || dialogName() )
4469 	{
4470 		if ( xdialogPresent ( ) )
4471 		{
4472 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xdialog");return (char const *)1;}
4473 			lWasGraphicDialog = 1 ;
4474 			strcpy ( lDialogString , "(Xdialog " ) ;
4475 		}
4476 		else if ( isatty ( 1 ) )
4477 		{
4478 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;}
4479 			strcpy ( lDialogString , "@echo lala;(dialog " ) ;
4480 		}
4481 		else
4482 		{
4483 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;}
4484 			lWasXterm = 1 ;
4485 			strcpy ( lDialogString , terminalName() ) ;
4486 			strcat ( lDialogString , "'(" ) ;
4487 			strcat ( lDialogString , dialogName() ) ;
4488 			strcat ( lDialogString , " " ) ;
4489 		}
4490 
4491  		if ( aTitle && strlen(aTitle) )
4492 		{
4493 			strcat(lDialogString, "--title \"") ;
4494 			strcat(lDialogString, aTitle) ;
4495 			strcat(lDialogString, "\" ") ;
4496 		}
4497 
4498 		if ( !xdialogPresent() && !gdialogPresent() )
4499 		{
4500 			strcat(lDialogString, "--backtitle \"") ;
4501 			strcat(lDialogString,
4502 				"tab -> focus | spacebar -> select | / -> populate | enter -> ok input line") ;
4503 			strcat(lDialogString, "\" ") ;
4504 		}
4505 
4506 		strcat ( lDialogString , "--fselect \"" ) ;
4507 		if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) )
4508 		{
4509 			if ( ! strchr(aDefaultPathAndFile, '/') )
4510 			{
4511 				strcat(lDialogString, "./") ;
4512 			}
4513 			strcat(lDialogString, aDefaultPathAndFile) ;
4514 		}
4515 		else if ( ! isatty ( 1 ) && !lWasGraphicDialog )
4516 		{
4517 			strcat(lDialogString, getenv("HOME")) ;
4518 			strcat(lDialogString, "/") ;
4519 		}
4520 		else
4521 		{
4522 			strcat(lDialogString, "./") ;
4523 		}
4524 
4525 		if ( lWasGraphicDialog )
4526 		{
4527 			strcat(lDialogString, "\" 0 60 ) 2>&1 ") ;
4528 		}
4529 		else
4530 		{
4531 			strcat(lDialogString, "\" 0 60  >/dev/tty) ") ;
4532 			if ( lWasXterm )
4533 			{
4534 			  strcat ( lDialogString ,
4535 				"2>/tmp/tinyfd.txt';cat /tmp/tinyfd.txt;rm /tmp/tinyfd.txt");
4536 			}
4537 			else
4538 			{
4539 				strcat(lDialogString, "2>&1 ; clear >/dev/tty") ;
4540 			}
4541 		}
4542 	}
4543 	else
4544 	{
4545 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){return tinyfd_inputBox (aTitle,NULL,NULL);}
4546 		p = tinyfd_inputBox ( aTitle , "Save file" , "" ) ;
4547 		getPathWithoutFinalSlash ( lString , p ) ;
4548 		if ( strlen ( lString ) && ! dirExists ( lString ) )
4549 		{
4550 			return NULL ;
4551 		}
4552 		getLastName(lString,p);
4553 		if ( ! strlen(lString) )
4554 		{
4555 			return NULL;
4556 		}
4557 		return p ;
4558 	}
4559 
4560 	/* printf ( "lDialogString: %s\n" , lDialogString ) ; */
4561     if ( ! ( lIn = popen ( lDialogString , "r" ) ) )
4562     {
4563         return NULL ;
4564     }
4565     while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL )
4566     {}
4567     pclose ( lIn ) ;
4568     if ( lBuff[strlen ( lBuff ) -1] == '\n' )
4569     {
4570     	lBuff[strlen ( lBuff ) -1] = '\0' ;
4571     }
4572 	/* printf ( "lBuff: %s\n" , lBuff ) ; */
4573 	if ( ! strlen(lBuff) )
4574 	{
4575 		return NULL;
4576 	}
4577     getPathWithoutFinalSlash ( lString , lBuff ) ;
4578     if ( strlen ( lString ) && ! dirExists ( lString ) )
4579     {
4580         return NULL ;
4581     }
4582 	getLastName(lString,lBuff);
4583 	if ( ! filenameValid(lString) )
4584 	{
4585 		return NULL;
4586 	}
4587     return lBuff ;
4588 }
4589 
4590 
4591 /* in case of multiple files, the separator is | */
tinyfd_openFileDialog(char const * const aTitle,char const * const aDefaultPathAndFile,int const aNumOfFilterPatterns,char const * const * const aFilterPatterns,char const * const aSingleFilterDescription,int const aAllowMultipleSelects)4592 char const * tinyfd_openFileDialog (
4593     char const * const aTitle , /* NULL or "" */
4594     char const * const aDefaultPathAndFile , /* NULL or "" */
4595     int const aNumOfFilterPatterns , /* 0 */
4596     char const * const * const aFilterPatterns , /* NULL or {"*.jpg","*.png"} */
4597     char const * const aSingleFilterDescription , /* NULL or "image files" */
4598     int const aAllowMultipleSelects ) /* 0 or 1 */
4599 {
4600 	static char lBuff [MAX_MULTIPLE_FILES*MAX_PATH_OR_CMD] ;
4601 	char lDialogString [MAX_PATH_OR_CMD] ;
4602 	char lString [MAX_PATH_OR_CMD] ;
4603 	int i ;
4604 	FILE * lIn ;
4605 	char * p ;
4606 	char const * p2 ;
4607 	int lWasKdialog = 0 ;
4608 	int lWasGraphicDialog = 0 ;
4609 	int lWasXterm = 0 ;
4610 	lBuff[0]='\0';
4611 
4612 	if ( osascriptPresent ( ) )
4613 	{
4614 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"applescript");return (char const *)1;}
4615 		strcpy ( lDialogString , "osascript ");
4616 		if ( ! osx9orBetter() ) strcat ( lDialogString , " -e 'tell application \"System Events\"' -e 'Activate'");
4617 		strcat ( lDialogString , " -e 'try' -e '" );
4618     if ( ! aAllowMultipleSelects )
4619     {
4620 
4621 
4622 			strcat ( lDialogString , "POSIX path of ( " );
4623 		}
4624 		else
4625 		{
4626 			strcat ( lDialogString , "set mylist to " );
4627 		}
4628 		strcat ( lDialogString , "choose file " );
4629 	    if ( aTitle && strlen(aTitle) )
4630 	    {
4631 			strcat(lDialogString, "with prompt \"") ;
4632 			strcat(lDialogString, aTitle) ;
4633 			strcat(lDialogString, "\" ") ;
4634 	    }
4635 		getPathWithoutFinalSlash ( lString , aDefaultPathAndFile ) ;
4636 		if ( strlen(lString) )
4637 		{
4638 			strcat(lDialogString, "default location \"") ;
4639 			strcat(lDialogString, lString ) ;
4640 			strcat(lDialogString , "\" " ) ;
4641 		}
4642 		if ( aNumOfFilterPatterns > 0 )
4643 		{
4644 			strcat(lDialogString , "of type {\"" );
4645 #ifdef __APPLE__
4646 			strcat(lDialogString, "public.");
4647 #endif
4648 			strcat ( lDialogString , aFilterPatterns [0] + 2 ) ;
4649 			strcat ( lDialogString , "\"" ) ;
4650 			for ( i = 1 ; i < aNumOfFilterPatterns ; i ++ )
4651 			{
4652 				strcat ( lDialogString , ",\"" ) ;
4653 #ifdef __APPLE__
4654 				strcat(lDialogString, "public.");
4655 #endif
4656 				strcat ( lDialogString , aFilterPatterns [i] + 2) ;
4657 				strcat ( lDialogString , "\"" ) ;
4658 			}
4659 			strcat ( lDialogString , "} " ) ;
4660 		}
4661 		if ( aAllowMultipleSelects )
4662 		{
4663 			strcat ( lDialogString , "multiple selections allowed true ' " ) ;
4664 			strcat ( lDialogString ,
4665 					"-e 'set mystring to POSIX path of item 1 of mylist' " );
4666 			strcat ( lDialogString ,
4667 					"-e 'repeat with  i from 2 to the count of mylist' " );
4668 			strcat ( lDialogString , "-e 'set mystring to mystring & \"|\"' " );
4669 			strcat ( lDialogString ,
4670 			"-e 'set mystring to mystring & POSIX path of item i of mylist' " );
4671 			strcat ( lDialogString , "-e 'end repeat' " );
4672 			strcat ( lDialogString , "-e 'mystring' " );
4673 		}
4674 		else
4675 		{
4676 			strcat ( lDialogString , ")' " ) ;
4677 		}
4678 		strcat(lDialogString, "-e 'on error number -128' " ) ;
4679 		strcat(lDialogString, "-e 'end try'") ;
4680 		if ( ! osx9orBetter() ) strcat ( lDialogString, " -e 'end tell'") ;
4681 	}
4682   else if ( zenityPresent() || matedialogPresent() )
4683   {
4684 		if ( zenityPresent() )
4685 		{
4686 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity");return (char const *)1;}
4687       strcpy ( lDialogString , "zenity --file-selection" ) ;
4688 		}
4689 		else
4690 		{
4691 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"matedialog");return (char const *)1;}
4692 			strcpy ( lDialogString , "matedialog --file-selection" ) ;
4693 		}
4694 
4695 		if ( aAllowMultipleSelects )
4696 		{
4697 			strcat ( lDialogString , " --multiple" ) ;
4698 		}
4699 		if ( aTitle && strlen(aTitle) )
4700 		{
4701 			strcat(lDialogString, " --title=\"") ;
4702 			strcat(lDialogString, aTitle) ;
4703 			strcat(lDialogString, "\"") ;
4704 		}
4705 		if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) )
4706 		{
4707 			strcat(lDialogString, " --filename=\"") ;
4708 			strcat(lDialogString, aDefaultPathAndFile) ;
4709 			strcat(lDialogString, "\"") ;
4710 		}
4711     if ( aNumOfFilterPatterns > 0 )
4712     {
4713       strcat ( lDialogString , " --file-filter='" ) ;
4714 			if ( aSingleFilterDescription && strlen(aSingleFilterDescription) )
4715 			{
4716 				strcat ( lDialogString , aSingleFilterDescription ) ;
4717 				strcat ( lDialogString , " | " ) ;
4718 			}
4719       for ( i = 0 ; i < aNumOfFilterPatterns ; i ++ )
4720       {
4721           strcat ( lDialogString , aFilterPatterns [i] ) ;
4722           strcat ( lDialogString , " " ) ;
4723       }
4724 		  strcat ( lDialogString , "' --file-filter='All files | *'" ) ;
4725 		}
4726 	}
4727 	else if ( kdialogPresent() )
4728 	{
4729 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"kdialog");return (char const *)1;}
4730 		lWasKdialog = 1 ;
4731 		strcpy ( lDialogString , "kdialog --getopenfilename" ) ;
4732 		if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) )
4733 		{
4734 			strcat(lDialogString, " \"") ;
4735 			strcat(lDialogString, aDefaultPathAndFile ) ;
4736 
4737 			strcat(lDialogString , "\"" ) ;
4738 		}
4739 		else
4740 		{
4741 			strcat(lDialogString, " :" ) ;
4742 		}
4743 		if ( aNumOfFilterPatterns > 0 )
4744 		{
4745 			strcat(lDialogString , " \"" ) ;
4746 			for ( i = 0 ; i < aNumOfFilterPatterns ; i ++ )
4747 			{
4748 				strcat ( lDialogString , aFilterPatterns [i] ) ;
4749 				strcat ( lDialogString , " " ) ;
4750 			}
4751 			if ( aSingleFilterDescription && strlen(aSingleFilterDescription) )
4752 			{
4753 				strcat ( lDialogString , " | " ) ;
4754 				strcat ( lDialogString , aSingleFilterDescription ) ;
4755 			}
4756 			strcat ( lDialogString , "\"" ) ;
4757 		}
4758 		if ( aAllowMultipleSelects )
4759 		{
4760 			strcat ( lDialogString , " --multiple --separate-output" ) ;
4761 		}
4762 		if ( aTitle && strlen(aTitle) )
4763 		{
4764 			strcat(lDialogString, " --title \"") ;
4765 			strcat(lDialogString, aTitle) ;
4766 			strcat(lDialogString, "\"") ;
4767 		}
4768 	}
4769   else if ( ! xdialogPresent() && tkinter2Present ( ) )
4770   {
4771 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"tkinter");return (char const *)1;}
4772 		strcpy ( lDialogString , gPython2Name ) ;
4773 		if ( ! isatty ( 1 ) && isDarwin ( ) )
4774 		{
4775         	strcat ( lDialogString , " -i" ) ;  /* for osx without console */
4776 		}
4777 		strcat ( lDialogString ,
4778 " -c \"import Tkinter,tkFileDialog;root=Tkinter.Tk();root.withdraw();");
4779 
4780    	if ( isDarwin ( ) )
4781    	{
4782 			strcat ( lDialogString ,
4783 "import os;os.system('''/usr/bin/osascript -e 'tell app \\\"Finder\\\" to set \
4784 frontmost of process \\\"Python\\\" to true' ''');");
4785 		}
4786 		strcat ( lDialogString , "lFiles=tkFileDialog.askopenfilename(");
4787     if ( aAllowMultipleSelects )
4788     {
4789 			strcat ( lDialogString , "multiple=1," ) ;
4790     }
4791     if ( aTitle && strlen(aTitle) )
4792     {
4793 			strcat(lDialogString, "title='") ;
4794 			strcat(lDialogString, aTitle) ;
4795 			strcat(lDialogString, "',") ;
4796     }
4797     if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) )
4798     {
4799 			getPathWithoutFinalSlash ( lString , aDefaultPathAndFile ) ;
4800 			if ( strlen(lString) )
4801 			{
4802 				strcat(lDialogString, "initialdir='") ;
4803 				strcat(lDialogString, lString ) ;
4804 				strcat(lDialogString , "'," ) ;
4805 			}
4806 			getLastName ( lString , aDefaultPathAndFile ) ;
4807 			if ( strlen(lString) )
4808 			{
4809 				strcat(lDialogString, "initialfile='") ;
4810 				strcat(lDialogString, lString ) ;
4811 				strcat(lDialogString , "'," ) ;
4812 			}
4813 		}
4814     if ( ( aNumOfFilterPatterns > 1 )
4815       || ( ( aNumOfFilterPatterns == 1 ) /*test because poor osx behaviour*/
4816 			&& ( aFilterPatterns[0][strlen(aFilterPatterns[0])-1] != '*' ) ) )
4817     {
4818 			strcat(lDialogString , "filetypes=(" ) ;
4819 			strcat ( lDialogString , "('" ) ;
4820 			if ( aSingleFilterDescription && strlen(aSingleFilterDescription) )
4821 			{
4822 				strcat ( lDialogString , aSingleFilterDescription ) ;
4823 			}
4824 			strcat ( lDialogString , "',(" ) ;
4825 			for ( i = 0 ; i < aNumOfFilterPatterns ; i ++ )
4826 			{
4827 				strcat ( lDialogString , "'" ) ;
4828 				strcat ( lDialogString , aFilterPatterns [i] ) ;
4829 				strcat ( lDialogString , "'," ) ;
4830 			}
4831 			strcat ( lDialogString , "))," ) ;
4832 			strcat ( lDialogString , "('All files','*'))" ) ;
4833     }
4834 		strcat ( lDialogString , ");\
4835 \nif not isinstance(lFiles, tuple):\n\tprint lFiles\nelse:\
4836 \n\tlFilesString=''\n\tfor lFile in lFiles:\n\t\tlFilesString+=str(lFile)+'|'\
4837 \n\tprint lFilesString[:-1]\n\"" ) ;
4838 	}
4839 	else if ( xdialogPresent() || dialogName() )
4840 	{
4841 		if ( xdialogPresent ( ) )
4842 		{
4843 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xdialog");return (char const *)1;}
4844 			lWasGraphicDialog = 1 ;
4845 			strcpy ( lDialogString , "(Xdialog " ) ;
4846 		}
4847 		else if ( isatty ( 1 ) )
4848 		{
4849 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;}
4850 			strcpy ( lDialogString , "(dialog " ) ;
4851 		}
4852 		else
4853 		{
4854 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;}
4855 			lWasXterm = 1 ;
4856 			strcpy ( lDialogString , terminalName() ) ;
4857 			strcat ( lDialogString , "'(" ) ;
4858 			strcat ( lDialogString , dialogName() ) ;
4859 			strcat ( lDialogString , " " ) ;
4860 		}
4861 
4862 		if ( aTitle && strlen(aTitle) )
4863 		{
4864 			strcat(lDialogString, "--title \"") ;
4865 			strcat(lDialogString, aTitle) ;
4866 			strcat(lDialogString, "\" ") ;
4867 		}
4868 
4869 		if ( !xdialogPresent() && !gdialogPresent() )
4870 		{
4871 			strcat(lDialogString, "--backtitle \"") ;
4872 			strcat(lDialogString,
4873 				"tab -> focus | spacebar -> select | / -> populate | enter -> ok input line") ;
4874 			strcat(lDialogString, "\" ") ;
4875 		}
4876 
4877 		strcat ( lDialogString , "--fselect \"" ) ;
4878 		if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) )
4879 		{
4880 			if ( ! strchr(aDefaultPathAndFile, '/') )
4881 			{
4882 				strcat(lDialogString, "./") ;
4883 			}
4884 			strcat(lDialogString, aDefaultPathAndFile) ;
4885 		}
4886 		else if ( ! isatty ( 1 ) && !lWasGraphicDialog )
4887 		{
4888 			strcat(lDialogString, getenv("HOME")) ;
4889 			strcat(lDialogString, "/");
4890 		}
4891 		else
4892 		{
4893 			strcat(lDialogString, "./") ;
4894 		}
4895 
4896 		if ( lWasGraphicDialog )
4897 		{
4898 			strcat(lDialogString, "\" 0 60 ) 2>&1 ") ;
4899 		}
4900 		else
4901 		{
4902 			strcat(lDialogString, "\" 0 60  >/dev/tty) ") ;
4903 			if ( lWasXterm )
4904 			{
4905 				strcat ( lDialogString ,
4906 				"2>/tmp/tinyfd.txt';cat /tmp/tinyfd.txt;rm /tmp/tinyfd.txt");
4907 			}
4908 			else
4909 			{
4910 				strcat(lDialogString, "2>&1 ; clear >/dev/tty") ;
4911 			}
4912 		}
4913 	}
4914 	else
4915 	{
4916 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){return tinyfd_inputBox (aTitle,NULL,NULL);}
4917 		p2 = tinyfd_inputBox(aTitle, "Open file","");
4918 		if ( ! fileExists (p2) )
4919 		{
4920 			return NULL ;
4921 		}
4922 		return p2 ;
4923 	}
4924 
4925      /* printf ( "lDialogString: %s\n" , lDialogString ) ; */
4926     if ( ! ( lIn = popen ( lDialogString , "r" ) ) )
4927     {
4928         return NULL ;
4929     }
4930 	lBuff[0]='\0';
4931 	p=lBuff;
4932 	while ( fgets ( p , sizeof ( lBuff ) , lIn ) != NULL )
4933 	{
4934 		p += strlen ( p );
4935 	}
4936     pclose ( lIn ) ;
4937     if ( lBuff[strlen ( lBuff ) -1] == '\n' )
4938     {
4939     	lBuff[strlen ( lBuff ) -1] = '\0' ;
4940     }
4941     /* printf ( "lBuff: %s\n" , lBuff ) ; */
4942 	if ( lWasKdialog && aAllowMultipleSelects )
4943 	{
4944 		p = lBuff ;
4945 		while ( ( p = strchr ( p , '\n' ) ) )
4946 			* p = '|' ;
4947 	}
4948 	/* printf ( "lBuff2: %s\n" , lBuff ) ; */
4949 	if ( ! strlen ( lBuff )  )
4950 	{
4951 		return NULL;
4952 	}
4953 	if ( aAllowMultipleSelects && strchr(lBuff, '|') )
4954 	{
4955 		p2 = ensureFilesExist( lBuff , lBuff ) ;
4956 	}
4957 	else if ( fileExists (lBuff) )
4958 	{
4959 		p2 = lBuff ;
4960 	}
4961 	else
4962 	{
4963 		return NULL ;
4964 	}
4965 	/* printf ( "lBuff3: %s\n" , p2 ) ; */
4966 
4967 	return p2 ;
4968 }
4969 
4970 
tinyfd_selectFolderDialog(char const * const aTitle,char const * const aDefaultPath)4971 char const * tinyfd_selectFolderDialog (
4972 	char const * const aTitle , /* "" */
4973 	char const * const aDefaultPath ) /* "" */
4974 {
4975 	static char lBuff [MAX_PATH_OR_CMD] ;
4976 	char lDialogString [MAX_PATH_OR_CMD] ;
4977 	FILE * lIn ;
4978 	char const * p ;
4979 	int lWasGraphicDialog = 0 ;
4980 	int lWasXterm = 0 ;
4981 	lBuff[0]='\0';
4982 
4983 	if ( osascriptPresent ( ))
4984 	{
4985 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"applescript");return (char const *)1;}
4986 		strcpy ( lDialogString , "osascript ");
4987 		if ( ! osx9orBetter() ) strcat ( lDialogString , " -e 'tell application \"System Events\"' -e 'Activate'");
4988 		strcat ( lDialogString , " -e 'try' -e 'POSIX path of ( choose folder ");
4989 		if ( aTitle && strlen(aTitle) )
4990 		{
4991 		strcat(lDialogString, "with prompt \"") ;
4992 		strcat(lDialogString, aTitle) ;
4993 		strcat(lDialogString, "\" ") ;
4994 		}
4995 		if ( aDefaultPath && strlen(aDefaultPath) )
4996 		{
4997 			strcat(lDialogString, "default location \"") ;
4998 			strcat(lDialogString, aDefaultPath ) ;
4999 			strcat(lDialogString , "\" " ) ;
5000 		}
5001 		strcat ( lDialogString , ")' " ) ;
5002 		strcat(lDialogString, "-e 'on error number -128' " ) ;
5003 		strcat(lDialogString, "-e 'end try'") ;
5004 		if ( ! osx9orBetter() ) strcat ( lDialogString, " -e 'end tell'") ;
5005 	}
5006   else if ( zenityPresent() || matedialogPresent() )
5007   {
5008 		if ( zenityPresent() )
5009 		{
5010 	 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity");return (char const *)1;}
5011 			strcpy ( lDialogString , "zenity --file-selection --directory" ) ;
5012 		}
5013 		else
5014 		{
5015 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"matedialog");return (char const *)1;}
5016 			strcpy ( lDialogString , "matedialog --file-selection --directory" ) ;
5017 		}
5018 
5019 		if ( aTitle && strlen(aTitle) )
5020 		{
5021 			strcat(lDialogString, " --title=\"") ;
5022 			strcat(lDialogString, aTitle) ;
5023 			strcat(lDialogString, "\"") ;
5024 		}
5025 		if ( aDefaultPath && strlen(aDefaultPath) )
5026 		{
5027 			strcat(lDialogString, " --filename=\"") ;
5028 			strcat(lDialogString, aDefaultPath) ;
5029 			strcat(lDialogString, "\"") ;
5030 		}
5031 	}
5032 	else if ( kdialogPresent() )
5033 	{
5034 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"kdialog");return (char const *)1;}
5035 		strcpy ( lDialogString , "kdialog --getexistingdirectory" ) ;
5036 		if ( aDefaultPath && strlen(aDefaultPath) )
5037 		{
5038 			strcat(lDialogString, " \"") ;
5039 			strcat(lDialogString, aDefaultPath ) ;
5040 			strcat(lDialogString , "\"" ) ;
5041 		}
5042 		else
5043 		{
5044 			strcat(lDialogString, " :" ) ;
5045 		}
5046 		if ( aTitle && strlen(aTitle) )
5047 		{
5048 			strcat(lDialogString, " --title \"") ;
5049 			strcat(lDialogString, aTitle) ;
5050 			strcat(lDialogString, "\"") ;
5051 		}
5052 	}
5053 	else if ( ! xdialogPresent() && tkinter2Present ( ) )
5054 	{
5055 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"tkinter");return (char const *)1;}
5056 		strcpy ( lDialogString , gPython2Name ) ;
5057 		if ( ! isatty ( 1 ) && isDarwin ( ) )
5058 		{
5059         	strcat ( lDialogString , " -i" ) ;  /* for osx without console */
5060 		}
5061         strcat ( lDialogString ,
5062 " -c \"import Tkinter,tkFileDialog;root=Tkinter.Tk();root.withdraw();");
5063 
5064     	if ( isDarwin ( ) )
5065     	{
5066 			strcat ( lDialogString ,
5067 "import os;os.system('''/usr/bin/osascript -e 'tell app \\\"Finder\\\" to set \
5068 frontmost of process \\\"Python\\\" to true' ''');");
5069 		}
5070 
5071 		strcat ( lDialogString , "print tkFileDialog.askdirectory(");
5072 	    if ( aTitle && strlen(aTitle) )
5073 	    {
5074 			strcat(lDialogString, "title='") ;
5075 			strcat(lDialogString, aTitle) ;
5076 			strcat(lDialogString, "',") ;
5077 	    }
5078         if ( aDefaultPath && strlen(aDefaultPath) )
5079         {
5080 				strcat(lDialogString, "initialdir='") ;
5081 				strcat(lDialogString, aDefaultPath ) ;
5082 				strcat(lDialogString , "'" ) ;
5083 		}
5084 		strcat ( lDialogString , ")\"" ) ;
5085 	}
5086 	else if ( xdialogPresent() || dialogName() )
5087 	{
5088 		if ( xdialogPresent ( ) )
5089 		{
5090 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xdialog");return (char const *)1;}
5091 			lWasGraphicDialog = 1 ;
5092 			strcpy ( lDialogString , "(Xdialog " ) ;
5093 		}
5094 		else if ( isatty ( 1 ) )
5095 		{
5096 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;}
5097 			strcpy ( lDialogString , "(dialog " ) ;
5098 		}
5099 		else
5100 		{
5101 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;}
5102 			lWasXterm = 1 ;
5103 			strcpy ( lDialogString , terminalName() ) ;
5104 			strcat ( lDialogString , "'(" ) ;
5105 			strcat ( lDialogString , dialogName() ) ;
5106 			strcat ( lDialogString , " " ) ;
5107 		}
5108 
5109 		if ( aTitle && strlen(aTitle) )
5110 		{
5111 			strcat(lDialogString, "--title \"") ;
5112 			strcat(lDialogString, aTitle) ;
5113 			strcat(lDialogString, "\" ") ;
5114 		}
5115 
5116 		if ( !xdialogPresent() && !gdialogPresent() )
5117 		{
5118 			strcat(lDialogString, "--backtitle \"") ;
5119 			strcat(lDialogString,
5120 				"tab -> focus | spacebar -> select | / -> populate | enter -> ok input line") ;
5121 			strcat(lDialogString, "\" ") ;
5122 		}
5123 
5124 		strcat ( lDialogString , "--dselect \"" ) ;
5125 		if ( aDefaultPath && strlen(aDefaultPath) )
5126 		{
5127 			strcat(lDialogString, aDefaultPath) ;
5128 			ensureFinalSlash(lDialogString);
5129 		}
5130 		else if ( ! isatty ( 1 ) && !lWasGraphicDialog )
5131 		{
5132 			strcat(lDialogString, getenv("HOME")) ;
5133 			strcat(lDialogString, "/");
5134 		}
5135 		else
5136 		{
5137 			strcat(lDialogString, "./") ;
5138 		}
5139 
5140 		if ( lWasGraphicDialog )
5141 		{
5142 			strcat(lDialogString, "\" 0 60 ) 2>&1 ") ;
5143 		}
5144 		else
5145 		{
5146 			strcat(lDialogString, "\" 0 60  >/dev/tty) ") ;
5147 			if ( lWasXterm )
5148 			{
5149 			  strcat ( lDialogString ,
5150 				"2>/tmp/tinyfd.txt';cat /tmp/tinyfd.txt;rm /tmp/tinyfd.txt");
5151 			}
5152 			else
5153 			{
5154 				strcat(lDialogString, "2>&1 ; clear >/dev/tty") ;
5155 			}
5156 		}
5157 	}
5158 	else
5159 	{
5160 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){return tinyfd_inputBox (aTitle,NULL,NULL);}
5161 		p = tinyfd_inputBox(aTitle, "Select folder","");
5162 		if ( !p || ! strlen ( p ) || ! dirExists ( p ) )
5163 		{
5164 			return NULL ;
5165 		}
5166 		return p ;
5167 	}
5168     /* printf ( "lDialogString: %s\n" , lDialogString ) ; */
5169     if ( ! ( lIn = popen ( lDialogString , "r" ) ) )
5170     {
5171         return NULL ;
5172     }
5173 	while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL )
5174 	{}
5175 	pclose ( lIn ) ;
5176     if ( lBuff[strlen ( lBuff ) -1] == '\n' )
5177     {
5178     	lBuff[strlen ( lBuff ) -1] = '\0' ;
5179     }
5180 	/* printf ( "lBuff: %s\n" , lBuff ) ; */
5181 	if ( ! strlen ( lBuff ) || ! dirExists ( lBuff ) )
5182 	{
5183 		return NULL ;
5184 	}
5185 	return lBuff ;
5186 }
5187 
5188 
5189 /* returns the hexcolor as a string "#FF0000" */
5190 /* aoResultRGB also contains the result */
5191 /* aDefaultRGB is used only if aDefaultHexRGB is NULL */
5192 /* aDefaultRGB and aoResultRGB can be the same array */
tinyfd_colorChooser(char const * const aTitle,char const * const aDefaultHexRGB,unsigned char const aDefaultRGB[3],unsigned char aoResultRGB[3])5193 char const * tinyfd_colorChooser(
5194 	char const * const aTitle , /* NULL or "" */
5195 	char const * const aDefaultHexRGB , /* NULL or "#FF0000"*/
5196 	unsigned char const aDefaultRGB[3] , /* { 0 , 255 , 255 } */
5197 	unsigned char aoResultRGB[3] ) /* { 0 , 0 , 0 } */
5198 {
5199 	static char lBuff [128] ;
5200 	char lTmp [128] ;
5201 	char lDialogString [MAX_PATH_OR_CMD] ;
5202 	char lDefaultHexRGB[8];
5203 	char * lpDefaultHexRGB;
5204 	unsigned char lDefaultRGB[3];
5205 	char const * p;
5206  	FILE * lIn ;
5207 	int i ;
5208 	int lWasZenity3 = 0 ;
5209 	int lWasOsascript = 0 ;
5210 	int lWasXdialog = 0 ;
5211 	lBuff[0]='\0';
5212 
5213 	if ( aDefaultHexRGB )
5214 	{
5215 		Hex2RGB ( aDefaultHexRGB , lDefaultRGB ) ;
5216 		lpDefaultHexRGB = (char *) aDefaultHexRGB ;
5217 	}
5218 	else
5219 	{
5220 		lDefaultRGB[0]=aDefaultRGB[0];
5221 		lDefaultRGB[1]=aDefaultRGB[1];
5222 		lDefaultRGB[2]=aDefaultRGB[2];
5223 		RGB2Hex( aDefaultRGB , lDefaultHexRGB ) ;
5224 		lpDefaultHexRGB = (char *) lDefaultHexRGB ;
5225 	}
5226 
5227 	if ( osascriptPresent ( ) )
5228 	{
5229 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"applescript");return (char const *)1;}
5230 		lWasOsascript = 1 ;
5231 		strcpy ( lDialogString , "osascript");
5232 
5233 		if ( ! osx9orBetter() )
5234 		{
5235 			strcat ( lDialogString , " -e 'tell application \"System Events\"' -e 'Activate'");
5236 			strcat ( lDialogString , " -e 'try' -e 'set mycolor to choose color default color {");
5237 		}
5238 		else
5239 		{
5240 			strcat ( lDialogString ,
5241 " -e 'try' -e 'tell app (path to frontmost application as Unicode text) \
5242 to set mycolor to choose color default color {");
5243 		}
5244 
5245 		sprintf(lTmp, "%d", 256 * lDefaultRGB[0] ) ;
5246 		strcat(lDialogString, lTmp ) ;
5247 		strcat(lDialogString, "," ) ;
5248 		sprintf(lTmp, "%d", 256 * lDefaultRGB[1] ) ;
5249 		strcat(lDialogString, lTmp ) ;
5250 		strcat(lDialogString, "," ) ;
5251 		sprintf(lTmp, "%d", 256 * lDefaultRGB[2] ) ;
5252 		strcat(lDialogString, lTmp ) ;
5253 		strcat(lDialogString, "}' " ) ;
5254 		strcat ( lDialogString ,
5255 "-e 'set mystring to ((item 1 of mycolor) div 256 as integer) as string' " );
5256 		strcat ( lDialogString ,
5257 "-e 'repeat with i from 2 to the count of mycolor' " );
5258 		strcat ( lDialogString ,
5259 "-e 'set mystring to mystring & \" \" & ((item i of mycolor) div 256 as integer) as string' " );
5260 		strcat ( lDialogString , "-e 'end repeat' " );
5261 		strcat ( lDialogString , "-e 'mystring' ");
5262 		strcat(lDialogString, "-e 'on error number -128' " ) ;
5263 		strcat(lDialogString, "-e 'end try'") ;
5264 		if ( ! osx9orBetter() ) strcat ( lDialogString, " -e 'end tell'") ;
5265 	}
5266 	else if ( zenity3Present() || matedialogPresent() )
5267 	{
5268 		lWasZenity3 = 1 ;
5269 		if ( zenity3Present() )
5270 		{
5271 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity3");return (char const *)1;}
5272 			sprintf ( lDialogString ,
5273 "zenity --color-selection --show-palette --color=%s" , lpDefaultHexRGB ) ;
5274 		}
5275 		else
5276 		{
5277 			if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"matedialog");return (char const *)1;}
5278 			sprintf ( lDialogString ,
5279 "matedialog --color-selection --show-palette --color=%s" , lpDefaultHexRGB ) ;
5280 		}
5281 
5282 		if ( aTitle && strlen(aTitle) )
5283 		{
5284 			strcat(lDialogString, " --title=\"") ;
5285 			strcat(lDialogString, aTitle) ;
5286 			strcat(lDialogString, "\"") ;
5287 		}
5288 	}
5289 	else if ( kdialogPresent() )
5290 	{
5291 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"kdialog");return (char const *)1;}
5292 		sprintf ( lDialogString ,
5293 "kdialog --getcolor --default '%s'" , lpDefaultHexRGB ) ;
5294 		if ( aTitle && strlen(aTitle) )
5295 		{
5296 			strcat(lDialogString, " --title \"") ;
5297 			strcat(lDialogString, aTitle) ;
5298 			strcat(lDialogString, "\"") ;
5299 		}
5300 	}
5301 	else if ( xdialogPresent() )
5302 	{
5303 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xdialog");return (char const *)1;}
5304 		lWasXdialog = 1 ;
5305 		strcpy ( lDialogString , "Xdialog --colorsel \"" ) ;
5306 		if ( aTitle && strlen(aTitle) )
5307 		{
5308 			strcat(lDialogString, aTitle) ;
5309 		}
5310 		strcat(lDialogString, "\" 0 60 ") ;
5311 		sprintf(lTmp,"%hhu %hhu %hhu",lDefaultRGB[0],
5312 				lDefaultRGB[1],lDefaultRGB[2]);
5313 		strcat(lDialogString, lTmp) ;
5314 		strcat(lDialogString, " 2>&1");
5315 	}
5316 	else if ( tkinter2Present ( ) )
5317 	{
5318 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"tkinter");return (char const *)1;}
5319 		strcpy ( lDialogString , gPython2Name ) ;
5320 		if ( ! isatty ( 1 ) && isDarwin ( ) )
5321 		{
5322         	strcat ( lDialogString , " -i" ) ;  /* for osx without console */
5323 		}
5324 
5325 		strcat ( lDialogString ,
5326 " -c \"import Tkinter,tkColorChooser;root=Tkinter.Tk();root.withdraw();");
5327 
5328 		if ( isDarwin ( ) )
5329 		{
5330 			strcat ( lDialogString ,
5331 "import os;os.system('''osascript -e 'tell app \\\"Finder\\\" to set \
5332 frontmost of process \\\"Python\\\" to true' ''');");
5333 		}
5334 
5335 		strcat ( lDialogString , "res=tkColorChooser.askcolor(color='" ) ;
5336 		strcat(lDialogString, lpDefaultHexRGB ) ;
5337 		strcat(lDialogString, "'") ;
5338 
5339 
5340 	    if ( aTitle && strlen(aTitle) )
5341 	    {
5342 			strcat(lDialogString, ",title='") ;
5343 			strcat(lDialogString, aTitle) ;
5344 			strcat(lDialogString, "'") ;
5345 	    }
5346 		strcat ( lDialogString , ");\
5347 \nif res[1] is not None:\n\tprint res[1]\"" ) ;
5348 	}
5349 	else
5350 	{
5351 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){return tinyfd_inputBox (aTitle,NULL,NULL);}
5352 		p = tinyfd_inputBox(aTitle,
5353 				"Enter hex rgb color (i.e. #f5ca20)",lpDefaultHexRGB);
5354 		if ( !p || (strlen(p) != 7) || (p[0] != '#') )
5355 		{
5356 			return NULL ;
5357 		}
5358 		for ( i = 1 ; i < 7 ; i ++ )
5359 		{
5360 			if ( ! isxdigit( p[i] ) )
5361 			{
5362 				return NULL ;
5363 			}
5364 		}
5365 		Hex2RGB(p,aoResultRGB);
5366 		return p ;
5367 	}
5368 
5369 	/* printf ( "lDialogString: %s\n" , lDialogString ) ; */
5370 	if ( ! ( lIn = popen ( lDialogString , "r" ) ) )
5371 	{
5372 		return NULL ;
5373     }
5374 	while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL )
5375 	{
5376 	}
5377 	pclose ( lIn ) ;
5378     if ( ! strlen ( lBuff ) )
5379     {
5380         return NULL ;
5381     }
5382 	/* printf ( "len Buff: %lu\n" , strlen(lBuff) ) ; */
5383 	/* printf ( "lBuff0: %s\n" , lBuff ) ; */
5384     if ( lBuff[strlen ( lBuff ) -1] == '\n' )
5385     {
5386     	lBuff[strlen ( lBuff ) -1] = '\0' ;
5387     }
5388     if ( lWasZenity3 )
5389     {
5390 		if ( lBuff[0] == '#' ) {
5391 		    lBuff[3]=lBuff[5];
5392 		    lBuff[4]=lBuff[6];
5393 		    lBuff[5]=lBuff[9];
5394 		    lBuff[6]=lBuff[10];
5395 		    lBuff[7]='\0';
5396 	        Hex2RGB(lBuff,aoResultRGB);
5397 		}
5398 		else if ( lBuff[3] == '(' ) {
5399 			sscanf(lBuff,"rgb(%hhu,%hhu,%hhu",
5400 					& aoResultRGB[0], & aoResultRGB[1],& aoResultRGB[2]);
5401 			RGB2Hex(aoResultRGB,lBuff);
5402 		}
5403 		else if ( lBuff[4] == '(' ) {
5404 			sscanf(lBuff,"rgba(%hhu,%hhu,%hhu",
5405 					& aoResultRGB[0], & aoResultRGB[1],& aoResultRGB[2]);
5406 			RGB2Hex(aoResultRGB,lBuff);
5407 		}
5408     }
5409     else if ( lWasOsascript || lWasXdialog )
5410     {
5411 		/* printf ( "lBuff: %s\n" , lBuff ) ; */
5412     	sscanf(lBuff,"%hhu %hhu %hhu",
5413 			   & aoResultRGB[0], & aoResultRGB[1],& aoResultRGB[2]);
5414     	RGB2Hex(aoResultRGB,lBuff);
5415     }
5416     else
5417     {
5418 		Hex2RGB(lBuff,aoResultRGB);
5419 	}
5420 	/* printf("%d %d %d\n", aoResultRGB[0],aoResultRGB[1],aoResultRGB[2]); */
5421 	/* printf ( "lBuff: %s\n" , lBuff ) ; */
5422 	return lBuff ;
5423 }
5424 
5425 
5426 /* not cross platform - zenity only */
5427 /* contributed by Attila Dusnoki */
tinyfd_arrayDialog(char const * const aTitle,int const aNumOfColumns,char const * const * const aColumns,int const aNumOfRows,char const * const * const aCells)5428 char const * tinyfd_arrayDialog (
5429 	char const * const aTitle , /* "" */
5430 	int const aNumOfColumns , /* 2 */
5431 	char const * const * const aColumns , /* {"Column 1","Column 2"} */
5432 	int const aNumOfRows , /* 2 */
5433 	char const * const * const aCells )
5434 		/* {"Row1 Col1","Row1 Col2","Row2 Col1","Row2 Col2"} */
5435 {
5436 	static char lBuff [MAX_PATH_OR_CMD] ;
5437 	char lDialogString [MAX_PATH_OR_CMD] ;
5438 	FILE * lIn ;
5439 	lBuff[0]='\0';
5440 	int i ;
5441 
5442 	if ( zenityPresent() )
5443 	{
5444 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity");return (char const *)1;}
5445 		strcpy ( lDialogString , "zenity --list --print-column=ALL" ) ;
5446 		if ( aTitle && strlen(aTitle) )
5447 		{
5448 			strcat(lDialogString, " --title=\"") ;
5449 			strcat(lDialogString, aTitle) ;
5450 			strcat(lDialogString, "\"") ;
5451 		}
5452 
5453 		if ( aColumns && (aNumOfColumns > 0) )
5454 		{
5455 			for ( i = 0 ; i < aNumOfColumns ; i ++ )
5456 			{
5457 				strcat ( lDialogString , " --column=\"" ) ;
5458 				strcat ( lDialogString , aColumns [i] ) ;
5459 				strcat ( lDialogString , "\"" ) ;
5460 			}
5461 		}
5462 
5463 		if ( aCells && (aNumOfRows > 0) )
5464 		{
5465 			strcat ( lDialogString , " " ) ;
5466 			for ( i = 0 ; i < aNumOfRows*aNumOfColumns ; i ++ )
5467 			{
5468 				strcat ( lDialogString , "\"" ) ;
5469 				strcat ( lDialogString , aCells [i] ) ;
5470 				strcat ( lDialogString , "\" " ) ;
5471 			}
5472 		}
5473 	}
5474 	else
5475 	{
5476 		if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"");return (char const *)0;}
5477 		return NULL ;
5478 	}
5479 
5480 	/* printf ( "lDialogString: %s\n" , lDialogString ) ; */
5481 	if ( ! ( lIn = popen ( lDialogString , "r" ) ) )
5482 	{
5483 		return NULL ;
5484 	}
5485 	while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL )
5486 	{}
5487 	pclose ( lIn ) ;
5488 	if ( lBuff[strlen ( lBuff ) -1] == '\n' )
5489 	{
5490 		lBuff[strlen ( lBuff ) -1] = '\0' ;
5491 	}
5492 	/* printf ( "lBuff: %s\n" , lBuff ) ; */
5493 	if ( ! strlen ( lBuff ) )
5494 	{
5495 		return NULL ;
5496 	}
5497 	return lBuff ;
5498 }
5499 #endif /* _WIN32 */
5500 
5501 
5502 /*
5503 int main(void)
5504 {
5505 char const * lTmp;
5506 char const * lTheSaveFileName;
5507 char const * lTheOpenFileName;
5508 char const * lTheSelectFolderName;
5509 char const * lTheHexColor;
5510 char const * lWillBeGraphicMode;
5511 unsigned char lRgbColor[3];
5512 FILE * lIn;
5513 char lBuffer[1024];
5514 char lThePassword[1024];
5515 char const * lFilterPatterns[2] = { "*.txt", "*.text" };
5516 
5517 lWillBeGraphicMode = tinyfd_inputBox("tinyfd_query", NULL, NULL);
5518 
5519 if (lWillBeGraphicMode)
5520 {
5521 	strcpy(lBuffer, "graphic mode: ");
5522 }
5523 else
5524 {
5525 	strcpy(lBuffer, "console mode: ");
5526 }
5527 
5528 strcat(lBuffer, tinyfd_response);
5529 strcpy(lThePassword, "tinyfiledialogs v");
5530 strcat(lThePassword, tinyfd_version);
5531 tinyfd_messageBox(lThePassword, lBuffer, "ok", "info", 0);
5532 
5533 if (lWillBeGraphicMode && !tinyfd_forceConsole)
5534 {
5535 	tinyfd_forceConsole = tinyfd_messageBox("Hello World",
5536 		"force dialogs into console mode?\
5537 						\n\t(it is better if dialog is installed)",
5538 						"yesno", "question", 0);
5539 }
5540 
5541 lTmp = tinyfd_inputBox(
5542 	"a password box", "your password will be revealed", NULL);
5543 
5544 if (!lTmp) return 1;
5545 
5546 strcpy(lThePassword, lTmp);
5547 
5548 lTheSaveFileName = tinyfd_saveFileDialog(
5549 	"let us save this password",
5550 	"passwordFile.txt",
5551 	2,
5552 	lFilterPatterns,
5553 	NULL);
5554 
5555 if (!lTheSaveFileName)
5556 {
5557 	tinyfd_messageBox(
5558 		"Error",
5559 		"Save file name is NULL",
5560 		"ok",
5561 		"error",
5562 		1);
5563 	return 1;
5564 }
5565 
5566 lIn = fopen(lTheSaveFileName, "w");
5567 if (!lIn)
5568 {
5569 	tinyfd_messageBox(
5570 		"Error",
5571 		"Can not open this file in write mode",
5572 		"ok",
5573 		"error",
5574 		1);
5575 	return 1;
5576 }
5577 fputs(lThePassword, lIn);
5578 fclose(lIn);
5579 
5580 lTheOpenFileName = tinyfd_openFileDialog(
5581 	"let us read the password back",
5582 	"",
5583 	2,
5584 	lFilterPatterns,
5585 	NULL,
5586 	0);
5587 
5588 if (!lTheOpenFileName)
5589 {
5590 	tinyfd_messageBox(
5591 		"Error",
5592 		"Open file name is NULL",
5593 		"ok",
5594 		"error",
5595 		1);
5596 	return 1;
5597 }
5598 
5599 lIn = fopen(lTheOpenFileName, "r");
5600 
5601 if (!lIn)
5602 {
5603 	tinyfd_messageBox(
5604 		"Error",
5605 		"Can not open this file in read mode",
5606 		"ok",
5607 		"error",
5608 		1);
5609 	return(1);
5610 }
5611 lBuffer[0] = '\0';
5612 fgets(lBuffer, sizeof(lBuffer), lIn);
5613 fclose(lIn);
5614 
5615 tinyfd_messageBox("your password is",
5616 	lBuffer, "ok", "info", 1);
5617 
5618 lTheSelectFolderName = tinyfd_selectFolderDialog(
5619 	"let us just select a directory", NULL);
5620 
5621 if (!lTheSelectFolderName)
5622 {
5623 	tinyfd_messageBox(
5624 		"Error",
5625 		"Select folder name is NULL",
5626 		"ok",
5627 		"error",
5628 		1);
5629 	return 1;
5630 }
5631 
5632 tinyfd_messageBox("The selected folder is",
5633 	lTheSelectFolderName, "ok", "info", 1);
5634 
5635 lTheHexColor = tinyfd_colorChooser(
5636 	"choose a nice color",
5637 	"#FF0077",
5638 	lRgbColor,
5639 	lRgbColor);
5640 
5641 if (!lTheHexColor)
5642 {
5643 	tinyfd_messageBox(
5644 		"Error",
5645 		"hexcolor is NULL",
5646 		"ok",
5647 		"error",
5648 		1);
5649 	return 1;
5650 }
5651 
5652 tinyfd_messageBox("The selected hexcolor is",
5653 	lTheHexColor, "ok", "info", 1);
5654 
5655 	return 0;
5656 }
5657 */
5658 
5659 #ifdef _MSC_VER
5660 #pragma warning(default:4996)
5661 #pragma warning(default:4100)
5662 #pragma warning(default:4706)
5663 #pragma warning(pop)
5664 #endif
5665