]> cygwin.com Git - cygwin-apps/cygutils.git/blob - src/cygstart/cygstart.c
version 1.4.15
[cygwin-apps/cygutils.git] / src / cygstart / cygstart.c
1 /*
2 * cygstart - Let Windows start a program, or open a file or URL
3 *
4 * (c) 2002 Michael Schaap <cygstart(at)mscha.org>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * See the COPYING file for full license information.
20 */
21
22 #if HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25 #include "common.h"
26
27 #include <stdlib.h>
28 #include <wchar.h>
29 #include <locale.h>
30 #ifdef __CYGWIN__
31 #include <sys/cygwin.h>
32 #endif
33
34 /* The official name of this program (e.g., no `g' prefix). */
35 #define PROGRAM_NAME "cygstart"
36 #define AUTHORS "Michael Schaap"
37
38 /* Predefined actions */
39 #define ACTION_OPEN "open"
40 #define ACTION_EXPLORE "explore"
41 #define ACTION_EDIT "edit"
42 #define ACTION_FIND "find"
43 #define ACTION_PRINT "print"
44
45 /* MSDN reference URL */
46 #define MSDN_URL "http://msdn.microsoft.com/en-us/library/bb762153%28VS.85%29.aspx"
47
48 static const char versionID[] = PACKAGE_VERSION;
49 static const char revID[] =
50 "$Id$";
51 static const char copyrightID[] =
52 "Copyright (c) 2002,...\n"
53 "Michael Schaap. All rights reserved.\n" "Licensed under GPL v2.0\n";
54
55 /* The name this program was run with. */
56 static char *program_name;
57 static poptContext optCon;
58
59 typedef enum StartFlags
60 {
61 SF_NONE = 0,
62 SF_VERBOSE = 1 << 0,
63 SF_WAIT = 1 << 1,
64 } StartFlags;
65
66 /* ShellExecuteW returns an HINSTANCE -- which is a pointer whose
67 * size differs on 32bit and 64bit platforms -- but it is really
68 * an integer type, NOT a pointer. We need to cast it to an integer
69 * type, but...which one? This ugliness avoids compile warnings.
70 */
71 #ifdef __x86_64
72 #define INTEGER_CAST long long
73 #else
74 #define INTEGER_CAST int
75 #endif
76
77 static int cygStart (const char *aPath, const wchar_t * action,
78 const wchar_t * args, const char *workDir,
79 int show, StartFlags startFlags);
80 static int winStart (const wchar_t * aPath, const wchar_t * action,
81 const wchar_t * args, const wchar_t * workDir,
82 int show, StartFlags startFlags);
83 static char *startError (INTEGER_CAST err);
84 static const char *getVersion (void);
85 static void printTopDescription (FILE * f, char *name);
86 static void printBottomDescription (FILE * f, char *name);
87 static void usage (FILE * f, char *name);
88 static void help (FILE * f, char *name);
89 static void version (FILE * f, char *name);
90 static void license (FILE * f, char *name);
91
92 static size_t
93 mbstowcs_noerr (wchar_t * wcs, const char *mbs, size_t n)
94 {
95 size_t wcsLen = mbstowcs (wcs, mbs, n);
96 if (wcsLen == (size_t) - 1)
97 {
98 fprintf (stderr, "%s: multibyte to wide string conversion error\n",
99 program_name);
100 exit (1);
101 }
102 return wcsLen;
103 }
104
105 static wchar_t *
106 mbstowcs_dup (const char *mbs)
107 {
108 size_t len = mbstowcs (NULL, mbs, 0);
109 if (len == (size_t) - 1)
110 {
111 fprintf (stderr, "%s: multibyte to wide string conversion error\n",
112 program_name);
113 exit (1);
114 }
115 wchar_t *wcs = (wchar_t *) malloc (sizeof (wchar_t) * (len + 1));
116 size_t wcsLen = mbstowcs_noerr (wcs, mbs, len);
117 wcs[wcsLen] = L'\0';
118 return wcs;
119 }
120
121 int
122 main (int argc, const char **argv)
123 {
124 const char *arg;
125 const char **rest;
126 int rc;
127 int ret;
128 wchar_t *action = NULL;
129 char *file = NULL;
130 size_t argLength;
131 const char **tmp;
132 wchar_t *args = NULL;
133 char *workDir = NULL;
134 int show = SW_SHOWNORMAL;
135 StartFlags startFlags = SF_NONE;
136
137 setlocale (LC_ALL, "");
138
139 /* Action options */
140 struct poptOption actionOptionsTable[] = {
141 {"action", 'a', POPT_ARG_STRING, NULL, 'a',
142 "Use specified action instead of default", NULL},
143 {"open", 'o', POPT_ARG_NONE, NULL, 'o',
144 "Short for: --action open", NULL},
145 {"explore", 'x', POPT_ARG_NONE, NULL, 'x',
146 "Short for: --action explore", NULL},
147 {"edit", 'e', POPT_ARG_NONE, NULL, 'e',
148 "Short for: --action edit", NULL},
149 {"find", 'f', POPT_ARG_NONE, NULL, 'f',
150 "Short for: --action find", NULL},
151 {"print", 'p', POPT_ARG_NONE, NULL, 'p',
152 "Short for: --action print", NULL},
153 {NULL, '\0', 0, NULL, 0, NULL, NULL}
154 };
155
156 /* Directory options */
157 struct poptOption directoryOptionsTable[] = {
158 {"directory", 'd', POPT_ARG_STRING, NULL, 'd',
159 "Set working directory", NULL},
160 {NULL, '\0', 0, NULL, 0, NULL, NULL}
161 };
162
163 /* Show options */
164 struct poptOption showOptionsTable[] = {
165 {"hide", '\0', POPT_ARG_NONE, NULL, 'H',
166 "Hides the window and activates another window", NULL},
167 {"maximize", '\0', POPT_ARG_NONE, NULL, 'M',
168 "Maximizes the specified window", NULL},
169 {"minimize", '\0', POPT_ARG_NONE, NULL, 'N',
170 "Minimizes the specified window and activates the next top-level "
171 "window in the z-order", NULL},
172 {"restore", '\0', POPT_ARG_NONE, NULL, 'R',
173 "Activates and displays the window. If the window is minimized or "
174 "maximized, Windows restores it to its original size and position. "
175 "An application should specify this flag when restoring a minimized "
176 "window", NULL},
177 {"show", '\0', POPT_ARG_NONE, NULL, 'S',
178 "Activates the window and displays it in its current size and "
179 "position", NULL},
180 {"showmaximized", '\0', POPT_ARG_NONE, NULL, 'X',
181 "Activates the window and displays it as a maximized window", NULL},
182 {"showminimized", '\0', POPT_ARG_NONE, NULL, 'Y',
183 "Activates the window and displays it as a minimized window", NULL},
184 {"showminnoactive", '\0', POPT_ARG_NONE, NULL, 'Z',
185 "Displays the window as a minimized window. The active window "
186 "remains active", NULL},
187 {"showna", '\0', POPT_ARG_NONE, NULL, 'A',
188 "Displays the window in its current state. The active window "
189 "remains active", NULL},
190 {"shownoactivate", '\0', POPT_ARG_NONE, NULL, 'V',
191 "Displays a window in its most recent size and position. The "
192 "active window remains active", NULL},
193 {"shownormal", '\0', POPT_ARG_NONE, NULL, 'O',
194 "Activates and displays a window. If the window is minimized or "
195 "maximized, Windows restores it to its original size and position. "
196 "An application should specify this flag when displaying the window "
197 "for the first time", NULL},
198 {NULL, '\0', 0, NULL, 0, NULL, NULL}
199 };
200
201 /* Startup options */
202 struct poptOption startupOptionsTable[] = {
203 {"wait", 'w', POPT_ARG_NONE, NULL, 'w',
204 "Waits until the started application terminates before exiting.",
205 NULL},
206 {NULL, '\0', 0, NULL, 0, NULL, NULL}
207 };
208
209 /* Troubleshooting options */
210 struct poptOption troubleOptionsTable[] = {
211 {"verbose", 'v', POPT_ARG_NONE, NULL, 'E',
212 "Show the actual ShellExecute call made", NULL},
213 {NULL, '\0', 0, NULL, 0, NULL, NULL}
214 };
215
216 /* Help options */
217 struct poptOption helpOptionsTable[] = {
218 {"help", '?', POPT_ARG_NONE, NULL, '?',
219 "Show this help message", NULL},
220 {"usage", '\0', POPT_ARG_NONE, NULL, 'u',
221 "Display brief usage message", NULL},
222 {"version", '\0', POPT_ARG_NONE, NULL, 'v',
223 "Display version information", NULL},
224 {"license", '\0', POPT_ARG_NONE, NULL, 'l',
225 "Display licensing information", NULL},
226 {"reference", '\0', POPT_ARG_NONE, NULL, 'r',
227 "Open MSDN reference for ShellExecute", NULL},
228 {NULL, '\0', 0, NULL, 0, NULL, NULL}
229 };
230
231 struct poptOption opt[] = {
232 {NULL, '\0', POPT_ARG_INCLUDE_TABLE, actionOptionsTable, 0,
233 "Action options", NULL},
234 {NULL, '\0', POPT_ARG_INCLUDE_TABLE, directoryOptionsTable, 0,
235 "Directory options", NULL},
236 {NULL, '\0', POPT_ARG_INCLUDE_TABLE, showOptionsTable, 0,
237 "Show options", NULL},
238 {NULL, '\0', POPT_ARG_INCLUDE_TABLE, startupOptionsTable, 0,
239 "Startup options", NULL},
240 {NULL, '\0', POPT_ARG_INCLUDE_TABLE, troubleOptionsTable, 0,
241 "Troubleshooting options", NULL},
242 {NULL, '\0', POPT_ARG_INCLUDE_TABLE, helpOptionsTable, 0,
243 "Help options", NULL},
244 {NULL, '\0', 0, NULL, 0, NULL, NULL}
245 };
246
247 if ((program_name = strdup (argv[0])) == NULL)
248 {
249 fprintf (stderr, "%s: memory allocation error\n", argv[0]);
250 exit (1);
251 }
252
253 /* Parse options */
254 optCon = poptGetContext (NULL, argc, argv, opt, POPT_CONTEXT_POSIXMEHARDER);
255 poptSetOtherOptionHelp (optCon, "[OPTION]... FILE [ARGUMENTS]");
256 while ((rc = poptGetNextOpt (optCon)) > 0)
257 {
258 switch (rc)
259 {
260 /* Help options */
261 case '?':
262 help (stdout, program_name);
263 poptFreeContext (optCon);
264 free (program_name);
265 if (action)
266 free (action);
267 if (workDir)
268 free (workDir);
269 return (0);
270 case 'u':
271 usage (stdout, program_name);
272 poptFreeContext (optCon);
273 free (program_name);
274 if (action)
275 free (action);
276 if (workDir)
277 free (workDir);
278 return (0);
279 case 'v':
280 version (stdout, program_name);
281 poptFreeContext (optCon);
282 free (program_name);
283 if (action)
284 free (action);
285 if (workDir)
286 free (workDir);
287 return (0);
288 case 'l':
289 license (stdout, program_name);
290 poptFreeContext (optCon);
291 free (program_name);
292 if (action)
293 free (action);
294 if (workDir)
295 free (workDir);
296 return (0);
297 case 'r':
298 cygStart (MSDN_URL, NULL, NULL, NULL, SW_NORMAL, startFlags);
299 poptFreeContext (optCon);
300 free (program_name);
301 if (action)
302 free (action);
303 if (workDir)
304 free (workDir);
305 return (0);
306
307 /* Action options */
308 case 'a':
309 if (arg = poptGetOptArg (optCon))
310 {
311 if ((action = mbstowcs_dup (arg)) == NULL)
312 {
313 fprintf (stderr, "%s: memory allocation error\n", argv[0]);
314 exit (1);
315 }
316 }
317 break;
318 case 'o':
319 if ((action = mbstowcs_dup (ACTION_OPEN)) == NULL)
320 {
321 fprintf (stderr, "%s: memory allocation error\n", argv[0]);
322 exit (1);
323 }
324 break;
325 case 'x':
326 if ((action = mbstowcs_dup (ACTION_EXPLORE)) == NULL)
327 {
328 fprintf (stderr, "%s: memory allocation error\n", argv[0]);
329 exit (1);
330 }
331 break;
332 case 'e':
333 if ((action = mbstowcs_dup (ACTION_EDIT)) == NULL)
334 {
335 fprintf (stderr, "%s: memory allocation error\n", argv[0]);
336 exit (1);
337 }
338 break;
339 case 'f':
340 if ((action = mbstowcs_dup (ACTION_FIND)) == NULL)
341 {
342 fprintf (stderr, "%s: memory allocation error\n", argv[0]);
343 exit (1);
344 }
345 break;
346 case 'p':
347 if ((action = mbstowcs_dup (ACTION_PRINT)) == NULL)
348 {
349 fprintf (stderr, "%s: memory allocation error\n", argv[0]);
350 exit (1);
351 }
352 break;
353
354 /* Directory options */
355 case 'd':
356 if (arg = poptGetOptArg (optCon))
357 {
358 if ((workDir = strdup (arg)) == NULL)
359 {
360 fprintf (stderr, "%s: memory allocation error\n", argv[0]);
361 exit (1);
362 }
363 }
364 break;
365
366 /* Show options */
367 case 'H':
368 show = SW_HIDE;
369 break;
370 case 'M':
371 show = SW_MAXIMIZE;
372 break;
373 case 'N':
374 show = SW_MINIMIZE;
375 break;
376 case 'R':
377 show = SW_RESTORE;
378 break;
379 case 'S':
380 show = SW_SHOW;
381 break;
382 case 'X':
383 show = SW_SHOWMAXIMIZED;
384 break;
385 case 'Y':
386 show = SW_SHOWMINIMIZED;
387 break;
388 case 'Z':
389 show = SW_SHOWMINNOACTIVE;
390 break;
391 case 'A':
392 show = SW_SHOWNA;
393 break;
394 case 'V':
395 show = SW_SHOWNOACTIVATE;
396 break;
397 case 'O':
398 show = SW_SHOWNORMAL;
399 break;
400
401 /* Startup options */
402 case 'w':
403 startFlags |= SF_WAIT;
404 break;
405
406 /* Troubleshooting options */
407 case 'E':
408 startFlags |= SF_VERBOSE;
409 break;
410 }
411 }
412 if (rc < -1)
413 {
414 fprintf (stderr, "%s: bad argument %s: %s\n",
415 program_name, poptBadOption (optCon, POPT_BADOPTION_NOALIAS),
416 poptStrerror (rc));
417 poptFreeContext (optCon);
418 free (program_name);
419 if (action)
420 free (action);
421 if (workDir)
422 free (workDir);
423 return (2);
424 }
425 rest = poptGetArgs (optCon);
426
427 /* Determine file (or program, or URL) to start */
428 if (rest && *rest)
429 {
430 if ((file = strdup (*rest)) == NULL)
431 {
432 fprintf (stderr, "%s: memory allocation error\n", argv[0]);
433 exit (1);
434 }
435 rest++;
436 }
437 else
438 {
439 usage (stdout, program_name);
440 return (2);
441 }
442
443 /* Retrieve any arguments */
444 if (rest && *rest)
445 {
446 tmp = rest;
447 argLength = strlen (*tmp);
448 while (tmp++ && *tmp)
449 {
450 argLength += 1 + strlen (*tmp);
451 }
452 if ((args = (wchar_t *) malloc (sizeof (wchar_t) * (argLength + 1)))
453 == NULL)
454 {
455 fprintf (stderr, "%s: memory allocation error\n", argv[0]);
456 exit (1);
457 }
458 size_t argOffset = mbstowcs_noerr (args, *rest, argLength);
459 while (rest++ && *rest)
460 {
461 args[argOffset++] = L' ';
462 size_t len = mbstowcs_noerr (args + argOffset, *rest,
463 argLength - argOffset);
464 argOffset += len;
465 }
466 args[argOffset] = L'\0';
467 }
468
469 /* Start it! */
470 ret = cygStart (file, action, args, workDir, show, startFlags);
471
472 poptFreeContext (optCon);
473 free (program_name);
474 if (action)
475 free (action);
476 if (args)
477 free (args);
478 if (workDir)
479 free (workDir);
480 if (file)
481 free (file);
482
483 return ret;
484 }
485
486 /* ShellExecute*W is TOO SLOW when there is '\\?\' */
487 static const wchar_t *
488 skipLocalUNCPart (const wchar_t * path)
489 {
490 size_t offset = 0;
491 if ((wcslen (path) < MAX_PATH + 4)
492 && (!wcsncmp (path, L"\\\\?\\", 4)) && (path[5] == L':'))
493 return path + 4;
494 else
495 return path;
496 }
497
498 #if defined(__CYGWIN__)
499 static int
500 cygstart_posix_to_win_w (const char *posix_mbs_path, wchar_t **w32_wcs_path)
501 {
502 int rc = 0;
503 ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_W|CCP_RELATIVE,
504 posix_mbs_path, NULL, 0);
505 if (len < 0)
506 {
507 fprintf (stderr,
508 "%s: error converting path `%s' from cygwin to native format: %s\n",
509 program_name, posix_mbs_path, strerror (errno));
510 rc = 1;
511 goto err_cleanup;
512 }
513
514 *w32_wcs_path = (wchar_t *) malloc ((len + 1) * sizeof (wchar_t));
515 if (!*w32_wcs_path)
516 {
517 fprintf (stderr, "%s: memory allocation error\n", program_name);
518 rc = 1;
519 goto err_cleanup;
520 }
521
522 if (cygwin_conv_path (CCP_POSIX_TO_WIN_W|CCP_RELATIVE,
523 posix_mbs_path, *w32_wcs_path,
524 (len + 1) * sizeof (wchar_t)) < 0)
525 {
526 fprintf (stderr,
527 "%s: error converting path `%s' from cygwin to format: %s\n",
528 program_name, posix_mbs_path, strerror (errno));
529 rc = 1;
530 goto err_cleanup;
531 }
532 return rc;
533
534 err_cleanup:
535 if (*w32_wcs_path)
536 free (*w32_wcs_path);
537
538 return rc;
539 }
540 #endif /* __CYGWIN__ */
541
542 static int
543 cygstart_mbs_to_wcs (const char *mbs_path, wchar_t **wcs_path)
544 {
545 int rc = 0;
546 size_t len = mbstowcs (NULL, mbs_path, 0);
547 if (len == (size_t) - 1)
548 {
549 fprintf (stderr, "%s: error converting path `%s' to unicode: %s\n",
550 program_name, mbs_path, strerror (errno));
551 rc = 1;
552 goto err_cleanup;
553 }
554
555 *wcs_path = (wchar_t *) malloc ((len + 1) * sizeof (wchar_t));
556 if (!(*wcs_path))
557 {
558 fprintf (stderr, "%s: memory allocation error\n", program_name);
559 rc = 1;
560 goto err_cleanup;
561 }
562
563 if (mbstowcs (*wcs_path, mbs_path, (len + 1) * sizeof (wchar_t)) ==
564 (size_t) - 1)
565 {
566 fprintf (stderr, "%s: error converting path `%s' to unicode: %s\n",
567 program_name, mbs_path, strerror (errno));
568 rc = 1;
569 goto err_cleanup;
570 }
571
572 (*wcs_path)[len] = L'\0';
573 return rc;
574
575 err_cleanup:
576 if (*wcs_path)
577 free (*wcs_path);
578
579 return rc;
580 }
581
582 /* Start a program, or open a file or URL, using Cygwin POSIX paths */
583 static int
584 cygStart (const char *aPath, const wchar_t * action,
585 const wchar_t * args, const char *workDir,
586 int show, StartFlags startFlags)
587 {
588 wchar_t *winPath = NULL;
589 wchar_t *winDir = NULL;
590 const wchar_t *pWinPath = NULL;
591 const wchar_t *pWinDir = NULL;
592 int rc = 0;
593
594 if (strncmp (aPath, "file://", 7) == 0)
595 aPath += 7;
596 #ifdef __CYGWIN__
597 /* Convert file path from POSIX to Windows, unless it looks like a URL */
598 if (!strstr (aPath, "://") && strncmp (aPath, "mailto:", 7) != 0)
599 {
600 rc = cygstart_posix_to_win_w (aPath, &winPath);
601 if (rc) goto cleanup;
602 pWinPath = skipLocalUNCPart (winPath);
603 }
604 else
605 #endif /* __CYGWIN__ */
606 {
607 rc = cygstart_mbs_to_wcs (aPath, &winPath);
608 if (rc) goto cleanup;
609 pWinPath = winPath;
610 }
611
612 /* Convert working directory, if any, from POSIX to Windows */
613 if (workDir)
614 {
615 #ifdef __CYGWIN__
616 rc = cygstart_posix_to_win_w (workDir, &winDir);
617 #else
618 rc = cygstart_mbs_to_wcs (workDir, &winDir);
619 #endif
620 if (rc) goto cleanup;
621 pWinDir = skipLocalUNCPart (winDir);
622 rc = winStart (pWinPath, action, args, pWinDir, show, startFlags);
623 }
624 else
625 {
626 rc = winStart (pWinPath, action, args, NULL, show, startFlags);
627 }
628
629 cleanup:
630 if (winDir)
631 free (winDir);
632 if (winPath)
633 free (winPath);
634
635 return rc;
636 }
637
638 static void printLastError (FILE * file);
639
640 /* Start a program, or open a file or URL, using Windows paths */
641 static int
642 winStart (const wchar_t * aPath, const wchar_t * action,
643 const wchar_t * args, const wchar_t * workDir,
644 int show, StartFlags startFlags)
645 {
646 #ifdef __CYGWIN__
647 /* Need to sync the Windows environment */
648 cygwin_internal (CW_SYNC_WINENV);
649 #endif
650
651 if (startFlags & SF_VERBOSE)
652 {
653 wprintf
654 (L"ShellExecute(NULL, \"%ls\", \"%ls\", \"%ls\", \"%ls\", %d)\n",
655 action, aPath, args, workDir, show);
656 }
657
658 if (!(startFlags & SF_WAIT))
659 {
660 INTEGER_CAST ret =
661 (INTEGER_CAST) ShellExecuteW (NULL, action, aPath, args, workDir, show);
662
663 if (ret >= 32)
664 {
665 return 0;
666 }
667 else
668 {
669 fwprintf (stderr, L"Unable to start '%ls': %s\n", aPath,
670 startError (ret));
671 return 1;
672 }
673 }
674 else
675 {
676 SHELLEXECUTEINFOW sei;
677
678 memset (&sei, 0, sizeof (sei));
679 sei.cbSize = sizeof (sei);
680 sei.lpVerb = action;
681 sei.lpFile = aPath;
682 sei.lpParameters = args;
683 sei.lpDirectory = workDir;
684 sei.nShow = show;
685 sei.fMask |= SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;
686
687 if (!ShellExecuteExW (&sei))
688 {
689 if (((INTEGER_CAST)sei.hInstApp) < 32)
690 {
691 fwprintf (stderr, L"Unable to start '%ls': %s\n", aPath,
692 startError ((INTEGER_CAST) sei.hInstApp));
693 return 1;
694 }
695 else
696 {
697 fwprintf (stderr, L"Unable to start '%ls': ", aPath);
698 printLastError (stderr);
699 fprintf (stderr, "\n");
700 return 1;
701 }
702 }
703
704 if (sei.hProcess)
705 {
706 DWORD code;
707 WaitForSingleObject (sei.hProcess, INFINITE);
708 if (!GetExitCodeProcess (sei.hProcess, &code))
709 {
710 code = 1;
711 }
712 CloseHandle (sei.hProcess);
713 return (int) code;
714 }
715
716 return 0;
717 }
718 }
719
720 /* Print a correctly-localized error message for GetLastError() to the given
721 file descriptor. */
722 static void
723 printLastError (FILE * file)
724 {
725 LPSTR buf = 0;
726
727 if (!FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError (), 0, (LPSTR) & buf, 0, // min size
728 0))
729 {
730 // avoid recursion getting message - possible but infinite-prone
731 fprintf (file, "Couldn't retrieve error message");
732 return;
733 }
734
735 fputs (buf, file);
736
737 LocalFree (buf);
738 }
739
740 /* Return an error message, given a ShellExecute return code */
741 static char *
742 startError (INTEGER_CAST err)
743 {
744 switch (err)
745 {
746 case 0:
747 return "The operating system is out of memory or resources.";
748 case ERROR_FILE_NOT_FOUND:
749 return "The specified file was not found.";
750 case ERROR_PATH_NOT_FOUND:
751 return "The specified path was not found.";
752 case ERROR_BAD_FORMAT:
753 return "The .exe file is invalid (non-Win32 .exe or error in "
754 ".exe image).";
755 case SE_ERR_ACCESSDENIED:
756 return "The operating system denied access to the specified file.";
757 case SE_ERR_ASSOCINCOMPLETE:
758 return "The file name association is incomplete or invalid.";
759 case SE_ERR_DDEBUSY:
760 return "The DDE transaction could not be completed because "
761 "other DDE transactions were being processed.";
762 case SE_ERR_DDEFAIL:
763 return "The DDE transaction failed.";
764 case SE_ERR_DDETIMEOUT:
765 return "The DDE transaction could not be completed because the "
766 "request timed out.";
767 case SE_ERR_DLLNOTFOUND:
768 return "The specified dynamic-link library was not found.";
769 case SE_ERR_NOASSOC:
770 return "There is no application associated with the given file "
771 "name extension.";
772 case SE_ERR_OOM:
773 return "There was not enough memory to complete the operation.";
774 case SE_ERR_SHARE:
775 return "A sharing violation occurred.";
776 default:
777 return "An unknown error occurred.";
778 }
779 }
780
781 static const char *
782 getVersion ()
783 {
784 return versionID;
785 }
786
787 static void
788 printTopDescription (FILE * f, char *name)
789 {
790 fprintf (f, "%s is part of cygutils version %s\n", name, getVersion ());
791 fprintf (f, "%s was originally authored by %s\n", name, AUTHORS);
792 fprintf (f, "\nLet Windows start a program or open a file or URL.\n\n");
793 }
794
795 static void
796 printBottomDescription (FILE * f, char *name)
797 {
798 fprintf (f, "\n");
799 fprintf (f, "With thanks to MSDN: <%s>\n\n", MSDN_URL);
800 fprintf (f, "Please report any bugs to <cygwin(at)cygwin.com>.\n");
801 }
802
803 static
804 printLicense (FILE * f, char *name)
805 {
806 fprintf (f,
807 "This program is free software: you can redistribute it and/or modify\n"
808 "it under the terms of the GNU General Public License as published by\n"
809 "the Free Software Foundation, either version 3 of the License, or\n"
810 "(at your option) any later version.\n\n"
811 "This program is distributed in the hope that it will be useful,\n"
812 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
813 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
814 "GNU General Public License for more details.\n\n"
815 "You should have received a copy of the GNU General Public License\n"
816 "along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n"
817 "See the COPYING file for full license information.\n");
818 }
819
820 static void
821 usage (FILE * f, char *name)
822 {
823 poptPrintUsage (optCon, f, 0);
824 }
825
826 static void
827 help (FILE * f, char *name)
828 {
829 printTopDescription (f, name);
830 poptPrintHelp (optCon, f, 0);
831 printBottomDescription (f, name);
832 }
833
834 static void
835 version (FILE * f, char *name)
836 {
837 printTopDescription (f, name);
838 }
839
840 static void
841 license (FILE * f, char *name)
842 {
843 printTopDescription (f, name);
844 printLicense (f, name);
845 }
This page took 0.093279 seconds and 5 git commands to generate.