]>
Commit | Line | Data |
---|---|---|
c4453a3d | 1 | /* mkshortcut.c -- create a Windows shortcut |
0bb67178 | 2 | * |
0bb67178 CW |
3 | * Copyright (c) 2002 Joshua Daniel Franklin |
4 | * | |
5 | * This program is free software; you can redistribute it and/or | |
6 | * modify it under the terms of the GNU General Public License | |
7 | * as published by the Free Software Foundation; either version 2 | |
8 | * of the License, or (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
c4453a3d | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
0bb67178 CW |
13 | * GNU General Public License for more details. |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, write to the Free Software | |
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
18 | * | |
19 | * See the COPYING file for license information. | |
20 | * | |
21 | * Exit values | |
22 | * 1: user error (syntax error) | |
23 | * 2: system error (out of memory, etc.) | |
24 | * 3: windows error (interface failed) | |
c4453a3d CW |
25 | * |
26 | * Compile with: gcc -o prog.exe mkshortcut.c -lpopt -lole32 -luuid | |
7ab0751f | 27 | * (You'd need to uncomment the moved to common.h lines.) |
0bb67178 CW |
28 | * |
29 | */ | |
c4453a3d | 30 | |
0bb67178 CW |
31 | #if HAVE_CONFIG_H |
32 | # include "config.h" | |
c4453a3d | 33 | #endif |
0bb67178 | 34 | #include "common.h" |
5f56ef9c CW |
35 | |
36 | #define NOCOMATTRIBUTE | |
37 | ||
38 | #include <shlobj.h> | |
39 | #include <olectlid.h> | |
0bb67178 CW |
40 | /* moved to common.h */ |
41 | /* | |
5f56ef9c | 42 | #include <stdio.h> |
c4453a3d | 43 | #include <popt.h> |
0bb67178 CW |
44 | */ |
45 | ||
c4453a3d CW |
46 | static const char versionStr[] = "$Revision$"; |
47 | static const char versionID[] = "1.02.0"; | |
0bb67178 CW |
48 | /* for CVS */ |
49 | static const char revID[] = | |
7ab0751f | 50 | "$Id$"; |
0bb67178 | 51 | static const char copyrightID[] = |
7ab0751f | 52 | "Copyright (c) 2002\nJoshua Daniel Franklin. All rights reserved.\nLicensed under GPL v2.0\n"; |
5f56ef9c | 53 | |
c4453a3d CW |
54 | typedef struct optvals_s { |
55 | int icon_flag; | |
56 | int unix_flag; | |
57 | int windows_flag; | |
58 | int allusers_flag; | |
59 | int desktop_flag; | |
60 | int smprograms_flag; | |
6d007d60 | 61 | int show_flag; |
c4453a3d CW |
62 | int offset; |
63 | char * name_arg; | |
b2682e03 | 64 | char * dir_name_arg; |
c4453a3d CW |
65 | char * argument_arg; |
66 | char * target_arg; | |
67 | char * icon_name_arg; | |
68 | } optvals; | |
5f56ef9c | 69 | |
c4453a3d CW |
70 | static int mkshortcut(optvals opts, poptContext optCon); |
71 | static void printTopDescription(FILE * f, char * name); | |
72 | static void printBottomDescription(FILE * f, char * name); | |
73 | static char * getVersion(char * s, int slen); | |
74 | static void usage(poptContext optCon, FILE * f, char * name); | |
75 | static void help(poptContext optCon, FILE * f, char * name); | |
76 | static void version(poptContext optCon, FILE * f, char * name); | |
77 | static void license(poptContext optCon, FILE * f, char * name); | |
78 | ||
79 | static char *program_name; | |
80 | ||
81 | int | |
82 | main (int argc, const char **argv) | |
7ab0751f | 83 | { |
c4453a3d CW |
84 | poptContext optCon; |
85 | const char ** rest; | |
86 | int rc; | |
87 | int ec = 0; | |
88 | optvals opts; | |
89 | ||
90 | const char *tmp_str; | |
91 | int icon_offset_flag; | |
92 | char icon_name[MAX_PATH]; | |
93 | const char * arg; | |
94 | ||
95 | struct poptOption helpOptionsTable[] = { | |
96 | { "help", 'h', POPT_ARG_NONE, NULL, '?', \ | |
97 | "Show this help message", NULL}, | |
98 | { "usage", '\0', POPT_ARG_NONE, NULL, 'u', \ | |
99 | "Display brief usage message", NULL}, | |
100 | { "version", 'v', POPT_ARG_NONE, NULL, 'v', \ | |
101 | "Display version information", NULL}, | |
102 | { "license", '\0', POPT_ARG_NONE, NULL, 'l', \ | |
103 | "Display licensing information", NULL}, | |
104 | { NULL, '\0', 0, NULL, 0, NULL, NULL } | |
105 | }; | |
106 | ||
107 | struct poptOption generalOptionsTable[] = { | |
108 | { "arguments", 'a', POPT_ARG_STRING, NULL, 'a', \ | |
109 | "Use arguments ARGS", "ARGS"}, | |
110 | { "icon", 'i', POPT_ARG_STRING, NULL, 'i', \ | |
111 | "icon file for link to use", "iconfile"}, | |
112 | { "iconoffset", 'j', POPT_ARG_INT, &(opts.offset), 'j', \ | |
113 | "offset of icon in icon file (default is 0)", NULL}, | |
114 | { "name", 'n', POPT_ARG_STRING, NULL, 'n', \ | |
115 | "name for link (defaults to TARGET)", "NAME"}, | |
6d007d60 CW |
116 | { "show", 's', POPT_ARG_STRING, NULL, 's', \ |
117 | "window to show: normal, minimized, maximized", "norm|min|max"}, | |
b2682e03 CW |
118 | { "workingdir", 'w', POPT_ARG_STRING, NULL, 'w', \ |
119 | "set working directory (defaults to directory path of TARGET)", "PATH"}, | |
c4453a3d CW |
120 | { "allusers", 'A', POPT_ARG_VAL, &(opts.allusers_flag), 1, \ |
121 | "use 'All Users' instead of current user for -D,-P", NULL}, | |
122 | { "desktop", 'D', POPT_ARG_VAL, &(opts.desktop_flag), 1, \ | |
123 | "create link relative to 'Desktop' directory", NULL}, | |
124 | { "smprograms", 'P', POPT_ARG_VAL, &(opts.smprograms_flag), 1, \ | |
125 | "create link relative to Start Menu 'Programs' directory", NULL}, | |
126 | { NULL, '\0', 0, NULL, 0, NULL, NULL } | |
127 | }; | |
128 | ||
129 | struct poptOption opt[] = { | |
130 | { NULL, '\0', POPT_ARG_INCLUDE_TABLE, generalOptionsTable, 0, \ | |
131 | "General options", NULL }, | |
132 | { NULL, '\0', POPT_ARG_INCLUDE_TABLE, helpOptionsTable, 0, \ | |
133 | "Help options", NULL }, | |
134 | { NULL, '\0', 0, NULL, 0, NULL, NULL } | |
135 | }; | |
136 | ||
137 | tmp_str = strrchr (argv[0], '/'); | |
138 | if (tmp_str == NULL) { | |
139 | tmp_str = strrchr (argv[0], '\\'); | |
140 | } | |
141 | if (tmp_str == NULL) { | |
142 | tmp_str = argv[0]; | |
143 | } else { | |
144 | tmp_str++; | |
145 | } | |
146 | if ((program_name = strdup(tmp_str)) == NULL ) { | |
147 | fprintf(stderr, "%s: memory allocation error\n", argv[0]); | |
148 | exit(2); | |
149 | } | |
150 | ||
151 | icon_offset_flag = 0; | |
152 | ||
153 | opts.offset = 0; | |
154 | opts.icon_flag = 0; | |
155 | opts.unix_flag = 0; | |
156 | opts.windows_flag = 0; | |
157 | opts.allusers_flag = 0; | |
158 | opts.desktop_flag = 0; | |
159 | opts.smprograms_flag = 0; | |
6d007d60 | 160 | opts.show_flag = SW_SHOWNORMAL; |
c4453a3d CW |
161 | opts.target_arg = NULL; |
162 | opts.argument_arg = NULL; | |
163 | opts.name_arg = NULL; | |
b2682e03 | 164 | opts.dir_name_arg = NULL; |
c4453a3d CW |
165 | opts.icon_name_arg = NULL; |
166 | ||
167 | /* Parse options */ | |
168 | optCon = poptGetContext(NULL, argc, argv, opt, 0); | |
169 | poptSetOtherOptionHelp(optCon, "[OPTION]* TARGET"); | |
170 | while ((rc = poptGetNextOpt(optCon)) > 0) { | |
171 | switch (rc) { | |
172 | case '?': help(optCon, stderr, program_name); | |
173 | goto exit; | |
174 | case 'u': usage(optCon, stderr, program_name); | |
175 | goto exit; | |
176 | case 'v': version(optCon, stderr, program_name); | |
177 | goto exit; | |
178 | case 'l': license(optCon, stderr, program_name); | |
179 | goto exit; | |
180 | case 'i': opts.icon_flag = 1; | |
181 | if (arg = poptGetOptArg(optCon)) { | |
182 | cygwin_conv_to_full_win32_path (arg, icon_name); | |
183 | if ((opts.icon_name_arg = strdup(icon_name)) == NULL ) { | |
184 | fprintf(stderr, "%s: memory allocation error\n", program_name); | |
185 | ec=2; | |
186 | goto exit; | |
187 | } | |
188 | } | |
189 | break; | |
190 | case 'j': icon_offset_flag = 1; | |
191 | break; | |
192 | case 'n': if (arg = poptGetOptArg(optCon)) { | |
193 | if ((opts.name_arg = strdup(arg)) == NULL ) { | |
194 | fprintf(stderr, "%s: memory allocation error\n", program_name); | |
195 | ec=2; | |
196 | goto exit; | |
197 | } | |
198 | } | |
199 | break; | |
6d007d60 CW |
200 | case 's': if (arg = poptGetOptArg(optCon)) { |
201 | if (strcmp(arg, "min") == 0) { | |
202 | opts.show_flag = SW_SHOWMINNOACTIVE; | |
203 | } else if (strcmp(arg, "max") == 0) { | |
204 | opts.show_flag = SW_SHOWMAXIMIZED; | |
205 | } else if (strcmp(arg, "norm") == 0) { | |
206 | opts.show_flag = SW_SHOWNORMAL; | |
207 | } else { | |
208 | fprintf(stderr, "%s: %s not valid for show window\n", | |
209 | program_name, arg); | |
210 | ec=2; | |
211 | goto exit; | |
212 | } | |
213 | } | |
214 | break; | |
b2682e03 CW |
215 | case 'w': if (arg = poptGetOptArg(optCon)) { |
216 | if ((opts.dir_name_arg = strdup(arg)) == NULL ) { | |
217 | fprintf(stderr, "%s: memory allocation error\n", program_name); | |
218 | ec=2; | |
219 | goto exit; | |
220 | } | |
221 | } | |
222 | break; | |
c4453a3d CW |
223 | case 'a': if (arg = poptGetOptArg(optCon)) { |
224 | if ((opts.argument_arg = strdup(arg)) == NULL ) { | |
225 | fprintf(stderr, "%s: memory allocation error\n", program_name); | |
226 | ec=2; | |
227 | goto exit; | |
228 | } | |
229 | } | |
230 | break; | |
231 | // case 'A' | |
232 | // case 'D' | |
233 | // case 'P' all handled by popt itself | |
234 | } | |
235 | } | |
236 | ||
237 | if (icon_offset_flag & !opts.icon_flag) { | |
238 | fprintf(stderr, | |
239 | "%s: --iconoffset|-j only valid in conjuction with --icon|-i\n", | |
240 | program_name); | |
241 | usage(optCon, stderr, program_name); | |
242 | ec=1; | |
243 | goto exit; | |
244 | } | |
245 | ||
246 | if (opts.smprograms_flag && opts.desktop_flag) { | |
247 | fprintf(stderr, | |
248 | "%s: --smprograms|-P not valid in conjuction with --desktop|-D\n", | |
249 | program_name); | |
250 | usage(optCon, stderr, program_name); | |
251 | ec=1; | |
252 | goto exit; | |
253 | } | |
254 | ||
255 | if (rc < -1 ) { | |
256 | fprintf(stderr, "%s: bad argument %s: %s\n", | |
257 | program_name, poptBadOption(optCon, POPT_BADOPTION_NOALIAS), | |
258 | poptStrerror(rc)); | |
259 | ec = 1; | |
260 | goto exit; | |
261 | } | |
262 | ||
263 | rest = poptGetArgs(optCon); | |
264 | ||
265 | if (rest && *rest) { | |
266 | if ((opts.target_arg = strdup(*rest)) == NULL) { | |
267 | fprintf(stderr, "%s: memory allocation error\n", program_name); | |
268 | ec=2; | |
269 | goto exit; | |
7ab0751f | 270 | } |
c4453a3d CW |
271 | rest++; |
272 | if (rest && *rest) { | |
273 | fprintf(stderr, "%s: Too many arguments: ", program_name); | |
274 | while (*rest) | |
275 | fprintf(stderr, "%s ", *rest++); | |
276 | fprintf(stderr, "\n"); | |
277 | usage(optCon, stderr, program_name); | |
278 | ec=1; | |
279 | } else { | |
280 | // THE MEAT GOES HERE | |
281 | ec = mkshortcut(opts, optCon); | |
282 | } | |
283 | } else { | |
284 | fprintf(stderr, "%s: TARGET not specified\n", program_name); | |
285 | usage(optCon, stderr, program_name); | |
286 | ec=1; | |
287 | } | |
288 | ||
289 | exit: | |
290 | poptFreeContext(optCon); | |
291 | if (opts.target_arg) { free(opts.target_arg); } | |
292 | if (opts.name_arg) { free(opts.name_arg); } | |
b2682e03 | 293 | if (opts.dir_name_arg) { free(opts.dir_name_arg); } |
c4453a3d CW |
294 | if (opts.argument_arg) { free(opts.argument_arg); } |
295 | if (opts.icon_name_arg) { free(opts.icon_name_arg); } | |
296 | free(program_name); | |
297 | return(ec); | |
7ab0751f CW |
298 | } |
299 | ||
c4453a3d | 300 | int mkshortcut(optvals opts, poptContext optCon) |
5f56ef9c | 301 | { |
7ab0751f CW |
302 | char link_name[MAX_PATH]; |
303 | char exe_name[MAX_PATH]; | |
304 | char dir_name[MAX_PATH]; | |
c4453a3d CW |
305 | char *buf_str, *tmp_str; |
306 | int tmp; | |
7ab0751f CW |
307 | |
308 | /* For OLE interface */ | |
5f56ef9c CW |
309 | LPITEMIDLIST id; |
310 | HRESULT hres; | |
7ab0751f CW |
311 | IShellLink *shell_link; |
312 | IPersistFile *persist_file; | |
5f56ef9c CW |
313 | WCHAR widepath[MAX_PATH]; |
314 | ||
7ab0751f | 315 | buf_str = (char *) malloc (PATH_MAX); |
c4453a3d CW |
316 | if (buf_str == NULL) { |
317 | fprintf (stderr, "%s: out of memory\n", program_name); | |
318 | return(2); | |
319 | } | |
5f56ef9c | 320 | |
7ab0751f | 321 | /* If there's a colon in the TARGET, it should be a URL */ |
c4453a3d | 322 | if (strchr (opts.target_arg, ':') != NULL) |
7ab0751f CW |
323 | { |
324 | /* Nope, somebody's trying a W32 path */ | |
c4453a3d CW |
325 | if (opts.target_arg[1] == ':') { |
326 | fprintf(stderr, "%s: all paths must be in POSIX format\n", | |
327 | program_name); | |
328 | usage (optCon, stderr, program_name); | |
329 | return(1); | |
330 | } | |
331 | strcpy (exe_name, opts.target_arg); | |
7ab0751f CW |
332 | dir_name[0] = '\0'; /* No working dir for URL */ |
333 | } | |
334 | /* Convert TARGET to win32 path */ | |
5f56ef9c | 335 | else |
7ab0751f | 336 | { |
c4453a3d | 337 | strcpy (buf_str, opts.target_arg); |
7ab0751f | 338 | cygwin_conv_to_full_win32_path (buf_str, exe_name); |
5f56ef9c | 339 | |
b2682e03 CW |
340 | /* Get a working dir from 'w' option */ |
341 | if (opts.dir_name_arg != NULL) | |
342 | { | |
343 | if (strchr (opts.dir_name_arg, ':') != NULL) | |
344 | { | |
345 | fprintf(stderr, "%s: all paths must be in POSIX format\n", | |
346 | program_name); | |
347 | usage (optCon, stderr, program_name); | |
348 | return(1); | |
349 | } | |
350 | cygwin_conv_to_win32_path (opts.dir_name_arg, dir_name); | |
351 | } | |
7ab0751f | 352 | /* Get a working dir from the exepath */ |
b2682e03 CW |
353 | else |
354 | { | |
355 | tmp_str = strrchr (exe_name, '\\'); | |
356 | tmp = strlen (exe_name) - strlen (tmp_str); | |
357 | strncpy (dir_name, exe_name, tmp); | |
358 | dir_name[tmp] = '\0'; | |
359 | } | |
7ab0751f | 360 | } |
5f56ef9c | 361 | |
7ab0751f | 362 | /* Generate a name for the link if not given */ |
c4453a3d | 363 | if (opts.name_arg == NULL) |
5f56ef9c | 364 | { |
7ab0751f | 365 | /* Strip trailing /'s if any */ |
c4453a3d | 366 | strcpy (buf_str, opts.target_arg); |
7ab0751f CW |
367 | tmp_str = buf_str; |
368 | tmp = strlen (buf_str) - 1; | |
369 | while (strrchr (buf_str, '/') == (buf_str + tmp)) | |
370 | { | |
371 | buf_str[tmp] = '\0'; | |
372 | tmp--; | |
373 | } | |
374 | /* Get basename */ | |
375 | while (*buf_str) | |
376 | { | |
377 | if (*buf_str == '/') | |
378 | tmp_str = buf_str + 1; | |
379 | buf_str++; | |
380 | } | |
381 | strcpy (link_name, tmp_str); | |
c4453a3d | 382 | } |
7ab0751f CW |
383 | /* User specified a name, so check it and convert */ |
384 | else | |
5f56ef9c | 385 | { |
c4453a3d | 386 | if (opts.desktop_flag || opts.smprograms_flag) |
7ab0751f CW |
387 | { |
388 | /* Cannot have absolute path relative to Desktop/SM Programs */ | |
c4453a3d CW |
389 | if (opts.name_arg[0] == '/') { |
390 | fprintf(stderr, "%s: absolute pathnames not allowed with -D/-P\n", | |
391 | program_name); | |
392 | usage (optCon, stderr, program_name); | |
393 | return(1); | |
394 | } | |
7ab0751f CW |
395 | } |
396 | /* Sigh. Another W32 path */ | |
c4453a3d CW |
397 | if (strchr (opts.name_arg, ':') != NULL) { |
398 | fprintf(stderr, "%s: all paths must be in POSIX format\n", | |
399 | program_name); | |
400 | usage (optCon, stderr, program_name); | |
401 | return(1); | |
402 | } | |
403 | cygwin_conv_to_win32_path (opts.name_arg, link_name); | |
404 | } | |
7ab0751f CW |
405 | |
406 | /* Add suffix to link name if necessary */ | |
407 | if (strlen (link_name) > 4) | |
5f56ef9c | 408 | { |
7ab0751f CW |
409 | tmp = strlen (link_name) - 4; |
410 | if (strncmp (link_name + tmp, ".lnk", 4) != 0) | |
411 | strcat (link_name, ".lnk"); | |
5f56ef9c | 412 | } |
7ab0751f CW |
413 | else |
414 | strcat (link_name, ".lnk"); | |
5f56ef9c | 415 | |
7ab0751f | 416 | /* Prepend relative path if necessary */ |
c4453a3d | 417 | if (opts.desktop_flag) |
7ab0751f CW |
418 | { |
419 | strcpy (buf_str, link_name); | |
c4453a3d | 420 | if (!opts.allusers_flag) |
7ab0751f CW |
421 | SHGetSpecialFolderLocation (NULL, CSIDL_DESKTOPDIRECTORY, &id); |
422 | else | |
423 | SHGetSpecialFolderLocation (NULL, CSIDL_COMMON_DESKTOPDIRECTORY, &id); | |
424 | SHGetPathFromIDList (id, link_name); | |
425 | /* Make sure Win95 without "All Users" has output */ | |
426 | if (strlen (link_name) == 0) | |
427 | { | |
428 | SHGetSpecialFolderLocation (NULL, CSIDL_DESKTOPDIRECTORY, &id); | |
429 | SHGetPathFromIDList (id, link_name); | |
430 | } | |
431 | strcat (link_name, "\\"); | |
432 | strcat (link_name, buf_str); | |
5f56ef9c | 433 | } |
5f56ef9c | 434 | |
c4453a3d | 435 | if (opts.smprograms_flag) |
7ab0751f CW |
436 | { |
437 | strcpy (buf_str, link_name); | |
c4453a3d | 438 | if (!opts.allusers_flag) |
7ab0751f CW |
439 | SHGetSpecialFolderLocation (NULL, CSIDL_PROGRAMS, &id); |
440 | else | |
441 | SHGetSpecialFolderLocation (NULL, CSIDL_COMMON_PROGRAMS, &id); | |
442 | SHGetPathFromIDList (id, link_name); | |
443 | /* Make sure Win95 without "All Users" has output */ | |
444 | if (strlen (link_name) == 0) | |
445 | { | |
446 | SHGetSpecialFolderLocation (NULL, CSIDL_PROGRAMS, &id); | |
447 | SHGetPathFromIDList (id, link_name); | |
448 | } | |
449 | strcat (link_name, "\\"); | |
450 | strcat (link_name, buf_str); | |
5f56ef9c | 451 | } |
5f56ef9c | 452 | |
7ab0751f CW |
453 | /* Beginning of Windows interface */ |
454 | hres = OleInitialize (NULL); | |
455 | if (hres != S_FALSE && hres != S_OK) | |
456 | { | |
c4453a3d CW |
457 | fprintf (stderr, "%s: Could not initialize OLE interface\n", |
458 | program_name); | |
459 | return (3); | |
7ab0751f | 460 | } |
5f56ef9c | 461 | |
7ab0751f CW |
462 | hres = |
463 | CoCreateInstance (&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, | |
464 | &IID_IShellLink, (void **) &shell_link); | |
465 | if (SUCCEEDED (hres)) | |
5f56ef9c | 466 | { |
7ab0751f CW |
467 | hres = |
468 | shell_link->lpVtbl->QueryInterface (shell_link, &IID_IPersistFile, | |
469 | (void **) &persist_file); | |
470 | if (SUCCEEDED (hres)) | |
471 | { | |
472 | shell_link->lpVtbl->SetPath (shell_link, exe_name); | |
473 | /* Put the POSIX path in the "Description", just to be nice */ | |
474 | cygwin_conv_to_full_posix_path (exe_name, buf_str); | |
475 | shell_link->lpVtbl->SetDescription (shell_link, buf_str); | |
476 | shell_link->lpVtbl->SetWorkingDirectory (shell_link, dir_name); | |
c4453a3d CW |
477 | if (opts.argument_arg) |
478 | shell_link->lpVtbl->SetArguments (shell_link, opts.argument_arg); | |
479 | if (opts.icon_flag) | |
480 | shell_link->lpVtbl->SetIconLocation (shell_link, opts.icon_name_arg, | |
481 | opts.offset); | |
6d007d60 CW |
482 | if (opts.show_flag != SW_SHOWNORMAL) |
483 | shell_link->lpVtbl->SetShowCmd(shell_link, opts.show_flag); | |
484 | ||
5f56ef9c | 485 | |
7ab0751f CW |
486 | /* Make link name Unicode-compliant */ |
487 | hres = | |
488 | MultiByteToWideChar (CP_ACP, 0, link_name, -1, widepath, | |
489 | MAX_PATH); | |
490 | if (!SUCCEEDED (hres)) | |
491 | { | |
492 | fprintf (stderr, "%s: Unicode translation failed%d\n", | |
c4453a3d CW |
493 | program_name, hres); |
494 | return (3); | |
7ab0751f CW |
495 | } |
496 | hres = persist_file->lpVtbl->Save (persist_file, widepath, TRUE); | |
497 | if (!SUCCEEDED (hres)) | |
498 | { | |
499 | fprintf (stderr, | |
c4453a3d CW |
500 | "%s: Saving \"%s\" failed; does the target directory exist?\n", |
501 | program_name, link_name); | |
502 | return (3); | |
7ab0751f CW |
503 | } |
504 | persist_file->lpVtbl->Release (persist_file); | |
505 | shell_link->lpVtbl->Release (shell_link); | |
506 | } | |
507 | else | |
508 | { | |
c4453a3d CW |
509 | fprintf (stderr, "%s: QueryInterface failed\n", program_name); |
510 | return (3); | |
7ab0751f | 511 | } |
5f56ef9c | 512 | } |
7ab0751f | 513 | else |
5f56ef9c | 514 | { |
c4453a3d CW |
515 | fprintf (stderr, "%s: CoCreateInstance failed\n", program_name); |
516 | return (3); | |
5f56ef9c | 517 | } |
c4453a3d CW |
518 | } |
519 | ||
520 | static char * getVersion(char * s, int slen) | |
521 | { | |
522 | const char *v = strchr (versionStr, ':'); | |
523 | ||
524 | int len; | |
525 | if (!v) { | |
526 | v = "?"; | |
527 | len = 1; | |
528 | } else { | |
529 | v += 2; | |
530 | len = strchr (v, ' ') - v; | |
531 | } | |
532 | snprintf (s,slen,"%.*s", len, v); | |
533 | return s; | |
534 | } | |
535 | ||
536 | static void printTopDescription(FILE * f, char * name) | |
537 | { | |
538 | char s[20]; | |
539 | fprintf(f, "%s (cygutils) version %s\n", name, getVersion(s, 20)); | |
540 | fprintf(f, " create a Windows shortcut\n\n"); | |
541 | } | |
542 | static void printBottomDescription(FILE * f, char * name) | |
543 | { | |
014ae39c | 544 | fprintf(f, "\nNOTE: All filename arguments must be in unix (POSIX) format\n"); |
c4453a3d CW |
545 | } |
546 | static printLicense(FILE * f, char * name) | |
547 | { | |
548 | fprintf(f, "This program is free software; you can redistribute it and/or\n"); | |
549 | fprintf(f, "modify it under the terms of the GNU General Public License\n"); | |
550 | fprintf(f, "as published by the Free Software Foundation; either version 2\n"); | |
551 | fprintf(f, "of the License, or (at your option) any later version.\n"); | |
552 | fprintf(f, "\n"); | |
553 | fprintf(f, "This program is distributed in the hope that it will be useful,\n"); | |
554 | fprintf(f, "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); | |
555 | fprintf(f, "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); | |
556 | fprintf(f, "GNU General Public License for more details.\n"); | |
557 | fprintf(f, "\n"); | |
558 | fprintf(f, "You should have received a copy of the GNU General Public License\n"); | |
559 | fprintf(f, "along with this program; if not, write to the Free Software\n"); | |
560 | fprintf(f, "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n"); | |
561 | fprintf(f, "\n"); | |
562 | fprintf(f, "See the COPYING file for license information.\n"); | |
563 | } | |
564 | static void usage(poptContext optCon, FILE * f, char * name) | |
565 | { | |
566 | poptPrintUsage(optCon, f, 0); | |
567 | } | |
7ab0751f | 568 | |
c4453a3d CW |
569 | static void help(poptContext optCon, FILE * f, char * name) |
570 | { | |
571 | printTopDescription(f, name); | |
572 | poptPrintHelp(optCon, f, 0); | |
014ae39c | 573 | printBottomDescription(f, name); |
c4453a3d CW |
574 | } |
575 | ||
576 | static void version(poptContext optCon, FILE * f, char * name) | |
577 | { | |
578 | printTopDescription(f, name); | |
579 | fprintf(f, copyrightID); | |
5f56ef9c | 580 | } |
c4453a3d CW |
581 | |
582 | static void license(poptContext optCon, FILE * f, char * name) | |
583 | { | |
584 | printTopDescription(f, name); | |
585 | printLicense(f, name); | |
c4453a3d CW |
586 | } |
587 |