├── files.xml ├── README.md ├── tinyfiledialogs.h └── tinyfiledialogs.c /files.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Official version hosted at https://sourceforge.net/projects/tinyfiledialogs/ 2 | 3 | This version is _not_ official and is currently updated as required by https://github.com/haxelime/lime only 4 | 5 | # tinyfiledialogs 6 | 7 |
  8 |  _________
  9 | /         \   tiny file dialogs ( cross-platform C C++ )
 10 | |tiny file|   v2.9.3 [July 12, 2017] zlib licence
 11 | | dialogs |   InputBox PasswordBox MessageBox ColorPicker
 12 | \____  ___/   OpenFileDialog SaveFileDialog SelectFolderDialog		
 13 |      \|       ASCII UTF-8 (and also MBCS UTF-16 for windows)
 14 |               Native dialog library for WINDOWS MAC OSX GTK+ QT CONSOLE
 15 |   
 16 | SSH supported via automatic switch to console mode or X11 forwarding
 17 | 
 18 | tested with C & C++ compilers on 
 19 |     Visual Studio MinGW OSX LINUX FREEBSD OPENBSD ILLUMOS SOLARIS MINIX RASPBIAN
 20 | using
 21 |     Gnome Kde Mate Cinnamon Unity Lxde Lxqt Xfce Enlightenment
 22 |     WindowMaker IceWm Cde Jds OpenBox Awesome Jwm
 23 | 
 24 | bindings for LUA and C# dll
 25 | included in LWJGL(java), rust, Allegrobasic
 26 | 
 27 |                    http://tinyfiledialogs.sourceforge.net
 28 |                 git://git.code.sf.net/p/tinyfiledialogs/code
 29 |  _________________________________________________________________________
 30 | |                                                                         |
 31 | | CONTACT me directly via the email address at the top of the header file |
 32 | |_________________________________________________________________________|
 33 | 
 34 | if you absolutely want them, the windows only wchar_t prototypes are in the header file
 35 | 
 36 | int tinyfd_messageBox (
 37 |     char const * const aTitle , // ""
 38 |     char const * const aMessage , // "" may contain \n \t
 39 |     char const * const aDialogType , // "ok" "okcancel" "yesno" "yesnocancel"
 40 |     char const * const aIconType , // "info" "warning" "error" "question"
 41 |     int const aDefaultButton ) ;
 42 |         // 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel
 43 | 
 44 | char const * tinyfd_inputBox (
 45 |     char const * const aTitle , // ""
 46 |     char const * const aMessage , // "" may NOT contain \n \t on windows
 47 |     char const * const aDefaultInput ) ; // "" , if NULL it's a passwordBox
 48 |         // returns NULL on cancel
 49 | 
 50 | char const * tinyfd_saveFileDialog (
 51 |     char const * const aTitle , // ""
 52 |     char const * const aDefaultPathAndFile , // ""
 53 |     int const aNumOfFilterPatterns , // 0
 54 |     char const * const * const aFilterPatterns , // NULL | {"*.txt"}
 55 |     char const * const aSingleFilterDescription ) ; // NULL | "text files"
 56 |         // returns NULL on cancel
 57 | 
 58 | char const * tinyfd_openFileDialog (
 59 |     char const * const aTitle , // ""
 60 |     char const * const aDefaultPathAndFile , // ""
 61 |     int const aNumOfFilterPatterns , // 0
 62 |     char const * const * const aFilterPatterns , // NULL {"*.jpg","*.png"}
 63 |     char const * const aSingleFilterDescription , // NULL | "image files"
 64 |     int const aAllowMultipleSelects ) ; // 0
 65 |         // in case of multiple files, the separator is |
 66 |         // returns NULL on cancel
 67 | 
 68 | char const * tinyfd_selectFolderDialog (
 69 |     char const * const aTitle , // ""
 70 |     char const * const aDefaultPath ) ; // ""
 71 |         // returns NULL on cancel
 72 | 
 73 | char const * tinyfd_colorChooser(
 74 |     char const * const aTitle , // ""
 75 |     char const * const aDefaultHexRGB , // NULL or "#FF0000”
 76 |     unsigned char const aDefaultRGB[3] , // { 0 , 255 , 255 }
 77 |     unsigned char aoResultRGB[3] ) ; // { 0 , 0 , 0 }
 78 |         // returns the hexcolor as a string "#FF0000"
 79 |         // aoResultRGB also contains the result
 80 |         // aDefaultRGB is used only if aDefaultHexRGB is NULL
 81 |         // aDefaultRGB and aoResultRGB can be the same array
 82 |         // returns NULL on cancel
 83 | 
 84 | - This is not for android nor ios.
 85 | - The code is pure C, perfectly compatible with C++.
 86 | - the windows only wchar_t (utf-16) prototypes are in the header file
 87 | - windows is fully supported from XP to 10 (maybe even older versions)
 88 | - C# & LUA via dll, see files in the folder EXTRAS 
 89 | - OSX supported from 10.4 to 10.12 (maybe even older versions)
 90 | - Avoid using " and ' in titles and messages.
 91 | - There's one file filter only, it may contain several patterns.
 92 | - If no filter description is provided,
 93 |   the list of patterns will become the description.
 94 | - char const * filterPatterns[3] = { "*.obj" , "*.stl" , "*.dxf" } ;
 95 | - On windows link against Comdlg32.lib and Ole32.lib
 96 |   (on windows the no linking claim is a lie)
 97 |   This linking is not compulsary for console mode (see header file).
 98 | - On unix: it tries command line calls, so no such need (NO LINKING).
 99 | - On unix you need applescript, zenity, matedialog, qarma, kdialog, Xdialog,
100 |   python2/tkinter or dialog (will open a terminal if running without console).
101 | - One of those is already included on most (if not all) desktops.
102 | - In the absence of those it will use gdialog, gxmessage or whiptail
103 |   with a textinputbox.
104 | - If nothing is found, it switches to basic console input,
105 |   it opens a console if needed (requires xterm + bash).
106 | - Use windows separators on windows and unix separators on unix.
107 | - String memory is preallocated statically for all the returned values.
108 | - File and path names are tested before return, they are valid.
109 | - If you pass only a path instead of path + filename,
110 |   make sure it ends with a separator.
111 | - tinyfd_forceConsole=1; at run time, forces dialogs into console mode.
112 | - On windows, console mode only make sense for console applications.
113 | - Mutiple selects are not allowed in console mode.
114 | - The package dialog must be installed to run in enhanced console mode.
115 |   It is already installed on most unix systems.
116 | - On osx, the package dialog can be installed via http://macports.org
117 | - On windows, for enhanced console mode,
118 |   dialog.exe should be copied somewhere on your executable path.
119 |   It can be found at the bottom of the following page:
120 |   http://andrear.altervista.org/home/cdialog.php
121 | - If dialog is missing, it will switch to basic console input.
122 | - You can query the type of dialog that will be use.
123 | - MinGW needs gcc >= v4.9 otherwise some headers are incomplete.
124 | 
125 | - Here is the Hello World:
126 |             if a console is missing, it will use graphic dialogs
127 |             if a graphical display is absent, it will use console dialogs
128 | 
129 | 
130 | hello.c
131 | #include 
132 | #include 
133 | #include "tinyfiledialogs.h"
134 | int main()
135 | {
136 | 	char const * lTmp;
137 | 	char const * lTheSaveFileName;
138 | 	char const * lTheOpenFileName;
139 | 	char const * lTheSelectFolderName;
140 | 	char const * lTheHexColor;
141 | 	char const * lWillBeGraphicMode;
142 | 	unsigned char lRgbColor[3];
143 | 	FILE * lIn;
144 | 	char lBuffer[1024];
145 | 	char lThePassword[1024];
146 | 	char const * lFilterPatterns[2] = { "*.txt", "*.text" };
147 | 
148 | 	lWillBeGraphicMode = tinyfd_inputBox("tinyfd_query", NULL, NULL);
149 | 
150 | 	if (lWillBeGraphicMode)
151 | 	{
152 | 		strcpy(lBuffer, "graphic mode: ");
153 | 	}
154 | 	else
155 | 	{
156 | 		strcpy(lBuffer, "console mode: ");
157 | 	}
158 | 
159 | 	strcat(lBuffer, tinyfd_response);
160 | 	strcpy(lThePassword, "tinyfiledialogs v");
161 | 	strcat(lThePassword, tinyfd_version);
162 | 	tinyfd_messageBox(lThePassword, lBuffer, "ok", "info", 0);
163 | 
164 | 	if ( lWillBeGraphicMode && ! tinyfd_forceConsole )
165 | 	{
166 | 		tinyfd_forceConsole = ! tinyfd_messageBox("Hello World",
167 | 			"graphic dialogs [yes] / console mode [no]?",
168 | 			"yesno", "question", 1);
169 | 	}
170 | 
171 | 	lTmp = tinyfd_inputBox(
172 | 		"a password box", "your password will be revealed", NULL);
173 | 
174 | 	if (!lTmp) return 1 ;
175 | 
176 | 	/* copy lTmp because saveDialog would overwrites
177 | 	inputBox static buffer in basicinput mode */
178 | 
179 | 	strcpy(lThePassword, lTmp);
180 | 
181 | 	lTheSaveFileName = tinyfd_saveFileDialog(
182 | 		"let us save this password",
183 | 		"passwordFile.txt",
184 | 		2,
185 | 		lFilterPatterns,
186 | 		NULL);
187 | 
188 | 	if (! lTheSaveFileName)
189 | 	{
190 | 		tinyfd_messageBox(
191 | 			"Error",
192 | 			"Save file name is NULL",
193 | 			"ok",
194 | 			"error",
195 | 			1);
196 | 		return 1 ;
197 | 	}
198 | 
199 | 	lIn = fopen(lTheSaveFileName, "w");
200 | 	if (!lIn)
201 | 	{
202 | 		tinyfd_messageBox(
203 | 			"Error",
204 | 			"Can not open this file in write mode",
205 | 			"ok",
206 | 			"error",
207 | 			1);
208 | 		return 1 ;
209 | 	}
210 | 	fputs(lThePassword, lIn);
211 | 	fclose(lIn);
212 | 
213 | 	lTheOpenFileName = tinyfd_openFileDialog(
214 | 		"let us read the password back",
215 | 		"",
216 | 		2,
217 | 		lFilterPatterns,
218 | 		NULL,
219 | 		0);
220 | 
221 | 	if (! lTheOpenFileName)
222 | 	{
223 | 		tinyfd_messageBox(
224 | 			"Error",
225 | 			"Open file name is NULL",
226 | 			"ok",
227 | 			"error",
228 | 			1);
229 | 		return 1 ;
230 | 	}
231 | 
232 | 	lIn = fopen(lTheOpenFileName, "r");
233 | 
234 | 	if (!lIn)
235 | 	{
236 | 		tinyfd_messageBox(
237 | 			"Error",
238 | 			"Can not open this file in read mode",
239 | 			"ok",
240 | 			"error",
241 | 			1);
242 | 		return(1);
243 | 	}
244 | 	lBuffer[0] = '\0';
245 | 	fgets(lBuffer, sizeof(lBuffer), lIn);
246 | 	fclose(lIn);
247 | 
248 | 	tinyfd_messageBox("your password is",
249 | 			lBuffer, "ok", "info", 1);
250 | 
251 | 	lTheSelectFolderName = tinyfd_selectFolderDialog(
252 | 		"let us just select a directory", NULL);
253 | 
254 | 	if (!lTheSelectFolderName)
255 | 	{
256 | 		tinyfd_messageBox(
257 | 			"Error",
258 | 			"Select folder name is NULL",
259 | 			"ok",
260 | 			"error",
261 | 			1);
262 | 		return 1;
263 | 	}
264 | 
265 | 	tinyfd_messageBox("The selected folder is",
266 | 		lTheSelectFolderName, "ok", "info", 1);
267 | 
268 | 	lTheHexColor = tinyfd_colorChooser(
269 | 		"choose a nice color",
270 | 		"#FF0077",
271 | 		lRgbColor,
272 | 		lRgbColor);
273 | 
274 | 	if (!lTheHexColor)
275 | 	{
276 | 		tinyfd_messageBox(
277 | 			"Error",
278 | 			"hexcolor is NULL",
279 | 			"ok",
280 | 			"error",
281 | 			1);
282 | 		return 1;
283 | 	}
284 | 
285 | 	tinyfd_messageBox("The selected hexcolor is",
286 | 		lTheHexColor, "ok", "info", 1);
287 | 
288 | 	return 0;
289 | }
290 | 
291 | 
292 | OSX :
293 | $ gcc -o hello.app hello.c tinyfiledialogs.c
294 | 
295 | UNIX :
296 | $ gcc -o hello hello.c tinyfiledialogs.c
297 | ( or clang tcc cc CC )
298 | 
299 | MinGW (needs gcc >= v4.9 otherwise some headers are incomplete):
300 | > gcc -o hello.exe hello.c tinyfiledialogs.c -LC:/mingw/lib -lcomdlg32 -lole32
301 | (unfortunately some headers are missing with tcc)
302 | 
303 | VisualStudio :
304 |     Create a console application project,
305 |     it links against Comdlg32.lib & Ole32.lib.
306 | 
307 | 
308 | -------------------------------------------------------------------------------- /tinyfiledialogs.h: -------------------------------------------------------------------------------- 1 | /*_________ 2 | / \ tinyfiledialogs.h v2.9.3 [July 12, 2017] zlib licence 3 | |tiny file| Unique header file created [November 9, 2014] 4 | | dialogs | Copyright (c) 2014 - 2017 Guillaume Vareille http://ysengrin.com 5 | \____ ___/ http://tinyfiledialogs.sourceforge.net 6 | \| 7 | git://git.code.sf.net/p/tinyfiledialogs/code 8 | ______________________________________________ 9 | | | 10 | | email: tinyfiledialogs@ysengrin.com | 11 | |______________________________________________| 12 | 13 | A big thank you to Don Heyse http://ldglite.sf.net for 14 | his code contributions, bug corrections & thorough testing! 15 | 16 | git://git.code.sf.net/p/tinyfiledialogs/code 17 | 18 | Please 19 | 1) let me know 20 | - if you are including tiny file dialogs, 21 | I'll be happy to add your link to the list of projects using it. 22 | - If you are using it on different hardware / OS / compiler. 23 | 2) leave a review on Sourceforge. Thanks. 24 | 25 | tiny file dialogs (cross-platform C C++) 26 | InputBox PasswordBox MessageBox ColorPicker 27 | OpenFileDialog SaveFileDialog SelectFolderDialog 28 | Native dialog library for WINDOWS MAC OSX GTK+ QT CONSOLE & more 29 | SSH supported via automatic switch to console mode or X11 forwarding 30 | 31 | One C file (add it to your C or C++ project) with 6 functions: 32 | - message & question 33 | - input & password 34 | - save file 35 | - open file(s) 36 | - select folder 37 | - color picker 38 | 39 | Complements OpenGL GLFW GLUT GLUI VTK SFML TGUI SDL Ogre Unity3d ION OpenCV 40 | CEGUI MathGL GLM CPW GLOW IMGUI MyGUI GLT NGL STB & GUI less programs 41 | 42 | NO INIT 43 | NO MAIN LOOP 44 | NO LINKING 45 | NO INCLUDE 46 | 47 | The dialogs can be forced into console mode 48 | 49 | Windows (XP to 10) ASCII MBCS UTF-8 UTF-16 50 | - native code & vbs create the graphic dialogs 51 | - enhanced console mode can use dialog.exe from 52 | http://andrear.altervista.org/home/cdialog.php 53 | - basic console input 54 | 55 | Unix (command line calls) ASCII UTF-8 56 | - applescript 57 | - zenity / matedialog / qarma (zenity for qt) 58 | - kdialog 59 | - Xdialog 60 | - python2 tkinter 61 | - dialog (opens a console if needed) 62 | - basic console input 63 | The same executable can run across desktops & distributions 64 | 65 | tested with C & C++ compilers 66 | on VisualStudio MinGW Mac Linux Bsd Solaris Minix Raspbian 67 | using Gnome Kde Enlightenment Mate Cinnamon Unity 68 | Lxde Lxqt Xfce WindowMaker IceWm Cde Jds OpenBox Awesome Jwm 69 | 70 | bindings for LUA and C# dll 71 | included in LWJGL(java), rust, Allegrobasic 72 | 73 | - License - 74 | 75 | This software is provided 'as-is', without any express or implied 76 | warranty. In no event will the authors be held liable for any damages 77 | arising from the use of this software. 78 | 79 | Permission is granted to anyone to use this software for any purpose, 80 | including commercial applications, and to alter it and redistribute it 81 | freely, subject to the following restrictions: 82 | 83 | 1. The origin of this software must not be misrepresented; you must not 84 | claim that you wrote the original software. If you use this software 85 | in a product, an acknowledgment in the product documentation would be 86 | appreciated but is not required. 87 | 2. Altered source versions must be plainly marked as such, and must not be 88 | misrepresented as being the original software. 89 | 3. This notice may not be removed or altered from any source distribution. 90 | */ 91 | 92 | #ifndef TINYFILEDIALOGS_H 93 | #define TINYFILEDIALOGS_H 94 | 95 | /* #define TINYFD_NOLIB */ 96 | /* On windows, define TINYFD_NOLIB here 97 | if you don't want to include the code creating the graphic dialogs. 98 | Then you won't need to link against Comdlg32.lib and Ole32.lib */ 99 | 100 | /* if tinydialogs.c is compiled with a C++ compiler rather than with a C compiler 101 | (ie. you change the extension from .c to .cpp), you need to comment out: 102 | extern "C" { 103 | and the corresponding closing bracket near the end of this file: 104 | } 105 | */ 106 | #ifdef __cplusplus 107 | extern "C" { 108 | #endif 109 | 110 | extern char tinyfd_version[8]; /* contains tinyfd current version number */ 111 | 112 | #ifdef _WIN32 113 | /* for UTF-16 use the functions at the end of this files */ 114 | extern int tinyfd_winUtf8; /* 0 (default) or 1 */ 115 | /* on windows string char can be 0:MBSC or 1:UTF-8 116 | unless your code is really prepared for UTF-8 on windows, leave this on MBSC. 117 | Or you can use the UTF-16 (wchar) prototypes at the end of ths file.*/ 118 | #endif 119 | 120 | extern int tinyfd_forceConsole ; /* 0 (default) or 1 */ 121 | /* for unix & windows: 0 (graphic mode) or 1 (console mode). 122 | 0: try to use a graphic solution, if it fails then it uses console mode. 123 | 1: forces all dialogs into console mode even when an X server is present, 124 | if the package dialog (and a console is present) or dialog.exe is installed. 125 | on windows it only make sense for console applications */ 126 | 127 | extern char tinyfd_response[1024]; 128 | /* if you pass "tinyfd_query" as aTitle, 129 | the functions will not display the dialogs 130 | but will return 0 for console mode, 1 for graphic mode. 131 | tinyfd_response is then filled with the retain solution. 132 | possible values for tinyfd_response are (all lowercase) 133 | for the graphic mode: 134 | windows applescript zenity zenity3 matedialog qarma kdialog 135 | xdialog tkinter gdialog gxmessage xmessage 136 | for the console mode: 137 | dialog whiptail basicinput */ 138 | 139 | int tinyfd_messageBox ( 140 | char const * const aTitle , /* "" */ 141 | char const * const aMessage , /* "" may contain \n \t */ 142 | char const * const aDialogType , /* "ok" "okcancel" "yesno" "yesnocancel" */ 143 | char const * const aIconType , /* "info" "warning" "error" "question" */ 144 | int const aDefaultButton ) ; 145 | /* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */ 146 | 147 | char const * tinyfd_inputBox ( 148 | char const * const aTitle , /* "" */ 149 | char const * const aMessage , /* "" may NOT contain \n \t on windows */ 150 | char const * const aDefaultInput ) ; /* "" , if NULL it's a passwordBox */ 151 | /* returns NULL on cancel */ 152 | 153 | char const * tinyfd_saveFileDialog ( 154 | char const * const aTitle , /* "" */ 155 | char const * const aDefaultPathAndFile , /* "" */ 156 | int const aNumOfFilterPatterns , /* 0 */ 157 | char const * const * const aFilterPatterns , /* NULL | {"*.jpg","*.png"} */ 158 | char const * const aSingleFilterDescription ) ; /* NULL | "text files" */ 159 | /* returns NULL on cancel */ 160 | 161 | char const * tinyfd_openFileDialog ( 162 | char const * const aTitle , /* "" */ 163 | char const * const aDefaultPathAndFile , /* "" */ 164 | int const aNumOfFilterPatterns , /* 0 */ 165 | char const * const * const aFilterPatterns , /* NULL {"*.jpg","*.png"} */ 166 | char const * const aSingleFilterDescription , /* NULL | "image files" */ 167 | int const aAllowMultipleSelects ) ; /* 0 or 1 */ 168 | /* in case of multiple files, the separator is | */ 169 | /* returns NULL on cancel */ 170 | 171 | char const * tinyfd_selectFolderDialog ( 172 | char const * const aTitle , /* "" */ 173 | char const * const aDefaultPath ) ; /* "" */ 174 | /* returns NULL on cancel */ 175 | 176 | char const * tinyfd_colorChooser( 177 | char const * const aTitle , /* "" */ 178 | char const * const aDefaultHexRGB , /* NULL or "#FF0000" */ 179 | unsigned char const aDefaultRGB[3] , /* { 0 , 255 , 255 } */ 180 | unsigned char aoResultRGB[3] ) ; /* { 0 , 0 , 0 } */ 181 | /* returns the hexcolor as a string "#FF0000" */ 182 | /* aoResultRGB also contains the result */ 183 | /* aDefaultRGB is used only if aDefaultHexRGB is NULL */ 184 | /* aDefaultRGB and aoResultRGB can be the same array */ 185 | /* returns NULL on cancel */ 186 | 187 | 188 | /************ NOT CROSS PLATFORM SECTION STARTS HERE ************************/ 189 | #ifdef _WIN32 190 | #ifndef TINYFD_NOLIB 191 | 192 | /* windows only - utf-16 version */ 193 | int tinyfd_messageBoxW( 194 | wchar_t const * const aTitle , 195 | wchar_t const * const aMessage, /* "" may contain \n \t */ 196 | wchar_t const * const aDialogType, /* "ok" "okcancel" "yesno" */ 197 | wchar_t const * const aIconType, /* "info" "warning" "error" "question" */ 198 | int const aDefaultButton ); /* 0 for cancel/no , 1 for ok/yes */ 199 | /* returns 0 for cancel/no , 1 for ok/yes */ 200 | 201 | /* windows only - utf-16 version */ 202 | wchar_t const * tinyfd_saveFileDialogW( 203 | wchar_t const * const aTitle, /* NULL or "" */ 204 | wchar_t const * const aDefaultPathAndFile, /* NULL or "" */ 205 | int const aNumOfFilterPatterns, /* 0 */ 206 | wchar_t const * const * const aFilterPatterns, /* NULL or {"*.jpg","*.png"} */ 207 | wchar_t const * const aSingleFilterDescription); /* NULL or "image files" */ 208 | /* returns NULL on cancel */ 209 | 210 | /* windows only - utf-16 version */ 211 | wchar_t const * tinyfd_openFileDialogW( 212 | wchar_t const * const aTitle, /* "" */ 213 | wchar_t const * const aDefaultPathAndFile, /* "" */ 214 | int const aNumOfFilterPatterns , /* 0 */ 215 | wchar_t const * const * const aFilterPatterns, /* NULL {"*.jpg","*.png"} */ 216 | wchar_t const * const aSingleFilterDescription, /* NULL | "image files" */ 217 | int const aAllowMultipleSelects ) ; /* 0 or 1 */ 218 | /* in case of multiple files, the separator is | */ 219 | /* returns NULL on cancel */ 220 | 221 | /* windows only - utf-16 version */ 222 | wchar_t const * tinyfd_selectFolderDialogW( 223 | wchar_t const * const aTitle, /* "" */ 224 | wchar_t const * const aDefaultPath); /* "" */ 225 | /* returns NULL on cancel */ 226 | 227 | /* windows only - utf-16 version */ 228 | wchar_t const * tinyfd_colorChooserW( 229 | wchar_t const * const aTitle, /* "" */ 230 | wchar_t const * const aDefaultHexRGB, /* NULL or "#FF0000" */ 231 | unsigned char const aDefaultRGB[3] , /* { 0 , 255 , 255 } */ 232 | unsigned char aoResultRGB[3] ) ; /* { 0 , 0 , 0 } */ 233 | /* returns the hexcolor as a string "#FF0000" */ 234 | /* aoResultRGB also contains the result */ 235 | /* aDefaultRGB is used only if aDefaultHexRGB is NULL */ 236 | /* aDefaultRGB and aoResultRGB can be the same array */ 237 | /* returns NULL on cancel */ 238 | 239 | 240 | #endif /*TINYFD_NOLIB*/ 241 | #else /*_WIN32*/ 242 | 243 | /* unix zenity only */ 244 | char const * tinyfd_arrayDialog( 245 | char const * const aTitle , /* "" */ 246 | int const aNumOfColumns , /* 2 */ 247 | char const * const * const aColumns, /* {"Column 1","Column 2"} */ 248 | int const aNumOfRows, /* 2*/ 249 | char const * const * const aCells); 250 | /* {"Row1 Col1","Row1 Col2","Row2 Col1","Row2 Col2"} */ 251 | 252 | #endif /*_WIN32 */ 253 | 254 | #ifdef __cplusplus 255 | } 256 | #endif 257 | 258 | #endif /* TINYFILEDIALOGS_H */ 259 | 260 | /* 261 | - This is not for android nor ios. 262 | - The code is pure C, perfectly compatible with C++. 263 | - the windows only wchar_t (utf-16) prototypes are in the header file 264 | - windows is fully supported from XP to 10 (maybe even older versions) 265 | - C# & LUA via dll, see example files 266 | - OSX supported from 10.4 to 10.11 (maybe even older versions) 267 | - Avoid using " and ' in titles and messages. 268 | - There's one file filter only, it may contain several patterns. 269 | - If no filter description is provided, 270 | the list of patterns will become the description. 271 | - char const * filterPatterns[3] = { "*.obj" , "*.stl" , "*.dxf" } ; 272 | - On windows link against Comdlg32.lib and Ole32.lib 273 | This linking is not compulsary for console mode (see above). 274 | - On unix: it tries command line calls, so no such need. 275 | - On unix you need applescript, zenity, matedialog, qarma, kdialog, Xdialog, 276 | python2/tkinter or dialog (will open a terminal if running without console). 277 | - One of those is already included on most (if not all) desktops. 278 | - In the absence of those it will use gdialog, gxmessage or whiptail 279 | with a textinputbox. 280 | - If nothing is found, it switches to basic console input, 281 | it opens a console if needed (requires xterm + bash). 282 | - Use windows separators on windows and unix separators on unix. 283 | - String memory is preallocated statically for all the returned values. 284 | - File and path names are tested before return, they are valid. 285 | - If you pass only a path instead of path + filename, 286 | make sure it ends with a separator. 287 | - tinyfd_forceConsole=1; at run time, forces dialogs into console mode. 288 | - On windows, console mode only make sense for console applications. 289 | - Mutiple selects are not allowed in console mode. 290 | - The package dialog must be installed to run in enhanced console mode. 291 | It is already installed on most unix systems. 292 | - On osx, the package dialog can be installed via http://macports.org 293 | - On windows, for enhanced console mode, 294 | dialog.exe should be copied somewhere on your executable path. 295 | It can be found at the bottom of the following page: 296 | http://andrear.altervista.org/home/cdialog.php 297 | - If dialog is missing, it will switch to basic console input. 298 | - You can query the type of dialog that will be use. 299 | - MinGW needs gcc >= v4.9 otherwise some headers are incomplete. 300 | - The Hello World (and a bit more) is on the sourceforge site: 301 | */ 302 | -------------------------------------------------------------------------------- /tinyfiledialogs.c: -------------------------------------------------------------------------------- 1 | /*_________ 2 | / \ tinyfiledialogs.c v2.9.3 [July 12, 2017] zlib licence 3 | |tiny file| Unique code file created [November 9, 2014] 4 | | dialogs | Copyright (c) 2014 - 2017 Guillaume Vareille http://ysengrin.com 5 | \____ ___/ http://tinyfiledialogs.sourceforge.net 6 | \| 7 | git://git.code.sf.net/p/tinyfiledialogs/code 8 | ______________________________________________ 9 | | | 10 | | email: tinyfiledialogs@ysengrin.com | 11 | |______________________________________________| 12 | 13 | A big thank you to Don Heyse http://ldglite.sf.net for 14 | his code contributions, bug corrections & thorough testing! 15 | 16 | Please 17 | 1) let me know 18 | - if you are including tiny file dialogs, 19 | I'll be happy to add your link to the list of projects using it. 20 | - If you are using it on different hardware / OS / compiler. 21 | 2) leave a review on Sourceforge. Thanks. 22 | 23 | tiny file dialogs (cross-platform C C++) 24 | InputBox PasswordBox MessageBox ColorPicker 25 | OpenFileDialog SaveFileDialog SelectFolderDialog 26 | Native dialog library for WINDOWS MAC OSX GTK+ QT CONSOLE & more 27 | SSH supported via automatic switch to console mode or X11 forwarding 28 | 29 | One C file (add it to your C or C++ project) with 6 functions: 30 | - message & question 31 | - input & password 32 | - save file 33 | - open file(s) 34 | - select folder 35 | - color picker 36 | 37 | Complements OpenGL GLFW GLUT GLUI VTK SFML TGUI SDL Ogre Unity3d ION OpenCV 38 | CEGUI MathGL GLM CPW GLOW IMGUI MyGUI GLT NGL STB & GUI less programs 39 | 40 | NO INIT 41 | NO MAIN LOOP 42 | NO LINKING 43 | NO INCLUDE 44 | 45 | The dialogs can be forced into console mode 46 | 47 | Windows (XP to 10) ASCII MBCS UTF-8 UTF-16 48 | - native code & vbs create the graphic dialogs 49 | - enhanced console mode can use dialog.exe from 50 | http://andrear.altervista.org/home/cdialog.php 51 | - basic console input 52 | 53 | Unix (command line calls) ASCII UTF-8 54 | - applescript 55 | - zenity / matedialog / qarma (zenity for qt) 56 | - kdialog 57 | - Xdialog 58 | - python2 tkinter 59 | - dialog (opens a console if needed) 60 | - basic console input 61 | The same executable can run across desktops & distributions 62 | 63 | tested with C & C++ compilers 64 | on VisualStudio MinGW Mac Linux Bsd Solaris Minix Raspbian 65 | using Gnome Kde Enlightenment Mate Cinnamon Unity 66 | Lxde Lxqt Xfce WindowMaker IceWm Cde Jds OpenBox Awesome Jwm 67 | 68 | bindings for LUA and C# dll 69 | included in LWJGL(java), rust, Allegrobasic 70 | 71 | - License - 72 | 73 | This software is provided 'as-is', without any express or implied 74 | warranty. In no event will the authors be held liable for any damages 75 | arising from the use of this software. 76 | 77 | Permission is granted to anyone to use this software for any purpose, 78 | including commercial applications, and to alter it and redistribute it 79 | freely, subject to the following restrictions: 80 | 81 | 1. The origin of this software must not be misrepresented; you must not 82 | claim that you wrote the original software. If you use this software 83 | in a product, an acknowledgment in the product documentation would be 84 | appreciated but is not required. 85 | 2. Altered source versions must be plainly marked as such, and must not be 86 | misrepresented as being the original software. 87 | 3. This notice may not be removed or altered from any source distribution. 88 | */ 89 | 90 | #include 91 | #include 92 | #include 93 | #include 94 | #include 95 | 96 | #include "tinyfiledialogs.h" 97 | /* #define TINYFD_NOLIB */ 98 | 99 | #ifdef _WIN32 100 | #ifndef _WIN32_WINNT 101 | #define _WIN32_WINNT 0x0500 102 | #endif 103 | #ifndef TINYFD_NOLIB 104 | #include 105 | /*#define TINYFD_NOSELECTFOLDERWIN*/ 106 | #ifndef TINYFD_NOSELECTFOLDERWIN 107 | #include 108 | #endif /*TINYFD_NOSELECTFOLDERWIN*/ 109 | #endif 110 | #include 111 | /*#include */ 112 | #define SLASH "\\" 113 | int tinyfd_winUtf8 = 0 ; /* on windows string char can be 0:MBSC or 1:UTF-8 */ 114 | #else 115 | #include 116 | #include 117 | #include /* on old systems try instead */ 118 | #include 119 | #include 120 | #define SLASH "/" 121 | #endif /* _WIN32 */ 122 | 123 | #define MAX_PATH_OR_CMD 1024 /* _MAX_PATH or MAX_PATH */ 124 | #define MAX_MULTIPLE_FILES 32 125 | 126 | char tinyfd_version [8] = "2.9.3"; 127 | 128 | static int tinyfd_verbose = 0 ; /* print on unix the command line calls */ 129 | 130 | #if defined(TINYFD_NOLIB) && defined(_WIN32) 131 | int tinyfd_forceConsole = 1 ; 132 | #else 133 | int tinyfd_forceConsole = 0 ; /* 0 (default) or 1 */ 134 | #endif 135 | /* for unix & windows: 0 (graphic mode) or 1 (console mode). 136 | 0: try to use a graphic solution, if it fails then it uses console mode. 137 | 1: forces all dialogs into console mode even when the X server is present, 138 | if the package dialog (and a console is present) or dialog.exe is installed. 139 | on windows it only make sense for console applications */ 140 | 141 | char tinyfd_response[1024]; 142 | /* if you pass "tinyfd_query" as aTitle, 143 | the functions will not display the dialogs 144 | but and return 0 for console mode, 1 for graphic mode. 145 | tinyfd_response is then filled with the retain solution. 146 | possible values for tinyfd_response are (all lowercase) 147 | for the graphic mode: 148 | windows applescript zenity zenity3 matedialog qarma kdialog 149 | tkinter gxmessage gmessage xmessage xdialog gdialog 150 | for the console mode: 151 | dialog whiptail basicinput */ 152 | 153 | #if defined(TINYFD_NOLIB) && defined(_WIN32) 154 | static int gWarningDisplayed = 1 ; 155 | #else 156 | static int gWarningDisplayed = 0 ; 157 | #endif 158 | 159 | static char gTitle[]="missing software! (we will try basic console input)"; 160 | 161 | #ifdef _WIN32 162 | static char gMessageWin[] = "\ 163 | ___________\n\ 164 | / \\ \n\ 165 | | tiny file |\n\ 166 | | dialogs |\n\ 167 | \\_____ ____/\n\ 168 | \\|\ 169 | tiny file dialogs on Windows needs:\ 170 | \n\ta graphic display\ 171 | \nor\tdialog.exe (enhanced console mode)\ 172 | \nor\ta console for basic input"; 173 | #else 174 | static char gMessageUnix[] = "\ 175 | ___________\n\ 176 | / \\ \n\ 177 | | tiny file |\n\ 178 | | dialogs |\n\ 179 | \\_____ ____/\n\ 180 | \\|\ 181 | \ntiny file dialogs on UNIX needs:\n\tapplescript\ 182 | \nor\tzenity / matedialog\ 183 | \nor\tqarma (zenity for qt)\ 184 | \nor\tkdialog\ 185 | \nor\tXdialog\ 186 | \nor\tpython 2 + tkinter\ 187 | \nor\tdialog (opens a console xterm if needed)\ 188 | \nor\txterm + bash (opens a console for basic input)\ 189 | \nor\tit will use the existing console for basic input"; 190 | #endif 191 | 192 | #ifdef _MSC_VER 193 | #pragma warning(disable:4996) /* allows usage of strncpy, strcpy, strcat, sprintf, fopen */ 194 | #pragma warning(disable:4100) /* allows usage of strncpy, strcpy, strcat, sprintf, fopen */ 195 | #pragma warning(disable:4706) /* allows usage of strncpy, strcpy, strcat, sprintf, fopen */ 196 | #endif 197 | 198 | static char * getPathWithoutFinalSlash( 199 | char * const aoDestination, /* make sure it is allocated, use _MAX_PATH */ 200 | char const * const aSource) /* aoDestination and aSource can be the same */ 201 | { 202 | char const * lTmp ; 203 | if ( aSource ) 204 | { 205 | lTmp = strrchr(aSource, '/'); 206 | if (!lTmp) 207 | { 208 | lTmp = strrchr(aSource, '\\'); 209 | } 210 | if (lTmp) 211 | { 212 | strncpy(aoDestination, aSource, lTmp - aSource ); 213 | aoDestination[lTmp - aSource] = '\0'; 214 | } 215 | else 216 | { 217 | * aoDestination = '\0'; 218 | } 219 | } 220 | else 221 | { 222 | * aoDestination = '\0'; 223 | } 224 | return aoDestination; 225 | } 226 | 227 | 228 | static char * getLastName( 229 | char * const aoDestination, /* make sure it is allocated */ 230 | char const * const aSource) 231 | { 232 | /* copy the last name after '/' or '\' */ 233 | char const * lTmp ; 234 | if ( aSource ) 235 | { 236 | lTmp = strrchr(aSource, '/'); 237 | if (!lTmp) 238 | { 239 | lTmp = strrchr(aSource, '\\'); 240 | } 241 | if (lTmp) 242 | { 243 | strcpy(aoDestination, lTmp + 1); 244 | } 245 | else 246 | { 247 | strcpy(aoDestination, aSource); 248 | } 249 | } 250 | else 251 | { 252 | * aoDestination = '\0'; 253 | } 254 | return aoDestination; 255 | } 256 | 257 | 258 | static void ensureFinalSlash ( char * const aioString ) 259 | { 260 | if ( aioString && strlen ( aioString ) ) 261 | { 262 | char * lastcar = aioString + strlen ( aioString ) - 1 ; 263 | if ( strncmp ( lastcar , SLASH , 1 ) ) 264 | { 265 | strcat ( lastcar , SLASH ) ; 266 | } 267 | } 268 | } 269 | 270 | 271 | static void Hex2RGB( char const aHexRGB [8] , 272 | unsigned char aoResultRGB [3] ) 273 | { 274 | char lColorChannel [8] ; 275 | if ( aoResultRGB ) 276 | { 277 | if ( aHexRGB ) 278 | { 279 | strcpy(lColorChannel, aHexRGB ) ; 280 | aoResultRGB[2] = (unsigned char)strtoul(lColorChannel+5,NULL,16); 281 | lColorChannel[5] = '\0'; 282 | aoResultRGB[1] = (unsigned char)strtoul(lColorChannel+3,NULL,16); 283 | lColorChannel[3] = '\0'; 284 | aoResultRGB[0] = (unsigned char)strtoul(lColorChannel+1,NULL,16); 285 | /* printf("%d %d %d\n", aoResultRGB[0], aoResultRGB[1], aoResultRGB[2]); */ 286 | } 287 | else 288 | { 289 | aoResultRGB[0]=0; 290 | aoResultRGB[1]=0; 291 | aoResultRGB[2]=0; 292 | } 293 | } 294 | } 295 | 296 | static void RGB2Hex( unsigned char const aRGB [3] , 297 | char aoResultHexRGB [8] ) 298 | { 299 | if ( aoResultHexRGB ) 300 | { 301 | if ( aRGB ) 302 | { 303 | #if defined(__GNUC__) && defined(_WIN32) 304 | sprintf(aoResultHexRGB, "#%02hx%02hx%02hx", 305 | #else 306 | sprintf(aoResultHexRGB, "#%02hhx%02hhx%02hhx", 307 | #endif 308 | aRGB[0], aRGB[1], aRGB[2]); 309 | /* printf("aoResultHexRGB %s\n", aoResultHexRGB); */ 310 | } 311 | else 312 | { 313 | aoResultHexRGB[0]=0; 314 | aoResultHexRGB[1]=0; 315 | aoResultHexRGB[2]=0; 316 | } 317 | } 318 | } 319 | 320 | 321 | static void replaceSubStr ( char const * const aSource , 322 | char const * const aOldSubStr , 323 | char const * const aNewSubStr , 324 | char * const aoDestination ) 325 | { 326 | char const * pOccurence ; 327 | char const * p ; 328 | char const * lNewSubStr = "" ; 329 | int lOldSubLen = strlen ( aOldSubStr ) ; 330 | 331 | if ( ! aSource ) 332 | { 333 | * aoDestination = '\0' ; 334 | return ; 335 | } 336 | if ( ! aOldSubStr ) 337 | { 338 | strcpy ( aoDestination , aSource ) ; 339 | return ; 340 | } 341 | if ( aNewSubStr ) 342 | { 343 | lNewSubStr = aNewSubStr ; 344 | } 345 | p = aSource ; 346 | * aoDestination = '\0' ; 347 | while ( ( pOccurence = strstr ( p , aOldSubStr ) ) != NULL ) 348 | { 349 | strncat ( aoDestination , p , pOccurence - p ) ; 350 | strcat ( aoDestination , lNewSubStr ) ; 351 | p = pOccurence + lOldSubLen ; 352 | } 353 | strcat ( aoDestination , p ) ; 354 | } 355 | 356 | 357 | static int filenameValid( char const * const aFileNameWithoutPath ) 358 | { 359 | if ( ! aFileNameWithoutPath 360 | || ! strlen(aFileNameWithoutPath) 361 | || strpbrk(aFileNameWithoutPath , "\\/:*?\"<>|") ) 362 | { 363 | return 0 ; 364 | } 365 | return 1 ; 366 | } 367 | 368 | 369 | static int fileExists( char const * const aFilePathAndName ) 370 | { 371 | FILE * lIn ; 372 | if ( ! aFilePathAndName || ! strlen(aFilePathAndName) ) 373 | { 374 | return 0 ; 375 | } 376 | lIn = fopen( aFilePathAndName , "r" ) ; 377 | if ( ! lIn ) 378 | { 379 | return 0 ; 380 | } 381 | fclose ( lIn ) ; 382 | return 1 ; 383 | } 384 | 385 | 386 | /* source and destination can be the same or ovelap*/ 387 | static char const * ensureFilesExist( char * const aDestination , 388 | char const * const aSourcePathsAndNames) 389 | { 390 | char * lDestination = aDestination ; 391 | char const * p ; 392 | char const * p2 ; 393 | int lLen ; 394 | 395 | if ( ! aSourcePathsAndNames ) 396 | { 397 | return NULL ; 398 | } 399 | lLen = strlen( aSourcePathsAndNames ) ; 400 | if ( ! lLen ) 401 | { 402 | return NULL ; 403 | } 404 | 405 | p = aSourcePathsAndNames ; 406 | while ( (p2 = strchr(p, '|')) != NULL ) 407 | { 408 | lLen = p2-p ; 409 | memmove(lDestination,p,lLen); 410 | lDestination[lLen] = '\0'; 411 | if ( fileExists ( lDestination ) ) 412 | { 413 | lDestination += lLen ; 414 | * lDestination = '|'; 415 | lDestination ++ ; 416 | } 417 | p = p2 + 1 ; 418 | } 419 | if ( fileExists ( p ) ) 420 | { 421 | lLen = strlen(p) ; 422 | memmove(lDestination,p,lLen); 423 | lDestination[lLen] = '\0'; 424 | } 425 | else 426 | { 427 | * (lDestination-1) = '\0'; 428 | } 429 | return aDestination ; 430 | } 431 | 432 | 433 | static void wipefile(char const * const aFilename) 434 | { 435 | int i; 436 | struct stat st; 437 | FILE * lIn; 438 | 439 | if (stat(aFilename, &st) == 0) 440 | { 441 | if ((lIn = fopen(aFilename, "w"))) 442 | { 443 | for (i = 0; i < st.st_size; i++) 444 | { 445 | fputc('A', lIn); 446 | } 447 | } 448 | fclose(lIn); 449 | } 450 | } 451 | 452 | #ifdef _WIN32 453 | 454 | static int replaceChr ( char * const aString , 455 | char const aOldChr , 456 | char const aNewChr ) 457 | { 458 | char * p ; 459 | int lRes = 0 ; 460 | 461 | if ( ! aString ) 462 | { 463 | return 0 ; 464 | } 465 | 466 | if ( aOldChr == aNewChr ) 467 | { 468 | return 0 ; 469 | } 470 | 471 | p = aString ; 472 | while ( (p = strchr ( p , aOldChr )) ) 473 | { 474 | * p = aNewChr ; 475 | p ++ ; 476 | lRes = 1 ; 477 | } 478 | return lRes ; 479 | } 480 | 481 | 482 | static int dirExists ( char const * const aDirPath ) 483 | { 484 | struct stat lInfo; 485 | if ( ! aDirPath || ! strlen ( aDirPath ) ) 486 | return 0 ; 487 | if ( stat ( aDirPath , & lInfo ) != 0 ) 488 | return 0 ; 489 | else if ( lInfo.st_mode & S_IFDIR ) 490 | return 1 ; 491 | else 492 | return 0 ; 493 | } 494 | 495 | #ifndef TINYFD_NOLIB 496 | 497 | static wchar_t * getPathWithoutFinalSlashW( 498 | wchar_t * const aoDestination, /* make sure it is allocated, use _MAX_PATH */ 499 | wchar_t const * const aSource) /* aoDestination and aSource can be the same */ 500 | { 501 | wchar_t const * lTmp; 502 | if (aSource) 503 | { 504 | lTmp = wcsrchr(aSource, L'/'); 505 | if (!lTmp) 506 | { 507 | lTmp = wcsrchr(aSource, L'\\'); 508 | } 509 | if (lTmp) 510 | { 511 | wcsncpy(aoDestination, aSource, lTmp - aSource); 512 | aoDestination[lTmp - aSource] = L'\0'; 513 | } 514 | else 515 | { 516 | *aoDestination = L'\0'; 517 | } 518 | } 519 | else 520 | { 521 | *aoDestination = L'\0'; 522 | } 523 | return aoDestination; 524 | } 525 | 526 | 527 | static wchar_t * getLastNameW( 528 | wchar_t * const aoDestination, /* make sure it is allocated */ 529 | wchar_t const * const aSource) 530 | { 531 | /* copy the last name after '/' or '\' */ 532 | wchar_t const * lTmp; 533 | if (aSource) 534 | { 535 | lTmp = wcsrchr(aSource, L'/'); 536 | if (!lTmp) 537 | { 538 | lTmp = wcsrchr(aSource, L'\\'); 539 | } 540 | if (lTmp) 541 | { 542 | wcscpy(aoDestination, lTmp + 1); 543 | } 544 | else 545 | { 546 | wcscpy(aoDestination, aSource); 547 | } 548 | } 549 | else 550 | { 551 | *aoDestination = L'\0'; 552 | } 553 | return aoDestination; 554 | } 555 | 556 | 557 | static void Hex2RGBW(wchar_t const aHexRGB[8], 558 | unsigned char aoResultRGB[3]) 559 | { 560 | wchar_t lColorChannel[8]; 561 | if (aoResultRGB) 562 | { 563 | if (aHexRGB) 564 | { 565 | wcscpy(lColorChannel, aHexRGB); 566 | aoResultRGB[2] = (unsigned char)wcstoul(lColorChannel + 5, NULL, 16); 567 | lColorChannel[5] = '\0'; 568 | aoResultRGB[1] = (unsigned char)wcstoul(lColorChannel + 3, NULL, 16); 569 | lColorChannel[3] = '\0'; 570 | aoResultRGB[0] = (unsigned char)wcstoul(lColorChannel + 1, NULL, 16); 571 | /* printf("%d %d %d\n", aoResultRGB[0], aoResultRGB[1], aoResultRGB[2]); */ 572 | } 573 | else 574 | { 575 | aoResultRGB[0] = 0; 576 | aoResultRGB[1] = 0; 577 | aoResultRGB[2] = 0; 578 | } 579 | } 580 | } 581 | 582 | 583 | static void RGB2HexW( 584 | unsigned char const aRGB[3], 585 | wchar_t aoResultHexRGB[8]) 586 | { 587 | if (aoResultHexRGB) 588 | { 589 | if (aRGB) 590 | { 591 | #if defined(__GNUC__) && __GNUC__ < 5 592 | swprintf(aoResultHexRGB, L"#%02hhx%02hhx%02hhx", aRGB[0], aRGB[1], aRGB[2]); 593 | #else 594 | swprintf(aoResultHexRGB, 8, L"#%02hhx%02hhx%02hhx", aRGB[0], aRGB[1], aRGB[2]); 595 | #endif 596 | /* wprintf(L"aoResultHexRGB %s\n", aoResultHexRGB); */ 597 | } 598 | else 599 | { 600 | aoResultHexRGB[0] = 0; 601 | aoResultHexRGB[1] = 0; 602 | aoResultHexRGB[2] = 0; 603 | } 604 | } 605 | } 606 | 607 | 608 | #if !defined(WC_ERR_INVALID_CHARS) 609 | /* undefined prior to Vista, so not yet in MINGW header file */ 610 | #define WC_ERR_INVALID_CHARS 0x00000080 611 | #endif 612 | 613 | 614 | static int sizeUtf16(char const * const aUtf8string) 615 | { 616 | return MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, 617 | aUtf8string, -1, NULL, 0); 618 | } 619 | 620 | 621 | static int sizeUtf8(wchar_t const * const aUtf16string) 622 | { 623 | return WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, 624 | aUtf16string, -1, NULL, 0, NULL, NULL); 625 | } 626 | 627 | 628 | static wchar_t * utf8to16(char const * const aUtf8string) 629 | { 630 | wchar_t * lUtf16string ; 631 | int lSize = sizeUtf16(aUtf8string); 632 | lUtf16string = (wchar_t *) malloc( lSize * sizeof(wchar_t) ); 633 | lSize = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, 634 | aUtf8string, -1, lUtf16string, lSize); 635 | if (lSize == 0) 636 | { 637 | free(lUtf16string); 638 | return NULL; 639 | } 640 | return lUtf16string; 641 | } 642 | 643 | 644 | static char * utf16to8(wchar_t const * const aUtf16string) 645 | { 646 | char * lUtf8string ; 647 | int lSize = sizeUtf8(aUtf16string); 648 | lUtf8string = (char *) malloc( lSize ); 649 | lSize = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, 650 | aUtf16string, -1, lUtf8string, lSize, NULL, NULL); 651 | if (lSize == 0) 652 | { 653 | free(lUtf8string); 654 | return NULL; 655 | } 656 | return lUtf8string; 657 | } 658 | 659 | 660 | static void runSilentA(char const * const aString) 661 | { 662 | STARTUPINFOA StartupInfo; 663 | PROCESS_INFORMATION ProcessInfo; 664 | char * lArgs; 665 | char * pEnvCMD = NULL; 666 | char * pDefaultCMD = "CMD.EXE"; 667 | ULONG rc; 668 | int lStringLen = 0; 669 | 670 | memset(&StartupInfo, 0, sizeof(StartupInfo)); 671 | StartupInfo.cb = sizeof(STARTUPINFOA); 672 | StartupInfo.dwFlags = STARTF_USESHOWWINDOW; 673 | StartupInfo.wShowWindow = SW_HIDE; 674 | 675 | if ( aString ) 676 | { 677 | lStringLen = strlen(aString); 678 | } 679 | lArgs = (char *) malloc( MAX_PATH_OR_CMD + lStringLen ); 680 | 681 | pEnvCMD = getenv("COMSPEC"); 682 | 683 | if (pEnvCMD){ 684 | 685 | strcpy(lArgs, pEnvCMD); 686 | } 687 | else{ 688 | strcpy(lArgs, pDefaultCMD); 689 | } 690 | 691 | /* c to execute then terminate the command window */ 692 | strcat(lArgs, " /c "); 693 | 694 | /* application and parameters to run from the command window */ 695 | strcat(lArgs, aString); 696 | 697 | if (!CreateProcessA(NULL, lArgs, NULL, NULL, FALSE, 698 | CREATE_NEW_CONSOLE, NULL, NULL, 699 | &StartupInfo, &ProcessInfo)) 700 | { 701 | free(lArgs); 702 | return; /* GetLastError(); */ 703 | } 704 | 705 | WaitForSingleObject(ProcessInfo.hProcess, INFINITE); 706 | if (!GetExitCodeProcess(ProcessInfo.hProcess, &rc)) 707 | rc = 0; 708 | 709 | CloseHandle(ProcessInfo.hThread); 710 | CloseHandle(ProcessInfo.hProcess); 711 | 712 | free(lArgs); 713 | return; /* rc */ 714 | } 715 | 716 | 717 | static void runSilentW(wchar_t const * const aString) 718 | { 719 | STARTUPINFOW StartupInfo; 720 | PROCESS_INFORMATION ProcessInfo; 721 | ULONG rc; 722 | wchar_t * lArgs; 723 | wchar_t * pEnvCMD; 724 | wchar_t * pDefaultCMD = L"CMD.EXE"; 725 | int lStringLen = 0; 726 | 727 | memset(&StartupInfo, 0, sizeof(StartupInfo)); 728 | StartupInfo.cb = sizeof(STARTUPINFOW); 729 | StartupInfo.dwFlags = STARTF_USESHOWWINDOW; 730 | StartupInfo.wShowWindow = SW_HIDE; 731 | 732 | if ( aString ) 733 | { 734 | lStringLen = wcslen(aString); 735 | } 736 | lArgs = (wchar_t *) malloc( (MAX_PATH_OR_CMD + lStringLen) * sizeof(wchar_t) ); 737 | 738 | pEnvCMD = utf8to16( getenv("COMSPEC") ); 739 | if (pEnvCMD) 740 | { 741 | wcscpy(lArgs, pEnvCMD); 742 | free(pEnvCMD); 743 | } 744 | else 745 | { 746 | wcscpy(lArgs, pDefaultCMD); 747 | } 748 | 749 | /* c to execute then terminate the command window */ 750 | wcscat(lArgs, L" /c "); 751 | 752 | /* application and parameters to run from the command window */ 753 | wcscat(lArgs, aString); 754 | 755 | if (!CreateProcessW(NULL, lArgs, NULL, NULL, FALSE, 756 | CREATE_NEW_CONSOLE, NULL, NULL, 757 | &StartupInfo, &ProcessInfo)) 758 | { 759 | free(lArgs); 760 | return; /* GetLastError(); */ 761 | } 762 | 763 | WaitForSingleObject(ProcessInfo.hProcess, INFINITE); 764 | if (!GetExitCodeProcess(ProcessInfo.hProcess, &rc)) 765 | { 766 | rc = 0; 767 | } 768 | 769 | CloseHandle(ProcessInfo.hThread); 770 | CloseHandle(ProcessInfo.hProcess); 771 | 772 | free(lArgs); 773 | return; /* rc */ 774 | } 775 | 776 | 777 | int tinyfd_messageBoxW( 778 | wchar_t const * const aTitle, /* NULL or "" */ 779 | wchar_t const * const aMessage, /* NULL or "" may contain \n and \t */ 780 | wchar_t const * const aDialogType, /* "ok" "okcancel" "yesno" "yesnocancel" */ 781 | wchar_t const * const aIconType, /* "info" "warning" "error" "question" */ 782 | int const aDefaultButton) /* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */ 783 | { 784 | int lBoxReturnValue; 785 | UINT aCode; 786 | 787 | if (aIconType && !wcscmp(L"warning", aIconType)) 788 | { 789 | aCode = MB_ICONWARNING; 790 | } 791 | else if (aIconType && !wcscmp(L"error", aIconType)) 792 | { 793 | aCode = MB_ICONERROR; 794 | } 795 | else if (aIconType && !wcscmp(L"question", aIconType)) 796 | { 797 | aCode = MB_ICONQUESTION; 798 | } 799 | else 800 | { 801 | aCode = MB_ICONINFORMATION; 802 | } 803 | 804 | if (aDialogType && !wcscmp(L"okcancel", aDialogType)) 805 | { 806 | aCode += MB_OKCANCEL; 807 | if (!aDefaultButton) 808 | { 809 | aCode += MB_DEFBUTTON2; 810 | } 811 | } 812 | else if (aDialogType && !wcscmp(L"yesno", aDialogType)) 813 | { 814 | aCode += MB_YESNO; 815 | if (!aDefaultButton) 816 | { 817 | aCode += MB_DEFBUTTON2; 818 | } 819 | } 820 | else 821 | { 822 | aCode += MB_OK; 823 | } 824 | 825 | lBoxReturnValue = MessageBoxW(NULL, aMessage, aTitle, aCode); 826 | if (((aDialogType 827 | && wcscmp(L"okcancel", aDialogType) 828 | && wcscmp(L"yesno", aDialogType))) 829 | || (lBoxReturnValue == IDOK) 830 | || (lBoxReturnValue == IDYES)) 831 | { 832 | return 1; 833 | } 834 | else 835 | { 836 | return 0; 837 | } 838 | } 839 | 840 | 841 | static int messageBoxWinGui8( 842 | char const * const aTitle, /* NULL or "" */ 843 | char const * const aMessage, /* NULL or "" may contain \n and \t */ 844 | char const * const aDialogType, /* "ok" "okcancel" "yesno" "yesnocancel" */ 845 | char const * const aIconType, /* "info" "warning" "error" "question" */ 846 | int const aDefaultButton) /* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */ 847 | { 848 | int lIntRetVal; 849 | wchar_t * lTitle; 850 | wchar_t * lMessage; 851 | wchar_t * lDialogType; 852 | wchar_t * lIconType; 853 | 854 | lTitle = utf8to16(aTitle); 855 | lMessage = utf8to16(aMessage); 856 | lDialogType = utf8to16(aDialogType); 857 | lIconType = utf8to16(aIconType); 858 | 859 | lIntRetVal = tinyfd_messageBoxW(lTitle, lMessage, 860 | lDialogType, lIconType, aDefaultButton ); 861 | 862 | free(lTitle); 863 | free(lMessage); 864 | free(lDialogType); 865 | free(lIconType); 866 | 867 | return lIntRetVal ; 868 | } 869 | 870 | 871 | static char const * inputBoxWinGui( 872 | char * const aoBuff , 873 | char const * const aTitle , /* NULL or "" */ 874 | char const * const aMessage , /* NULL or "" may NOT contain \n nor \t */ 875 | char const * const aDefaultInput ) /* "" , if NULL it's a passwordBox */ 876 | { 877 | char * lDialogString; 878 | FILE * lIn; 879 | int lResult; 880 | int lTitleLen; 881 | int lMessageLen; 882 | wchar_t * lDialogStringW; 883 | 884 | lTitleLen = aTitle ? strlen(aTitle) : 0 ; 885 | lMessageLen = aMessage ? strlen(aMessage) : 0 ; 886 | lDialogString = (char *)malloc(3 * MAX_PATH_OR_CMD + lTitleLen + lMessageLen); 887 | 888 | if (aDefaultInput) 889 | { 890 | sprintf(lDialogString, "%s\\AppData\\Local\\Temp\\tinyfd.vbs", 891 | getenv("USERPROFILE")); 892 | } 893 | else 894 | { 895 | sprintf(lDialogString, "%s\\AppData\\Local\\Temp\\tinyfd.hta", 896 | getenv("USERPROFILE")); 897 | } 898 | lIn = fopen(lDialogString, "w"); 899 | if (!lIn) 900 | { 901 | free(lDialogString); 902 | return NULL; 903 | } 904 | 905 | if ( aDefaultInput ) 906 | { 907 | strcpy(lDialogString, "Dim result:result=InputBox(\""); 908 | if (aMessage && strlen(aMessage)) 909 | { 910 | strcat(lDialogString, aMessage); 911 | } 912 | strcat(lDialogString, "\",\""); 913 | if (aTitle && strlen(aTitle)) 914 | { 915 | strcat(lDialogString, aTitle); 916 | } 917 | strcat(lDialogString, "\",\""); 918 | if (aDefaultInput && strlen(aDefaultInput)) 919 | { 920 | strcat(lDialogString, aDefaultInput); 921 | } 922 | strcat(lDialogString, "\"):If IsEmpty(result) then:WScript.Echo 0"); 923 | strcat(lDialogString, ":Else: WScript.Echo \"1\" & result : End If"); 924 | } 925 | else 926 | { 927 | sprintf(lDialogString, "\n\ 928 | \n\ 929 | \n\ 930 | %s\n\ 931 | \n\ 940 | \n\ 941 | \n\ 984 | \n\ 985 | \n\ 986 | \n\ 987 | \n\ 988 | \n\ 991 | \n\ 999 | \n\ 1000 |
\n\ 989 | %s\n\ 990 | \n\ 992 | \n\ 993 | \n\ 994 |
\n\ 995 |

\n\ 996 | \n\ 997 |
\n\ 998 |
\n\ 1001 | \n\ 1002 | \n\ 1003 | \n\ 1007 | \n\ 1008 |
\n\ 1004 |
\n\ 1006 |
\n\ 1009 | \n\ 1010 | \n\ 1011 | " , aTitle ? aTitle : "", aMessage ? aMessage : "") ; 1012 | } 1013 | fputs(lDialogString, lIn); 1014 | fclose(lIn); 1015 | 1016 | strcpy(lDialogString, ""); 1017 | 1018 | if (aDefaultInput) 1019 | { 1020 | strcat(lDialogString, "cscript.exe "); 1021 | strcat(lDialogString, "//Nologo "); 1022 | strcat(lDialogString,"%USERPROFILE%\\AppData\\Local\\Temp\\tinyfd.vbs"); 1023 | strcat(lDialogString, " > %USERPROFILE%\\AppData\\Local\\Temp\\tinyfd.txt"); 1024 | } 1025 | else 1026 | { 1027 | strcat(lDialogString, 1028 | "mshta.exe %USERPROFILE%\\AppData\\Local\\Temp\\tinyfd.hta"); 1029 | } 1030 | 1031 | /* printf ( "lDialogString: %s\n" , lDialogString ) ; */ 1032 | 1033 | if (tinyfd_winUtf8) 1034 | { 1035 | lDialogStringW = utf8to16(lDialogString); 1036 | runSilentW(lDialogStringW); 1037 | free(lDialogStringW); 1038 | } 1039 | else 1040 | { 1041 | runSilentA(lDialogString); 1042 | } 1043 | 1044 | /* 1045 | if (!(lIn = _popen(lDialogString, "r"))) 1046 | { 1047 | free(lDialogString); 1048 | return NULL; 1049 | } 1050 | while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL) 1051 | { 1052 | } 1053 | _pclose(lIn); 1054 | if (aoBuff[strlen(aoBuff) - 1] == '\n') 1055 | { 1056 | aoBuff[strlen(aoBuff) - 1] = '\0'; 1057 | } 1058 | */ 1059 | 1060 | if (aDefaultInput) 1061 | { 1062 | sprintf(lDialogString, "%s\\AppData\\Local\\Temp\\tinyfd.txt", 1063 | getenv("USERPROFILE")); 1064 | if (!(lIn = fopen(lDialogString, "r"))) 1065 | { 1066 | remove(lDialogString); 1067 | free(lDialogString); 1068 | return NULL; 1069 | } 1070 | while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL) 1071 | {} 1072 | fclose(lIn); 1073 | remove(lDialogString); 1074 | 1075 | sprintf(lDialogString, "%s\\AppData\\Local\\Temp\\tinyfd.vbs", 1076 | getenv("USERPROFILE")); 1077 | } 1078 | else 1079 | { 1080 | sprintf(lDialogString, "%s\\AppData\\Local\\Temp\\tinyfd.txt", 1081 | getenv("USERPROFILE")); 1082 | if (!(lIn = fopen(lDialogString, "r"))) 1083 | { 1084 | remove(lDialogString); 1085 | free(lDialogString); 1086 | return NULL; 1087 | } 1088 | while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL) 1089 | {} 1090 | fclose(lIn); 1091 | 1092 | wipefile(lDialogString); 1093 | remove(lDialogString); 1094 | sprintf(lDialogString, "%s\\AppData\\Local\\Temp\\tinyfd.hta", 1095 | getenv("USERPROFILE")); 1096 | } 1097 | remove(lDialogString); 1098 | free(lDialogString); 1099 | /* printf ( "aoBuff: %s\n" , aoBuff ) ; */ 1100 | lResult = strncmp(aoBuff, "1", 1) ? 0 : 1; 1101 | /* printf ( "lResult: %d \n" , lResult ) ; */ 1102 | if (!lResult) 1103 | { 1104 | return NULL ; 1105 | } 1106 | 1107 | if (aoBuff[strlen(aoBuff) - 1] == '\n') 1108 | { 1109 | aoBuff[strlen(aoBuff) - 1] = '\0'; 1110 | } 1111 | 1112 | /* printf ( "aoBuff+1: %s\n" , aoBuff+1 ) ; */ 1113 | return aoBuff + 1; 1114 | } 1115 | 1116 | 1117 | wchar_t const * tinyfd_saveFileDialogW( 1118 | wchar_t const * const aTitle, /* NULL or "" */ 1119 | wchar_t const * const aDefaultPathAndFile, /* NULL or "" */ 1120 | int const aNumOfFilterPatterns, /* 0 */ 1121 | wchar_t const * const * const aFilterPatterns, /* NULL or {"*.jpg","*.png"} */ 1122 | wchar_t const * const aSingleFilterDescription) /* NULL or "image files" */ 1123 | { 1124 | static wchar_t lBuff[MAX_PATH_OR_CMD]; 1125 | wchar_t lDirname[MAX_PATH_OR_CMD]; 1126 | wchar_t lDialogString[MAX_PATH_OR_CMD]; 1127 | wchar_t lFilterPatterns[MAX_PATH_OR_CMD] = L""; 1128 | wchar_t * p; 1129 | wchar_t * lRetval; 1130 | int i; 1131 | HRESULT lHResult; 1132 | OPENFILENAMEW ofn = {0}; 1133 | 1134 | lHResult = CoInitializeEx(NULL, 0); 1135 | 1136 | getPathWithoutFinalSlashW(lDirname, aDefaultPathAndFile); 1137 | getLastNameW(lBuff, aDefaultPathAndFile); 1138 | 1139 | if (aNumOfFilterPatterns > 0) 1140 | { 1141 | if (aSingleFilterDescription && wcslen(aSingleFilterDescription)) 1142 | { 1143 | wcscpy(lFilterPatterns, aSingleFilterDescription); 1144 | wcscat(lFilterPatterns, L"\n"); 1145 | } 1146 | wcscat(lFilterPatterns, aFilterPatterns[0]); 1147 | for (i = 1; i < aNumOfFilterPatterns; i++) 1148 | { 1149 | wcscat(lFilterPatterns, L";"); 1150 | wcscat(lFilterPatterns, aFilterPatterns[i]); 1151 | } 1152 | wcscat(lFilterPatterns, L"\n"); 1153 | if (!(aSingleFilterDescription && wcslen(aSingleFilterDescription))) 1154 | { 1155 | wcscpy(lDialogString, lFilterPatterns); 1156 | wcscat(lFilterPatterns, lDialogString); 1157 | } 1158 | wcscat(lFilterPatterns, L"All Files\n*.*\n"); 1159 | p = lFilterPatterns; 1160 | while ((p = wcschr(p, L'\n')) != NULL) 1161 | { 1162 | *p = L'\0'; 1163 | p++; 1164 | } 1165 | } 1166 | 1167 | ofn.lStructSize = sizeof(OPENFILENAMEW); 1168 | ofn.hwndOwner = 0; 1169 | ofn.hInstance = 0; 1170 | ofn.lpstrFilter = lFilterPatterns && wcslen(lFilterPatterns) ? lFilterPatterns : NULL; 1171 | ofn.lpstrCustomFilter = NULL; 1172 | ofn.nMaxCustFilter = 0; 1173 | ofn.nFilterIndex = 1; 1174 | ofn.lpstrFile = lBuff; 1175 | 1176 | ofn.nMaxFile = MAX_PATH_OR_CMD; 1177 | ofn.lpstrFileTitle = NULL; 1178 | ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT; 1179 | ofn.lpstrInitialDir = lDirname && wcslen(lDirname) ? lDirname : NULL; 1180 | ofn.lpstrTitle = aTitle && wcslen(aTitle) ? aTitle : NULL; 1181 | ofn.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR; 1182 | ofn.nFileOffset = 0; 1183 | ofn.nFileExtension = 0; 1184 | ofn.lpstrDefExt = NULL; 1185 | ofn.lCustData = 0L; 1186 | ofn.lpfnHook = NULL; 1187 | ofn.lpTemplateName = NULL; 1188 | 1189 | if (GetSaveFileNameW(&ofn) == 0) 1190 | { 1191 | lRetval = NULL; 1192 | } 1193 | else 1194 | { 1195 | lRetval = lBuff; 1196 | } 1197 | 1198 | if (lHResult == S_OK || lHResult == S_FALSE) 1199 | { 1200 | CoUninitialize(); 1201 | } 1202 | return lRetval; 1203 | } 1204 | 1205 | 1206 | static char const * saveFileDialogWinGui8( 1207 | char * const aoBuff, 1208 | char const * const aTitle, /* NULL or "" */ 1209 | char const * const aDefaultPathAndFile, /* NULL or "" */ 1210 | int const aNumOfFilterPatterns, /* 0 */ 1211 | char const * const * const aFilterPatterns, /* NULL or {"*.jpg","*.png"} */ 1212 | char const * const aSingleFilterDescription) /* NULL or "image files" */ 1213 | { 1214 | wchar_t * lTitle; 1215 | wchar_t * lDefaultPathAndFile; 1216 | wchar_t * lSingleFilterDescription; 1217 | wchar_t * * lFilterPatterns; 1218 | wchar_t const * lTmpWChar; 1219 | char * lTmpChar; 1220 | int i ; 1221 | 1222 | lFilterPatterns = (wchar_t **) malloc(aNumOfFilterPatterns*sizeof(wchar_t *)); 1223 | for (i = 0; i < aNumOfFilterPatterns; i++) 1224 | { 1225 | lFilterPatterns[i] = utf8to16(aFilterPatterns[i]); 1226 | } 1227 | 1228 | lTitle = utf8to16(aTitle); 1229 | lDefaultPathAndFile = utf8to16(aDefaultPathAndFile); 1230 | lSingleFilterDescription = utf8to16(aSingleFilterDescription); 1231 | 1232 | lTmpWChar = tinyfd_saveFileDialogW( 1233 | lTitle, 1234 | lDefaultPathAndFile, 1235 | aNumOfFilterPatterns, 1236 | (wchar_t const** ) /*stupid cast for gcc*/ 1237 | lFilterPatterns, 1238 | lSingleFilterDescription); 1239 | 1240 | free(lTitle); 1241 | free(lDefaultPathAndFile); 1242 | free(lSingleFilterDescription); 1243 | for (i = 0; i < aNumOfFilterPatterns; i++) 1244 | { 1245 | free(lFilterPatterns[i]); 1246 | } 1247 | free(lFilterPatterns); 1248 | 1249 | if (!lTmpWChar) 1250 | { 1251 | return NULL; 1252 | } 1253 | 1254 | lTmpChar = utf16to8(lTmpWChar); 1255 | strcpy(aoBuff, lTmpChar); 1256 | free(lTmpChar); 1257 | 1258 | return aoBuff; 1259 | } 1260 | 1261 | 1262 | wchar_t const * tinyfd_openFileDialogW( 1263 | wchar_t const * const aTitle, /* NULL or "" */ 1264 | wchar_t const * const aDefaultPathAndFile, /* NULL or "" */ 1265 | int const aNumOfFilterPatterns, /* 0 */ 1266 | wchar_t const * const * const aFilterPatterns, /* NULL or {"*.jpg","*.png"} */ 1267 | wchar_t const * const aSingleFilterDescription, /* NULL or "image files" */ 1268 | int const aAllowMultipleSelects) /* 0 or 1 */ 1269 | { 1270 | static wchar_t lBuff[MAX_MULTIPLE_FILES*MAX_PATH_OR_CMD]; 1271 | 1272 | size_t lLengths[MAX_MULTIPLE_FILES]; 1273 | wchar_t lDirname[MAX_PATH_OR_CMD]; 1274 | wchar_t lFilterPatterns[MAX_PATH_OR_CMD] = L""; 1275 | wchar_t lDialogString[MAX_PATH_OR_CMD]; 1276 | wchar_t * lPointers[MAX_MULTIPLE_FILES]; 1277 | wchar_t * lRetval, * p; 1278 | int i, j; 1279 | size_t lBuffLen; 1280 | HRESULT lHResult; 1281 | OPENFILENAMEW ofn = { 0 }; 1282 | 1283 | lHResult = CoInitializeEx(NULL, 0); 1284 | 1285 | getPathWithoutFinalSlashW(lDirname, aDefaultPathAndFile); 1286 | getLastNameW(lBuff, aDefaultPathAndFile); 1287 | 1288 | if (aNumOfFilterPatterns > 0) 1289 | { 1290 | if (aSingleFilterDescription && wcslen(aSingleFilterDescription)) 1291 | { 1292 | wcscpy(lFilterPatterns, aSingleFilterDescription); 1293 | wcscat(lFilterPatterns, L"\n"); 1294 | } 1295 | wcscat(lFilterPatterns, aFilterPatterns[0]); 1296 | for (i = 1; i < aNumOfFilterPatterns; i++) 1297 | { 1298 | wcscat(lFilterPatterns, L";"); 1299 | wcscat(lFilterPatterns, aFilterPatterns[i]); 1300 | } 1301 | wcscat(lFilterPatterns, L"\n"); 1302 | if (!(aSingleFilterDescription && wcslen(aSingleFilterDescription))) 1303 | { 1304 | wcscpy(lDialogString, lFilterPatterns); 1305 | wcscat(lFilterPatterns, lDialogString); 1306 | } 1307 | wcscat(lFilterPatterns, L"All Files\n*.*\n"); 1308 | p = lFilterPatterns; 1309 | while ((p = wcschr(p, L'\n')) != NULL) 1310 | { 1311 | *p = L'\0'; 1312 | p++; 1313 | } 1314 | } 1315 | 1316 | ofn.lStructSize = sizeof(OPENFILENAME); 1317 | ofn.hwndOwner = 0; 1318 | ofn.hInstance = 0; 1319 | ofn.lpstrFilter = lFilterPatterns && wcslen(lFilterPatterns) ? lFilterPatterns : NULL; 1320 | ofn.lpstrCustomFilter = NULL; 1321 | ofn.nMaxCustFilter = 0; 1322 | ofn.nFilterIndex = 1; 1323 | ofn.lpstrFile = lBuff; 1324 | ofn.nMaxFile = MAX_PATH_OR_CMD; 1325 | ofn.lpstrFileTitle = NULL; 1326 | ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT; 1327 | ofn.lpstrInitialDir = lDirname && wcslen(lDirname) ? lDirname : NULL; 1328 | ofn.lpstrTitle = aTitle && wcslen(aTitle) ? aTitle : NULL; 1329 | ofn.Flags = OFN_EXPLORER | OFN_NOCHANGEDIR; 1330 | ofn.nFileOffset = 0; 1331 | ofn.nFileExtension = 0; 1332 | ofn.lpstrDefExt = NULL; 1333 | ofn.lCustData = 0L; 1334 | ofn.lpfnHook = NULL; 1335 | ofn.lpTemplateName = NULL; 1336 | 1337 | if (aAllowMultipleSelects) 1338 | { 1339 | ofn.Flags |= OFN_ALLOWMULTISELECT; 1340 | } 1341 | 1342 | if (GetOpenFileNameW(&ofn) == 0) 1343 | { 1344 | lRetval = NULL; 1345 | } 1346 | else 1347 | { 1348 | lBuffLen = wcslen(lBuff); 1349 | lPointers[0] = lBuff + lBuffLen + 1; 1350 | if (!aAllowMultipleSelects || (lPointers[0][0] == L'\0')) 1351 | { 1352 | lRetval = lBuff; 1353 | } 1354 | else 1355 | { 1356 | i = 0; 1357 | do 1358 | { 1359 | lLengths[i] = wcslen(lPointers[i]); 1360 | lPointers[i + 1] = lPointers[i] + lLengths[i] + 1; 1361 | i++; 1362 | } while (lPointers[i][0] != L'\0'); 1363 | i--; 1364 | p = lBuff + MAX_MULTIPLE_FILES*MAX_PATH_OR_CMD - 1; 1365 | *p = L'\0'; 1366 | for (j = i; j >= 0; j--) 1367 | { 1368 | p -= lLengths[j]; 1369 | memmove(p, lPointers[j], lLengths[j]*sizeof(wchar_t)); 1370 | p--; 1371 | *p = L'\\'; 1372 | p -= lBuffLen; 1373 | memmove(p, lBuff, lBuffLen*sizeof(wchar_t)); 1374 | p--; 1375 | *p = L'|'; 1376 | } 1377 | p++; 1378 | lRetval = p; 1379 | } 1380 | } 1381 | 1382 | if (lHResult == S_OK || lHResult == S_FALSE) 1383 | { 1384 | CoUninitialize(); 1385 | } 1386 | return lRetval; 1387 | } 1388 | 1389 | 1390 | static char const * openFileDialogWinGui8( 1391 | char * const aoBuff, 1392 | char const * const aTitle, /* NULL or "" */ 1393 | char const * const aDefaultPathAndFile, /* NULL or "" */ 1394 | int const aNumOfFilterPatterns, /* 0 */ 1395 | char const * const * const aFilterPatterns, /* NULL or {"*.jpg","*.png"} */ 1396 | char const * const aSingleFilterDescription, /* NULL or "image files" */ 1397 | int const aAllowMultipleSelects) /* 0 or 1 */ 1398 | { 1399 | wchar_t * lTitle; 1400 | wchar_t * lDefaultPathAndFile; 1401 | wchar_t * lSingleFilterDescription; 1402 | wchar_t * * lFilterPatterns; 1403 | wchar_t const * lTmpWChar; 1404 | char * lTmpChar; 1405 | int i; 1406 | 1407 | lFilterPatterns = (wchar_t * *) malloc(aNumOfFilterPatterns*sizeof(wchar_t *)); 1408 | for (i = 0; i < aNumOfFilterPatterns; i++) 1409 | { 1410 | lFilterPatterns[i] = utf8to16(aFilterPatterns[i]); 1411 | } 1412 | 1413 | lTitle = utf8to16(aTitle); 1414 | lDefaultPathAndFile = utf8to16(aDefaultPathAndFile); 1415 | lSingleFilterDescription = utf8to16(aSingleFilterDescription); 1416 | 1417 | lTmpWChar = tinyfd_openFileDialogW( 1418 | lTitle, 1419 | lDefaultPathAndFile, 1420 | aNumOfFilterPatterns, 1421 | (wchar_t const**) /*stupid cast for gcc*/ 1422 | lFilterPatterns, 1423 | lSingleFilterDescription, 1424 | aAllowMultipleSelects); 1425 | 1426 | free(lTitle); 1427 | free(lDefaultPathAndFile); 1428 | free(lSingleFilterDescription); 1429 | for (i = 0; i < aNumOfFilterPatterns; i++) 1430 | { 1431 | free(lFilterPatterns[i]); 1432 | } 1433 | free(lFilterPatterns); 1434 | 1435 | if (!lTmpWChar) 1436 | { 1437 | return NULL; 1438 | } 1439 | 1440 | lTmpChar = utf16to8(lTmpWChar); 1441 | strcpy(aoBuff, lTmpChar); 1442 | free(lTmpChar); 1443 | 1444 | return aoBuff; 1445 | } 1446 | 1447 | #ifndef TINYFD_NOSELECTFOLDERWIN 1448 | static int __stdcall BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) 1449 | { 1450 | if (uMsg == BFFM_INITIALIZED) 1451 | { 1452 | SendMessage(hwnd, BFFM_SETSELECTION, TRUE, pData); 1453 | } 1454 | return 0; 1455 | } 1456 | 1457 | static int __stdcall BrowseCallbackProcW(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) 1458 | { 1459 | if (uMsg == BFFM_INITIALIZED) 1460 | { 1461 | SendMessage(hwnd, BFFM_SETSELECTIONW, TRUE, (LPARAM)pData); 1462 | } 1463 | return 0; 1464 | } 1465 | 1466 | wchar_t const * tinyfd_selectFolderDialogW( 1467 | wchar_t const * const aTitle, /* NULL or "" */ 1468 | wchar_t const * const aDefaultPath) /* NULL or "" */ 1469 | { 1470 | static wchar_t lBuff[MAX_PATH_OR_CMD]; 1471 | 1472 | BROWSEINFOW bInfo; 1473 | LPITEMIDLIST lpItem; 1474 | HRESULT lHResult; 1475 | 1476 | lHResult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 1477 | 1478 | bInfo.hwndOwner = 0; 1479 | bInfo.pidlRoot = NULL; 1480 | bInfo.pszDisplayName = lBuff; 1481 | bInfo.lpszTitle = aTitle && wcslen(aTitle) ? aTitle : NULL; 1482 | if (lHResult == S_OK || lHResult == S_FALSE) 1483 | { 1484 | bInfo.ulFlags = BIF_USENEWUI; 1485 | } 1486 | bInfo.lpfn = BrowseCallbackProcW; 1487 | bInfo.lParam = (LPARAM)aDefaultPath; 1488 | bInfo.iImage = -1; 1489 | 1490 | lpItem = SHBrowseForFolderW(&bInfo); 1491 | if (lpItem) 1492 | { 1493 | SHGetPathFromIDListW(lpItem, lBuff); 1494 | } 1495 | 1496 | if (lHResult == S_OK || lHResult == S_FALSE) 1497 | { 1498 | CoUninitialize(); 1499 | } 1500 | 1501 | if (lpItem) 1502 | { 1503 | return lBuff; 1504 | } 1505 | else 1506 | { 1507 | return NULL; 1508 | } 1509 | } 1510 | 1511 | 1512 | static char const * selectFolderDialogWinGui8 ( 1513 | char * const aoBuff , 1514 | char const * const aTitle , /* NULL or "" */ 1515 | char const * const aDefaultPath ) /* NULL or "" */ 1516 | { 1517 | wchar_t * lTitle; 1518 | wchar_t * lDefaultPath; 1519 | wchar_t const * lTmpWChar; 1520 | char * lTmpChar; 1521 | 1522 | lTitle = utf8to16(aTitle); 1523 | lDefaultPath = utf8to16(aDefaultPath); 1524 | 1525 | lTmpWChar = tinyfd_selectFolderDialogW( 1526 | lTitle, 1527 | lDefaultPath); 1528 | 1529 | free(lTitle); 1530 | free(lDefaultPath); 1531 | if (!lTmpWChar) 1532 | { 1533 | return NULL; 1534 | } 1535 | 1536 | lTmpChar = utf16to8(lTmpWChar); 1537 | strcpy(aoBuff, lTmpChar); 1538 | free(lTmpChar); 1539 | 1540 | return aoBuff; 1541 | } 1542 | #endif /*TINYFD_NOSELECTFOLDERWIN*/ 1543 | 1544 | 1545 | wchar_t const * tinyfd_colorChooserW( 1546 | wchar_t const * const aTitle, /* NULL or "" */ 1547 | wchar_t const * const aDefaultHexRGB, /* NULL or "#FF0000"*/ 1548 | unsigned char const aDefaultRGB[3], /* { 0 , 255 , 255 } */ 1549 | unsigned char aoResultRGB[3]) /* { 0 , 0 , 0 } */ 1550 | { 1551 | static wchar_t lResultHexRGB[8]; 1552 | CHOOSECOLORW cc; 1553 | COLORREF crCustColors[16]; 1554 | unsigned char lDefaultRGB[3]; 1555 | int lRet; 1556 | 1557 | HRESULT lHResult; 1558 | lHResult = CoInitializeEx(NULL, 0); 1559 | 1560 | if (aDefaultHexRGB) 1561 | { 1562 | Hex2RGBW(aDefaultHexRGB, lDefaultRGB); 1563 | } 1564 | else 1565 | { 1566 | lDefaultRGB[0] = aDefaultRGB[0]; 1567 | lDefaultRGB[1] = aDefaultRGB[1]; 1568 | lDefaultRGB[2] = aDefaultRGB[2]; 1569 | } 1570 | 1571 | /* we can't use aTitle */ 1572 | cc.lStructSize = sizeof(CHOOSECOLOR); 1573 | cc.hwndOwner = NULL; 1574 | cc.hInstance = NULL; 1575 | cc.rgbResult = RGB(lDefaultRGB[0], lDefaultRGB[1], lDefaultRGB[2]); 1576 | cc.lpCustColors = crCustColors; 1577 | cc.Flags = CC_RGBINIT | CC_FULLOPEN; 1578 | cc.lCustData = 0; 1579 | cc.lpfnHook = NULL; 1580 | cc.lpTemplateName = NULL; 1581 | 1582 | lRet = ChooseColorW(&cc); 1583 | 1584 | if (!lRet) 1585 | { 1586 | return NULL; 1587 | } 1588 | 1589 | aoResultRGB[0] = GetRValue(cc.rgbResult); 1590 | aoResultRGB[1] = GetGValue(cc.rgbResult); 1591 | aoResultRGB[2] = GetBValue(cc.rgbResult); 1592 | 1593 | RGB2HexW(aoResultRGB, lResultHexRGB); 1594 | 1595 | if (lHResult == S_OK || lHResult == S_FALSE) 1596 | { 1597 | CoUninitialize(); 1598 | } 1599 | 1600 | return lResultHexRGB; 1601 | } 1602 | 1603 | 1604 | static char const * colorChooserWinGui8( 1605 | char const * const aTitle, /* NULL or "" */ 1606 | char const * const aDefaultHexRGB, /* NULL or "#FF0000"*/ 1607 | unsigned char const aDefaultRGB[3], /* { 0 , 255 , 255 } */ 1608 | unsigned char aoResultRGB[3]) /* { 0 , 0 , 0 } */ 1609 | { 1610 | static char lResultHexRGB[8]; 1611 | 1612 | wchar_t * lTitle; 1613 | wchar_t * lDefaultHexRGB; 1614 | wchar_t const * lTmpWChar; 1615 | char * lTmpChar; 1616 | 1617 | lTitle = utf8to16(aTitle); 1618 | lDefaultHexRGB = utf8to16(aDefaultHexRGB); 1619 | 1620 | lTmpWChar = tinyfd_colorChooserW( 1621 | lTitle, 1622 | lDefaultHexRGB, 1623 | aDefaultRGB, 1624 | aoResultRGB ); 1625 | 1626 | free(lTitle); 1627 | free(lDefaultHexRGB); 1628 | if (!lTmpWChar) 1629 | { 1630 | return NULL; 1631 | } 1632 | 1633 | lTmpChar = utf16to8(lTmpWChar); 1634 | strcpy(lResultHexRGB, lTmpChar); 1635 | free(lTmpChar); 1636 | 1637 | return lResultHexRGB; 1638 | } 1639 | 1640 | 1641 | static int messageBoxWinGuiA ( 1642 | char const * const aTitle , /* NULL or "" */ 1643 | char const * const aMessage , /* NULL or "" may contain \n and \t */ 1644 | char const * const aDialogType , /* "ok" "okcancel" "yesno" "yesnocancel" */ 1645 | char const * const aIconType , /* "info" "warning" "error" "question" */ 1646 | int const aDefaultButton ) /* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */ 1647 | { 1648 | int lBoxReturnValue; 1649 | UINT aCode ; 1650 | 1651 | if ( aIconType && ! strcmp( "warning" , aIconType ) ) 1652 | { 1653 | aCode = MB_ICONWARNING ; 1654 | } 1655 | else if ( aIconType && ! strcmp("error", aIconType)) 1656 | { 1657 | aCode = MB_ICONERROR ; 1658 | } 1659 | else if ( aIconType && ! strcmp("question", aIconType)) 1660 | { 1661 | aCode = MB_ICONQUESTION ; 1662 | } 1663 | else 1664 | { 1665 | aCode = MB_ICONINFORMATION ; 1666 | } 1667 | 1668 | if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) ) 1669 | { 1670 | aCode += MB_OKCANCEL ; 1671 | if ( ! aDefaultButton ) 1672 | { 1673 | aCode += MB_DEFBUTTON2 ; 1674 | } 1675 | } 1676 | else if ( aDialogType && ! strcmp( "yesno" , aDialogType ) ) 1677 | { 1678 | aCode += MB_YESNO ; 1679 | if ( ! aDefaultButton ) 1680 | { 1681 | aCode += MB_DEFBUTTON2 ; 1682 | } 1683 | } 1684 | else if (aDialogType && !strcmp("yesnocancel", aDialogType)) 1685 | { 1686 | aCode += MB_YESNOCANCEL; 1687 | if (!aDefaultButton) 1688 | { 1689 | aCode += MB_DEFBUTTON3; 1690 | } 1691 | else if (aDefaultButton == 2) 1692 | { 1693 | aCode += MB_DEFBUTTON2; 1694 | } 1695 | } 1696 | else 1697 | { 1698 | aCode += MB_OK ; 1699 | } 1700 | 1701 | lBoxReturnValue = MessageBoxA(NULL, aMessage, aTitle, aCode); 1702 | 1703 | if (((aDialogType && !strcmp("yesnocancel", aDialogType)) 1704 | && (lBoxReturnValue == IDNO))) 1705 | { 1706 | return 2; 1707 | } 1708 | 1709 | if ( ( ( aDialogType 1710 | && strcmp("yesnocancel", aDialogType) 1711 | && strcmp("okcancel", aDialogType) 1712 | && strcmp("yesno", aDialogType))) 1713 | || (lBoxReturnValue == IDOK) 1714 | || (lBoxReturnValue == IDYES) ) 1715 | { 1716 | return 1 ; 1717 | } 1718 | else 1719 | { 1720 | return 0 ; 1721 | } 1722 | } 1723 | 1724 | 1725 | static char const * saveFileDialogWinGuiA ( 1726 | char * const aoBuff , 1727 | char const * const aTitle , /* NULL or "" */ 1728 | char const * const aDefaultPathAndFile , /* NULL or "" */ 1729 | int const aNumOfFilterPatterns , /* 0 */ 1730 | char const * const * const aFilterPatterns , /* NULL or {"*.jpg","*.png"} */ 1731 | char const * const aSingleFilterDescription ) /* NULL or "image files" */ 1732 | { 1733 | char lDirname [MAX_PATH_OR_CMD] ; 1734 | char lDialogString[MAX_PATH_OR_CMD]; 1735 | char lFilterPatterns[MAX_PATH_OR_CMD] = ""; 1736 | int i ; 1737 | char * p; 1738 | char * lRetval; 1739 | HRESULT lHResult; 1740 | OPENFILENAMEA ofn = { 0 }; 1741 | 1742 | lHResult = CoInitializeEx(NULL,0); 1743 | 1744 | getPathWithoutFinalSlash(lDirname, aDefaultPathAndFile); 1745 | getLastName(aoBuff, aDefaultPathAndFile); 1746 | 1747 | if (aNumOfFilterPatterns > 0) 1748 | { 1749 | if ( aSingleFilterDescription && strlen(aSingleFilterDescription) ) 1750 | { 1751 | strcpy(lFilterPatterns, aSingleFilterDescription); 1752 | strcat(lFilterPatterns, "\n"); 1753 | } 1754 | strcat(lFilterPatterns, aFilterPatterns[0]); 1755 | for (i = 1; i < aNumOfFilterPatterns; i++) 1756 | { 1757 | strcat(lFilterPatterns, ";"); 1758 | strcat(lFilterPatterns, aFilterPatterns[i]); 1759 | } 1760 | strcat(lFilterPatterns, "\n"); 1761 | if ( ! (aSingleFilterDescription && strlen(aSingleFilterDescription) ) ) 1762 | { 1763 | strcpy(lDialogString, lFilterPatterns); 1764 | strcat(lFilterPatterns, lDialogString); 1765 | } 1766 | strcat(lFilterPatterns, "All Files\n*.*\n"); 1767 | p = lFilterPatterns; 1768 | while ((p = strchr(p, '\n')) != NULL) 1769 | { 1770 | *p = '\0'; 1771 | p ++ ; 1772 | } 1773 | } 1774 | 1775 | ofn.lStructSize = sizeof(OPENFILENAME) ; 1776 | ofn.hwndOwner = 0 ; 1777 | ofn.hInstance = 0 ; 1778 | ofn.lpstrFilter = lFilterPatterns && strlen(lFilterPatterns) ? lFilterPatterns : NULL; 1779 | ofn.lpstrCustomFilter = NULL ; 1780 | ofn.nMaxCustFilter = 0 ; 1781 | ofn.nFilterIndex = 1 ; 1782 | ofn.lpstrFile = aoBuff; 1783 | 1784 | ofn.nMaxFile = MAX_PATH_OR_CMD ; 1785 | ofn.lpstrFileTitle = NULL ; 1786 | ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT ; 1787 | ofn.lpstrInitialDir = lDirname && strlen(lDirname) ? lDirname : NULL; 1788 | ofn.lpstrTitle = aTitle && strlen(aTitle) ? aTitle : NULL; 1789 | ofn.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR ; 1790 | ofn.nFileOffset = 0 ; 1791 | ofn.nFileExtension = 0 ; 1792 | ofn.lpstrDefExt = NULL ; 1793 | ofn.lCustData = 0L ; 1794 | ofn.lpfnHook = NULL ; 1795 | ofn.lpTemplateName = NULL ; 1796 | 1797 | if ( GetSaveFileNameA ( & ofn ) == 0 ) 1798 | { 1799 | lRetval = NULL ; 1800 | } 1801 | else 1802 | { 1803 | lRetval = aoBuff ; 1804 | } 1805 | 1806 | if (lHResult==S_OK || lHResult==S_FALSE) 1807 | { 1808 | CoUninitialize(); 1809 | } 1810 | return lRetval ; 1811 | } 1812 | 1813 | 1814 | static char const * openFileDialogWinGuiA ( 1815 | char * const aoBuff , 1816 | char const * const aTitle , /* NULL or "" */ 1817 | char const * const aDefaultPathAndFile , /* NULL or "" */ 1818 | int const aNumOfFilterPatterns , /* 0 */ 1819 | char const * const * const aFilterPatterns , /* NULL or {"*.jpg","*.png"} */ 1820 | char const * const aSingleFilterDescription , /* NULL or "image files" */ 1821 | int const aAllowMultipleSelects ) /* 0 or 1 */ 1822 | { 1823 | char lDirname [MAX_PATH_OR_CMD] ; 1824 | char lFilterPatterns[MAX_PATH_OR_CMD] = ""; 1825 | char lDialogString[MAX_PATH_OR_CMD] ; 1826 | char * lPointers[MAX_MULTIPLE_FILES]; 1827 | size_t lLengths[MAX_MULTIPLE_FILES]; 1828 | int i , j ; 1829 | char * p; 1830 | size_t lBuffLen ; 1831 | char * lRetval; 1832 | HRESULT lHResult; 1833 | OPENFILENAMEA ofn = {0}; 1834 | 1835 | lHResult = CoInitializeEx(NULL,0); 1836 | 1837 | getPathWithoutFinalSlash(lDirname, aDefaultPathAndFile); 1838 | getLastName(aoBuff, aDefaultPathAndFile); 1839 | 1840 | if (aNumOfFilterPatterns > 0) 1841 | { 1842 | if ( aSingleFilterDescription && strlen(aSingleFilterDescription) ) 1843 | { 1844 | strcpy(lFilterPatterns, aSingleFilterDescription); 1845 | strcat(lFilterPatterns, "\n"); 1846 | } 1847 | strcat(lFilterPatterns, aFilterPatterns[0]); 1848 | for (i = 1; i < aNumOfFilterPatterns; i++) 1849 | { 1850 | strcat(lFilterPatterns, ";"); 1851 | strcat(lFilterPatterns, aFilterPatterns[i]); 1852 | } 1853 | strcat(lFilterPatterns, "\n"); 1854 | if ( ! (aSingleFilterDescription && strlen(aSingleFilterDescription) ) ) 1855 | { 1856 | strcpy(lDialogString, lFilterPatterns); 1857 | strcat(lFilterPatterns, lDialogString); 1858 | } 1859 | strcat(lFilterPatterns, "All Files\n*.*\n"); 1860 | p = lFilterPatterns; 1861 | while ((p = strchr(p, '\n')) != NULL) 1862 | { 1863 | *p = '\0'; 1864 | p ++ ; 1865 | } 1866 | } 1867 | 1868 | ofn.lStructSize = sizeof ( OPENFILENAME ) ; 1869 | ofn.hwndOwner = 0 ; 1870 | ofn.hInstance = 0 ; 1871 | ofn.lpstrFilter = lFilterPatterns && strlen(lFilterPatterns) ? lFilterPatterns : NULL; 1872 | ofn.lpstrCustomFilter = NULL ; 1873 | ofn.nMaxCustFilter = 0 ; 1874 | ofn.nFilterIndex = 1 ; 1875 | ofn.lpstrFile = aoBuff ; 1876 | ofn.nMaxFile = MAX_PATH_OR_CMD ; 1877 | ofn.lpstrFileTitle = NULL ; 1878 | ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT ; 1879 | ofn.lpstrInitialDir = lDirname && strlen(lDirname) ? lDirname : NULL; 1880 | ofn.lpstrTitle = aTitle && strlen(aTitle) ? aTitle : NULL; 1881 | ofn.Flags = OFN_EXPLORER | OFN_NOCHANGEDIR ; 1882 | ofn.nFileOffset = 0 ; 1883 | ofn.nFileExtension = 0 ; 1884 | ofn.lpstrDefExt = NULL ; 1885 | ofn.lCustData = 0L ; 1886 | ofn.lpfnHook = NULL ; 1887 | ofn.lpTemplateName = NULL ; 1888 | 1889 | if ( aAllowMultipleSelects ) 1890 | { 1891 | ofn.Flags |= OFN_ALLOWMULTISELECT; 1892 | } 1893 | 1894 | if ( GetOpenFileNameA ( & ofn ) == 0 ) 1895 | { 1896 | lRetval = NULL ; 1897 | } 1898 | else 1899 | { 1900 | lBuffLen = strlen(aoBuff) ; 1901 | lPointers[0] = aoBuff + lBuffLen + 1 ; 1902 | if ( !aAllowMultipleSelects || (lPointers[0][0] == '\0') ) 1903 | { 1904 | lRetval = aoBuff ; 1905 | } 1906 | else 1907 | { 1908 | i = 0 ; 1909 | do 1910 | { 1911 | lLengths[i] = strlen(lPointers[i]); 1912 | lPointers[i+1] = lPointers[i] + lLengths[i] + 1 ; 1913 | i ++ ; 1914 | } 1915 | while ( lPointers[i][0] != '\0' ); 1916 | i--; 1917 | p = aoBuff + MAX_MULTIPLE_FILES*MAX_PATH_OR_CMD - 1 ; 1918 | * p = '\0'; 1919 | for ( j = i ; j >=0 ; j-- ) 1920 | { 1921 | p -= lLengths[j]; 1922 | memmove(p, lPointers[j], lLengths[j]); 1923 | p--; 1924 | *p = '\\'; 1925 | p -= lBuffLen ; 1926 | memmove(p, aoBuff, lBuffLen); 1927 | p--; 1928 | *p = '|'; 1929 | } 1930 | p++; 1931 | lRetval = p ; 1932 | } 1933 | } 1934 | 1935 | if (lHResult==S_OK || lHResult==S_FALSE) 1936 | { 1937 | CoUninitialize(); 1938 | } 1939 | return lRetval; 1940 | } 1941 | 1942 | #ifndef TINYFD_NOSELECTFOLDERWIN 1943 | static char const * selectFolderDialogWinGuiA ( 1944 | char * const aoBuff , 1945 | char const * const aTitle , /* NULL or "" */ 1946 | char const * const aDefaultPath ) /* NULL or "" */ 1947 | { 1948 | BROWSEINFOA bInfo ; 1949 | LPITEMIDLIST lpItem ; 1950 | HRESULT lHResult; 1951 | 1952 | lHResult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 1953 | 1954 | /* we can't use aDefaultPath */ 1955 | bInfo.hwndOwner = 0 ; 1956 | bInfo.pidlRoot = NULL ; 1957 | bInfo.pszDisplayName = aoBuff ; 1958 | bInfo.lpszTitle = aTitle && strlen(aTitle) ? aTitle : NULL; 1959 | if (lHResult == S_OK || lHResult == S_FALSE) 1960 | { 1961 | bInfo.ulFlags = BIF_USENEWUI; 1962 | } 1963 | bInfo.lpfn = BrowseCallbackProc; 1964 | bInfo.lParam = (LPARAM)aDefaultPath; 1965 | bInfo.iImage = -1 ; 1966 | 1967 | lpItem = SHBrowseForFolderA ( & bInfo ) ; 1968 | if ( lpItem ) 1969 | { 1970 | SHGetPathFromIDListA ( lpItem , aoBuff ) ; 1971 | } 1972 | 1973 | if (lHResult==S_OK || lHResult==S_FALSE) 1974 | { 1975 | CoUninitialize(); 1976 | } 1977 | return aoBuff ; 1978 | } 1979 | #endif /*TINYFD_NOSELECTFOLDERWIN*/ 1980 | 1981 | 1982 | static char const * colorChooserWinGuiA( 1983 | char const * const aTitle, /* NULL or "" */ 1984 | char const * const aDefaultHexRGB, /* NULL or "#FF0000"*/ 1985 | unsigned char const aDefaultRGB[3], /* { 0 , 255 , 255 } */ 1986 | unsigned char aoResultRGB[3]) /* { 0 , 0 , 0 } */ 1987 | { 1988 | static char lResultHexRGB[8]; 1989 | 1990 | CHOOSECOLORA cc; 1991 | COLORREF crCustColors[16]; 1992 | unsigned char lDefaultRGB[3]; 1993 | int lRet; 1994 | 1995 | if ( aDefaultHexRGB ) 1996 | { 1997 | Hex2RGB(aDefaultHexRGB, lDefaultRGB); 1998 | } 1999 | else 2000 | { 2001 | lDefaultRGB[0]=aDefaultRGB[0]; 2002 | lDefaultRGB[1]=aDefaultRGB[1]; 2003 | lDefaultRGB[2]=aDefaultRGB[2]; 2004 | } 2005 | 2006 | /* we can't use aTitle */ 2007 | cc.lStructSize = sizeof ( CHOOSECOLOR ) ; 2008 | cc.hwndOwner = NULL ; 2009 | cc.hInstance = NULL ; 2010 | cc.rgbResult = RGB(lDefaultRGB[0], lDefaultRGB[1], lDefaultRGB[2]); 2011 | cc.lpCustColors = crCustColors; 2012 | cc.Flags = CC_RGBINIT | CC_FULLOPEN; 2013 | cc.lCustData = 0; 2014 | cc.lpfnHook = NULL; 2015 | cc.lpTemplateName = NULL; 2016 | 2017 | lRet = ChooseColorA(&cc); 2018 | 2019 | if ( ! lRet ) 2020 | { 2021 | return NULL; 2022 | } 2023 | 2024 | aoResultRGB[0] = GetRValue(cc.rgbResult); 2025 | aoResultRGB[1] = GetGValue(cc.rgbResult); 2026 | aoResultRGB[2] = GetBValue(cc.rgbResult); 2027 | 2028 | RGB2Hex(aoResultRGB, lResultHexRGB); 2029 | 2030 | return lResultHexRGB; 2031 | } 2032 | 2033 | #endif /* TINYFD_NOLIB */ 2034 | 2035 | static int dialogPresent ( ) 2036 | { 2037 | static int lDialogPresent = -1 ; 2038 | char lBuff [MAX_PATH_OR_CMD] ; 2039 | FILE * lIn ; 2040 | char const * lString = "dialog.exe"; 2041 | if ( lDialogPresent < 0 ) 2042 | { 2043 | if (!(lIn = _popen("where dialog.exe","r"))) 2044 | { 2045 | lDialogPresent = 0 ; 2046 | return 0 ; 2047 | } 2048 | while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) 2049 | {} 2050 | _pclose ( lIn ) ; 2051 | if ( lBuff[strlen ( lBuff ) -1] == '\n' ) 2052 | { 2053 | lBuff[strlen ( lBuff ) -1] = '\0' ; 2054 | } 2055 | if ( strcmp(lBuff+strlen(lBuff)-strlen(lString),lString) ) 2056 | { 2057 | lDialogPresent = 0 ; 2058 | } 2059 | else 2060 | { 2061 | lDialogPresent = 1 ; 2062 | } 2063 | } 2064 | return lDialogPresent; 2065 | } 2066 | 2067 | 2068 | static int messageBoxWinConsole ( 2069 | char const * const aTitle , /* NULL or "" */ 2070 | char const * const aMessage , /* NULL or "" may contain \n and \t */ 2071 | char const * const aDialogType , /* "ok" "okcancel" "yesno" "yesnocancel" */ 2072 | char const * const aIconType , /* "info" "warning" "error" "question" */ 2073 | int const aDefaultButton ) /* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */ 2074 | { 2075 | char lDialogString[MAX_PATH_OR_CMD]; 2076 | char lDialogFile[MAX_PATH_OR_CMD]; 2077 | FILE * lIn; 2078 | char lBuff [MAX_PATH_OR_CMD] = ""; 2079 | 2080 | strcpy ( lDialogString , "dialog " ) ; 2081 | if ( aTitle && strlen(aTitle) ) 2082 | { 2083 | strcat(lDialogString, "--title \"") ; 2084 | strcat(lDialogString, aTitle) ; 2085 | strcat(lDialogString, "\" ") ; 2086 | } 2087 | 2088 | if ( aDialogType && ( !strcmp( "okcancel" , aDialogType ) 2089 | || !strcmp("yesno", aDialogType) || !strcmp("yesnocancel", aDialogType) ) ) 2090 | { 2091 | strcat(lDialogString, "--backtitle \"") ; 2092 | strcat(lDialogString, "tab: move focus") ; 2093 | strcat(lDialogString, "\" ") ; 2094 | } 2095 | 2096 | if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) ) 2097 | { 2098 | if ( ! aDefaultButton ) 2099 | { 2100 | strcat ( lDialogString , "--defaultno " ) ; 2101 | } 2102 | strcat ( lDialogString , 2103 | "--yes-label \"Ok\" --no-label \"Cancel\" --yesno " ) ; 2104 | } 2105 | else if ( aDialogType && ! strcmp( "yesno" , aDialogType ) ) 2106 | { 2107 | if ( ! aDefaultButton ) 2108 | { 2109 | strcat ( lDialogString , "--defaultno " ) ; 2110 | } 2111 | strcat ( lDialogString , "--yesno " ) ; 2112 | } 2113 | else if (aDialogType && !strcmp("yesnocancel", aDialogType)) 2114 | { 2115 | if (!aDefaultButton) 2116 | { 2117 | strcat(lDialogString, "--defaultno "); 2118 | } 2119 | strcat(lDialogString, "--menu "); 2120 | } 2121 | else 2122 | { 2123 | strcat ( lDialogString , "--msgbox " ) ; 2124 | } 2125 | 2126 | strcat ( lDialogString , "\"" ) ; 2127 | if ( aMessage && strlen(aMessage) ) 2128 | { 2129 | replaceSubStr ( aMessage , "\n" , "\\n" , lBuff ) ; 2130 | strcat(lDialogString, lBuff) ; 2131 | lBuff[0]='\0'; 2132 | } 2133 | strcat(lDialogString, "\" "); 2134 | 2135 | if (aDialogType && !strcmp("yesnocancel", aDialogType)) 2136 | { 2137 | strcat(lDialogString, "0 60 0 Yes \"\" No \"\""); 2138 | strcat(lDialogString, "2>>"); 2139 | } 2140 | else 2141 | { 2142 | strcat(lDialogString, "10 60"); 2143 | strcat(lDialogString, " && echo 1 > "); 2144 | } 2145 | 2146 | strcpy(lDialogFile, getenv("USERPROFILE")); 2147 | strcat(lDialogFile, "\\AppData\\Local\\Temp\\tinyfd.txt"); 2148 | strcat(lDialogString, lDialogFile); 2149 | 2150 | /*if (tinyfd_verbose) printf ( "lDialogString: %s\n" , lDialogString ) ;*/ 2151 | system ( lDialogString ) ; 2152 | 2153 | if (!(lIn = fopen(lDialogFile, "r"))) 2154 | { 2155 | remove(lDialogFile); 2156 | return 0 ; 2157 | } 2158 | while (fgets(lBuff, sizeof(lBuff), lIn) != NULL) 2159 | {} 2160 | fclose(lIn); 2161 | remove(lDialogFile); 2162 | if ( lBuff[strlen ( lBuff ) -1] == '\n' ) 2163 | { 2164 | lBuff[strlen ( lBuff ) -1] = '\0' ; 2165 | } 2166 | 2167 | /* if (tinyfd_verbose) printf("lBuff: %s\n", lBuff); */ 2168 | if ( ! strlen(lBuff) ) 2169 | { 2170 | return 0; 2171 | } 2172 | 2173 | if (aDialogType && !strcmp("yesnocancel", aDialogType)) 2174 | { 2175 | if (lBuff[0] == 'Y') return 1; 2176 | else return 2; 2177 | } 2178 | 2179 | return 1; 2180 | } 2181 | 2182 | 2183 | static char const * inputBoxWinConsole( 2184 | char * const aoBuff , 2185 | char const * const aTitle , /* NULL or "" */ 2186 | char const * const aMessage , /* NULL or "" may NOT contain \n nor \t */ 2187 | char const * const aDefaultInput ) /* "" , if NULL it's a passwordBox */ 2188 | { 2189 | char lDialogString[MAX_PATH_OR_CMD]; 2190 | char lDialogFile[MAX_PATH_OR_CMD]; 2191 | FILE * lIn; 2192 | int lResult; 2193 | 2194 | strcpy(lDialogFile, getenv("USERPROFILE")); 2195 | strcat(lDialogFile, "\\AppData\\Local\\Temp\\tinyfd.txt"); 2196 | strcpy(lDialogString , "echo|set /p=1 >" ) ; 2197 | strcat(lDialogString, lDialogFile); 2198 | strcat( lDialogString , " & " ) ; 2199 | 2200 | strcat ( lDialogString , "dialog " ) ; 2201 | if ( aTitle && strlen(aTitle) ) 2202 | { 2203 | strcat(lDialogString, "--title \"") ; 2204 | strcat(lDialogString, aTitle) ; 2205 | strcat(lDialogString, "\" ") ; 2206 | } 2207 | 2208 | strcat(lDialogString, "--backtitle \"") ; 2209 | strcat(lDialogString, "tab: move focus") ; 2210 | if ( ! aDefaultInput ) 2211 | { 2212 | strcat(lDialogString, " (sometimes nothing, no blink nor star, is shown in text field)") ; 2213 | } 2214 | 2215 | strcat(lDialogString, "\" ") ; 2216 | 2217 | if ( ! aDefaultInput ) 2218 | { 2219 | strcat ( lDialogString , "--insecure --passwordbox" ) ; 2220 | } 2221 | else 2222 | { 2223 | strcat ( lDialogString , "--inputbox" ) ; 2224 | } 2225 | strcat ( lDialogString , " \"" ) ; 2226 | if ( aMessage && strlen(aMessage) ) 2227 | { 2228 | strcat(lDialogString, aMessage) ; 2229 | } 2230 | strcat(lDialogString,"\" 10 60 ") ; 2231 | if ( aDefaultInput && strlen(aDefaultInput) ) 2232 | { 2233 | strcat(lDialogString, "\"") ; 2234 | strcat(lDialogString, aDefaultInput) ; 2235 | strcat(lDialogString, "\" ") ; 2236 | } 2237 | 2238 | strcat(lDialogString, "2>>"); 2239 | strcpy(lDialogFile, getenv("USERPROFILE")); 2240 | strcat(lDialogFile, "\\AppData\\Local\\Temp\\tinyfd.txt"); 2241 | strcat(lDialogString, lDialogFile); 2242 | strcat(lDialogString, " || echo 0 > "); 2243 | strcat(lDialogString, lDialogFile); 2244 | 2245 | /* printf ( "lDialogString: %s\n" , lDialogString ) ; */ 2246 | system ( lDialogString ) ; 2247 | 2248 | if (!(lIn = fopen(lDialogFile, "r"))) 2249 | { 2250 | remove(lDialogFile); 2251 | return 0 ; 2252 | } 2253 | while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL) 2254 | {} 2255 | fclose(lIn); 2256 | 2257 | wipefile(lDialogFile); 2258 | remove(lDialogFile); 2259 | if ( aoBuff[strlen ( aoBuff ) -1] == '\n' ) 2260 | { 2261 | aoBuff[strlen ( aoBuff ) -1] = '\0' ; 2262 | } 2263 | /* printf ( "aoBuff: %s\n" , aoBuff ) ; */ 2264 | 2265 | /* printf ( "aoBuff: %s len: %lu \n" , aoBuff , strlen(aoBuff) ) ; */ 2266 | lResult = strncmp ( aoBuff , "1" , 1) ? 0 : 1 ; 2267 | /* printf ( "lResult: %d \n" , lResult ) ; */ 2268 | if ( ! lResult ) 2269 | { 2270 | return NULL ; 2271 | } 2272 | /* printf ( "aoBuff+1: %s\n" , aoBuff+1 ) ; */ 2273 | return aoBuff+3 ; 2274 | } 2275 | 2276 | 2277 | static char const * saveFileDialogWinConsole ( 2278 | char * const aoBuff , 2279 | char const * const aTitle , /* NULL or "" */ 2280 | char const * const aDefaultPathAndFile ) /* NULL or "" */ 2281 | { 2282 | char lDialogString[MAX_PATH_OR_CMD]; 2283 | char lPathAndFile[MAX_PATH_OR_CMD] = ""; 2284 | FILE * lIn; 2285 | 2286 | strcpy ( lDialogString , "dialog " ) ; 2287 | if ( aTitle && strlen(aTitle) ) 2288 | { 2289 | strcat(lDialogString, "--title \"") ; 2290 | strcat(lDialogString, aTitle) ; 2291 | strcat(lDialogString, "\" ") ; 2292 | } 2293 | 2294 | strcat(lDialogString, "--backtitle \"") ; 2295 | strcat(lDialogString, 2296 | "tab: focus | /: populate | spacebar: fill text field | ok: TEXT FIELD ONLY") ; 2297 | strcat(lDialogString, "\" ") ; 2298 | 2299 | strcat ( lDialogString , "--fselect \"" ) ; 2300 | if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) 2301 | { 2302 | /* dialog.exe uses unix separators even on windows */ 2303 | strcpy(lPathAndFile, aDefaultPathAndFile); 2304 | replaceChr ( lPathAndFile , '\\' , '/' ) ; 2305 | } 2306 | 2307 | /* dialog.exe needs at least one separator */ 2308 | if ( ! strchr(lPathAndFile, '/') ) 2309 | { 2310 | strcat(lDialogString, "./") ; 2311 | } 2312 | strcat(lDialogString, lPathAndFile) ; 2313 | strcat(lDialogString, "\" 0 60 2>"); 2314 | strcpy(lPathAndFile, getenv("USERPROFILE")); 2315 | strcat(lPathAndFile, "\\AppData\\Local\\Temp\\tinyfd.txt"); 2316 | strcat(lDialogString, lPathAndFile); 2317 | 2318 | /* printf ( "lDialogString: %s\n" , lDialogString ) ; */ 2319 | system ( lDialogString ) ; 2320 | 2321 | if (!(lIn = fopen(lPathAndFile, "r"))) 2322 | { 2323 | remove(lPathAndFile); 2324 | return NULL; 2325 | } 2326 | while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL) 2327 | {} 2328 | fclose(lIn); 2329 | remove(lPathAndFile); 2330 | replaceChr ( aoBuff , '/' , '\\' ) ; 2331 | /* printf ( "aoBuff: %s\n" , aoBuff ) ; */ 2332 | getLastName(lDialogString,aoBuff); 2333 | if ( ! strlen(lDialogString) ) 2334 | { 2335 | return NULL; 2336 | } 2337 | return aoBuff; 2338 | } 2339 | 2340 | 2341 | static char const * openFileDialogWinConsole ( 2342 | char * const aoBuff , 2343 | char const * const aTitle , /* NULL or "" */ 2344 | char const * const aDefaultPathAndFile , /* NULL or "" */ 2345 | int const aAllowMultipleSelects ) /* 0 or 1 */ 2346 | { 2347 | char lFilterPatterns[MAX_PATH_OR_CMD] = ""; 2348 | char lDialogString[MAX_PATH_OR_CMD] ; 2349 | FILE * lIn; 2350 | 2351 | strcpy ( lDialogString , "dialog " ) ; 2352 | if ( aTitle && strlen(aTitle) ) 2353 | { 2354 | strcat(lDialogString, "--title \"") ; 2355 | strcat(lDialogString, aTitle) ; 2356 | strcat(lDialogString, "\" ") ; 2357 | } 2358 | 2359 | strcat(lDialogString, "--backtitle \"") ; 2360 | strcat(lDialogString, 2361 | "tab: focus | /: populate | spacebar: fill text field | ok: TEXT FIELD ONLY") ; 2362 | strcat(lDialogString, "\" ") ; 2363 | 2364 | strcat ( lDialogString , "--fselect \"" ) ; 2365 | if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) 2366 | { 2367 | /* dialog.exe uses unix separators even on windows */ 2368 | strcpy(lFilterPatterns, aDefaultPathAndFile); 2369 | replaceChr ( lFilterPatterns , '\\' , '/' ) ; 2370 | } 2371 | 2372 | /* dialog.exe needs at least one separator */ 2373 | if ( ! strchr(lFilterPatterns, '/') ) 2374 | { 2375 | strcat(lDialogString, "./") ; 2376 | } 2377 | strcat(lDialogString, lFilterPatterns) ; 2378 | strcat(lDialogString, "\" 0 60 2>"); 2379 | strcpy(lFilterPatterns, getenv("USERPROFILE")); 2380 | strcat(lFilterPatterns, "\\AppData\\Local\\Temp\\tinyfd.txt"); 2381 | strcat(lDialogString, lFilterPatterns); 2382 | 2383 | /* printf ( "lDialogString: %s\n" , lDialogString ) ; */ 2384 | system ( lDialogString ) ; 2385 | 2386 | if (!(lIn = fopen(lFilterPatterns, "r"))) 2387 | { 2388 | remove(lFilterPatterns); 2389 | return NULL; 2390 | } 2391 | while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL) 2392 | {} 2393 | fclose(lIn); 2394 | remove(lFilterPatterns); 2395 | replaceChr ( aoBuff , '/' , '\\' ) ; 2396 | /* printf ( "aoBuff: %s\n" , aoBuff ) ; */ 2397 | return aoBuff; 2398 | } 2399 | 2400 | 2401 | static char const * selectFolderDialogWinConsole ( 2402 | char * const aoBuff , 2403 | char const * const aTitle , /* NULL or "" */ 2404 | char const * const aDefaultPath ) /* NULL or "" */ 2405 | { 2406 | char lDialogString [MAX_PATH_OR_CMD] ; 2407 | char lString [MAX_PATH_OR_CMD] ; 2408 | FILE * lIn ; 2409 | 2410 | strcpy ( lDialogString , "dialog " ) ; 2411 | if ( aTitle && strlen(aTitle) ) 2412 | { 2413 | strcat(lDialogString, "--title \"") ; 2414 | strcat(lDialogString, aTitle) ; 2415 | strcat(lDialogString, "\" ") ; 2416 | } 2417 | 2418 | strcat(lDialogString, "--backtitle \"") ; 2419 | strcat(lDialogString, 2420 | "tab: focus | /: populate | spacebar: fill text field | ok: TEXT FIELD ONLY") ; 2421 | strcat(lDialogString, "\" ") ; 2422 | 2423 | strcat ( lDialogString , "--dselect \"" ) ; 2424 | if ( aDefaultPath && strlen(aDefaultPath) ) 2425 | { 2426 | /* dialog.exe uses unix separators even on windows */ 2427 | strcpy(lString, aDefaultPath) ; 2428 | ensureFinalSlash(lString); 2429 | replaceChr ( lString , '\\' , '/' ) ; 2430 | strcat(lDialogString, lString) ; 2431 | } 2432 | else 2433 | { 2434 | /* dialog.exe needs at least one separator */ 2435 | strcat(lDialogString, "./") ; 2436 | } 2437 | strcat(lDialogString, "\" 0 60 2>"); 2438 | strcpy(lString, getenv("USERPROFILE")); 2439 | strcat(lString, "\\AppData\\Local\\Temp\\tinyfd.txt"); 2440 | strcat(lDialogString, lString); 2441 | 2442 | /* printf ( "lDialogString: %s\n" , lDialogString ) ; */ 2443 | system ( lDialogString ) ; 2444 | 2445 | if (!(lIn = fopen(lString, "r"))) 2446 | { 2447 | remove(lString); 2448 | return NULL; 2449 | } 2450 | while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL) 2451 | {} 2452 | fclose(lIn); 2453 | remove(lString); 2454 | replaceChr ( aoBuff , '/' , '\\' ) ; 2455 | /* printf ( "aoBuff: %s\n" , aoBuff ) ; */ 2456 | return aoBuff; 2457 | } 2458 | 2459 | 2460 | int tinyfd_messageBox ( 2461 | char const * const aTitle , /* NULL or "" */ 2462 | char const * const aMessage , /* NULL or "" may contain \n and \t */ 2463 | char const * const aDialogType , /* "ok" "okcancel" "yesno" "yesnocancel" */ 2464 | char const * const aIconType , /* "info" "warning" "error" "question" */ 2465 | int const aDefaultButton ) /* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */ 2466 | { 2467 | char lChar ; 2468 | 2469 | #ifndef TINYFD_NOLIB 2470 | if ((!tinyfd_forceConsole || !(GetConsoleWindow() || dialogPresent())) 2471 | && (!getenv("SSH_CLIENT") || getenv("DISPLAY"))) 2472 | { 2473 | if (aTitle&&!strcmp(aTitle, "tinyfd_query")){ strcpy(tinyfd_response, "windows"); return 1; } 2474 | if (tinyfd_winUtf8) 2475 | { 2476 | return messageBoxWinGui8( 2477 | aTitle, aMessage, aDialogType, aIconType, aDefaultButton); 2478 | } 2479 | else 2480 | { 2481 | return messageBoxWinGuiA( 2482 | aTitle, aMessage, aDialogType, aIconType, aDefaultButton); 2483 | } 2484 | } 2485 | else 2486 | #endif /* TINYFD_NOLIB */ 2487 | if ( dialogPresent() ) 2488 | { 2489 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return 0;} 2490 | return messageBoxWinConsole( 2491 | aTitle,aMessage,aDialogType,aIconType,aDefaultButton); 2492 | } 2493 | else 2494 | { 2495 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return 0;} 2496 | if (!gWarningDisplayed && !tinyfd_forceConsole ) 2497 | { 2498 | gWarningDisplayed = 1; 2499 | printf("\n\n%s\n", gTitle); 2500 | printf("%s\n\n", gMessageWin); 2501 | } 2502 | if ( aTitle && strlen(aTitle) ) 2503 | { 2504 | printf ("\n%s\n\n", aTitle); 2505 | } 2506 | if ( aDialogType && !strcmp("yesno",aDialogType) ) 2507 | { 2508 | do 2509 | { 2510 | if ( aMessage && strlen(aMessage) ) 2511 | { 2512 | printf("%s\n",aMessage); 2513 | } 2514 | printf("y/n: "); 2515 | lChar = (char) tolower ( _getch() ) ; 2516 | printf("\n\n"); 2517 | } 2518 | while ( lChar != 'y' && lChar != 'n' ) ; 2519 | return lChar == 'y' ? 1 : 0 ; 2520 | } 2521 | else if ( aDialogType && !strcmp("okcancel",aDialogType) ) 2522 | { 2523 | do 2524 | { 2525 | if ( aMessage && strlen(aMessage) ) 2526 | { 2527 | printf("%s\n",aMessage); 2528 | } 2529 | printf("[O]kay/[C]ancel: "); 2530 | lChar = (char) tolower ( _getch() ) ; 2531 | printf("\n\n"); 2532 | } 2533 | while ( lChar != 'o' && lChar != 'c' ) ; 2534 | return lChar == 'o' ? 1 : 0 ; 2535 | } 2536 | else if (aDialogType && !strcmp("yesnocancel", aDialogType)) 2537 | { 2538 | do 2539 | { 2540 | if (aMessage && strlen(aMessage)) 2541 | { 2542 | printf("%s\n", aMessage); 2543 | } 2544 | printf("[Y]es/[N]o/[C]ancel: "); 2545 | lChar = (char)tolower(_getch()); 2546 | printf("\n\n"); 2547 | } while (lChar != 'y' && lChar != 'n' && lChar != 'c'); 2548 | return (lChar == 'y') ? 1 : (lChar == 'n') ? 2 : 0 ; 2549 | } 2550 | else 2551 | { 2552 | if ( aMessage && strlen(aMessage) ) 2553 | { 2554 | printf("%s\n\n",aMessage); 2555 | } 2556 | printf("press enter to continue "); 2557 | lChar = (char) _getch() ; 2558 | printf("\n\n"); 2559 | return 1 ; 2560 | } 2561 | } 2562 | } 2563 | 2564 | 2565 | /* returns NULL on cancel */ 2566 | char const * tinyfd_inputBox( 2567 | char const * const aTitle , /* NULL or "" */ 2568 | char const * const aMessage , /* NULL or "" may NOT contain \n nor \t */ 2569 | char const * const aDefaultInput ) /* "" , if NULL it's a passwordBox */ 2570 | { 2571 | static char lBuff [MAX_PATH_OR_CMD] ; 2572 | char * lEOF; 2573 | 2574 | #ifndef TINYFD_NOLIB 2575 | DWORD mode = 0; 2576 | HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); 2577 | 2578 | if ((!tinyfd_forceConsole || !( 2579 | GetConsoleWindow() || 2580 | dialogPresent())) 2581 | && ( !getenv("SSH_CLIENT") || getenv("DISPLAY") ) ) 2582 | { 2583 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"windows");return (char const *)1;} 2584 | lBuff[0]='\0'; 2585 | return inputBoxWinGui(lBuff,aTitle,aMessage,aDefaultInput); 2586 | } 2587 | else 2588 | #endif /* TINYFD_NOLIB */ 2589 | if ( dialogPresent() ) 2590 | { 2591 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} 2592 | lBuff[0]='\0'; 2593 | return inputBoxWinConsole(lBuff,aTitle,aMessage,aDefaultInput); 2594 | } 2595 | else 2596 | { 2597 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return (char const *)0;} 2598 | lBuff[0]='\0'; 2599 | if (!gWarningDisplayed && !tinyfd_forceConsole) 2600 | { 2601 | gWarningDisplayed = 1 ; 2602 | printf("\n\n%s\n", gTitle); 2603 | printf("%s\n\n", gMessageWin); 2604 | } 2605 | if ( aTitle && strlen(aTitle) ) 2606 | { 2607 | printf ("\n%s\n\n", aTitle); 2608 | } 2609 | if ( aMessage && strlen(aMessage) ) 2610 | { 2611 | printf("%s\n",aMessage); 2612 | } 2613 | printf("(ctrl-Z + enter to cancel): "); 2614 | #ifndef TINYFD_NOLIB 2615 | if ( ! aDefaultInput ) 2616 | { 2617 | GetConsoleMode(hStdin,&mode); 2618 | SetConsoleMode(hStdin,mode & (~ENABLE_ECHO_INPUT) ); 2619 | } 2620 | #endif /* TINYFD_NOLIB */ 2621 | lEOF = fgets(lBuff, MAX_PATH_OR_CMD, stdin); 2622 | if ( ! lEOF ) 2623 | { 2624 | return NULL; 2625 | } 2626 | #ifndef TINYFD_NOLIB 2627 | if ( ! aDefaultInput ) 2628 | { 2629 | SetConsoleMode(hStdin,mode); 2630 | printf ("\n"); 2631 | } 2632 | #endif /* TINYFD_NOLIB */ 2633 | printf ("\n"); 2634 | if ( strchr(lBuff,27) ) 2635 | { 2636 | return NULL ; 2637 | } 2638 | if ( lBuff[strlen ( lBuff ) -1] == '\n' ) 2639 | { 2640 | lBuff[strlen ( lBuff ) -1] = '\0' ; 2641 | } 2642 | return lBuff ; 2643 | } 2644 | } 2645 | 2646 | 2647 | char const * tinyfd_saveFileDialog ( 2648 | char const * const aTitle , /* NULL or "" */ 2649 | char const * const aDefaultPathAndFile , /* NULL or "" */ 2650 | int const aNumOfFilterPatterns , /* 0 */ 2651 | char const * const * const aFilterPatterns , /* NULL or {"*.jpg","*.png"} */ 2652 | char const * const aSingleFilterDescription ) /* NULL or "image files" */ 2653 | { 2654 | static char lBuff [MAX_PATH_OR_CMD] ; 2655 | char lString[MAX_PATH_OR_CMD] ; 2656 | char const * p ; 2657 | lBuff[0]='\0'; 2658 | #ifndef TINYFD_NOLIB 2659 | if ( ( !tinyfd_forceConsole || !( GetConsoleWindow() || dialogPresent() ) ) 2660 | && ( !getenv("SSH_CLIENT") || getenv("DISPLAY") ) ) 2661 | { 2662 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"windows");return (char const *)1;} 2663 | if (tinyfd_winUtf8) 2664 | { 2665 | p = saveFileDialogWinGui8(lBuff, 2666 | aTitle, aDefaultPathAndFile, aNumOfFilterPatterns, aFilterPatterns, aSingleFilterDescription); 2667 | } 2668 | else 2669 | { 2670 | p = saveFileDialogWinGuiA(lBuff, 2671 | aTitle, aDefaultPathAndFile, aNumOfFilterPatterns, aFilterPatterns, aSingleFilterDescription); 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 = saveFileDialogWinConsole(lBuff,aTitle,aDefaultPathAndFile); 2680 | } 2681 | else 2682 | { 2683 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return (char const *)0;} 2684 | p = tinyfd_inputBox(aTitle, "Save file",""); 2685 | } 2686 | 2687 | if ( ! p || ! strlen ( p ) ) 2688 | { 2689 | return NULL; 2690 | } 2691 | getPathWithoutFinalSlash ( lString , p ) ; 2692 | if ( strlen ( lString ) && ! dirExists ( lString ) ) 2693 | { 2694 | return NULL ; 2695 | } 2696 | getLastName(lString,p); 2697 | if ( ! filenameValid(lString) ) 2698 | { 2699 | return NULL; 2700 | } 2701 | return p ; 2702 | } 2703 | 2704 | 2705 | /* in case of multiple files, the separator is | */ 2706 | char const * tinyfd_openFileDialog ( 2707 | char const * const aTitle , /* NULL or "" */ 2708 | char const * const aDefaultPathAndFile , /* NULL or "" */ 2709 | int const aNumOfFilterPatterns , /* 0 */ 2710 | char const * const * const aFilterPatterns , /* NULL or {"*.jpg","*.png"} */ 2711 | char const * const aSingleFilterDescription , /* NULL or "image files" */ 2712 | int const aAllowMultipleSelects ) /* 0 or 1 */ 2713 | { 2714 | static char lBuff[MAX_MULTIPLE_FILES*MAX_PATH_OR_CMD]; 2715 | char const * p ; 2716 | #ifndef TINYFD_NOLIB 2717 | if ( ( !tinyfd_forceConsole || !( GetConsoleWindow() || dialogPresent() ) ) 2718 | && ( !getenv("SSH_CLIENT") || getenv("DISPLAY") ) ) 2719 | { 2720 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"windows");return (char const *)1;} 2721 | if (tinyfd_winUtf8) 2722 | { 2723 | p = openFileDialogWinGui8(lBuff, 2724 | aTitle, aDefaultPathAndFile, aNumOfFilterPatterns, 2725 | aFilterPatterns, aSingleFilterDescription, aAllowMultipleSelects); 2726 | } 2727 | else 2728 | { 2729 | p = openFileDialogWinGuiA(lBuff, 2730 | aTitle, aDefaultPathAndFile, aNumOfFilterPatterns, 2731 | aFilterPatterns, aSingleFilterDescription, aAllowMultipleSelects); 2732 | } 2733 | } 2734 | else 2735 | #endif /* TINYFD_NOLIB */ 2736 | if ( dialogPresent() ) 2737 | { 2738 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} 2739 | p = openFileDialogWinConsole(lBuff, 2740 | aTitle,aDefaultPathAndFile,aAllowMultipleSelects); 2741 | } 2742 | else 2743 | { 2744 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return (char const *)0;} 2745 | p = tinyfd_inputBox(aTitle, "Open file",""); 2746 | } 2747 | 2748 | if ( ! p || ! strlen ( p ) ) 2749 | { 2750 | return NULL; 2751 | } 2752 | if ( aAllowMultipleSelects && strchr(p, '|') ) 2753 | { 2754 | p = ensureFilesExist( lBuff , p ) ; 2755 | } 2756 | else if ( ! fileExists (p) ) 2757 | { 2758 | return NULL ; 2759 | } 2760 | /* printf ( "lBuff3: %s\n" , p ) ; */ 2761 | return p ; 2762 | } 2763 | 2764 | 2765 | char const * tinyfd_selectFolderDialog ( 2766 | char const * const aTitle , /* NULL or "" */ 2767 | char const * const aDefaultPath ) /* NULL or "" */ 2768 | { 2769 | static char lBuff [MAX_PATH_OR_CMD] ; 2770 | char const * p ; 2771 | #ifndef TINYFD_NOLIB 2772 | if ( ( !tinyfd_forceConsole || !( GetConsoleWindow() || dialogPresent() ) ) 2773 | && ( !getenv("SSH_CLIENT") || getenv("DISPLAY") ) ) 2774 | { 2775 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"windows");return (char const *)1;} 2776 | if (tinyfd_winUtf8) 2777 | { 2778 | #ifndef TINYFD_NOSELECTFOLDERWIN 2779 | p = selectFolderDialogWinGui8(lBuff, aTitle, aDefaultPath); 2780 | } 2781 | else 2782 | { 2783 | p = selectFolderDialogWinGuiA(lBuff, aTitle, aDefaultPath); 2784 | #endif /*TINYFD_NOSELECTFOLDERWIN*/ 2785 | } 2786 | } 2787 | else 2788 | #endif /* TINYFD_NOLIB */ 2789 | if ( dialogPresent() ) 2790 | { 2791 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} 2792 | p = selectFolderDialogWinConsole(lBuff,aTitle,aDefaultPath); 2793 | } 2794 | else 2795 | { 2796 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return (char const *)0;} 2797 | p = tinyfd_inputBox(aTitle, "Select folder",""); 2798 | } 2799 | 2800 | if ( ! p || ! strlen ( p ) || ! dirExists ( p ) ) 2801 | { 2802 | return NULL ; 2803 | } 2804 | return p ; 2805 | } 2806 | 2807 | 2808 | /* returns the hexcolor as a string "#FF0000" */ 2809 | /* aoResultRGB also contains the result */ 2810 | /* aDefaultRGB is used only if aDefaultHexRGB is NULL */ 2811 | /* aDefaultRGB and aoResultRGB can be the same array */ 2812 | char const * tinyfd_colorChooser( 2813 | char const * const aTitle, /* NULL or "" */ 2814 | char const * const aDefaultHexRGB, /* NULL or "#FF0000"*/ 2815 | unsigned char const aDefaultRGB[3], /* { 0 , 255 , 255 } */ 2816 | unsigned char aoResultRGB[3]) /* { 0 , 0 , 0 } */ 2817 | { 2818 | char lDefaultHexRGB[8]; 2819 | char * lpDefaultHexRGB; 2820 | int i; 2821 | char const * p ; 2822 | 2823 | #ifndef TINYFD_NOLIB 2824 | if ( (!tinyfd_forceConsole || !( GetConsoleWindow() || dialogPresent()) ) 2825 | && (!getenv("SSH_CLIENT") || getenv("DISPLAY")) ) 2826 | { 2827 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"windows");return (char const *)1;} 2828 | if (tinyfd_winUtf8) 2829 | { 2830 | return colorChooserWinGui8( 2831 | aTitle, aDefaultHexRGB, aDefaultRGB, aoResultRGB); 2832 | } 2833 | else 2834 | { 2835 | return colorChooserWinGuiA( 2836 | aTitle, aDefaultHexRGB, aDefaultRGB, aoResultRGB); 2837 | } 2838 | } 2839 | else 2840 | #endif /* TINYFD_NOLIB */ 2841 | if ( aDefaultHexRGB ) 2842 | { 2843 | lpDefaultHexRGB = (char *) aDefaultHexRGB ; 2844 | } 2845 | else 2846 | { 2847 | RGB2Hex( aDefaultRGB , lDefaultHexRGB ) ; 2848 | lpDefaultHexRGB = (char *) lDefaultHexRGB ; 2849 | } 2850 | p = tinyfd_inputBox(aTitle, 2851 | "Enter hex rgb color (i.e. #f5ca20)",lpDefaultHexRGB); 2852 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")) return p; 2853 | 2854 | if ( !p || (strlen(p) != 7) || (p[0] != '#') ) 2855 | { 2856 | return NULL ; 2857 | } 2858 | for ( i = 1 ; i < 7 ; i ++ ) 2859 | { 2860 | if ( ! isxdigit( p[i] ) ) 2861 | { 2862 | return NULL ; 2863 | } 2864 | } 2865 | Hex2RGB(p,aoResultRGB); 2866 | return p ; 2867 | } 2868 | 2869 | #else /* unix */ 2870 | 2871 | static char gPython2Name[16]; 2872 | 2873 | static int isDarwin ( ) 2874 | { 2875 | static int lsIsDarwin = -1 ; 2876 | struct utsname lUtsname ; 2877 | if ( lsIsDarwin < 0 ) 2878 | { 2879 | lsIsDarwin = !uname(&lUtsname) && !strcmp(lUtsname.sysname,"Darwin") ; 2880 | } 2881 | return lsIsDarwin ; 2882 | } 2883 | 2884 | 2885 | static int dirExists ( char const * const aDirPath ) 2886 | { 2887 | DIR * lDir ; 2888 | if ( ! aDirPath || ! strlen ( aDirPath ) ) 2889 | return 0 ; 2890 | lDir = opendir ( aDirPath ) ; 2891 | if ( ! lDir ) 2892 | { 2893 | return 0 ; 2894 | } 2895 | closedir ( lDir ) ; 2896 | return 1 ; 2897 | } 2898 | 2899 | 2900 | static int detectPresence ( char const * const aExecutable ) 2901 | { 2902 | char lBuff [MAX_PATH_OR_CMD] ; 2903 | char lTestedString [MAX_PATH_OR_CMD] = "which " ; 2904 | FILE * lIn ; 2905 | 2906 | strcat ( lTestedString , aExecutable ) ; 2907 | strcat( lTestedString, " 2>/dev/null "); 2908 | lIn = popen ( lTestedString , "r" ) ; 2909 | if ( ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) 2910 | && ( ! strchr ( lBuff , ':' ) ) 2911 | && ( strncmp(lBuff, "no ", 3) ) ) 2912 | { /* present */ 2913 | pclose ( lIn ) ; 2914 | if (tinyfd_verbose) printf("detectPresence %s %d\n", aExecutable, 1); 2915 | return 1 ; 2916 | } 2917 | else 2918 | { 2919 | pclose ( lIn ) ; 2920 | if (tinyfd_verbose) printf("detectPresence %s %d\n", aExecutable, 0); 2921 | return 0 ; 2922 | } 2923 | } 2924 | 2925 | 2926 | static char const * getVersion ( char const * const aExecutable ) /*version # must follow :*/ 2927 | { 2928 | static char lBuff [MAX_PATH_OR_CMD] ; 2929 | char lTestedString [MAX_PATH_OR_CMD] ; 2930 | FILE * lIn ; 2931 | char * lTmp ; 2932 | 2933 | strcpy ( lTestedString , aExecutable ) ; 2934 | strcat ( lTestedString , " --version" ) ; 2935 | 2936 | lIn = popen ( lTestedString , "r" ) ; 2937 | lTmp = fgets ( lBuff , sizeof ( lBuff ) , lIn ) ; 2938 | pclose ( lIn ) ; 2939 | if ( ! lTmp || !(lTmp = strchr ( lBuff , ':' )) ) return 0 ; 2940 | lTmp ++ ; 2941 | /* printf("lTmp %s\n", lTmp); */ 2942 | return lTmp ; 2943 | } 2944 | 2945 | 2946 | static int tryCommand ( char const * const aCommand ) 2947 | { 2948 | char lBuff [MAX_PATH_OR_CMD] ; 2949 | FILE * lIn ; 2950 | 2951 | lIn = popen ( aCommand , "r" ) ; 2952 | if ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) == NULL ) 2953 | { /* present */ 2954 | pclose ( lIn ) ; 2955 | return 1 ; 2956 | } 2957 | else 2958 | { 2959 | pclose ( lIn ) ; 2960 | return 0 ; 2961 | } 2962 | 2963 | } 2964 | 2965 | 2966 | static int isTerminalRunning() 2967 | { 2968 | return isatty(1); 2969 | } 2970 | 2971 | 2972 | static char const * dialogNameOnly ( ) 2973 | { 2974 | static char lDialogName[128] = "*" ; 2975 | if ( lDialogName[0] == '*' ) 2976 | { 2977 | if ( isDarwin() && strcpy(lDialogName , "/opt/local/bin/dialog" ) 2978 | && detectPresence ( lDialogName ) ) 2979 | {} 2980 | else if ( strcpy(lDialogName , "dialog" ) 2981 | && detectPresence ( lDialogName ) ) 2982 | {} 2983 | else 2984 | { 2985 | strcpy(lDialogName , "" ) ; 2986 | } 2987 | } 2988 | return lDialogName ; 2989 | } 2990 | 2991 | 2992 | int isDialogVersionBetter09b ( ) 2993 | { 2994 | char const * lDialogName ; 2995 | char * lVersion ; 2996 | int lMajor ; 2997 | int lMinor ; 2998 | int lDate ; 2999 | int lResult ; 3000 | char * lMinorP ; 3001 | char * lLetter ; 3002 | char lBuff[128] ; 3003 | 3004 | /*char lTest[128] = " 0.9b-20031126" ;*/ 3005 | 3006 | lDialogName = dialogNameOnly ( ) ; 3007 | if ( ! lDialogName || !(lVersion = (char *) getVersion(lDialogName)) ) return 0 ; 3008 | /*lVersion = lTest ;*/ 3009 | /*printf("lVersion %s\n", lVersion);*/ 3010 | strcpy(lBuff,lVersion); 3011 | lMajor = atoi ( strtok(lVersion," ,.-") ) ; 3012 | /*printf("lMajor %d\n", lMajor);*/ 3013 | lMinorP = strtok(0," ,.-abcdefghijklmnopqrstuvxyz"); 3014 | lMinor = atoi ( lMinorP ) ; 3015 | /*printf("lMinor %d\n", lMinor );*/ 3016 | lDate = atoi ( strtok(0," ,.-") ) ; 3017 | if (lDate<0) lDate = - lDate; 3018 | /*printf("lDate %d\n", lDate);*/ 3019 | lLetter = lMinorP + strlen(lMinorP) ; 3020 | strcpy(lVersion,lBuff); 3021 | strtok(lLetter," ,.-"); 3022 | /*printf("lLetter %s\n", lLetter);*/ 3023 | lResult = (lMajor > 0) || ( ( lMinor == 9 ) && (*lLetter == 'b') && (lDate >= 20031126) ); 3024 | /*printf("lResult %d\n", lResult);*/ 3025 | return lResult; 3026 | } 3027 | 3028 | 3029 | static int whiptailPresentOnly ( ) 3030 | { 3031 | static int lWhiptailPresent = -1 ; 3032 | if ( lWhiptailPresent < 0 ) 3033 | { 3034 | lWhiptailPresent = detectPresence ( "whiptail" ) ; 3035 | } 3036 | return lWhiptailPresent ; 3037 | } 3038 | 3039 | 3040 | static char const * terminalName ( ) 3041 | { 3042 | static char lTerminalName[128] = "*" ; 3043 | char lShellName[64] = "*" ; 3044 | 3045 | if ( lTerminalName[0] == '*' ) 3046 | { 3047 | if ( detectPresence ( "bash" ) ) 3048 | { 3049 | strcpy(lShellName , "bash -c " ) ; /*good for basic input*/ 3050 | } 3051 | else if ( dialogNameOnly() || whiptailPresentOnly() ) 3052 | { 3053 | strcpy(lShellName , "sh -c " ) ; /*good enough for dialog & whiptail*/ 3054 | } 3055 | else 3056 | { 3057 | return NULL ; 3058 | } 3059 | 3060 | if ( isDarwin() ) 3061 | { 3062 | if ( strcpy(lTerminalName , "/opt/X11/bin/xterm" ) 3063 | && detectPresence ( lTerminalName ) ) 3064 | { 3065 | strcat(lTerminalName , " -fa 'DejaVu Sans Mono' -fs 10 -title tinyfiledialogs -e " ) ; 3066 | strcat(lTerminalName , lShellName ) ; 3067 | } 3068 | else 3069 | { 3070 | strcpy(lTerminalName , "" ) ; 3071 | } 3072 | } 3073 | else if ( strcpy(lTerminalName,"xterm") /*good (small without parameters)*/ 3074 | && detectPresence(lTerminalName) ) 3075 | { 3076 | strcat(lTerminalName , " -fa 'DejaVu Sans Mono' -fs 10 -title tinyfiledialogs -e " ) ; 3077 | strcat(lTerminalName , lShellName ) ; 3078 | } 3079 | else if ( strcpy(lTerminalName,"terminator") /*good*/ 3080 | && detectPresence(lTerminalName) ) 3081 | { 3082 | strcat(lTerminalName , " -x " ) ; 3083 | strcat(lTerminalName , lShellName ) ; 3084 | } 3085 | else if ( strcpy(lTerminalName,"lxterminal") /*good*/ 3086 | && detectPresence(lTerminalName) ) 3087 | { 3088 | strcat(lTerminalName , " -e " ) ; 3089 | strcat(lTerminalName , lShellName ) ; 3090 | } 3091 | else if ( strcpy(lTerminalName,"konsole") /*good*/ 3092 | && detectPresence(lTerminalName) ) 3093 | { 3094 | strcat(lTerminalName , " -e " ) ; 3095 | strcat(lTerminalName , lShellName ) ; 3096 | } 3097 | else if ( strcpy(lTerminalName,"kterm") /*good*/ 3098 | && detectPresence(lTerminalName) ) 3099 | { 3100 | strcat(lTerminalName , " -e " ) ; 3101 | strcat(lTerminalName , lShellName ) ; 3102 | } 3103 | else if ( strcpy(lTerminalName,"xfce4-terminal") /*good*/ 3104 | && detectPresence(lTerminalName) ) 3105 | { 3106 | strcat(lTerminalName , " -x " ) ; 3107 | strcat(lTerminalName , lShellName ) ; 3108 | } 3109 | else if ( strcpy(lTerminalName,"mate-terminal") /*good*/ 3110 | && detectPresence(lTerminalName) ) 3111 | { 3112 | strcat(lTerminalName , " -x " ) ; 3113 | strcat(lTerminalName , lShellName ) ; 3114 | } 3115 | else if ( strcpy(lTerminalName,"Eterm") /*good*/ 3116 | && detectPresence(lTerminalName) ) 3117 | { 3118 | strcat(lTerminalName , " -e " ) ; 3119 | strcat(lTerminalName , lShellName ) ; 3120 | } 3121 | else if ( strcpy(lTerminalName,"evilvte") /*good*/ 3122 | && detectPresence(lTerminalName) ) 3123 | { 3124 | strcat(lTerminalName , " -e " ) ; 3125 | strcat(lTerminalName , lShellName ) ; 3126 | } 3127 | else if ( strcpy(lTerminalName,"pterm") /*good (only letters)*/ 3128 | && detectPresence(lTerminalName) ) 3129 | { 3130 | strcat(lTerminalName , " -e " ) ; 3131 | strcat(lTerminalName , lShellName ) ; 3132 | } 3133 | else 3134 | { 3135 | strcpy(lTerminalName , "" ) ; 3136 | } 3137 | /*else if ( strcpy(lTerminalName,"gnome-terminal") //bad (good if version < 3) 3138 | && detectPresence(lTerminalName) ) 3139 | { 3140 | strcat(lTerminalName , " --disable-factory -x " ) ; 3141 | strcat(lTerminalName , lShellName ) ; 3142 | }*/ 3143 | /* bad: koi rxterm guake tilda vala-terminal qterminal 3144 | aterm Terminal terminology sakura lilyterm weston-terminal 3145 | roxterm termit xvt rxvt mrxvt urxvt */ 3146 | } 3147 | if ( strlen(lTerminalName) ) 3148 | { 3149 | return lTerminalName ; 3150 | } 3151 | else 3152 | { 3153 | return NULL ; 3154 | } 3155 | } 3156 | 3157 | 3158 | static char const * dialogName ( ) 3159 | { 3160 | char const * lDialogName ; 3161 | lDialogName = dialogNameOnly ( ) ; 3162 | if ( strlen(lDialogName) && ( isTerminalRunning() || terminalName() ) ) 3163 | { 3164 | return lDialogName ; 3165 | } 3166 | else 3167 | { 3168 | return NULL ; 3169 | } 3170 | } 3171 | 3172 | 3173 | static int whiptailPresent ( ) 3174 | { 3175 | int lWhiptailPresent ; 3176 | lWhiptailPresent = whiptailPresentOnly ( ) ; 3177 | if ( lWhiptailPresent && ( isTerminalRunning() || terminalName() ) ) 3178 | { 3179 | return lWhiptailPresent ; 3180 | } 3181 | else 3182 | { 3183 | return 0 ; 3184 | } 3185 | } 3186 | 3187 | 3188 | 3189 | static int graphicMode() 3190 | { 3191 | return !( tinyfd_forceConsole && (isTerminalRunning() || terminalName()) ) 3192 | && ( getenv("DISPLAY") 3193 | || (isDarwin() && (!getenv("SSH_TTY") || getenv("DISPLAY") ) ) ) ; 3194 | } 3195 | 3196 | 3197 | static int xmessagePresent ( ) 3198 | { 3199 | static int lXmessagePresent = -1 ; 3200 | if ( lXmessagePresent < 0 ) 3201 | { 3202 | lXmessagePresent = detectPresence("xmessage");/*if not tty,not on osxpath*/ 3203 | } 3204 | return lXmessagePresent && graphicMode ( ) ; 3205 | } 3206 | 3207 | 3208 | static int gxmessagePresent ( ) 3209 | { 3210 | static int lGxmessagePresent = -1 ; 3211 | if ( lGxmessagePresent < 0 ) 3212 | { 3213 | lGxmessagePresent = detectPresence("gxmessage") ; 3214 | } 3215 | return lGxmessagePresent && graphicMode ( ) ; 3216 | } 3217 | 3218 | 3219 | static int gmessagePresent ( ) 3220 | { 3221 | static int lGmessagePresent = -1 ; 3222 | if ( lGmessagePresent < 0 ) 3223 | { 3224 | lGmessagePresent = detectPresence("gmessage") ; 3225 | } 3226 | return lGmessagePresent && graphicMode ( ) ; 3227 | } 3228 | 3229 | 3230 | static int notifysendPresent ( ) 3231 | { 3232 | static int lNotifysendPresent = -1 ; 3233 | if ( lNotifysendPresent < 0 ) 3234 | { 3235 | lNotifysendPresent = detectPresence("notify-send") ; 3236 | } 3237 | return lNotifysendPresent && graphicMode ( ) ; 3238 | } 3239 | 3240 | 3241 | static int xdialogPresent ( ) 3242 | { 3243 | static int lXdialogPresent = -1 ; 3244 | if ( lXdialogPresent < 0 ) 3245 | { 3246 | lXdialogPresent = detectPresence("Xdialog") ; 3247 | } 3248 | return lXdialogPresent && graphicMode ( ) ; 3249 | } 3250 | 3251 | 3252 | static int gdialogPresent ( ) 3253 | { 3254 | static int lGdialoglPresent = -1 ; 3255 | if ( lGdialoglPresent < 0 ) 3256 | { 3257 | lGdialoglPresent = detectPresence ( "gdialog" ) ; 3258 | } 3259 | return lGdialoglPresent && graphicMode ( ) ; 3260 | } 3261 | 3262 | 3263 | static int osascriptPresent ( ) 3264 | { 3265 | static int lOsascriptPresent = -1 ; 3266 | if ( lOsascriptPresent < 0 ) 3267 | { 3268 | gWarningDisplayed |= !!getenv("SSH_TTY"); 3269 | lOsascriptPresent = detectPresence ( "osascript" ) ; 3270 | } 3271 | return lOsascriptPresent && graphicMode() && !getenv("SSH_TTY") ; 3272 | } 3273 | 3274 | 3275 | static int kdialogPresent ( ) 3276 | { 3277 | static int lKdialogPresent = -1 ; 3278 | if ( lKdialogPresent < 0 ) 3279 | { 3280 | lKdialogPresent = detectPresence("kdialog") ; 3281 | } 3282 | return lKdialogPresent && graphicMode ( ) ; 3283 | } 3284 | 3285 | 3286 | static int qarmaPresent ( ) 3287 | { 3288 | static int lQarmaPresent = -1 ; 3289 | if ( lQarmaPresent < 0 ) 3290 | { 3291 | lQarmaPresent = detectPresence("qarma") ; 3292 | } 3293 | return lQarmaPresent && graphicMode ( ) ; 3294 | } 3295 | 3296 | 3297 | static int matedialogPresent ( ) 3298 | { 3299 | static int lMatedialogPresent = -1 ; 3300 | if ( lMatedialogPresent < 0 ) 3301 | { 3302 | lMatedialogPresent = detectPresence("matedialog") ; 3303 | } 3304 | return lMatedialogPresent && graphicMode ( ) ; 3305 | } 3306 | 3307 | 3308 | static int zenityPresent ( ) 3309 | { 3310 | static int lZenityPresent = -1 ; 3311 | if ( lZenityPresent < 0 ) 3312 | { 3313 | lZenityPresent = detectPresence("zenity") ; 3314 | } 3315 | return lZenityPresent && graphicMode ( ) ; 3316 | } 3317 | 3318 | 3319 | static int osx9orBetter ( ) 3320 | { 3321 | static int lOsx9orBetter = -1 ; 3322 | char lBuff [MAX_PATH_OR_CMD] ; 3323 | FILE * lIn ; 3324 | int V,v; 3325 | 3326 | if ( lOsx9orBetter < 0 ) 3327 | { 3328 | lOsx9orBetter = 0 ; 3329 | lIn = popen ( "osascript -e 'set osver to system version of (system info)'" , "r" ) ; 3330 | if ( ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) 3331 | && ( 2 == sscanf(lBuff, "%d.%d", &V, &v) ) ) 3332 | { 3333 | V = V * 100 + v; 3334 | if ( V >= 1009 ) 3335 | { 3336 | lOsx9orBetter = 1 ; 3337 | } 3338 | } 3339 | pclose ( lIn ) ; 3340 | /* printf ("Osx10 = %d, %d = <%s>\n", lOsx9orBetter, V, lBuff) ; */ 3341 | } 3342 | return lOsx9orBetter ; 3343 | } 3344 | 3345 | 3346 | static int zenity3Present ( ) 3347 | { 3348 | static int lZenity3Present = -1 ; 3349 | char lBuff [MAX_PATH_OR_CMD] ; 3350 | FILE * lIn ; 3351 | 3352 | if ( lZenity3Present < 0 ) 3353 | { 3354 | lZenity3Present = 0 ; 3355 | if ( zenityPresent() ) 3356 | { 3357 | lIn = popen ( "zenity --version" , "r" ) ; 3358 | if ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) 3359 | { 3360 | if ( atoi(lBuff) >= 3 ) 3361 | { 3362 | lZenity3Present = 3 ; 3363 | } 3364 | else if ( ( atoi(lBuff) == 2 ) && ( atoi(strtok(lBuff,".")+2 ) >= 32 ) ) 3365 | { 3366 | lZenity3Present = 2 ; 3367 | } 3368 | } 3369 | pclose ( lIn ) ; 3370 | } 3371 | } 3372 | return lZenity3Present && graphicMode ( ) ; 3373 | } 3374 | 3375 | 3376 | static int tkinter2Present ( ) 3377 | { 3378 | static int lTkinter2Present = -1 ; 3379 | char lPythonCommand[256]; 3380 | char lPythonParams[256] = 3381 | "-c \"try:\n\timport Tkinter;\nexcept:\n\tprint(0);\""; 3382 | int i; 3383 | 3384 | if ( lTkinter2Present < 0 ) 3385 | { 3386 | lTkinter2Present = 0 ; 3387 | strcpy(gPython2Name , "python" ) ; 3388 | sprintf ( lPythonCommand , "%s %s" , gPython2Name , lPythonParams ) ; 3389 | if ( ! detectPresence(gPython2Name) 3390 | || ! (lTkinter2Present = tryCommand(lPythonCommand)) ) 3391 | { 3392 | strcpy(gPython2Name , "python2" ) ; 3393 | if ( detectPresence(gPython2Name) ) 3394 | { 3395 | sprintf ( lPythonCommand , "%s %s" , gPython2Name , lPythonParams ) ; 3396 | lTkinter2Present = tryCommand(lPythonCommand); 3397 | } 3398 | else 3399 | { 3400 | for ( i = 9 ; i >= 0 ; i -- ) 3401 | { 3402 | sprintf ( gPython2Name , "python2.%d" , i ) ; 3403 | if ( detectPresence(gPython2Name) ) 3404 | { 3405 | sprintf ( lPythonCommand , "%s %s" , gPython2Name , lPythonParams ) ; 3406 | lTkinter2Present = tryCommand(lPythonCommand); 3407 | break ; 3408 | } 3409 | } 3410 | } 3411 | } 3412 | } 3413 | /* printf ("lTkinter2Present %d\n", lTkinter2Present) ; */ 3414 | /* printf ("gPython2Name %s\n", gPython2Name) ; */ 3415 | return lTkinter2Present && graphicMode() && !(isDarwin() && getenv("SSH_TTY") ); 3416 | } 3417 | 3418 | 3419 | int tinyfd_messageBox ( 3420 | char const * const aTitle , /* NULL or "" */ 3421 | char const * const aMessage , /* NULL or "" may contain \n and \t */ 3422 | char const * const aDialogType , /* "ok" "okcancel" "yesno" "yesnocancel" */ 3423 | char const * const aIconType , /* "info" "warning" "error" "question" */ 3424 | int const aDefaultButton ) /* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */ 3425 | { 3426 | char lBuff [MAX_PATH_OR_CMD] ; 3427 | char * lDialogString = NULL ; 3428 | char * lpDialogString; 3429 | FILE * lIn ; 3430 | int lWasGraphicDialog = 0 ; 3431 | int lWasXterm = 0 ; 3432 | int lResult ; 3433 | char lChar ; 3434 | struct termios infoOri; 3435 | struct termios info; 3436 | int lTitleLen ; 3437 | int lMessageLen ; 3438 | 3439 | lBuff[0]='\0'; 3440 | 3441 | lTitleLen = aTitle ? strlen(aTitle) : 0 ; 3442 | lMessageLen = aMessage ? strlen(aMessage) : 0 ; 3443 | if ( !aTitle || strcmp(aTitle,"tinyfd_query") ) 3444 | { 3445 | lDialogString = (char *) malloc( MAX_PATH_OR_CMD + lTitleLen + lMessageLen ); 3446 | } 3447 | 3448 | if ( osascriptPresent ( ) ) 3449 | { 3450 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"applescript");return 1;} 3451 | 3452 | strcpy ( lDialogString , "osascript "); 3453 | if ( ! osx9orBetter() ) strcat ( lDialogString , " -e 'tell application \"System Events\"' -e 'Activate'"); 3454 | strcat ( lDialogString , " -e 'try' -e 'set {vButton} to {button returned} of ( display dialog \"") ; 3455 | if ( aMessage && strlen(aMessage) ) 3456 | { 3457 | strcat(lDialogString, aMessage) ; 3458 | } 3459 | strcat(lDialogString, "\" ") ; 3460 | if ( aTitle && strlen(aTitle) ) 3461 | { 3462 | strcat(lDialogString, "with title \"") ; 3463 | strcat(lDialogString, aTitle) ; 3464 | strcat(lDialogString, "\" ") ; 3465 | } 3466 | strcat(lDialogString, "with icon ") ; 3467 | if ( aIconType && ! strcmp( "error" , aIconType ) ) 3468 | { 3469 | strcat(lDialogString, "stop " ) ; 3470 | } 3471 | else if ( aIconType && ! strcmp( "warning" , aIconType ) ) 3472 | { 3473 | strcat(lDialogString, "caution " ) ; 3474 | } 3475 | else /* question or info */ 3476 | { 3477 | strcat(lDialogString, "note " ) ; 3478 | } 3479 | if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) ) 3480 | { 3481 | if ( ! aDefaultButton ) 3482 | { 3483 | strcat ( lDialogString ,"default button \"Cancel\" " ) ; 3484 | } 3485 | } 3486 | else if ( aDialogType && ! strcmp( "yesno" , aDialogType ) ) 3487 | { 3488 | strcat ( lDialogString ,"buttons {\"No\", \"Yes\"} " ) ; 3489 | if (aDefaultButton) 3490 | { 3491 | strcat ( lDialogString ,"default button \"Yes\" " ) ; 3492 | } 3493 | else 3494 | { 3495 | strcat ( lDialogString ,"default button \"No\" " ) ; 3496 | } 3497 | strcat ( lDialogString ,"cancel button \"No\"" ) ; 3498 | } 3499 | else if ( aDialogType && ! strcmp( "yesnocancel" , aDialogType ) ) 3500 | { 3501 | strcat ( lDialogString ,"buttons {\"No\", \"Yes\", \"Cancel\"} " ) ; 3502 | switch (aDefaultButton) 3503 | { 3504 | case 1: strcat ( lDialogString ,"default button \"Yes\" " ) ; break; 3505 | case 2: strcat ( lDialogString ,"default button \"No\" " ) ; break; 3506 | case 0: strcat ( lDialogString ,"default button \"Cancel\" " ) ; break; 3507 | } 3508 | strcat ( lDialogString ,"cancel button \"Cancel\"" ) ; 3509 | } 3510 | else 3511 | { 3512 | strcat ( lDialogString ,"buttons {\"OK\"} " ) ; 3513 | strcat ( lDialogString ,"default button \"OK\" " ) ; 3514 | } 3515 | strcat ( lDialogString, ")' ") ; 3516 | 3517 | strcat ( lDialogString, 3518 | "-e 'if vButton is \"Yes\" then' -e 'return 1' -e 'else if vButton is \"No\" then' -e 'return 2' -e 'else' -e 'return 0' -e 'end if' " ); 3519 | 3520 | strcat ( lDialogString, "-e 'on error number -128' " ) ; 3521 | strcat ( lDialogString, "-e '0' " ); 3522 | 3523 | strcat ( lDialogString, "-e 'end try'") ; 3524 | if ( ! osx9orBetter() ) strcat ( lDialogString, " -e 'end tell'") ; 3525 | } 3526 | else if ( zenityPresent() || matedialogPresent() || qarmaPresent() ) 3527 | { 3528 | if ( zenityPresent() ) 3529 | { 3530 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity");return 1;} 3531 | strcpy ( lDialogString , "szAnswer=$(zenity --" ) ; 3532 | } 3533 | else if ( matedialogPresent() ) 3534 | { 3535 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"matedialog");return 1;} 3536 | strcpy ( lDialogString , "szAnswer=$(matedialog --" ) ; 3537 | } 3538 | else 3539 | { 3540 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"qarma");return 1;} 3541 | strcpy ( lDialogString , "szAnswer=$(qarma --" ) ; 3542 | } 3543 | 3544 | if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) ) 3545 | { 3546 | strcat ( lDialogString , 3547 | "question --ok-label=Ok --cancel-label=Cancel" ) ; 3548 | } 3549 | else if ( aDialogType && ! strcmp( "yesno" , aDialogType ) ) 3550 | { 3551 | strcat ( lDialogString , "question" ) ; 3552 | } 3553 | else if ( aDialogType && ! strcmp( "yesnocancel" , aDialogType ) ) 3554 | { 3555 | strcat ( lDialogString , "list --column \"\" --hide-header \"Yes\" \"No\"" ) ; 3556 | } 3557 | else if ( aIconType && ! strcmp( "error" , aIconType ) ) 3558 | { 3559 | strcat ( lDialogString , "error" ) ; 3560 | } 3561 | else if ( aIconType && ! strcmp( "warning" , aIconType ) ) 3562 | { 3563 | strcat ( lDialogString , "warning" ) ; 3564 | } 3565 | else 3566 | { 3567 | strcat ( lDialogString , "info" ) ; 3568 | } 3569 | if ( aTitle && strlen(aTitle) ) 3570 | { 3571 | strcat(lDialogString, " --title=\"") ; 3572 | strcat(lDialogString, aTitle) ; 3573 | strcat(lDialogString, "\"") ; 3574 | } 3575 | if ( aMessage && strlen(aMessage) ) 3576 | { 3577 | strcat(lDialogString, " --text=\"") ; 3578 | strcat(lDialogString, aMessage) ; 3579 | strcat(lDialogString, "\"") ; 3580 | } 3581 | if ( zenity3Present ( ) >= 3 ) 3582 | { 3583 | strcat ( lDialogString , " --icon-name=dialog-" ) ; 3584 | if ( aIconType && (! strcmp( "question" , aIconType ) 3585 | || ! strcmp( "error" , aIconType ) 3586 | || ! strcmp( "warning" , aIconType ) ) ) 3587 | { 3588 | strcat ( lDialogString , aIconType ) ; 3589 | } 3590 | else 3591 | { 3592 | strcat ( lDialogString , "information" ) ; 3593 | } 3594 | } 3595 | 3596 | if ( ! strcmp( "yesnocancel" , aDialogType ) ) 3597 | { 3598 | strcat ( lDialogString , 3599 | ");if [ $? = 1 ];then echo 0;elif [ $szAnswer = \"No\" ];then echo 2;else echo 1;fi"); 3600 | } 3601 | else 3602 | { 3603 | strcat ( lDialogString , ");if [ $? = 0 ];then echo 1;else echo 0;fi"); 3604 | } 3605 | } 3606 | else if ( kdialogPresent() ) 3607 | { 3608 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"kdialog");return 1;} 3609 | 3610 | strcpy ( lDialogString , "kdialog --" ) ; 3611 | if ( aDialogType && ( ! strcmp( "okcancel" , aDialogType ) 3612 | || ! strcmp( "yesno" , aDialogType ) || ! strcmp( "yesnocancel" , aDialogType ) ) ) 3613 | { 3614 | if ( aIconType && ( ! strcmp( "warning" , aIconType ) 3615 | || ! strcmp( "error" , aIconType ) ) ) 3616 | { 3617 | strcat ( lDialogString , "warning" ) ; 3618 | } 3619 | if ( ! strcmp( "yesnocancel" , aDialogType ) ) 3620 | { 3621 | strcat ( lDialogString , "yesnocancel" ) ; 3622 | } 3623 | else 3624 | { 3625 | strcat ( lDialogString , "yesno" ) ; 3626 | } 3627 | } 3628 | else if ( aIconType && ! strcmp( "error" , aIconType ) ) 3629 | { 3630 | strcat ( lDialogString , "error" ) ; 3631 | } 3632 | else if ( aIconType && ! strcmp( "warning" , aIconType ) ) 3633 | { 3634 | strcat ( lDialogString , "sorry" ) ; 3635 | } 3636 | else 3637 | { 3638 | strcat ( lDialogString , "msgbox" ) ; 3639 | } 3640 | strcat ( lDialogString , " \"" ) ; 3641 | if ( aMessage ) 3642 | { 3643 | strcat ( lDialogString , aMessage ) ; 3644 | } 3645 | strcat ( lDialogString , "\"" ) ; 3646 | if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) ) 3647 | { 3648 | strcat ( lDialogString , 3649 | " --yes-label Ok --no-label Cancel" ) ; 3650 | } 3651 | if ( aTitle && strlen(aTitle) ) 3652 | { 3653 | strcat(lDialogString, " --title \"") ; 3654 | strcat(lDialogString, aTitle) ; 3655 | strcat(lDialogString, "\"") ; 3656 | } 3657 | 3658 | if ( ! strcmp( "yesnocancel" , aDialogType ) ) 3659 | { 3660 | strcat ( lDialogString , "; x=$? ;if [ $x = 0 ] ;then echo 1;elif [ $x = 1 ] ;then echo 2;else echo 0;fi"); 3661 | } 3662 | else 3663 | { 3664 | strcat ( lDialogString , ";if [ $? = 0 ];then echo 1;else echo 0;fi"); 3665 | } 3666 | } 3667 | else if ( !gxmessagePresent() && !gmessagePresent() && !gdialogPresent() && !xdialogPresent() && tkinter2Present ( ) ) 3668 | { 3669 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"tkinter");return 1;} 3670 | 3671 | strcpy ( lDialogString , gPython2Name ) ; 3672 | if ( ! isTerminalRunning ( ) && isDarwin ( ) ) 3673 | { 3674 | strcat ( lDialogString , " -i" ) ; /* for osx without console */ 3675 | } 3676 | 3677 | strcat ( lDialogString , 3678 | " -c \"import Tkinter,tkMessageBox;root=Tkinter.Tk();root.withdraw();"); 3679 | 3680 | if ( isDarwin ( ) ) 3681 | { 3682 | strcat ( lDialogString , 3683 | "import os;os.system('''/usr/bin/osascript -e 'tell app \\\"Finder\\\" to set \ 3684 | frontmost of process \\\"Python\\\" to true' ''');"); 3685 | } 3686 | 3687 | strcat ( lDialogString ,"res=tkMessageBox." ) ; 3688 | if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) ) 3689 | { 3690 | strcat ( lDialogString , "askokcancel(" ) ; 3691 | if ( aDefaultButton ) 3692 | { 3693 | strcat ( lDialogString , "default=tkMessageBox.OK," ) ; 3694 | } 3695 | else 3696 | { 3697 | strcat ( lDialogString , "default=tkMessageBox.CANCEL," ) ; 3698 | } 3699 | } 3700 | else if ( aDialogType && ! strcmp( "yesno" , aDialogType ) ) 3701 | { 3702 | strcat ( lDialogString , "askyesno(" ) ; 3703 | if ( aDefaultButton ) 3704 | { 3705 | strcat ( lDialogString , "default=tkMessageBox.YES," ) ; 3706 | } 3707 | else 3708 | { 3709 | strcat ( lDialogString , "default=tkMessageBox.NO," ) ; 3710 | } 3711 | } 3712 | else if ( aDialogType && ! strcmp( "yesnocancel" , aDialogType ) ) 3713 | { 3714 | strcat ( lDialogString , "askyesnocancel(" ) ; 3715 | switch ( aDefaultButton ) 3716 | { 3717 | case 1: strcat ( lDialogString , "default=tkMessageBox.YES," ); break; 3718 | case 2: strcat ( lDialogString , "default=tkMessageBox.NO," ); break; 3719 | case 0: strcat ( lDialogString , "default=tkMessageBox.CANCEL," ); break; 3720 | } 3721 | } 3722 | else 3723 | { 3724 | strcat ( lDialogString , "showinfo(" ) ; 3725 | } 3726 | 3727 | strcat ( lDialogString , "icon='" ) ; 3728 | if ( aIconType && (! strcmp( "question" , aIconType ) 3729 | || ! strcmp( "error" , aIconType ) 3730 | || ! strcmp( "warning" , aIconType ) ) ) 3731 | { 3732 | strcat ( lDialogString , aIconType ) ; 3733 | } 3734 | else 3735 | { 3736 | strcat ( lDialogString , "info" ) ; 3737 | } 3738 | 3739 | strcat(lDialogString, "',") ; 3740 | if ( aTitle && strlen(aTitle) ) 3741 | { 3742 | strcat(lDialogString, "title='") ; 3743 | strcat(lDialogString, aTitle) ; 3744 | strcat(lDialogString, "',") ; 3745 | } 3746 | if ( aMessage && strlen(aMessage) ) 3747 | { 3748 | strcat(lDialogString, "message='") ; 3749 | lpDialogString = lDialogString + strlen(lDialogString); 3750 | replaceSubStr ( aMessage , "\n" , "\\n" , lpDialogString ) ; 3751 | strcat(lDialogString, "'") ; 3752 | } 3753 | 3754 | if ( aDialogType && ! strcmp( "yesnocancel" , aDialogType ) ) 3755 | { 3756 | strcat(lDialogString, ");\n\ 3757 | if res is None :\n\tprint 0\n\ 3758 | elif res is False :\n\tprint 2\n\ 3759 | else :\n\tprint 1\n\"" ) ; 3760 | } 3761 | else 3762 | { 3763 | strcat(lDialogString, ");\n\ 3764 | if res is False :\n\tprint 0\n\ 3765 | else :\n\tprint 1\n\"" ) ; 3766 | } 3767 | } 3768 | else if ( gxmessagePresent() || gmessagePresent() || (!gdialogPresent() && !xdialogPresent() && xmessagePresent()) ) 3769 | { 3770 | if ( gxmessagePresent() ) 3771 | { 3772 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"gxmessage");return 1;} 3773 | strcpy ( lDialogString , "gxmessage"); 3774 | } 3775 | else if ( gmessagePresent() ) 3776 | { 3777 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"gmessage");return 1;} 3778 | strcpy ( lDialogString , "gmessage"); 3779 | } 3780 | else 3781 | { 3782 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xmessage");return 1;} 3783 | strcpy ( lDialogString , "xmessage"); 3784 | } 3785 | 3786 | if ( aDialogType && ! strcmp("okcancel" , aDialogType) ) 3787 | { 3788 | strcat ( lDialogString , " -buttons Ok:1,Cancel:0"); 3789 | switch ( aDefaultButton ) 3790 | { 3791 | case 1: strcat ( lDialogString , " -default Ok"); break; 3792 | case 0: strcat ( lDialogString , " -default Cancel"); break; 3793 | } 3794 | } 3795 | else if ( aDialogType && ! strcmp("yesno" , aDialogType) ) 3796 | { 3797 | strcat ( lDialogString , " -buttons Yes:1,No:0"); 3798 | switch ( aDefaultButton ) 3799 | { 3800 | case 1: strcat ( lDialogString , " -default Yes"); break; 3801 | case 0: strcat ( lDialogString , " -default No"); break; 3802 | } 3803 | } 3804 | else if ( aDialogType && ! strcmp("yesnocancel" , aDialogType) ) 3805 | { 3806 | strcat ( lDialogString , " -buttons Yes:1,No:2,Cancel:0"); 3807 | switch ( aDefaultButton ) 3808 | { 3809 | case 1: strcat ( lDialogString , " -default Yes"); break; 3810 | case 2: strcat ( lDialogString , " -default No"); break; 3811 | case 0: strcat ( lDialogString , " -default Cancel"); break; 3812 | } 3813 | } 3814 | else 3815 | { 3816 | strcat ( lDialogString , " -buttons Ok:1"); 3817 | strcat ( lDialogString , " -default Ok"); 3818 | } 3819 | 3820 | strcat ( lDialogString , " -center \""); 3821 | if ( aMessage && strlen(aMessage) ) 3822 | { 3823 | strcat ( lDialogString , aMessage ) ; 3824 | } 3825 | strcat(lDialogString, "\"" ) ; 3826 | if ( aTitle && strlen(aTitle) ) 3827 | { 3828 | strcat ( lDialogString , " -title \""); 3829 | strcat ( lDialogString , aTitle ) ; 3830 | strcat ( lDialogString, "\"" ) ; 3831 | } 3832 | strcat ( lDialogString , " ; echo $? "); 3833 | } 3834 | else if ( xdialogPresent() || gdialogPresent() || dialogName() || whiptailPresent() ) 3835 | { 3836 | if ( gdialogPresent ( ) ) 3837 | { 3838 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"gdialog");return 1;} 3839 | lWasGraphicDialog = 1 ; 3840 | strcpy ( lDialogString , "(gdialog " ) ; 3841 | } 3842 | else if ( xdialogPresent ( ) ) 3843 | { 3844 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xdialog");return 1;} 3845 | lWasGraphicDialog = 1 ; 3846 | strcpy ( lDialogString , "(Xdialog " ) ; 3847 | } 3848 | else if ( dialogName ( ) ) 3849 | { 3850 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return 0;} 3851 | if ( isTerminalRunning ( ) ) 3852 | { 3853 | strcpy ( lDialogString , "(dialog " ) ; 3854 | } 3855 | else 3856 | { 3857 | lWasXterm = 1 ; 3858 | strcpy ( lDialogString , terminalName() ) ; 3859 | strcat ( lDialogString , "'(" ) ; 3860 | strcat ( lDialogString , dialogName() ) ; 3861 | strcat ( lDialogString , " " ) ; 3862 | } 3863 | } 3864 | else if ( isTerminalRunning ( ) ) 3865 | { 3866 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"whiptail");return 0;} 3867 | strcpy ( lDialogString , "(whiptail " ) ; 3868 | } 3869 | else 3870 | { 3871 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"whiptail");return 0;} 3872 | lWasXterm = 1 ; 3873 | strcpy ( lDialogString , terminalName() ) ; 3874 | strcat ( lDialogString , "'(whiptail " ) ; 3875 | } 3876 | 3877 | if ( aTitle && strlen(aTitle) ) 3878 | { 3879 | strcat(lDialogString, "--title \"") ; 3880 | strcat(lDialogString, aTitle) ; 3881 | strcat(lDialogString, "\" ") ; 3882 | } 3883 | 3884 | if ( !xdialogPresent() && !gdialogPresent() ) 3885 | { 3886 | if ( aDialogType && ( !strcmp( "okcancel" , aDialogType ) || !strcmp( "yesno" , aDialogType ) 3887 | || !strcmp( "yesnocancel" , aDialogType ) ) ) 3888 | { 3889 | strcat(lDialogString, "--backtitle \"") ; 3890 | strcat(lDialogString, "tab: move focus") ; 3891 | strcat(lDialogString, "\" ") ; 3892 | } 3893 | } 3894 | 3895 | if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) ) 3896 | { 3897 | if ( ! aDefaultButton ) 3898 | { 3899 | strcat ( lDialogString , "--defaultno " ) ; 3900 | } 3901 | strcat ( lDialogString , 3902 | "--yes-label \"Ok\" --no-label \"Cancel\" --yesno " ) ; 3903 | } 3904 | else if ( aDialogType && ! strcmp( "yesno" , aDialogType ) ) 3905 | { 3906 | if ( ! aDefaultButton ) 3907 | { 3908 | strcat ( lDialogString , "--defaultno " ) ; 3909 | } 3910 | strcat ( lDialogString , "--yesno " ) ; 3911 | } 3912 | else if (aDialogType && !strcmp("yesnocancel", aDialogType)) 3913 | { 3914 | if (!aDefaultButton) 3915 | { 3916 | strcat(lDialogString, "--defaultno "); 3917 | } 3918 | strcat(lDialogString, "--menu "); 3919 | } 3920 | else 3921 | { 3922 | strcat ( lDialogString , "--msgbox " ) ; 3923 | 3924 | } 3925 | strcat ( lDialogString , "\"" ) ; 3926 | if ( aMessage && strlen(aMessage) ) 3927 | { 3928 | strcat(lDialogString, aMessage) ; 3929 | } 3930 | strcat(lDialogString, "\" "); 3931 | 3932 | if ( lWasGraphicDialog ) 3933 | { 3934 | if (aDialogType && !strcmp("yesnocancel", aDialogType)) 3935 | { 3936 | strcat(lDialogString,"0 60 0 Yes \"\" No \"\") 2>/tmp/tinyfd.txt;\ 3937 | if [ $? = 0 ];then tinyfdBool=1;else tinyfdBool=0;fi;\ 3938 | tinyfdRes=$(cat /tmp/tinyfd.txt);echo $tinyfdBool$tinyfdRes") ; 3939 | } 3940 | else 3941 | { 3942 | strcat(lDialogString, 3943 | "10 60 ) 2>&1;if [ $? = 0 ];then echo 1;else echo 0;fi"); 3944 | } 3945 | } 3946 | else 3947 | { 3948 | if (aDialogType && !strcmp("yesnocancel", aDialogType)) 3949 | { 3950 | strcat(lDialogString,"0 60 0 Yes \"\" No \"\" >/dev/tty ) 2>/tmp/tinyfd.txt;\ 3951 | if [ $? = 0 ];then tinyfdBool=1;else tinyfdBool=0;fi;\ 3952 | tinyfdRes=$(cat /tmp/tinyfd.txt);echo $tinyfdBool$tinyfdRes") ; 3953 | 3954 | if ( lWasXterm ) 3955 | { 3956 | strcat(lDialogString," >/tmp/tinyfd0.txt';cat /tmp/tinyfd0.txt"); 3957 | } 3958 | else 3959 | { 3960 | strcat(lDialogString, "; clear >/dev/tty") ; 3961 | } 3962 | } 3963 | else 3964 | { 3965 | strcat(lDialogString, "10 60 >/dev/tty) 2>&1;if [ $? = 0 ];"); 3966 | if ( lWasXterm ) 3967 | { 3968 | strcat ( lDialogString , 3969 | "then\n\techo 1\nelse\n\techo 0\nfi >/tmp/tinyfd.txt';cat /tmp/tinyfd.txt;rm /tmp/tinyfd.txt"); 3970 | } 3971 | else 3972 | { 3973 | strcat(lDialogString, 3974 | "then echo 1;else echo 0;fi;clear >/dev/tty"); 3975 | } 3976 | } 3977 | } 3978 | } 3979 | else if ( ! isTerminalRunning ( ) && terminalName() ) 3980 | { 3981 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return 0;} 3982 | strcpy ( lDialogString , terminalName() ) ; 3983 | strcat ( lDialogString , "'" ) ; 3984 | if ( !gWarningDisplayed && !tinyfd_forceConsole) 3985 | { 3986 | gWarningDisplayed = 1 ; 3987 | strcat ( lDialogString , "echo \"" ) ; 3988 | strcat ( lDialogString, gTitle) ; 3989 | strcat ( lDialogString , "\";" ) ; 3990 | strcat ( lDialogString , "echo \"" ) ; 3991 | strcat ( lDialogString, gMessageUnix) ; 3992 | strcat ( lDialogString , "\";echo;echo;" ) ; 3993 | } 3994 | if ( aTitle && strlen(aTitle) ) 3995 | { 3996 | strcat ( lDialogString , "echo \"" ) ; 3997 | strcat ( lDialogString, aTitle) ; 3998 | strcat ( lDialogString , "\";echo;" ) ; 3999 | } 4000 | if ( aMessage && strlen(aMessage) ) 4001 | { 4002 | strcat ( lDialogString , "echo \"" ) ; 4003 | strcat ( lDialogString, aMessage) ; 4004 | strcat ( lDialogString , "\"; " ) ; 4005 | } 4006 | if ( aDialogType && !strcmp("yesno",aDialogType) ) 4007 | { 4008 | strcat ( lDialogString , "echo -n \"y/n: \"; " ) ; 4009 | strcat ( lDialogString , "stty sane -echo;" ) ; 4010 | strcat ( lDialogString , 4011 | "answer=$( while ! head -c 1 | grep -i [ny];do true ;done);"); 4012 | strcat ( lDialogString , 4013 | "if echo \"$answer\" | grep -iq \"^y\";then\n"); 4014 | strcat ( lDialogString , "\techo 1\nelse\n\techo 0\nfi" ) ; 4015 | } 4016 | else if ( aDialogType && !strcmp("okcancel",aDialogType) ) 4017 | { 4018 | strcat ( lDialogString , "echo -n \"[O]kay/[C]ancel: \"; " ) ; 4019 | strcat ( lDialogString , "stty sane -echo;" ) ; 4020 | strcat ( lDialogString , 4021 | "answer=$( while ! head -c 1 | grep -i [oc];do true ;done);"); 4022 | strcat ( lDialogString , 4023 | "if echo \"$answer\" | grep -iq \"^o\";then\n"); 4024 | strcat ( lDialogString , "\techo 1\nelse\n\techo 0\nfi" ) ; 4025 | } 4026 | else if ( aDialogType && !strcmp("yesnocancel",aDialogType) ) 4027 | { 4028 | strcat ( lDialogString , "echo -n \"[Y]es/[N]o/[C]ancel: \"; " ) ; 4029 | strcat ( lDialogString , "stty sane -echo;" ) ; 4030 | strcat ( lDialogString , 4031 | "answer=$( while ! head -c 1 | grep -i [nyc];do true ;done);"); 4032 | strcat ( lDialogString , 4033 | "if echo \"$answer\" | grep -iq \"^y\";then\n\techo 1\n"); 4034 | strcat ( lDialogString , "elif echo \"$answer\" | grep -iq \"^n\";then\n\techo 2\n" ) ; 4035 | strcat ( lDialogString , "else\n\techo 0\nfi" ) ; 4036 | } 4037 | else 4038 | { 4039 | strcat(lDialogString , "echo -n \"press enter to continue \"; "); 4040 | strcat ( lDialogString , "stty sane -echo;" ) ; 4041 | strcat ( lDialogString , 4042 | "answer=$( while ! head -c 1;do true ;done);echo 1"); 4043 | } 4044 | strcat ( lDialogString , 4045 | " >/tmp/tinyfd.txt';cat /tmp/tinyfd.txt;rm /tmp/tinyfd.txt"); 4046 | } 4047 | else if ( !isTerminalRunning() && notifysendPresent() && !strcmp("ok" , aDialogType) ) 4048 | { 4049 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"notify");return 1;} 4050 | 4051 | strcpy ( lDialogString , "notify-send \"" ) ; 4052 | if ( aTitle && strlen(aTitle) ) 4053 | { 4054 | strcat(lDialogString, aTitle) ; 4055 | strcat ( lDialogString , " | " ) ; 4056 | } 4057 | if ( aMessage && strlen(aMessage) ) 4058 | { 4059 | strcat(lDialogString, aMessage) ; 4060 | } 4061 | strcat ( lDialogString , "\"" ) ; 4062 | } 4063 | else 4064 | { 4065 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return 0;} 4066 | if ( !gWarningDisplayed && !tinyfd_forceConsole) 4067 | { 4068 | gWarningDisplayed = 1 ; 4069 | printf ("\n\n%s\n", gTitle); 4070 | printf ("%s\n\n", gMessageUnix); 4071 | } 4072 | if ( aTitle && strlen(aTitle) ) 4073 | { 4074 | printf ("\n%s\n", aTitle); 4075 | } 4076 | 4077 | tcgetattr(0, &infoOri); 4078 | tcgetattr(0, &info); 4079 | info.c_lflag &= ~ICANON; 4080 | info.c_cc[VMIN] = 1; 4081 | info.c_cc[VTIME] = 0; 4082 | tcsetattr(0, TCSANOW, &info); 4083 | if ( aDialogType && !strcmp("yesno",aDialogType) ) 4084 | { 4085 | do 4086 | { 4087 | if ( aMessage && strlen(aMessage) ) 4088 | { 4089 | printf("\n%s\n",aMessage); 4090 | } 4091 | printf("y/n: "); fflush(stdout); 4092 | lChar = tolower ( getchar() ) ; 4093 | printf("\n\n"); 4094 | } 4095 | while ( lChar != 'y' && lChar != 'n' ); 4096 | lResult = lChar == 'y' ? 1 : 0 ; 4097 | } 4098 | else if ( aDialogType && !strcmp("okcancel",aDialogType) ) 4099 | { 4100 | do 4101 | { 4102 | if ( aMessage && strlen(aMessage) ) 4103 | { 4104 | printf("\n%s\n",aMessage); 4105 | } 4106 | printf("[O]kay/[C]ancel: "); fflush(stdout); 4107 | lChar = tolower ( getchar() ) ; 4108 | printf("\n\n"); 4109 | } 4110 | while ( lChar != 'o' && lChar != 'c' ); 4111 | lResult = lChar == 'o' ? 1 : 0 ; 4112 | } 4113 | else if ( aDialogType && !strcmp("yesnocancel",aDialogType) ) 4114 | { 4115 | do 4116 | { 4117 | if ( aMessage && strlen(aMessage) ) 4118 | { 4119 | printf("\n%s\n",aMessage); 4120 | } 4121 | printf("[Y]es/[N]o/[C]ancel: "); fflush(stdout); 4122 | lChar = tolower ( getchar() ) ; 4123 | printf("\n\n"); 4124 | } 4125 | while ( lChar != 'y' && lChar != 'n' && lChar != 'c' ); 4126 | lResult = (lChar == 'y') ? 1 : (lChar == 'n') ? 2 : 0 ; 4127 | } 4128 | else 4129 | { 4130 | if ( aMessage && strlen(aMessage) ) 4131 | { 4132 | printf("\n%s\n\n",aMessage); 4133 | } 4134 | printf("press enter to continue "); fflush(stdout); 4135 | getchar() ; 4136 | printf("\n\n"); 4137 | lResult = 1 ; 4138 | } 4139 | tcsetattr(0, TCSANOW, &infoOri); 4140 | free(lDialogString); 4141 | return lResult ; 4142 | } 4143 | 4144 | if (tinyfd_verbose) printf ( "lDialogString: %s\n" , lDialogString ) ; 4145 | 4146 | if ( ! ( lIn = popen ( lDialogString , "r" ) ) ) 4147 | { 4148 | free(lDialogString); 4149 | return 0 ; 4150 | } 4151 | while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) 4152 | {} 4153 | 4154 | pclose ( lIn ) ; 4155 | 4156 | /* printf ( "lBuff: %s len: %lu \n" , lBuff , strlen(lBuff) ) ; */ 4157 | if ( lBuff[strlen ( lBuff ) -1] == '\n' ) 4158 | { 4159 | lBuff[strlen ( lBuff ) -1] = '\0' ; 4160 | } 4161 | /* printf ( "lBuff1: %s len: %lu \n" , lBuff , strlen(lBuff) ) ; */ 4162 | 4163 | if (aDialogType && !strcmp("yesnocancel", aDialogType)) 4164 | { 4165 | if ( lBuff[0]=='1' ) 4166 | { 4167 | if ( !strcmp ( lBuff+1 , "Yes" )) strcpy(lBuff,"1"); 4168 | else if ( !strcmp ( lBuff+1 , "No" )) strcpy(lBuff,"2"); 4169 | } 4170 | } 4171 | /* printf ( "lBuff2: %s len: %lu \n" , lBuff , strlen(lBuff) ) ; */ 4172 | 4173 | lResult = !strcmp ( lBuff , "2" ) ? 2 : !strcmp ( lBuff , "1" ) ? 1 : 0; 4174 | 4175 | /* printf ( "lResult: %d\n" , lResult ) ; */ 4176 | free(lDialogString); 4177 | return lResult ; 4178 | } 4179 | 4180 | 4181 | /* returns NULL on cancel */ 4182 | char const * tinyfd_inputBox( 4183 | char const * const aTitle , /* NULL or "" */ 4184 | char const * const aMessage , /* NULL or "" may NOT contain \n nor \t */ 4185 | char const * const aDefaultInput ) /* "" , if NULL it's a passwordBox */ 4186 | { 4187 | static char lBuff[MAX_PATH_OR_CMD]; 4188 | char * lDialogString = NULL; 4189 | char * lpDialogString; 4190 | FILE * lIn ; 4191 | int lResult ; 4192 | int lWasGdialog = 0 ; 4193 | int lWasGraphicDialog = 0 ; 4194 | int lWasXterm = 0 ; 4195 | int lWasBasicXterm = 0 ; 4196 | struct termios oldt ; 4197 | struct termios newt ; 4198 | char * lEOF; 4199 | int lTitleLen ; 4200 | int lMessageLen ; 4201 | 4202 | lBuff[0]='\0'; 4203 | 4204 | lTitleLen = aTitle ? strlen(aTitle) : 0 ; 4205 | lMessageLen = aMessage ? strlen(aMessage) : 0 ; 4206 | if ( !aTitle || strcmp(aTitle,"tinyfd_query") ) 4207 | { 4208 | lDialogString = (char *) malloc( MAX_PATH_OR_CMD + lTitleLen + lMessageLen ); 4209 | } 4210 | 4211 | if ( osascriptPresent ( ) ) 4212 | { 4213 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"applescript");return (char const *)1;} 4214 | strcpy ( lDialogString , "osascript "); 4215 | if ( ! osx9orBetter() ) strcat ( lDialogString , " -e 'tell application \"System Events\"' -e 'Activate'"); 4216 | strcat ( lDialogString , " -e 'try' -e 'display dialog \"") ; 4217 | if ( aMessage && strlen(aMessage) ) 4218 | { 4219 | strcat(lDialogString, aMessage) ; 4220 | } 4221 | strcat(lDialogString, "\" ") ; 4222 | strcat(lDialogString, "default answer \"") ; 4223 | if ( aDefaultInput && strlen(aDefaultInput) ) 4224 | { 4225 | strcat(lDialogString, aDefaultInput) ; 4226 | } 4227 | strcat(lDialogString, "\" ") ; 4228 | if ( ! aDefaultInput ) 4229 | { 4230 | strcat(lDialogString, "hidden answer true ") ; 4231 | } 4232 | if ( aTitle && strlen(aTitle) ) 4233 | { 4234 | strcat(lDialogString, "with title \"") ; 4235 | strcat(lDialogString, aTitle) ; 4236 | strcat(lDialogString, "\" ") ; 4237 | } 4238 | strcat(lDialogString, "with icon note' ") ; 4239 | strcat(lDialogString, "-e '\"1\" & text returned of result' " ); 4240 | strcat(lDialogString, "-e 'on error number -128' " ) ; 4241 | strcat(lDialogString, "-e '0' " ); 4242 | strcat(lDialogString, "-e 'end try'") ; 4243 | if ( ! osx9orBetter() ) strcat(lDialogString, " -e 'end tell'") ; 4244 | } 4245 | else if ( zenityPresent() || matedialogPresent() || qarmaPresent() ) 4246 | { 4247 | if ( zenityPresent() ) 4248 | { 4249 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity");return (char const *)1;} 4250 | strcpy ( lDialogString , "szAnswer=$(zenity --entry" ) ; 4251 | } 4252 | else if ( matedialogPresent() ) 4253 | { 4254 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"matedialog");return (char const *)1;} 4255 | strcpy ( lDialogString , "szAnswer=$(matedialog --entry" ) ; 4256 | } 4257 | else 4258 | { 4259 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"qarma");return (char const *)1;} 4260 | strcpy ( lDialogString , "szAnswer=$(qarma --entry" ) ; 4261 | } 4262 | 4263 | if ( aTitle && strlen(aTitle) ) 4264 | { 4265 | strcat(lDialogString, " --title=\"") ; 4266 | strcat(lDialogString, aTitle) ; 4267 | strcat(lDialogString, "\"") ; 4268 | } 4269 | if ( aMessage && strlen(aMessage) ) 4270 | { 4271 | strcat(lDialogString, " --text=\"") ; 4272 | strcat(lDialogString, aMessage) ; 4273 | strcat(lDialogString, "\"") ; 4274 | } 4275 | if ( aDefaultInput && strlen(aDefaultInput) ) 4276 | { 4277 | strcat(lDialogString, " --entry-text=\"") ; 4278 | strcat(lDialogString, aDefaultInput) ; 4279 | strcat(lDialogString, "\"") ; 4280 | } 4281 | else 4282 | { 4283 | strcat(lDialogString, " --hide-text") ; 4284 | } 4285 | strcat ( lDialogString , 4286 | ");if [ $? = 0 ];then echo 1$szAnswer;else echo 0$szAnswer;fi"); 4287 | } 4288 | else if ( kdialogPresent() ) 4289 | { 4290 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"kdialog");return (char const *)1;} 4291 | strcpy ( lDialogString , "szAnswer=$(kdialog" ) ; 4292 | if ( ! aDefaultInput ) 4293 | { 4294 | strcat(lDialogString, " --password ") ; 4295 | } 4296 | else 4297 | { 4298 | strcat(lDialogString, " --inputbox ") ; 4299 | 4300 | } 4301 | strcat(lDialogString, "\"") ; 4302 | if ( aMessage && strlen(aMessage) ) 4303 | { 4304 | strcat(lDialogString, aMessage ) ; 4305 | } 4306 | strcat(lDialogString , "\" \"" ) ; 4307 | if ( aDefaultInput && strlen(aDefaultInput) ) 4308 | { 4309 | strcat(lDialogString, aDefaultInput ) ; 4310 | } 4311 | strcat(lDialogString , "\"" ) ; 4312 | if ( aTitle && strlen(aTitle) ) 4313 | { 4314 | strcat(lDialogString, " --title \"") ; 4315 | strcat(lDialogString, aTitle) ; 4316 | strcat(lDialogString, "\"") ; 4317 | } 4318 | strcat ( lDialogString , 4319 | ");if [ $? = 0 ];then echo 1$szAnswer;else echo 0$szAnswer;fi"); 4320 | } 4321 | else if ( gxmessagePresent() || gmessagePresent() ) 4322 | { 4323 | if ( gxmessagePresent() ) { 4324 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"gxmessage");return (char const *)1;} 4325 | strcpy ( lDialogString , "szAnswer=$(gxmessage -buttons Ok:1,Cancel:0 -center \""); 4326 | } 4327 | else 4328 | { 4329 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"gmessage");return (char const *)1;} 4330 | strcpy ( lDialogString , "szAnswer=$(gmessage -buttons Ok:1,Cancel:0 -center \""); 4331 | } 4332 | 4333 | if ( aMessage && strlen(aMessage) ) 4334 | { 4335 | strcat ( lDialogString , aMessage ) ; 4336 | } 4337 | strcat(lDialogString, "\"" ) ; 4338 | if ( aTitle && strlen(aTitle) ) 4339 | { 4340 | strcat ( lDialogString , " -title \""); 4341 | strcat ( lDialogString , aTitle ) ; 4342 | strcat(lDialogString, "\" " ) ; 4343 | } 4344 | strcat(lDialogString, " -entrytext \"" ) ; 4345 | if ( aDefaultInput && strlen(aDefaultInput) ) 4346 | { 4347 | strcat ( lDialogString , aDefaultInput ) ; 4348 | } 4349 | strcat(lDialogString, "\"" ) ; 4350 | strcat ( lDialogString , ");echo $?$szAnswer"); 4351 | } 4352 | else if ( !gdialogPresent() && tkinter2Present ( ) ) 4353 | { 4354 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"tkinter");return (char const *)1;} 4355 | strcpy ( lDialogString , gPython2Name ) ; 4356 | if ( ! isTerminalRunning ( ) && isDarwin ( ) ) 4357 | { 4358 | strcat ( lDialogString , " -i" ) ; /* for osx without console */ 4359 | } 4360 | 4361 | strcat ( lDialogString , 4362 | " -c \"import Tkinter,tkSimpleDialog;root=Tkinter.Tk();root.withdraw();"); 4363 | 4364 | if ( isDarwin ( ) ) 4365 | { 4366 | strcat ( lDialogString , 4367 | "import os;os.system('''/usr/bin/osascript -e 'tell app \\\"Finder\\\" to set \ 4368 | frontmost of process \\\"Python\\\" to true' ''');"); 4369 | } 4370 | 4371 | strcat ( lDialogString ,"res=tkSimpleDialog.askstring(" ) ; 4372 | if ( aTitle && strlen(aTitle) ) 4373 | { 4374 | strcat(lDialogString, "title='") ; 4375 | strcat(lDialogString, aTitle) ; 4376 | strcat(lDialogString, "',") ; 4377 | } 4378 | if ( aMessage && strlen(aMessage) ) 4379 | { 4380 | 4381 | strcat(lDialogString, "prompt='") ; 4382 | lpDialogString = lDialogString + strlen(lDialogString); 4383 | replaceSubStr ( aMessage , "\n" , "\\n" , lpDialogString ) ; 4384 | strcat(lDialogString, "',") ; 4385 | } 4386 | if ( aDefaultInput ) 4387 | { 4388 | if ( strlen(aDefaultInput) ) 4389 | { 4390 | strcat(lDialogString, "initialvalue='") ; 4391 | strcat(lDialogString, aDefaultInput) ; 4392 | strcat(lDialogString, "',") ; 4393 | } 4394 | } 4395 | else 4396 | { 4397 | strcat(lDialogString, "show='*'") ; 4398 | } 4399 | strcat(lDialogString, ");\nif res is None :\n\tprint 0"); 4400 | strcat(lDialogString, "\nelse :\n\tprint '1'+res\n\"" ) ; 4401 | } 4402 | else if ( gdialogPresent() || xdialogPresent() 4403 | || dialogName() || whiptailPresent() ) 4404 | { 4405 | if ( gdialogPresent ( ) ) 4406 | { 4407 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"gdialog");return (char const *)1;} 4408 | lWasGraphicDialog = 1 ; 4409 | lWasGdialog = 1 ; 4410 | strcpy ( lDialogString , "(gdialog " ) ; 4411 | } 4412 | else if ( xdialogPresent ( ) ) 4413 | { 4414 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xdialog");return (char const *)1;} 4415 | lWasGraphicDialog = 1 ; 4416 | strcpy ( lDialogString , "(Xdialog " ) ; 4417 | } 4418 | else if ( dialogName ( ) ) 4419 | { 4420 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} 4421 | if ( isTerminalRunning ( ) ) 4422 | { 4423 | strcpy ( lDialogString , "(dialog " ) ; 4424 | } 4425 | else 4426 | { 4427 | lWasXterm = 1 ; 4428 | strcpy ( lDialogString , terminalName() ) ; 4429 | strcat ( lDialogString , "'(" ) ; 4430 | strcat ( lDialogString , dialogName() ) ; 4431 | strcat ( lDialogString , " " ) ; 4432 | } 4433 | } 4434 | else if ( isTerminalRunning ( ) ) 4435 | { 4436 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"whiptail");return (char const *)0;} 4437 | strcpy ( lDialogString , "(whiptail " ) ; 4438 | } 4439 | else 4440 | { 4441 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"whiptail");return (char const *)0;} 4442 | lWasXterm = 1 ; 4443 | strcpy ( lDialogString , terminalName() ) ; 4444 | strcat ( lDialogString , "'(whiptail " ) ; 4445 | } 4446 | 4447 | if ( aTitle && strlen(aTitle) ) 4448 | { 4449 | strcat(lDialogString, "--title \"") ; 4450 | strcat(lDialogString, aTitle) ; 4451 | strcat(lDialogString, "\" ") ; 4452 | } 4453 | 4454 | if ( !xdialogPresent() && !gdialogPresent() ) 4455 | { 4456 | strcat(lDialogString, "--backtitle \"") ; 4457 | strcat(lDialogString, "tab: move focus") ; 4458 | if ( ! aDefaultInput && !lWasGdialog ) 4459 | { 4460 | strcat(lDialogString, " (sometimes nothing, no blink nor star, is shown in text field)") ; 4461 | } 4462 | strcat(lDialogString, "\" ") ; 4463 | } 4464 | 4465 | if ( aDefaultInput || lWasGdialog ) 4466 | { 4467 | strcat ( lDialogString , "--inputbox" ) ; 4468 | } 4469 | else 4470 | { 4471 | if ( !lWasGraphicDialog && dialogName() && isDialogVersionBetter09b() ) 4472 | { 4473 | strcat ( lDialogString , "--insecure " ) ; 4474 | } 4475 | strcat ( lDialogString , "--passwordbox" ) ; 4476 | } 4477 | strcat ( lDialogString , " \"" ) ; 4478 | if ( aMessage && strlen(aMessage) ) 4479 | { 4480 | strcat(lDialogString, aMessage) ; 4481 | } 4482 | strcat(lDialogString,"\" 10 60 ") ; 4483 | if ( aDefaultInput && strlen(aDefaultInput) ) 4484 | { 4485 | strcat(lDialogString, "\"") ; 4486 | strcat(lDialogString, aDefaultInput) ; 4487 | strcat(lDialogString, "\" ") ; 4488 | } 4489 | if ( lWasGraphicDialog ) 4490 | { 4491 | strcat(lDialogString,") 2>/tmp/tinyfd.txt;\ 4492 | if [ $? = 0 ];then tinyfdBool=1;else tinyfdBool=0;fi;\ 4493 | tinyfdRes=$(cat /tmp/tinyfd.txt);echo $tinyfdBool$tinyfdRes") ; 4494 | } 4495 | else 4496 | { 4497 | strcat(lDialogString,">/dev/tty ) 2>/tmp/tinyfd.txt;\ 4498 | if [ $? = 0 ];then tinyfdBool=1;else tinyfdBool=0;fi;\ 4499 | tinyfdRes=$(cat /tmp/tinyfd.txt);echo $tinyfdBool$tinyfdRes") ; 4500 | 4501 | if ( lWasXterm ) 4502 | { 4503 | strcat(lDialogString," >/tmp/tinyfd0.txt';cat /tmp/tinyfd0.txt"); 4504 | } 4505 | else 4506 | { 4507 | strcat(lDialogString, "; clear >/dev/tty") ; 4508 | } 4509 | } 4510 | } 4511 | else if ( ! isTerminalRunning ( ) && terminalName() ) 4512 | { 4513 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return (char const *)0;} 4514 | lWasBasicXterm = 1 ; 4515 | strcpy ( lDialogString , terminalName() ) ; 4516 | strcat ( lDialogString , "'" ) ; 4517 | if ( !gWarningDisplayed && !tinyfd_forceConsole) 4518 | { 4519 | tinyfd_messageBox(gTitle,gMessageUnix,"ok","warning",0); 4520 | gWarningDisplayed = 1 ; 4521 | } 4522 | if ( aTitle && strlen(aTitle) && !tinyfd_forceConsole) 4523 | { 4524 | strcat ( lDialogString , "echo \"" ) ; 4525 | strcat ( lDialogString, aTitle) ; 4526 | strcat ( lDialogString , "\";echo;" ) ; 4527 | } 4528 | 4529 | strcat ( lDialogString , "echo \"" ) ; 4530 | if ( aMessage && strlen(aMessage) ) 4531 | { 4532 | strcat ( lDialogString, aMessage) ; 4533 | } 4534 | strcat ( lDialogString , "\";read " ) ; 4535 | if ( ! aDefaultInput ) 4536 | { 4537 | strcat ( lDialogString , "-s " ) ; 4538 | } 4539 | strcat ( lDialogString , "-p \"" ) ; 4540 | strcat ( lDialogString , "(esc+enter to cancel): \" ANSWER " ) ; 4541 | strcat ( lDialogString , ";echo 1$ANSWER >/tmp/tinyfd.txt';" ) ; 4542 | strcat ( lDialogString , "cat -v /tmp/tinyfd.txt"); 4543 | } 4544 | else 4545 | { 4546 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return (char const *)0;} 4547 | if ( !gWarningDisplayed && !tinyfd_forceConsole) 4548 | { 4549 | tinyfd_messageBox(gTitle,gMessageUnix,"ok","warning",0); 4550 | gWarningDisplayed = 1 ; 4551 | } 4552 | if ( aTitle && strlen(aTitle) ) 4553 | { 4554 | printf ("\n%s\n", aTitle); 4555 | } 4556 | if ( aMessage && strlen(aMessage) ) 4557 | { 4558 | printf("\n%s\n",aMessage); 4559 | } 4560 | printf("(esc+enter to cancel): "); fflush(stdout); 4561 | if ( ! aDefaultInput ) 4562 | { 4563 | tcgetattr(STDIN_FILENO, & oldt) ; 4564 | newt = oldt ; 4565 | newt.c_lflag &= ~ECHO ; 4566 | tcsetattr(STDIN_FILENO, TCSANOW, & newt); 4567 | } 4568 | 4569 | lEOF = fgets(lBuff, MAX_PATH_OR_CMD, stdin); 4570 | /* printf("lbuff<%c><%d>\n",lBuff[0],lBuff[0]); */ 4571 | if ( ! lEOF || (lBuff[0] == '\0') ) 4572 | { 4573 | free(lDialogString); 4574 | return NULL; 4575 | } 4576 | 4577 | if ( lBuff[0] == '\n' ) 4578 | { 4579 | lEOF = fgets(lBuff, MAX_PATH_OR_CMD, stdin); 4580 | /* printf("lbuff<%c><%d>\n",lBuff[0],lBuff[0]); */ 4581 | if ( ! lEOF || (lBuff[0] == '\0') ) 4582 | { 4583 | free(lDialogString); 4584 | return NULL; 4585 | } 4586 | } 4587 | 4588 | if ( ! aDefaultInput ) 4589 | { 4590 | tcsetattr(STDIN_FILENO, TCSANOW, & oldt); 4591 | printf ("\n"); 4592 | } 4593 | printf ("\n"); 4594 | if ( strchr(lBuff,27) ) 4595 | { 4596 | free(lDialogString); 4597 | return NULL ; 4598 | } 4599 | if ( lBuff[strlen ( lBuff ) -1] == '\n' ) 4600 | { 4601 | lBuff[strlen ( lBuff ) -1] = '\0' ; 4602 | } 4603 | free(lDialogString); 4604 | return lBuff ; 4605 | } 4606 | 4607 | if (tinyfd_verbose) printf ( "lDialogString: %s\n" , lDialogString ) ; 4608 | lIn = popen ( lDialogString , "r" ); 4609 | if ( ! lIn ) 4610 | { 4611 | if ( fileExists("/tmp/tinyfd.txt") ) 4612 | { 4613 | wipefile("/tmp/tinyfd.txt"); 4614 | remove("/tmp/tinyfd.txt"); 4615 | } 4616 | if ( fileExists("/tmp/tinyfd0.txt") ) 4617 | { 4618 | wipefile("/tmp/tinyfd0.txt"); 4619 | remove("/tmp/tinyfd0.txt"); 4620 | } 4621 | free(lDialogString); 4622 | return NULL ; 4623 | } 4624 | while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) 4625 | {} 4626 | 4627 | pclose ( lIn ) ; 4628 | 4629 | if ( fileExists("/tmp/tinyfd.txt") ) 4630 | { 4631 | wipefile("/tmp/tinyfd.txt"); 4632 | remove("/tmp/tinyfd.txt"); 4633 | } 4634 | if ( fileExists("/tmp/tinyfd0.txt") ) 4635 | { 4636 | wipefile("/tmp/tinyfd0.txt"); 4637 | remove("/tmp/tinyfd0.txt"); 4638 | } 4639 | 4640 | /* printf ( "len Buff: %lu\n" , strlen(lBuff) ) ; */ 4641 | /* printf ( "lBuff0: %s\n" , lBuff ) ; */ 4642 | if ( lBuff[strlen ( lBuff ) -1] == '\n' ) 4643 | { 4644 | lBuff[strlen ( lBuff ) -1] = '\0' ; 4645 | } 4646 | /* printf ( "lBuff1: %s len: %lu \n" , lBuff , strlen(lBuff) ) ; */ 4647 | if ( lWasBasicXterm ) 4648 | { 4649 | if ( strstr(lBuff,"^[") ) /* esc was pressed */ 4650 | { 4651 | free(lDialogString); 4652 | return NULL ; 4653 | } 4654 | } 4655 | 4656 | lResult = strncmp ( lBuff , "1" , 1) ? 0 : 1 ; 4657 | /* printf ( "lResult: %d \n" , lResult ) ; */ 4658 | if ( ! lResult ) 4659 | { 4660 | free(lDialogString); 4661 | return NULL ; 4662 | } 4663 | /* printf ( "lBuff+1: %s\n" , lBuff+1 ) ; */ 4664 | free(lDialogString); 4665 | 4666 | return lBuff+1 ; 4667 | } 4668 | 4669 | 4670 | char const * tinyfd_saveFileDialog ( 4671 | char const * const aTitle , /* NULL or "" */ 4672 | char const * const aDefaultPathAndFile , /* NULL or "" */ 4673 | int const aNumOfFilterPatterns , /* 0 */ 4674 | char const * const * const aFilterPatterns , /* NULL or {"*.jpg","*.png"} */ 4675 | char const * const aSingleFilterDescription ) /* NULL or "image files" */ 4676 | { 4677 | 4678 | static char lBuff [MAX_PATH_OR_CMD] ; 4679 | char lDialogString [MAX_PATH_OR_CMD] ; 4680 | char lString [MAX_PATH_OR_CMD] ; 4681 | int i ; 4682 | int lWasGraphicDialog = 0 ; 4683 | int lWasXterm = 0 ; 4684 | char const * p ; 4685 | FILE * lIn ; 4686 | lBuff[0]='\0'; 4687 | 4688 | if ( osascriptPresent ( ) ) 4689 | { 4690 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"applescript");return (char const *)1;} 4691 | strcpy ( lDialogString , "osascript "); 4692 | if ( ! osx9orBetter() ) strcat ( lDialogString , " -e 'tell application \"Finder\"' -e 'Activate'"); 4693 | strcat ( lDialogString , " -e 'try' -e 'POSIX path of ( choose file name " ); 4694 | if ( aTitle && strlen(aTitle) ) 4695 | { 4696 | strcat(lDialogString, "with prompt \"") ; 4697 | strcat(lDialogString, aTitle) ; 4698 | strcat(lDialogString, "\" ") ; 4699 | } 4700 | getPathWithoutFinalSlash ( lString , aDefaultPathAndFile ) ; 4701 | if ( strlen(lString) ) 4702 | { 4703 | strcat(lDialogString, "default location \"") ; 4704 | strcat(lDialogString, lString ) ; 4705 | strcat(lDialogString , "\" " ) ; 4706 | } 4707 | getLastName ( lString , aDefaultPathAndFile ) ; 4708 | if ( strlen(lString) ) 4709 | { 4710 | strcat(lDialogString, "default name \"") ; 4711 | strcat(lDialogString, lString ) ; 4712 | strcat(lDialogString , "\" " ) ; 4713 | } 4714 | strcat ( lDialogString , ")' " ) ; 4715 | strcat(lDialogString, "-e 'on error number -128' " ) ; 4716 | strcat(lDialogString, "-e 'end try'") ; 4717 | if ( ! osx9orBetter() ) strcat ( lDialogString, " -e 'end tell'") ; 4718 | } 4719 | else if ( zenityPresent() || matedialogPresent() || qarmaPresent() ) 4720 | { 4721 | if ( zenityPresent() ) 4722 | { 4723 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity");return (char const *)1;} 4724 | strcpy ( lDialogString , "zenity" ) ; 4725 | } 4726 | else if ( matedialogPresent() ) 4727 | { 4728 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"matedialog");return (char const *)1;} 4729 | strcpy ( lDialogString , "matedialog" ) ; 4730 | 4731 | } 4732 | else 4733 | { 4734 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"qarma");return (char const *)1;} 4735 | strcpy ( lDialogString , "qarma" ) ; 4736 | 4737 | } 4738 | strcat(lDialogString, " --file-selection --save --confirm-overwrite" ) ; 4739 | 4740 | if ( aTitle && strlen(aTitle) ) 4741 | { 4742 | strcat(lDialogString, " --title=\"") ; 4743 | strcat(lDialogString, aTitle) ; 4744 | strcat(lDialogString, "\"") ; 4745 | } 4746 | if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) 4747 | { 4748 | strcat(lDialogString, " --filename=\"") ; 4749 | strcat(lDialogString, aDefaultPathAndFile) ; 4750 | strcat(lDialogString, "\"") ; 4751 | } 4752 | if ( aNumOfFilterPatterns > 0 ) 4753 | { 4754 | strcat ( lDialogString , " --file-filter='" ) ; 4755 | if ( aSingleFilterDescription && strlen(aSingleFilterDescription) ) 4756 | { 4757 | strcat ( lDialogString , aSingleFilterDescription ) ; 4758 | strcat ( lDialogString , " | " ) ; 4759 | } 4760 | for ( i = 0 ; i < aNumOfFilterPatterns ; i ++ ) 4761 | { 4762 | strcat ( lDialogString , aFilterPatterns [i] ) ; 4763 | strcat ( lDialogString , " " ) ; 4764 | } 4765 | strcat ( lDialogString , "' --file-filter='All files | *'" ) ; 4766 | } 4767 | } 4768 | else if ( kdialogPresent() ) 4769 | { 4770 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"kdialog");return (char const *)1;} 4771 | strcpy ( lDialogString , "kdialog --getsavefilename" ) ; 4772 | if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) 4773 | { 4774 | strcat(lDialogString, " \"") ; 4775 | strcat(lDialogString, aDefaultPathAndFile ) ; 4776 | strcat(lDialogString , "\"" ) ; 4777 | } 4778 | else 4779 | { 4780 | strcat(lDialogString, " :" ) ; 4781 | } 4782 | if ( aNumOfFilterPatterns > 0 ) 4783 | { 4784 | strcat(lDialogString , " \"" ) ; 4785 | for ( i = 0 ; i < aNumOfFilterPatterns ; i ++ ) 4786 | { 4787 | strcat ( lDialogString , aFilterPatterns [i] ) ; 4788 | strcat ( lDialogString , " " ) ; 4789 | } 4790 | if ( aSingleFilterDescription && strlen(aSingleFilterDescription) ) 4791 | { 4792 | strcat ( lDialogString , " | " ) ; 4793 | strcat ( lDialogString , aSingleFilterDescription ) ; 4794 | } 4795 | strcat ( lDialogString , "\"" ) ; 4796 | } 4797 | if ( aTitle && strlen(aTitle) ) 4798 | { 4799 | strcat(lDialogString, " --title \"") ; 4800 | strcat(lDialogString, aTitle) ; 4801 | strcat(lDialogString, "\"") ; 4802 | } 4803 | } 4804 | else if ( ! xdialogPresent() && tkinter2Present ( ) ) 4805 | { 4806 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"tkinter");return (char const *)1;} 4807 | strcpy ( lDialogString , gPython2Name ) ; 4808 | if ( ! isTerminalRunning ( ) && isDarwin ( )) 4809 | { 4810 | strcat ( lDialogString , " -i" ) ; /* for osx without console */ 4811 | } 4812 | strcat ( lDialogString , 4813 | " -c \"import Tkinter,tkFileDialog;root=Tkinter.Tk();root.withdraw();"); 4814 | 4815 | if ( isDarwin ( ) ) 4816 | { 4817 | strcat ( lDialogString , 4818 | "import os;os.system('''/usr/bin/osascript -e 'tell app \\\"Finder\\\" to set\ 4819 | frontmost of process \\\"Python\\\" to true' ''');"); 4820 | } 4821 | 4822 | strcat ( lDialogString , "print tkFileDialog.asksaveasfilename("); 4823 | if ( aTitle && strlen(aTitle) ) 4824 | { 4825 | strcat(lDialogString, "title='") ; 4826 | strcat(lDialogString, aTitle) ; 4827 | strcat(lDialogString, "',") ; 4828 | } 4829 | if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) 4830 | { 4831 | getPathWithoutFinalSlash ( lString , aDefaultPathAndFile ) ; 4832 | if ( strlen(lString) ) 4833 | { 4834 | strcat(lDialogString, "initialdir='") ; 4835 | strcat(lDialogString, lString ) ; 4836 | strcat(lDialogString , "'," ) ; 4837 | } 4838 | getLastName ( lString , aDefaultPathAndFile ) ; 4839 | if ( strlen(lString) ) 4840 | { 4841 | strcat(lDialogString, "initialfile='") ; 4842 | strcat(lDialogString, lString ) ; 4843 | strcat(lDialogString , "'," ) ; 4844 | } 4845 | } 4846 | if ( ( aNumOfFilterPatterns > 1 ) 4847 | || ( (aNumOfFilterPatterns == 1) /* test because poor osx behaviour */ 4848 | && ( aFilterPatterns[0][strlen(aFilterPatterns[0])-1] != '*' ) ) ) 4849 | { 4850 | strcat(lDialogString , "filetypes=(" ) ; 4851 | strcat ( lDialogString , "('" ) ; 4852 | if ( aSingleFilterDescription && strlen(aSingleFilterDescription) ) 4853 | { 4854 | strcat ( lDialogString , aSingleFilterDescription ) ; 4855 | } 4856 | strcat ( lDialogString , "',(" ) ; 4857 | for ( i = 0 ; i < aNumOfFilterPatterns ; i ++ ) 4858 | { 4859 | strcat ( lDialogString , "'" ) ; 4860 | strcat ( lDialogString , aFilterPatterns [i] ) ; 4861 | strcat ( lDialogString , "'," ) ; 4862 | } 4863 | strcat ( lDialogString , "))," ) ; 4864 | strcat ( lDialogString , "('All files','*'))" ) ; 4865 | } 4866 | strcat ( lDialogString , ")\"" ) ; 4867 | } 4868 | else if ( xdialogPresent() || dialogName() ) 4869 | { 4870 | if ( xdialogPresent ( ) ) 4871 | { 4872 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xdialog");return (char const *)1;} 4873 | lWasGraphicDialog = 1 ; 4874 | strcpy ( lDialogString , "(Xdialog " ) ; 4875 | } 4876 | else if ( isTerminalRunning ( ) ) 4877 | { 4878 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} 4879 | strcpy ( lDialogString , "(dialog " ) ; 4880 | } 4881 | else 4882 | { 4883 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} 4884 | lWasXterm = 1 ; 4885 | strcpy ( lDialogString , terminalName() ) ; 4886 | strcat ( lDialogString , "'(" ) ; 4887 | strcat ( lDialogString , dialogName() ) ; 4888 | strcat ( lDialogString , " " ) ; 4889 | } 4890 | 4891 | if ( aTitle && strlen(aTitle) ) 4892 | { 4893 | strcat(lDialogString, "--title \"") ; 4894 | strcat(lDialogString, aTitle) ; 4895 | strcat(lDialogString, "\" ") ; 4896 | } 4897 | 4898 | if ( !xdialogPresent() && !gdialogPresent() ) 4899 | { 4900 | strcat(lDialogString, "--backtitle \"") ; 4901 | strcat(lDialogString, 4902 | "tab: focus | /: populate | spacebar: fill text field | ok: TEXT FIELD ONLY") ; 4903 | strcat(lDialogString, "\" ") ; 4904 | } 4905 | 4906 | strcat ( lDialogString , "--fselect \"" ) ; 4907 | if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) 4908 | { 4909 | if ( ! strchr(aDefaultPathAndFile, '/') ) 4910 | { 4911 | strcat(lDialogString, "./") ; 4912 | } 4913 | strcat(lDialogString, aDefaultPathAndFile) ; 4914 | } 4915 | else if ( ! isTerminalRunning ( ) && !lWasGraphicDialog ) 4916 | { 4917 | strcat(lDialogString, getenv("HOME")) ; 4918 | strcat(lDialogString, "/") ; 4919 | } 4920 | else 4921 | { 4922 | strcat(lDialogString, "./") ; 4923 | } 4924 | 4925 | if ( lWasGraphicDialog ) 4926 | { 4927 | strcat(lDialogString, "\" 0 60 ) 2>&1 ") ; 4928 | } 4929 | else 4930 | { 4931 | strcat(lDialogString, "\" 0 60 >/dev/tty) ") ; 4932 | if ( lWasXterm ) 4933 | { 4934 | strcat ( lDialogString , 4935 | "2>/tmp/tinyfd.txt';cat /tmp/tinyfd.txt;rm /tmp/tinyfd.txt"); 4936 | } 4937 | else 4938 | { 4939 | strcat(lDialogString, "2>&1 ; clear >/dev/tty") ; 4940 | } 4941 | } 4942 | } 4943 | else 4944 | { 4945 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){return tinyfd_inputBox (aTitle,NULL,NULL);} 4946 | p = tinyfd_inputBox ( aTitle , "Save file" , "" ) ; 4947 | getPathWithoutFinalSlash ( lString , p ) ; 4948 | if ( strlen ( lString ) && ! dirExists ( lString ) ) 4949 | { 4950 | return NULL ; 4951 | } 4952 | getLastName(lString,p); 4953 | if ( ! strlen(lString) ) 4954 | { 4955 | return NULL; 4956 | } 4957 | return p ; 4958 | } 4959 | 4960 | if (tinyfd_verbose) printf ( "lDialogString: %s\n" , lDialogString ) ; 4961 | if ( ! ( lIn = popen ( lDialogString , "r" ) ) ) 4962 | { 4963 | return NULL ; 4964 | } 4965 | while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) 4966 | {} 4967 | pclose ( lIn ) ; 4968 | if ( lBuff[strlen ( lBuff ) -1] == '\n' ) 4969 | { 4970 | lBuff[strlen ( lBuff ) -1] = '\0' ; 4971 | } 4972 | /* printf ( "lBuff: %s\n" , lBuff ) ; */ 4973 | if ( ! strlen(lBuff) ) 4974 | { 4975 | return NULL; 4976 | } 4977 | getPathWithoutFinalSlash ( lString , lBuff ) ; 4978 | if ( strlen ( lString ) && ! dirExists ( lString ) ) 4979 | { 4980 | return NULL ; 4981 | } 4982 | getLastName(lString,lBuff); 4983 | if ( ! filenameValid(lString) ) 4984 | { 4985 | return NULL; 4986 | } 4987 | return lBuff ; 4988 | } 4989 | 4990 | 4991 | /* in case of multiple files, the separator is | */ 4992 | char const * tinyfd_openFileDialog ( 4993 | char const * const aTitle , /* NULL or "" */ 4994 | char const * const aDefaultPathAndFile , /* NULL or "" */ 4995 | int const aNumOfFilterPatterns , /* 0 */ 4996 | char const * const * const aFilterPatterns , /* NULL or {"*.jpg","*.png"} */ 4997 | char const * const aSingleFilterDescription , /* NULL or "image files" */ 4998 | int const aAllowMultipleSelects ) /* 0 or 1 */ 4999 | { 5000 | static char lBuff [MAX_MULTIPLE_FILES*MAX_PATH_OR_CMD] ; 5001 | char lDialogString [MAX_PATH_OR_CMD] ; 5002 | char lString [MAX_PATH_OR_CMD] ; 5003 | int i ; 5004 | FILE * lIn ; 5005 | char * p ; 5006 | char const * p2 ; 5007 | int lWasKdialog = 0 ; 5008 | int lWasGraphicDialog = 0 ; 5009 | int lWasXterm = 0 ; 5010 | lBuff[0]='\0'; 5011 | 5012 | if ( osascriptPresent ( ) ) 5013 | { 5014 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"applescript");return (char const *)1;} 5015 | strcpy ( lDialogString , "osascript "); 5016 | if ( ! osx9orBetter() ) strcat ( lDialogString , " -e 'tell application \"System Events\"' -e 'Activate'"); 5017 | strcat ( lDialogString , " -e 'try' -e '" ); 5018 | if ( ! aAllowMultipleSelects ) 5019 | { 5020 | 5021 | 5022 | strcat ( lDialogString , "POSIX path of ( " ); 5023 | } 5024 | else 5025 | { 5026 | strcat ( lDialogString , "set mylist to " ); 5027 | } 5028 | strcat ( lDialogString , "choose file " ); 5029 | if ( aTitle && strlen(aTitle) ) 5030 | { 5031 | strcat(lDialogString, "with prompt \"") ; 5032 | strcat(lDialogString, aTitle) ; 5033 | strcat(lDialogString, "\" ") ; 5034 | } 5035 | getPathWithoutFinalSlash ( lString , aDefaultPathAndFile ) ; 5036 | if ( strlen(lString) ) 5037 | { 5038 | strcat(lDialogString, "default location \"") ; 5039 | strcat(lDialogString, lString ) ; 5040 | strcat(lDialogString , "\" " ) ; 5041 | } 5042 | if ( aNumOfFilterPatterns > 0 ) 5043 | { 5044 | strcat(lDialogString , "of type {\"" ); 5045 | strcat ( lDialogString , aFilterPatterns [0] + 2 ) ; 5046 | strcat ( lDialogString , "\"" ) ; 5047 | for ( i = 1 ; i < aNumOfFilterPatterns ; i ++ ) 5048 | { 5049 | strcat ( lDialogString , ",\"" ) ; 5050 | strcat ( lDialogString , aFilterPatterns [i] + 2) ; 5051 | strcat ( lDialogString , "\"" ) ; 5052 | } 5053 | strcat ( lDialogString , "} " ) ; 5054 | } 5055 | if ( aAllowMultipleSelects ) 5056 | { 5057 | strcat ( lDialogString , "multiple selections allowed true ' " ) ; 5058 | strcat ( lDialogString , 5059 | "-e 'set mystring to POSIX path of item 1 of mylist' " ); 5060 | strcat ( lDialogString , 5061 | "-e 'repeat with i from 2 to the count of mylist' " ); 5062 | strcat ( lDialogString , "-e 'set mystring to mystring & \"|\"' " ); 5063 | strcat ( lDialogString , 5064 | "-e 'set mystring to mystring & POSIX path of item i of mylist' " ); 5065 | strcat ( lDialogString , "-e 'end repeat' " ); 5066 | strcat ( lDialogString , "-e 'mystring' " ); 5067 | } 5068 | else 5069 | { 5070 | strcat ( lDialogString , ")' " ) ; 5071 | } 5072 | strcat(lDialogString, "-e 'on error number -128' " ) ; 5073 | strcat(lDialogString, "-e 'end try'") ; 5074 | if ( ! osx9orBetter() ) strcat ( lDialogString, " -e 'end tell'") ; 5075 | } 5076 | else if ( zenityPresent() || matedialogPresent() || qarmaPresent() ) 5077 | { 5078 | if ( zenityPresent() ) 5079 | { 5080 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity");return (char const *)1;} 5081 | strcpy ( lDialogString , "zenity --file-selection" ) ; 5082 | } 5083 | else if ( matedialogPresent() ) 5084 | { 5085 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"matedialog");return (char const *)1;} 5086 | strcpy ( lDialogString , "matedialog --file-selection" ) ; 5087 | } 5088 | else 5089 | { 5090 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"qarma");return (char const *)1;} 5091 | strcpy ( lDialogString , "qarma --file-selection" ) ; 5092 | } 5093 | 5094 | if ( aAllowMultipleSelects ) 5095 | { 5096 | strcat ( lDialogString , " --multiple" ) ; 5097 | } 5098 | if ( aTitle && strlen(aTitle) ) 5099 | { 5100 | strcat(lDialogString, " --title=\"") ; 5101 | strcat(lDialogString, aTitle) ; 5102 | strcat(lDialogString, "\"") ; 5103 | } 5104 | if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) 5105 | { 5106 | strcat(lDialogString, " --filename=\"") ; 5107 | strcat(lDialogString, aDefaultPathAndFile) ; 5108 | strcat(lDialogString, "\"") ; 5109 | } 5110 | if ( aNumOfFilterPatterns > 0 ) 5111 | { 5112 | strcat ( lDialogString , " --file-filter='" ) ; 5113 | if ( aSingleFilterDescription && strlen(aSingleFilterDescription) ) 5114 | { 5115 | strcat ( lDialogString , aSingleFilterDescription ) ; 5116 | strcat ( lDialogString , " | " ) ; 5117 | } 5118 | for ( i = 0 ; i < aNumOfFilterPatterns ; i ++ ) 5119 | { 5120 | strcat ( lDialogString , aFilterPatterns [i] ) ; 5121 | strcat ( lDialogString , " " ) ; 5122 | } 5123 | strcat ( lDialogString , "' --file-filter='All files | *'" ) ; 5124 | } 5125 | } 5126 | else if ( kdialogPresent() ) 5127 | { 5128 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"kdialog");return (char const *)1;} 5129 | lWasKdialog = 1 ; 5130 | strcpy ( lDialogString , "kdialog --getopenfilename" ) ; 5131 | if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) 5132 | { 5133 | strcat(lDialogString, " \"") ; 5134 | strcat(lDialogString, aDefaultPathAndFile ) ; 5135 | 5136 | strcat(lDialogString , "\"" ) ; 5137 | } 5138 | else 5139 | { 5140 | strcat(lDialogString, " :" ) ; 5141 | } 5142 | if ( aNumOfFilterPatterns > 0 ) 5143 | { 5144 | strcat(lDialogString , " \"" ) ; 5145 | for ( i = 0 ; i < aNumOfFilterPatterns ; i ++ ) 5146 | { 5147 | strcat ( lDialogString , aFilterPatterns [i] ) ; 5148 | strcat ( lDialogString , " " ) ; 5149 | } 5150 | if ( aSingleFilterDescription && strlen(aSingleFilterDescription) ) 5151 | { 5152 | strcat ( lDialogString , " | " ) ; 5153 | strcat ( lDialogString , aSingleFilterDescription ) ; 5154 | } 5155 | strcat ( lDialogString , "\"" ) ; 5156 | } 5157 | if ( aAllowMultipleSelects ) 5158 | { 5159 | strcat ( lDialogString , " --multiple --separate-output" ) ; 5160 | } 5161 | if ( aTitle && strlen(aTitle) ) 5162 | { 5163 | strcat(lDialogString, " --title \"") ; 5164 | strcat(lDialogString, aTitle) ; 5165 | strcat(lDialogString, "\"") ; 5166 | } 5167 | } 5168 | else if ( ! xdialogPresent() && tkinter2Present ( ) ) 5169 | { 5170 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"tkinter");return (char const *)1;} 5171 | strcpy ( lDialogString , gPython2Name ) ; 5172 | if ( ! isTerminalRunning ( ) && isDarwin ( ) ) 5173 | { 5174 | strcat ( lDialogString , " -i" ) ; /* for osx without console */ 5175 | } 5176 | strcat ( lDialogString , 5177 | " -c \"import Tkinter,tkFileDialog;root=Tkinter.Tk();root.withdraw();"); 5178 | 5179 | if ( isDarwin ( ) ) 5180 | { 5181 | strcat ( lDialogString , 5182 | "import os;os.system('''/usr/bin/osascript -e 'tell app \\\"Finder\\\" to set \ 5183 | frontmost of process \\\"Python\\\" to true' ''');"); 5184 | } 5185 | strcat ( lDialogString , "lFiles=tkFileDialog.askopenfilename("); 5186 | if ( aAllowMultipleSelects ) 5187 | { 5188 | strcat ( lDialogString , "multiple=1," ) ; 5189 | } 5190 | if ( aTitle && strlen(aTitle) ) 5191 | { 5192 | strcat(lDialogString, "title='") ; 5193 | strcat(lDialogString, aTitle) ; 5194 | strcat(lDialogString, "',") ; 5195 | } 5196 | if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) 5197 | { 5198 | getPathWithoutFinalSlash ( lString , aDefaultPathAndFile ) ; 5199 | if ( strlen(lString) ) 5200 | { 5201 | strcat(lDialogString, "initialdir='") ; 5202 | strcat(lDialogString, lString ) ; 5203 | strcat(lDialogString , "'," ) ; 5204 | } 5205 | getLastName ( lString , aDefaultPathAndFile ) ; 5206 | if ( strlen(lString) ) 5207 | { 5208 | strcat(lDialogString, "initialfile='") ; 5209 | strcat(lDialogString, lString ) ; 5210 | strcat(lDialogString , "'," ) ; 5211 | } 5212 | } 5213 | if ( ( aNumOfFilterPatterns > 1 ) 5214 | || ( ( aNumOfFilterPatterns == 1 ) /*test because poor osx behaviour*/ 5215 | && ( aFilterPatterns[0][strlen(aFilterPatterns[0])-1] != '*' ) ) ) 5216 | { 5217 | strcat(lDialogString , "filetypes=(" ) ; 5218 | strcat ( lDialogString , "('" ) ; 5219 | if ( aSingleFilterDescription && strlen(aSingleFilterDescription) ) 5220 | { 5221 | strcat ( lDialogString , aSingleFilterDescription ) ; 5222 | } 5223 | strcat ( lDialogString , "',(" ) ; 5224 | for ( i = 0 ; i < aNumOfFilterPatterns ; i ++ ) 5225 | { 5226 | strcat ( lDialogString , "'" ) ; 5227 | strcat ( lDialogString , aFilterPatterns [i] ) ; 5228 | strcat ( lDialogString , "'," ) ; 5229 | } 5230 | strcat ( lDialogString , "))," ) ; 5231 | strcat ( lDialogString , "('All files','*'))" ) ; 5232 | } 5233 | strcat ( lDialogString , ");\ 5234 | \nif not isinstance(lFiles, tuple):\n\tprint lFiles\nelse:\ 5235 | \n\tlFilesString=''\n\tfor lFile in lFiles:\n\t\tlFilesString+=str(lFile)+'|'\ 5236 | \n\tprint lFilesString[:-1]\n\"" ) ; 5237 | } 5238 | else if ( xdialogPresent() || dialogName() ) 5239 | { 5240 | if ( xdialogPresent ( ) ) 5241 | { 5242 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xdialog");return (char const *)1;} 5243 | lWasGraphicDialog = 1 ; 5244 | strcpy ( lDialogString , "(Xdialog " ) ; 5245 | } 5246 | else if ( isTerminalRunning ( ) ) 5247 | { 5248 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} 5249 | strcpy ( lDialogString , "(dialog " ) ; 5250 | } 5251 | else 5252 | { 5253 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} 5254 | lWasXterm = 1 ; 5255 | strcpy ( lDialogString , terminalName() ) ; 5256 | strcat ( lDialogString , "'(" ) ; 5257 | strcat ( lDialogString , dialogName() ) ; 5258 | strcat ( lDialogString , " " ) ; 5259 | } 5260 | 5261 | if ( aTitle && strlen(aTitle) ) 5262 | { 5263 | strcat(lDialogString, "--title \"") ; 5264 | strcat(lDialogString, aTitle) ; 5265 | strcat(lDialogString, "\" ") ; 5266 | } 5267 | 5268 | if ( !xdialogPresent() && !gdialogPresent() ) 5269 | { 5270 | strcat(lDialogString, "--backtitle \"") ; 5271 | strcat(lDialogString, 5272 | "tab: focus | /: populate | spacebar: fill text field | ok: TEXT FIELD ONLY") ; 5273 | strcat(lDialogString, "\" ") ; 5274 | } 5275 | 5276 | strcat ( lDialogString , "--fselect \"" ) ; 5277 | if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) 5278 | { 5279 | if ( ! strchr(aDefaultPathAndFile, '/') ) 5280 | { 5281 | strcat(lDialogString, "./") ; 5282 | } 5283 | strcat(lDialogString, aDefaultPathAndFile) ; 5284 | } 5285 | else if ( ! isTerminalRunning ( ) && !lWasGraphicDialog ) 5286 | { 5287 | strcat(lDialogString, getenv("HOME")) ; 5288 | strcat(lDialogString, "/"); 5289 | } 5290 | else 5291 | { 5292 | strcat(lDialogString, "./") ; 5293 | } 5294 | 5295 | if ( lWasGraphicDialog ) 5296 | { 5297 | strcat(lDialogString, "\" 0 60 ) 2>&1 ") ; 5298 | } 5299 | else 5300 | { 5301 | strcat(lDialogString, "\" 0 60 >/dev/tty) ") ; 5302 | if ( lWasXterm ) 5303 | { 5304 | strcat ( lDialogString , 5305 | "2>/tmp/tinyfd.txt';cat /tmp/tinyfd.txt;rm /tmp/tinyfd.txt"); 5306 | } 5307 | else 5308 | { 5309 | strcat(lDialogString, "2>&1 ; clear >/dev/tty") ; 5310 | } 5311 | } 5312 | } 5313 | else 5314 | { 5315 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){return tinyfd_inputBox (aTitle,NULL,NULL);} 5316 | p2 = tinyfd_inputBox(aTitle, "Open file",""); 5317 | if ( ! fileExists (p2) ) 5318 | { 5319 | return NULL ; 5320 | } 5321 | return p2 ; 5322 | } 5323 | 5324 | if (tinyfd_verbose) printf ( "lDialogString: %s\n" , lDialogString ) ; 5325 | if ( ! ( lIn = popen ( lDialogString , "r" ) ) ) 5326 | { 5327 | return NULL ; 5328 | } 5329 | lBuff[0]='\0'; 5330 | p=lBuff; 5331 | while ( fgets ( p , sizeof ( lBuff ) , lIn ) != NULL ) 5332 | { 5333 | p += strlen ( p ); 5334 | } 5335 | pclose ( lIn ) ; 5336 | if ( lBuff[strlen ( lBuff ) -1] == '\n' ) 5337 | { 5338 | lBuff[strlen ( lBuff ) -1] = '\0' ; 5339 | } 5340 | /* printf ( "lBuff: %s\n" , lBuff ) ; */ 5341 | if ( lWasKdialog && aAllowMultipleSelects ) 5342 | { 5343 | p = lBuff ; 5344 | while ( ( p = strchr ( p , '\n' ) ) ) 5345 | * p = '|' ; 5346 | } 5347 | /* printf ( "lBuff2: %s\n" , lBuff ) ; */ 5348 | if ( ! strlen ( lBuff ) ) 5349 | { 5350 | return NULL; 5351 | } 5352 | if ( aAllowMultipleSelects && strchr(lBuff, '|') ) 5353 | { 5354 | p2 = ensureFilesExist( lBuff , lBuff ) ; 5355 | } 5356 | else if ( fileExists (lBuff) ) 5357 | { 5358 | p2 = lBuff ; 5359 | } 5360 | else 5361 | { 5362 | return NULL ; 5363 | } 5364 | /* printf ( "lBuff3: %s\n" , p2 ) ; */ 5365 | 5366 | return p2 ; 5367 | } 5368 | 5369 | 5370 | char const * tinyfd_selectFolderDialog ( 5371 | char const * const aTitle , /* "" */ 5372 | char const * const aDefaultPath ) /* "" */ 5373 | { 5374 | static char lBuff [MAX_PATH_OR_CMD] ; 5375 | char lDialogString [MAX_PATH_OR_CMD] ; 5376 | FILE * lIn ; 5377 | char const * p ; 5378 | int lWasGraphicDialog = 0 ; 5379 | int lWasXterm = 0 ; 5380 | lBuff[0]='\0'; 5381 | 5382 | if ( osascriptPresent ( )) 5383 | { 5384 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"applescript");return (char const *)1;} 5385 | strcpy ( lDialogString , "osascript "); 5386 | if ( ! osx9orBetter() ) strcat ( lDialogString , " -e 'tell application \"System Events\"' -e 'Activate'"); 5387 | strcat ( lDialogString , " -e 'try' -e 'POSIX path of ( choose folder "); 5388 | if ( aTitle && strlen(aTitle) ) 5389 | { 5390 | strcat(lDialogString, "with prompt \"") ; 5391 | strcat(lDialogString, aTitle) ; 5392 | strcat(lDialogString, "\" ") ; 5393 | } 5394 | if ( aDefaultPath && strlen(aDefaultPath) ) 5395 | { 5396 | strcat(lDialogString, "default location \"") ; 5397 | strcat(lDialogString, aDefaultPath ) ; 5398 | strcat(lDialogString , "\" " ) ; 5399 | } 5400 | strcat ( lDialogString , ")' " ) ; 5401 | strcat(lDialogString, "-e 'on error number -128' " ) ; 5402 | strcat(lDialogString, "-e 'end try'") ; 5403 | if ( ! osx9orBetter() ) strcat ( lDialogString, " -e 'end tell'") ; 5404 | } 5405 | else if ( zenityPresent() || matedialogPresent() || qarmaPresent() ) 5406 | { 5407 | if ( zenityPresent() ) 5408 | { 5409 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity");return (char const *)1;} 5410 | strcpy ( lDialogString , "zenity --file-selection --directory" ) ; 5411 | } 5412 | else if ( matedialogPresent() ) 5413 | { 5414 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"matedialog");return (char const *)1;} 5415 | strcpy ( lDialogString , "matedialog --file-selection --directory" ) ; 5416 | } 5417 | else 5418 | { 5419 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"qarma");return (char const *)1;} 5420 | strcpy ( lDialogString , "qarma --file-selection --directory" ) ; 5421 | } 5422 | 5423 | if ( aTitle && strlen(aTitle) ) 5424 | { 5425 | strcat(lDialogString, " --title=\"") ; 5426 | strcat(lDialogString, aTitle) ; 5427 | strcat(lDialogString, "\"") ; 5428 | } 5429 | if ( aDefaultPath && strlen(aDefaultPath) ) 5430 | { 5431 | strcat(lDialogString, " --filename=\"") ; 5432 | strcat(lDialogString, aDefaultPath) ; 5433 | strcat(lDialogString, "\"") ; 5434 | } 5435 | } 5436 | else if ( kdialogPresent() ) 5437 | { 5438 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"kdialog");return (char const *)1;} 5439 | strcpy ( lDialogString , "kdialog --getexistingdirectory" ) ; 5440 | if ( aDefaultPath && strlen(aDefaultPath) ) 5441 | { 5442 | strcat(lDialogString, " \"") ; 5443 | strcat(lDialogString, aDefaultPath ) ; 5444 | strcat(lDialogString , "\"" ) ; 5445 | } 5446 | else 5447 | { 5448 | strcat(lDialogString, " :" ) ; 5449 | } 5450 | if ( aTitle && strlen(aTitle) ) 5451 | { 5452 | strcat(lDialogString, " --title \"") ; 5453 | strcat(lDialogString, aTitle) ; 5454 | strcat(lDialogString, "\"") ; 5455 | } 5456 | } 5457 | else if ( ! xdialogPresent() && tkinter2Present ( ) ) 5458 | { 5459 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"tkinter");return (char const *)1;} 5460 | strcpy ( lDialogString , gPython2Name ) ; 5461 | if ( ! isTerminalRunning ( ) && isDarwin ( ) ) 5462 | { 5463 | strcat ( lDialogString , " -i" ) ; /* for osx without console */ 5464 | } 5465 | strcat ( lDialogString , 5466 | " -c \"import Tkinter,tkFileDialog;root=Tkinter.Tk();root.withdraw();"); 5467 | 5468 | if ( isDarwin ( ) ) 5469 | { 5470 | strcat ( lDialogString , 5471 | "import os;os.system('''/usr/bin/osascript -e 'tell app \\\"Finder\\\" to set \ 5472 | frontmost of process \\\"Python\\\" to true' ''');"); 5473 | } 5474 | 5475 | strcat ( lDialogString , "print tkFileDialog.askdirectory("); 5476 | if ( aTitle && strlen(aTitle) ) 5477 | { 5478 | strcat(lDialogString, "title='") ; 5479 | strcat(lDialogString, aTitle) ; 5480 | strcat(lDialogString, "',") ; 5481 | } 5482 | if ( aDefaultPath && strlen(aDefaultPath) ) 5483 | { 5484 | strcat(lDialogString, "initialdir='") ; 5485 | strcat(lDialogString, aDefaultPath ) ; 5486 | strcat(lDialogString , "'" ) ; 5487 | } 5488 | strcat ( lDialogString , ")\"" ) ; 5489 | } 5490 | else if ( xdialogPresent() || dialogName() ) 5491 | { 5492 | if ( xdialogPresent ( ) ) 5493 | { 5494 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xdialog");return (char const *)1;} 5495 | lWasGraphicDialog = 1 ; 5496 | strcpy ( lDialogString , "(Xdialog " ) ; 5497 | } 5498 | else if ( isTerminalRunning ( ) ) 5499 | { 5500 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} 5501 | strcpy ( lDialogString , "(dialog " ) ; 5502 | } 5503 | else 5504 | { 5505 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} 5506 | lWasXterm = 1 ; 5507 | strcpy ( lDialogString , terminalName() ) ; 5508 | strcat ( lDialogString , "'(" ) ; 5509 | strcat ( lDialogString , dialogName() ) ; 5510 | strcat ( lDialogString , " " ) ; 5511 | } 5512 | 5513 | if ( aTitle && strlen(aTitle) ) 5514 | { 5515 | strcat(lDialogString, "--title \"") ; 5516 | strcat(lDialogString, aTitle) ; 5517 | strcat(lDialogString, "\" ") ; 5518 | } 5519 | 5520 | if ( !xdialogPresent() && !gdialogPresent() ) 5521 | { 5522 | strcat(lDialogString, "--backtitle \"") ; 5523 | strcat(lDialogString, 5524 | "tab: focus | /: populate | spacebar: fill text field | ok: TEXT FIELD ONLY") ; 5525 | strcat(lDialogString, "\" ") ; 5526 | } 5527 | 5528 | strcat ( lDialogString , "--dselect \"" ) ; 5529 | if ( aDefaultPath && strlen(aDefaultPath) ) 5530 | { 5531 | strcat(lDialogString, aDefaultPath) ; 5532 | ensureFinalSlash(lDialogString); 5533 | } 5534 | else if ( ! isTerminalRunning ( ) && !lWasGraphicDialog ) 5535 | { 5536 | strcat(lDialogString, getenv("HOME")) ; 5537 | strcat(lDialogString, "/"); 5538 | } 5539 | else 5540 | { 5541 | strcat(lDialogString, "./") ; 5542 | } 5543 | 5544 | if ( lWasGraphicDialog ) 5545 | { 5546 | strcat(lDialogString, "\" 0 60 ) 2>&1 ") ; 5547 | } 5548 | else 5549 | { 5550 | strcat(lDialogString, "\" 0 60 >/dev/tty) ") ; 5551 | if ( lWasXterm ) 5552 | { 5553 | strcat ( lDialogString , 5554 | "2>/tmp/tinyfd.txt';cat /tmp/tinyfd.txt;rm /tmp/tinyfd.txt"); 5555 | } 5556 | else 5557 | { 5558 | strcat(lDialogString, "2>&1 ; clear >/dev/tty") ; 5559 | } 5560 | } 5561 | } 5562 | else 5563 | { 5564 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){return tinyfd_inputBox (aTitle,NULL,NULL);} 5565 | p = tinyfd_inputBox(aTitle, "Select folder",""); 5566 | if ( !p || ! strlen ( p ) || ! dirExists ( p ) ) 5567 | { 5568 | return NULL ; 5569 | } 5570 | return p ; 5571 | } 5572 | if (tinyfd_verbose) printf ( "lDialogString: %s\n" , lDialogString ) ; 5573 | if ( ! ( lIn = popen ( lDialogString , "r" ) ) ) 5574 | { 5575 | return NULL ; 5576 | } 5577 | while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) 5578 | {} 5579 | pclose ( lIn ) ; 5580 | if ( lBuff[strlen ( lBuff ) -1] == '\n' ) 5581 | { 5582 | lBuff[strlen ( lBuff ) -1] = '\0' ; 5583 | } 5584 | /* printf ( "lBuff: %s\n" , lBuff ) ; */ 5585 | if ( ! strlen ( lBuff ) || ! dirExists ( lBuff ) ) 5586 | { 5587 | return NULL ; 5588 | } 5589 | return lBuff ; 5590 | } 5591 | 5592 | 5593 | /* returns the hexcolor as a string "#FF0000" */ 5594 | /* aoResultRGB also contains the result */ 5595 | /* aDefaultRGB is used only if aDefaultHexRGB is NULL */ 5596 | /* aDefaultRGB and aoResultRGB can be the same array */ 5597 | char const * tinyfd_colorChooser( 5598 | char const * const aTitle , /* NULL or "" */ 5599 | char const * const aDefaultHexRGB , /* NULL or "#FF0000"*/ 5600 | unsigned char const aDefaultRGB[3] , /* { 0 , 255 , 255 } */ 5601 | unsigned char aoResultRGB[3] ) /* { 0 , 0 , 0 } */ 5602 | { 5603 | static char lBuff [128] ; 5604 | char lTmp [128] ; 5605 | char lDialogString [MAX_PATH_OR_CMD] ; 5606 | char lDefaultHexRGB[8]; 5607 | char * lpDefaultHexRGB; 5608 | unsigned char lDefaultRGB[3]; 5609 | char const * p; 5610 | FILE * lIn ; 5611 | int i ; 5612 | int lWasZenity3 = 0 ; 5613 | int lWasOsascript = 0 ; 5614 | int lWasXdialog = 0 ; 5615 | lBuff[0]='\0'; 5616 | 5617 | if ( aDefaultHexRGB ) 5618 | { 5619 | Hex2RGB ( aDefaultHexRGB , lDefaultRGB ) ; 5620 | lpDefaultHexRGB = (char *) aDefaultHexRGB ; 5621 | } 5622 | else 5623 | { 5624 | lDefaultRGB[0]=aDefaultRGB[0]; 5625 | lDefaultRGB[1]=aDefaultRGB[1]; 5626 | lDefaultRGB[2]=aDefaultRGB[2]; 5627 | RGB2Hex( aDefaultRGB , lDefaultHexRGB ) ; 5628 | lpDefaultHexRGB = (char *) lDefaultHexRGB ; 5629 | } 5630 | 5631 | if ( osascriptPresent ( ) ) 5632 | { 5633 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"applescript");return (char const *)1;} 5634 | lWasOsascript = 1 ; 5635 | strcpy ( lDialogString , "osascript"); 5636 | 5637 | if ( ! osx9orBetter() ) 5638 | { 5639 | strcat ( lDialogString , " -e 'tell application \"System Events\"' -e 'Activate'"); 5640 | strcat ( lDialogString , " -e 'try' -e 'set mycolor to choose color default color {"); 5641 | } 5642 | else 5643 | { 5644 | strcat ( lDialogString , 5645 | " -e 'try' -e 'tell app (path to frontmost application as Unicode text) \ 5646 | to set mycolor to choose color default color {"); 5647 | } 5648 | 5649 | sprintf(lTmp, "%d", 256 * lDefaultRGB[0] ) ; 5650 | strcat(lDialogString, lTmp ) ; 5651 | strcat(lDialogString, "," ) ; 5652 | sprintf(lTmp, "%d", 256 * lDefaultRGB[1] ) ; 5653 | strcat(lDialogString, lTmp ) ; 5654 | strcat(lDialogString, "," ) ; 5655 | sprintf(lTmp, "%d", 256 * lDefaultRGB[2] ) ; 5656 | strcat(lDialogString, lTmp ) ; 5657 | strcat(lDialogString, "}' " ) ; 5658 | strcat ( lDialogString , 5659 | "-e 'set mystring to ((item 1 of mycolor) div 256 as integer) as string' " ); 5660 | strcat ( lDialogString , 5661 | "-e 'repeat with i from 2 to the count of mycolor' " ); 5662 | strcat ( lDialogString , 5663 | "-e 'set mystring to mystring & \" \" & ((item i of mycolor) div 256 as integer) as string' " ); 5664 | strcat ( lDialogString , "-e 'end repeat' " ); 5665 | strcat ( lDialogString , "-e 'mystring' "); 5666 | strcat(lDialogString, "-e 'on error number -128' " ) ; 5667 | strcat(lDialogString, "-e 'end try'") ; 5668 | if ( ! osx9orBetter() ) strcat ( lDialogString, " -e 'end tell'") ; 5669 | } 5670 | else if ( zenity3Present() || matedialogPresent() || qarmaPresent() ) 5671 | { 5672 | lWasZenity3 = 1 ; 5673 | if ( zenity3Present() ) 5674 | { 5675 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity3");return (char const *)1;} 5676 | sprintf ( lDialogString , 5677 | "zenity --color-selection --show-palette --color=%s" , lpDefaultHexRGB ) ; 5678 | } 5679 | else if ( matedialogPresent() ) 5680 | { 5681 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"matedialog");return (char const *)1;} 5682 | sprintf ( lDialogString , 5683 | "matedialog --color-selection --show-palette --color=%s" , lpDefaultHexRGB ) ; 5684 | } 5685 | else 5686 | { 5687 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"qarma");return (char const *)1;} 5688 | sprintf ( lDialogString , 5689 | "qarma --color-selection --show-palette --color=%s" , lpDefaultHexRGB ) ; 5690 | } 5691 | 5692 | if ( aTitle && strlen(aTitle) ) 5693 | { 5694 | strcat(lDialogString, " --title=\"") ; 5695 | strcat(lDialogString, aTitle) ; 5696 | strcat(lDialogString, "\"") ; 5697 | } 5698 | } 5699 | else if ( kdialogPresent() ) 5700 | { 5701 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"kdialog");return (char const *)1;} 5702 | sprintf ( lDialogString , 5703 | "kdialog --getcolor --default '%s'" , lpDefaultHexRGB ) ; 5704 | if ( aTitle && strlen(aTitle) ) 5705 | { 5706 | strcat(lDialogString, " --title \"") ; 5707 | strcat(lDialogString, aTitle) ; 5708 | strcat(lDialogString, "\"") ; 5709 | } 5710 | } 5711 | else if ( xdialogPresent() ) 5712 | { 5713 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xdialog");return (char const *)1;} 5714 | lWasXdialog = 1 ; 5715 | strcpy ( lDialogString , "Xdialog --colorsel \"" ) ; 5716 | if ( aTitle && strlen(aTitle) ) 5717 | { 5718 | strcat(lDialogString, aTitle) ; 5719 | } 5720 | strcat(lDialogString, "\" 0 60 ") ; 5721 | sprintf(lTmp,"%hhu %hhu %hhu",lDefaultRGB[0], 5722 | lDefaultRGB[1],lDefaultRGB[2]); 5723 | strcat(lDialogString, lTmp) ; 5724 | strcat(lDialogString, " 2>&1"); 5725 | } 5726 | else if ( tkinter2Present ( ) ) 5727 | { 5728 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"tkinter");return (char const *)1;} 5729 | strcpy ( lDialogString , gPython2Name ) ; 5730 | if ( ! isTerminalRunning ( ) && isDarwin ( ) ) 5731 | { 5732 | strcat ( lDialogString , " -i" ) ; /* for osx without console */ 5733 | } 5734 | 5735 | strcat ( lDialogString , 5736 | " -c \"import Tkinter,tkColorChooser;root=Tkinter.Tk();root.withdraw();"); 5737 | 5738 | if ( isDarwin ( ) ) 5739 | { 5740 | strcat ( lDialogString , 5741 | "import os;os.system('''osascript -e 'tell app \\\"Finder\\\" to set \ 5742 | frontmost of process \\\"Python\\\" to true' ''');"); 5743 | } 5744 | 5745 | strcat ( lDialogString , "res=tkColorChooser.askcolor(color='" ) ; 5746 | strcat(lDialogString, lpDefaultHexRGB ) ; 5747 | strcat(lDialogString, "'") ; 5748 | 5749 | 5750 | if ( aTitle && strlen(aTitle) ) 5751 | { 5752 | strcat(lDialogString, ",title='") ; 5753 | strcat(lDialogString, aTitle) ; 5754 | strcat(lDialogString, "'") ; 5755 | } 5756 | strcat ( lDialogString , ");\ 5757 | \nif res[1] is not None:\n\tprint res[1]\"" ) ; 5758 | } 5759 | else 5760 | { 5761 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){return tinyfd_inputBox (aTitle,NULL,NULL);} 5762 | p = tinyfd_inputBox(aTitle, 5763 | "Enter hex rgb color (i.e. #f5ca20)",lpDefaultHexRGB); 5764 | if ( !p || (strlen(p) != 7) || (p[0] != '#') ) 5765 | { 5766 | return NULL ; 5767 | } 5768 | for ( i = 1 ; i < 7 ; i ++ ) 5769 | { 5770 | if ( ! isxdigit( p[i] ) ) 5771 | { 5772 | return NULL ; 5773 | } 5774 | } 5775 | Hex2RGB(p,aoResultRGB); 5776 | return p ; 5777 | } 5778 | 5779 | if (tinyfd_verbose) printf ( "lDialogString: %s\n" , lDialogString ) ; 5780 | if ( ! ( lIn = popen ( lDialogString , "r" ) ) ) 5781 | { 5782 | return NULL ; 5783 | } 5784 | while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) 5785 | { 5786 | } 5787 | pclose ( lIn ) ; 5788 | if ( ! strlen ( lBuff ) ) 5789 | { 5790 | return NULL ; 5791 | } 5792 | /* printf ( "len Buff: %lu\n" , strlen(lBuff) ) ; */ 5793 | /* printf ( "lBuff0: %s\n" , lBuff ) ; */ 5794 | if ( lBuff[strlen ( lBuff ) -1] == '\n' ) 5795 | { 5796 | lBuff[strlen ( lBuff ) -1] = '\0' ; 5797 | } 5798 | if ( lWasZenity3 ) 5799 | { 5800 | if ( lBuff[0] == '#' ) { 5801 | lBuff[3]=lBuff[5]; 5802 | lBuff[4]=lBuff[6]; 5803 | lBuff[5]=lBuff[9]; 5804 | lBuff[6]=lBuff[10]; 5805 | lBuff[7]='\0'; 5806 | Hex2RGB(lBuff,aoResultRGB); 5807 | } 5808 | else if ( lBuff[3] == '(' ) { 5809 | sscanf(lBuff,"rgb(%hhu,%hhu,%hhu", 5810 | & aoResultRGB[0], & aoResultRGB[1],& aoResultRGB[2]); 5811 | RGB2Hex(aoResultRGB,lBuff); 5812 | } 5813 | else if ( lBuff[4] == '(' ) { 5814 | sscanf(lBuff,"rgba(%hhu,%hhu,%hhu", 5815 | & aoResultRGB[0], & aoResultRGB[1],& aoResultRGB[2]); 5816 | RGB2Hex(aoResultRGB,lBuff); 5817 | } 5818 | } 5819 | else if ( lWasOsascript || lWasXdialog ) 5820 | { 5821 | /* printf ( "lBuff: %s\n" , lBuff ) ; */ 5822 | sscanf(lBuff,"%hhu %hhu %hhu", 5823 | & aoResultRGB[0], & aoResultRGB[1],& aoResultRGB[2]); 5824 | RGB2Hex(aoResultRGB,lBuff); 5825 | } 5826 | else 5827 | { 5828 | Hex2RGB(lBuff,aoResultRGB); 5829 | } 5830 | /* printf("%d %d %d\n", aoResultRGB[0],aoResultRGB[1],aoResultRGB[2]); */ 5831 | /* printf ( "lBuff: %s\n" , lBuff ) ; */ 5832 | return lBuff ; 5833 | } 5834 | 5835 | 5836 | /* not cross platform - zenity only */ 5837 | /* contributed by Attila Dusnoki */ 5838 | char const * tinyfd_arrayDialog ( 5839 | char const * const aTitle , /* "" */ 5840 | int const aNumOfColumns , /* 2 */ 5841 | char const * const * const aColumns , /* {"Column 1","Column 2"} */ 5842 | int const aNumOfRows , /* 2 */ 5843 | char const * const * const aCells ) 5844 | /* {"Row1 Col1","Row1 Col2","Row2 Col1","Row2 Col2"} */ 5845 | { 5846 | static char lBuff [MAX_PATH_OR_CMD] ; 5847 | char lDialogString [MAX_PATH_OR_CMD] ; 5848 | FILE * lIn ; 5849 | lBuff[0]='\0'; 5850 | int i ; 5851 | 5852 | if ( zenityPresent() ) 5853 | { 5854 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity");return (char const *)1;} 5855 | strcpy ( lDialogString , "zenity --list --print-column=ALL" ) ; 5856 | if ( aTitle && strlen(aTitle) ) 5857 | { 5858 | strcat(lDialogString, " --title=\"") ; 5859 | strcat(lDialogString, aTitle) ; 5860 | strcat(lDialogString, "\"") ; 5861 | } 5862 | 5863 | if ( aColumns && (aNumOfColumns > 0) ) 5864 | { 5865 | for ( i = 0 ; i < aNumOfColumns ; i ++ ) 5866 | { 5867 | strcat ( lDialogString , " --column=\"" ) ; 5868 | strcat ( lDialogString , aColumns [i] ) ; 5869 | strcat ( lDialogString , "\"" ) ; 5870 | } 5871 | } 5872 | 5873 | if ( aCells && (aNumOfRows > 0) ) 5874 | { 5875 | strcat ( lDialogString , " " ) ; 5876 | for ( i = 0 ; i < aNumOfRows*aNumOfColumns ; i ++ ) 5877 | { 5878 | strcat ( lDialogString , "\"" ) ; 5879 | strcat ( lDialogString , aCells [i] ) ; 5880 | strcat ( lDialogString , "\" " ) ; 5881 | } 5882 | } 5883 | } 5884 | else 5885 | { 5886 | if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"");return (char const *)0;} 5887 | return NULL ; 5888 | } 5889 | 5890 | if (tinyfd_verbose) printf ( "lDialogString: %s\n" , lDialogString ) ; 5891 | if ( ! ( lIn = popen ( lDialogString , "r" ) ) ) 5892 | { 5893 | return NULL ; 5894 | } 5895 | while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) 5896 | {} 5897 | pclose ( lIn ) ; 5898 | if ( lBuff[strlen ( lBuff ) -1] == '\n' ) 5899 | { 5900 | lBuff[strlen ( lBuff ) -1] = '\0' ; 5901 | } 5902 | /* printf ( "lBuff: %s\n" , lBuff ) ; */ 5903 | if ( ! strlen ( lBuff ) ) 5904 | { 5905 | return NULL ; 5906 | } 5907 | return lBuff ; 5908 | } 5909 | #endif /* _WIN32 */ 5910 | 5911 | 5912 | /* 5913 | int main(void) 5914 | { 5915 | char const * lTmp; 5916 | char const * lTheSaveFileName; 5917 | char const * lTheOpenFileName; 5918 | char const * lTheSelectFolderName; 5919 | char const * lTheHexColor; 5920 | char const * lWillBeGraphicMode; 5921 | unsigned char lRgbColor[3]; 5922 | FILE * lIn; 5923 | char lBuffer[1024]; 5924 | char lThePassword[1024]; 5925 | char const * lFilterPatterns[2] = { "*.txt", "*.text" }; 5926 | 5927 | lWillBeGraphicMode = tinyfd_inputBox("tinyfd_query", NULL, NULL); 5928 | 5929 | if (lWillBeGraphicMode) 5930 | { 5931 | strcpy(lBuffer, "graphic mode: "); 5932 | } 5933 | else 5934 | { 5935 | strcpy(lBuffer, "console mode: "); 5936 | } 5937 | 5938 | strcat(lBuffer, tinyfd_response); 5939 | strcpy(lThePassword, "tinyfiledialogs v"); 5940 | strcat(lThePassword, tinyfd_version); 5941 | tinyfd_messageBox(lThePassword, lBuffer, "ok", "info", 0); 5942 | 5943 | if (lWillBeGraphicMode && !tinyfd_forceConsole) 5944 | { 5945 | tinyfd_forceConsole = ! tinyfd_messageBox("Hello World", 5946 | "graphic dialogs [yes] / console mode [no]?", 5947 | "yesno", "question", 1); 5948 | } 5949 | 5950 | lTmp = tinyfd_inputBox( 5951 | "a password box", "your password will be revealed", NULL); 5952 | 5953 | if (!lTmp) return 1; 5954 | 5955 | strcpy(lThePassword, lTmp); 5956 | 5957 | lTheSaveFileName = tinyfd_saveFileDialog( 5958 | "let us save this password", 5959 | "passwordFile.txt", 5960 | 2, 5961 | lFilterPatterns, 5962 | NULL); 5963 | 5964 | if (!lTheSaveFileName) 5965 | { 5966 | tinyfd_messageBox( 5967 | "Error", 5968 | "Save file name is NULL", 5969 | "ok", 5970 | "error", 5971 | 1); 5972 | return 1; 5973 | } 5974 | 5975 | lIn = fopen(lTheSaveFileName, "w"); 5976 | if (!lIn) 5977 | { 5978 | tinyfd_messageBox( 5979 | "Error", 5980 | "Can not open this file in write mode", 5981 | "ok", 5982 | "error", 5983 | 1); 5984 | return 1; 5985 | } 5986 | fputs(lThePassword, lIn); 5987 | fclose(lIn); 5988 | 5989 | lTheOpenFileName = tinyfd_openFileDialog( 5990 | "let us read the password back", 5991 | "", 5992 | 2, 5993 | lFilterPatterns, 5994 | NULL, 5995 | 0); 5996 | 5997 | if (!lTheOpenFileName) 5998 | { 5999 | tinyfd_messageBox( 6000 | "Error", 6001 | "Open file name is NULL", 6002 | "ok", 6003 | "error", 6004 | 1); 6005 | return 1; 6006 | } 6007 | 6008 | lIn = fopen(lTheOpenFileName, "r"); 6009 | 6010 | if (!lIn) 6011 | { 6012 | tinyfd_messageBox( 6013 | "Error", 6014 | "Can not open this file in read mode", 6015 | "ok", 6016 | "error", 6017 | 1); 6018 | return(1); 6019 | } 6020 | lBuffer[0] = '\0'; 6021 | fgets(lBuffer, sizeof(lBuffer), lIn); 6022 | fclose(lIn); 6023 | 6024 | tinyfd_messageBox("your password is", 6025 | lBuffer, "ok", "info", 1); 6026 | 6027 | lTheSelectFolderName = tinyfd_selectFolderDialog( 6028 | "let us just select a directory", NULL); 6029 | 6030 | if (!lTheSelectFolderName) 6031 | { 6032 | tinyfd_messageBox( 6033 | "Error", 6034 | "Select folder name is NULL", 6035 | "ok", 6036 | "error", 6037 | 1); 6038 | return 1; 6039 | } 6040 | 6041 | tinyfd_messageBox("The selected folder is", 6042 | lTheSelectFolderName, "ok", "info", 1); 6043 | 6044 | lTheHexColor = tinyfd_colorChooser( 6045 | "choose a nice color", 6046 | "#FF0077", 6047 | lRgbColor, 6048 | lRgbColor); 6049 | 6050 | if (!lTheHexColor) 6051 | { 6052 | tinyfd_messageBox( 6053 | "Error", 6054 | "hexcolor is NULL", 6055 | "ok", 6056 | "error", 6057 | 1); 6058 | return 1; 6059 | } 6060 | 6061 | tinyfd_messageBox("The selected hexcolor is", 6062 | lTheHexColor, "ok", "info", 1); 6063 | 6064 | return 0; 6065 | } 6066 | */ 6067 | 6068 | #ifdef _MSC_VER 6069 | #pragma warning(default:4996) 6070 | #pragma warning(default:4100) 6071 | #pragma warning(default:4706) 6072 | #endif 6073 | --------------------------------------------------------------------------------