]>
Commit | Line | Data |
---|---|---|
e05f3227 | 1 | /* cygpath.cc -- convert pathnames between Windows and Unix format |
1fd5e000 CF |
2 | |
3 | This file is part of Cygwin. | |
4 | ||
5 | This software is a copyrighted work licensed under the terms of the | |
6 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
7 | details. */ | |
8 | ||
9 | #include <stdio.h> | |
10 | #include <string.h> | |
26fb7ef5 CV |
11 | #include <wchar.h> |
12 | #include <locale.h> | |
1fd5e000 CF |
13 | #include <stdlib.h> |
14 | #include <limits.h> | |
15 | #include <getopt.h> | |
138d4f51 CF |
16 | #include <io.h> |
17 | #include <sys/fcntl.h> | |
1fd5e000 | 18 | #include <sys/cygwin.h> |
92b499ac | 19 | #include <cygwin/version.h> |
418068d4 | 20 | #include <ctype.h> |
e70dbe77 | 21 | #include <wctype.h> |
7c03f799 | 22 | #include <errno.h> |
9cfc9511 | 23 | |
d21b6359 CV |
24 | #define _WIN32_WINNT 0x0a00 |
25 | #define WINVER 0x0a00 | |
9cfc9511 CV |
26 | #define NOCOMATTRIBUTE |
27 | #include <windows.h> | |
28 | #include <userenv.h> | |
29 | #include <shlobj.h> | |
30 | #include <ntdef.h> | |
31 | #include <ntdll.h> | |
32 | ||
26fb7ef5 | 33 | #include "wide_path.h" |
71d8f118 | 34 | #include "loadlib.h" |
1fd5e000 CF |
35 | |
36 | static char *prog_name; | |
ca902991 | 37 | static char *file_arg, *output_arg; |
5aa8817e | 38 | static int path_flag, unix_flag, windows_flag, absolute_flag, cygdrive_flag; |
5bb52de4 CV |
39 | static int shortname_flag, longname_flag; |
40 | static int ignore_flag, allusers_flag, output_flag; | |
fc200025 | 41 | static int mixed_flag, options_from_file_flag, mode_flag; |
0a23799a | 42 | static UINT codepage; |
fc200025 | 43 | |
1050e57c | 44 | static const char *format_type_arg; |
1fd5e000 | 45 | |
6a344609 | 46 | static struct option long_options[] = { |
6a344609 | 47 | {(char *) "absolute", no_argument, NULL, 'a'}, |
1050e57c CF |
48 | {(char *) "close", required_argument, NULL, 'c'}, |
49 | {(char *) "dos", no_argument, NULL, 'd'}, | |
50 | {(char *) "file", required_argument, NULL, 'f'}, | |
51 | {(char *) "help", no_argument, NULL, 'h'}, | |
52 | {(char *) "ignore", no_argument, NULL, 'i'}, | |
53 | {(char *) "long-name", no_argument, NULL, 'l'}, | |
54 | {(char *) "mixed", no_argument, NULL, 'm'}, | |
f135dd3e | 55 | {(char *) "mode", no_argument, NULL, 'M'}, |
6a344609 CF |
56 | {(char *) "option", no_argument, NULL, 'o'}, |
57 | {(char *) "path", no_argument, NULL, 'p'}, | |
5aa8817e | 58 | {(char *) "proc-cygdrive", no_argument, NULL, 'U'}, |
1050e57c CF |
59 | {(char *) "short-name", no_argument, NULL, 's'}, |
60 | {(char *) "type", required_argument, NULL, 't'}, | |
6a344609 | 61 | {(char *) "unix", no_argument, NULL, 'u'}, |
92b499ac | 62 | {(char *) "version", no_argument, NULL, 'V'}, |
6a344609 | 63 | {(char *) "windows", no_argument, NULL, 'w'}, |
6a344609 CF |
64 | {(char *) "allusers", no_argument, NULL, 'A'}, |
65 | {(char *) "desktop", no_argument, NULL, 'D'}, | |
e355de81 | 66 | {(char *) "homeroot", no_argument, NULL, 'H'}, |
ca902991 | 67 | {(char *) "mydocs", no_argument, NULL, 'O'}, |
1050e57c CF |
68 | {(char *) "smprograms", no_argument, NULL, 'P'}, |
69 | {(char *) "sysdir", no_argument, NULL, 'S'}, | |
70 | {(char *) "windir", no_argument, NULL, 'W'}, | |
ca902991 | 71 | {(char *) "folder", required_argument, NULL, 'F'}, |
0a23799a | 72 | {(char *) "codepage", required_argument, NULL, 'C'}, |
6a344609 | 73 | {0, no_argument, 0, 0} |
1fd5e000 CF |
74 | }; |
75 | ||
5aa8817e | 76 | static char options[] = "ac:df:hilmMopst:uUVwAC:DHOPSWF:"; |
9b566b96 | 77 | |
e7fca6f8 | 78 | static void __attribute__ ((__noreturn__)) |
6a344609 | 79 | usage (FILE * stream, int status) |
1fd5e000 | 80 | { |
45b80bb4 CF |
81 | if (!ignore_flag || !status) |
82 | fprintf (stream, "\ | |
92b499ac CV |
83 | Usage: %1$s (-d|-m|-u|-w|-t TYPE) [-f FILE] [OPTION]... NAME...\n\ |
84 | %1$s [-c HANDLE] \n\ | |
85 | %1$s [-ADHOPSW] \n\ | |
86 | %1$s [-F ID] \n\ | |
87 | \n\ | |
aa275fe0 | 88 | Convert Unix and Windows format paths, or output system path information\n\ |
bd79b736 | 89 | \n\ |
1050e57c | 90 | Output type options:\n\ |
92b499ac | 91 | \n\ |
ca902991 | 92 | -d, --dos print DOS (short) form of NAMEs (C:\\PROGRA~1\\)\n\ |
1050e57c | 93 | -m, --mixed like --windows, but with regular slashes (C:/WINNT)\n\ |
ca902991 CV |
94 | -M, --mode report on mode of file (binmode or textmode)\n\ |
95 | -u, --unix (default) print Unix form of NAMEs (/cygdrive/c/winnt)\n\ | |
4c634492 | 96 | -w, --windows print Windows form of NAMEs (C:\\WINNT)\n\ |
1050e57c | 97 | -t, --type TYPE print TYPE form: 'dos', 'mixed', 'unix', or 'windows'\n\ |
92b499ac | 98 | \n\ |
33bd2d12 | 99 | Path conversion options:\n\ |
92b499ac | 100 | \n\ |
1050e57c | 101 | -a, --absolute output absolute path\n\ |
ca902991 CV |
102 | -l, --long-name print Windows long form of NAMEs (with -w, -m only)\n\ |
103 | -p, --path NAME is a PATH list (i.e., '/bin:/usr/bin')\n\ | |
5aa8817e CV |
104 | -U, --proc-cygdrive Emit /proc/cygdrive path instead of cygdrive prefix\n\ |
105 | when converting Windows path to UNIX path.\n\ | |
ca902991 | 106 | -s, --short-name print DOS (short) form of NAMEs (with -w, -m only)\n\ |
0a23799a CV |
107 | -C, --codepage CP print DOS, Windows, or mixed pathname in Windows\n\ |
108 | codepage CP. CP can be a numeric codepage identifier,\n\ | |
109 | or one of the reserved words ANSI, OEM, or UTF8.\n\ | |
92b499ac | 110 | If this option is missing, %1$s defaults to the\n\ |
0a23799a | 111 | character set defined by the current locale.\n\ |
92b499ac | 112 | \n\ |
1050e57c | 113 | System information:\n\ |
92b499ac | 114 | \n\ |
ca902991 CV |
115 | -A, --allusers use `All Users' instead of current user for -D, -O, -P\n\ |
116 | -D, --desktop output `Desktop' directory and exit\n\ | |
1050e57c | 117 | -H, --homeroot output `Profiles' directory (home root) and exit\n\ |
ca902991 CV |
118 | -O, --mydocs output `My Documents' directory and exit\n\ |
119 | -P, --smprograms output Start Menu `Programs' directory and exit\n\ | |
120 | -S, --sysdir output system directory and exit\n\ | |
121 | -W, --windir output `Windows' directory and exit\n\ | |
122 | -F, --folder ID output special folder with numeric ID and exit\n\ | |
92b499ac | 123 | ", prog_name); |
befdf18b CF |
124 | if (ignore_flag) |
125 | /* nothing to do */; | |
126 | else if (stream != stdout) | |
127 | fprintf(stream, "Try `%s --help' for more information.\n", prog_name); | |
128 | else | |
1050e57c | 129 | { |
befdf18b | 130 | fprintf (stream, "\ |
92b499ac | 131 | \n\ |
33bd2d12 | 132 | Other options:\n\ |
92b499ac | 133 | \n\ |
1050e57c CF |
134 | -f, --file FILE read FILE for input; use - to read from STDIN\n\ |
135 | -o, --option read options from FILE as well (for use with --file)\n\ | |
136 | -c, --close HANDLE close HANDLE (for use in captured process)\n\ | |
ca902991 | 137 | -i, --ignore ignore missing argument\n\ |
1050e57c | 138 | -h, --help output usage information and exit\n\ |
92b499ac CV |
139 | -V, --version output version information and exit\n\ |
140 | \n"); | |
1050e57c | 141 | } |
45b80bb4 CF |
142 | exit (ignore_flag ? 0 : status); |
143 | } | |
144 | ||
2dba45f4 CV |
145 | static inline BOOLEAN |
146 | RtlAllocateUnicodeString (PUNICODE_STRING uni, ULONG size) | |
147 | { | |
148 | uni->Length = 0; | |
d2cc418e | 149 | uni->MaximumLength = size / sizeof (WCHAR); |
2dba45f4 CV |
150 | uni->Buffer = (WCHAR *) malloc (size); |
151 | return uni->Buffer != NULL; | |
152 | } | |
153 | ||
0a23799a CV |
154 | static size_t |
155 | my_wcstombs (char *dest, const wchar_t *src, size_t n) | |
156 | { | |
157 | if (codepage) | |
158 | return WideCharToMultiByte (codepage, 0, src, -1, dest, n, NULL, NULL); | |
159 | else | |
160 | return wcstombs (dest, src, n); | |
161 | } | |
162 | ||
d2cc418e CV |
163 | #define HARDDISK_PREFIX L"\\Device\\Harddisk" |
164 | #define GLOBALROOT_PREFIX "\\\\.\\GLOBALROOT" | |
165 | ||
2dba45f4 CV |
166 | static char * |
167 | get_device_name (char *path) | |
168 | { | |
169 | UNICODE_STRING ntdev, tgtdev, ntdevdir; | |
170 | ANSI_STRING ans; | |
171 | OBJECT_ATTRIBUTES ntobj; | |
172 | NTSTATUS status; | |
173 | HANDLE lnk, dir; | |
d2cc418e | 174 | bool got_one = false; |
2dba45f4 CV |
175 | char *ret = strdup (path); |
176 | PDIRECTORY_BASIC_INFORMATION odi = (PDIRECTORY_BASIC_INFORMATION) | |
177 | alloca (4096); | |
178 | BOOLEAN restart; | |
179 | ULONG cont; | |
180 | ||
d2cc418e CV |
181 | if (!strncasecmp (path, GLOBALROOT_PREFIX "\\", sizeof (GLOBALROOT_PREFIX))) |
182 | path += sizeof (GLOBALROOT_PREFIX) - 1; | |
2dba45f4 CV |
183 | if (strncasecmp (path, "\\Device\\", 8)) |
184 | return ret; | |
185 | ||
d2cc418e | 186 | if (!RtlAllocateUnicodeString (&ntdev, 65534)) |
2dba45f4 | 187 | return ret; |
d2cc418e | 188 | if (!RtlAllocateUnicodeString (&tgtdev, 65534)) |
2dba45f4 CV |
189 | return ret; |
190 | RtlInitAnsiString (&ans, path); | |
191 | RtlAnsiStringToUnicodeString (&ntdev, &ans, FALSE); | |
192 | ||
193 | /* First check if the given device name is a symbolic link itself. If so, | |
194 | query it and use the new name as actual device name to search for in the | |
195 | DOS device name directory. If not, just use the incoming device name. */ | |
196 | InitializeObjectAttributes (&ntobj, &ntdev, OBJ_CASE_INSENSITIVE, NULL, NULL); | |
9cfc9511 | 197 | status = NtOpenSymbolicLinkObject (&lnk, SYMBOLIC_LINK_QUERY, &ntobj); |
2dba45f4 CV |
198 | if (NT_SUCCESS (status)) |
199 | { | |
9cfc9511 CV |
200 | status = NtQuerySymbolicLinkObject (lnk, &tgtdev, NULL); |
201 | NtClose (lnk); | |
2dba45f4 CV |
202 | if (!NT_SUCCESS (status)) |
203 | goto out; | |
204 | RtlCopyUnicodeString (&ntdev, &tgtdev); | |
205 | } | |
d2cc418e CV |
206 | else if (status != STATUS_OBJECT_TYPE_MISMATCH |
207 | && status != STATUS_OBJECT_PATH_SYNTAX_BAD) | |
2dba45f4 CV |
208 | goto out; |
209 | ||
210 | for (int i = 0; i < 2; ++i) | |
211 | { | |
212 | /* There are two DOS device directories, the local and the global dir. | |
213 | Try both, local first. */ | |
214 | RtlInitUnicodeString (&ntdevdir, i ? L"\\GLOBAL??" : L"\\??"); | |
215 | ||
216 | /* Open the directory... */ | |
217 | InitializeObjectAttributes (&ntobj, &ntdevdir, OBJ_CASE_INSENSITIVE, | |
218 | NULL, NULL); | |
9cfc9511 | 219 | status = NtOpenDirectoryObject (&dir, DIRECTORY_QUERY, &ntobj); |
2dba45f4 CV |
220 | if (!NT_SUCCESS (status)) |
221 | break; | |
222 | ||
223 | /* ...and scan it. */ | |
224 | for (restart = TRUE, cont = 0; | |
9cfc9511 | 225 | NT_SUCCESS (NtQueryDirectoryObject (dir, odi, 4096, TRUE, |
2dba45f4 CV |
226 | restart, &cont, NULL)); |
227 | restart = FALSE) | |
228 | { | |
229 | /* For each entry check if it's a symbolic link. */ | |
230 | InitializeObjectAttributes (&ntobj, &odi->ObjectName, | |
231 | OBJ_CASE_INSENSITIVE, dir, NULL); | |
9cfc9511 | 232 | status = NtOpenSymbolicLinkObject (&lnk, SYMBOLIC_LINK_QUERY, &ntobj); |
2dba45f4 CV |
233 | if (!NT_SUCCESS (status)) |
234 | continue; | |
235 | tgtdev.Length = 0; | |
236 | tgtdev.MaximumLength = 512; | |
237 | /* If so, query it and compare the target of the symlink with the | |
238 | incoming device name. */ | |
9cfc9511 CV |
239 | status = NtQuerySymbolicLinkObject (lnk, &tgtdev, NULL); |
240 | NtClose (lnk); | |
2dba45f4 CV |
241 | if (!NT_SUCCESS (status)) |
242 | continue; | |
d2cc418e CV |
243 | if (tgtdev.Length /* There's actually a symlink pointing to an |
244 | empty string: \??\GLOBALROOT -> "" */ | |
245 | && RtlEqualUnicodePathPrefix (&ntdev, &tgtdev, TRUE)) | |
2dba45f4 CV |
246 | { |
247 | /* If the comparison succeeds, the name of the directory entry is | |
248 | a valid DOS device name, if prepended with "\\.\". Return that | |
249 | valid DOS path. */ | |
d2cc418e CV |
250 | wchar_t *trailing = NULL; |
251 | if (ntdev.Length > tgtdev.Length) | |
252 | trailing = ntdev.Buffer + tgtdev.Length / sizeof (WCHAR); | |
2dba45f4 | 253 | ULONG len = RtlUnicodeStringToAnsiSize (&odi->ObjectName); |
d2cc418e CV |
254 | if (trailing) |
255 | len += my_wcstombs (NULL, trailing, 0); | |
bf4b8020 | 256 | free (ret); |
2dba45f4 CV |
257 | ret = (char *) malloc (len + 4); |
258 | strcpy (ret, "\\\\.\\"); | |
259 | ans.Length = 0; | |
260 | ans.MaximumLength = len; | |
261 | ans.Buffer = ret + 4; | |
262 | RtlUnicodeStringToAnsiString (&ans, &odi->ObjectName, FALSE); | |
d2cc418e CV |
263 | if (trailing) |
264 | my_wcstombs (ans.Buffer + ans.Length, trailing, | |
265 | ans.MaximumLength - ans.Length); | |
266 | ans.Buffer[ans.MaximumLength - 1] = '\0'; | |
267 | got_one = true; | |
708bbfd0 CV |
268 | /* Special case for local disks: It's most feasible if the |
269 | DOS device name reflects the DOS drive, so we check for this | |
270 | explicitly and only return prematurely if so. */ | |
708bbfd0 CV |
271 | if (ntdev.Length < wcslen (HARDDISK_PREFIX) |
272 | || wcsncasecmp (ntdev.Buffer, HARDDISK_PREFIX, 8) != 0 | |
273 | || (odi->ObjectName.Length == 2 * sizeof (WCHAR) | |
274 | && odi->ObjectName.Buffer[1] == L':')) | |
275 | { | |
d2cc418e CV |
276 | if (trailing) |
277 | { | |
278 | /* If there's a trailing path, it's a perfectly valid | |
279 | DOS pathname without the \\.\ prefix. Unless it's | |
1b23b30b | 280 | longer than MAX_PATH - 1 in which case it needs |
d2cc418e | 281 | the \\?\ prefix. */ |
ac5d7dcd | 282 | if ((len = strlen (ret + 4)) >= MAX_PATH) |
d2cc418e CV |
283 | ret[2] = '?'; |
284 | else | |
285 | memmove (ret, ret + 4, strlen (ret + 4) + 1); | |
286 | } | |
9cfc9511 | 287 | NtClose (dir); |
708bbfd0 CV |
288 | goto out; |
289 | } | |
2dba45f4 CV |
290 | } |
291 | } | |
9cfc9511 | 292 | NtClose (dir); |
2dba45f4 CV |
293 | } |
294 | ||
295 | out: | |
296 | free (tgtdev.Buffer); | |
297 | free (ntdev.Buffer); | |
d2cc418e CV |
298 | if (!got_one) |
299 | { | |
300 | free (ret); | |
301 | ret = (char *) malloc (sizeof (GLOBALROOT_PREFIX) + strlen (path)); | |
302 | if (ret) | |
303 | stpcpy (stpcpy (ret, GLOBALROOT_PREFIX), path); | |
304 | } | |
2dba45f4 CV |
305 | return ret; |
306 | } | |
307 | ||
308 | static char * | |
309 | get_device_paths (char *path) | |
310 | { | |
311 | char *sbuf; | |
312 | char *ptr; | |
313 | int n = 1; | |
314 | ||
315 | ptr = path; | |
316 | while ((ptr = strchr (ptr, ';'))) | |
317 | { | |
318 | ptr++; | |
319 | n++; | |
320 | } | |
321 | ||
322 | char *paths[n]; | |
323 | DWORD acc = 0; | |
324 | int i; | |
325 | if (!n) | |
326 | return strdup (""); | |
327 | ||
328 | for (i = 0, ptr = path; ptr; i++) | |
329 | { | |
330 | char *next = ptr; | |
331 | ptr = strchr (ptr, ';'); | |
332 | if (ptr) | |
333 | *ptr++ = 0; | |
334 | paths[i] = get_device_name (next); | |
335 | acc += strlen (paths[i]) + 1; | |
336 | } | |
337 | ||
338 | sbuf = (char *) malloc (acc + 1); | |
339 | if (sbuf == NULL) | |
340 | { | |
341 | fprintf (stderr, "%s: out of memory\n", prog_name); | |
342 | exit (1); | |
343 | } | |
344 | ||
345 | sbuf[0] = '\0'; | |
346 | for (i = 0; i < n; i++) | |
347 | { | |
348 | strcat (strcat (sbuf, paths[i]), ";"); | |
349 | free (paths[i]); | |
350 | } | |
351 | ||
352 | strchr (sbuf, '\0')[-1] = '\0'; | |
353 | return sbuf; | |
354 | } | |
355 | ||
45b80bb4 CF |
356 | static char * |
357 | get_short_paths (char *path) | |
358 | { | |
26fb7ef5 CV |
359 | wchar_t *sbuf; |
360 | wchar_t *sptr; | |
45b80bb4 CF |
361 | char *next; |
362 | char *ptr = path; | |
363 | char *end = strrchr (path, 0); | |
364 | DWORD acc = 0; | |
365 | DWORD len; | |
366 | ||
367 | while (ptr != NULL) | |
45b80bb4 | 368 | { |
6a344609 CF |
369 | next = ptr; |
370 | ptr = strchr (ptr, ';'); | |
371 | if (ptr) | |
372 | *ptr++ = 0; | |
26fb7ef5 CV |
373 | wide_path wpath (next); |
374 | len = GetShortPathNameW (wpath, NULL, 0); | |
cc3ce0bb | 375 | if (!len) |
6a344609 | 376 | { |
92b499ac CV |
377 | fprintf (stderr, "%s: cannot create short name of %s\n", |
378 | prog_name, next); | |
6a344609 CF |
379 | exit (2); |
380 | } | |
381 | acc += len + 1; | |
45b80bb4 | 382 | } |
26fb7ef5 | 383 | sptr = sbuf = (wchar_t *) malloc ((acc + 1) * sizeof (wchar_t)); |
45b80bb4 | 384 | if (sbuf == NULL) |
45b80bb4 | 385 | { |
6a344609 CF |
386 | fprintf (stderr, "%s: out of memory\n", prog_name); |
387 | exit (1); | |
45b80bb4 | 388 | } |
6a344609 CF |
389 | ptr = path; |
390 | for (;;) | |
391 | { | |
26fb7ef5 CV |
392 | wide_path wpath (ptr); |
393 | len = GetShortPathNameW (wpath, sptr, acc); | |
cc3ce0bb | 394 | if (!len) |
6a344609 | 395 | { |
92b499ac CV |
396 | fprintf (stderr, "%s: cannot create short name of %s\n", |
397 | prog_name, ptr); | |
6a344609 CF |
398 | exit (2); |
399 | } | |
45b80bb4 | 400 | |
6a344609 | 401 | ptr = strrchr (ptr, 0); |
26fb7ef5 | 402 | sptr = wcsrchr (sptr, 0); |
6a344609 CF |
403 | if (ptr == end) |
404 | break; | |
26fb7ef5 | 405 | *sptr = L';'; |
6a344609 | 406 | ++ptr, ++sptr; |
5bb52de4 | 407 | acc -= len + 1; |
6a344609 | 408 | } |
0a23799a | 409 | len = my_wcstombs (NULL, sbuf, 0) + 1; |
26fb7ef5 CV |
410 | ptr = (char *) malloc (len); |
411 | if (ptr == NULL) | |
412 | { | |
413 | fprintf (stderr, "%s: out of memory\n", prog_name); | |
414 | exit (1); | |
415 | } | |
0a23799a | 416 | my_wcstombs (ptr, sbuf, len); |
584c6643 | 417 | free (sbuf); |
26fb7ef5 | 418 | return ptr; |
45b80bb4 CF |
419 | } |
420 | ||
421 | static char * | |
422 | get_short_name (const char *filename) | |
423 | { | |
26fb7ef5 CV |
424 | wchar_t buf[32768]; |
425 | char *sbuf; | |
426 | wide_path wpath (filename); | |
427 | DWORD len = GetShortPathNameW (wpath, buf, 32768); | |
cc3ce0bb | 428 | if (!len) |
6a344609 | 429 | { |
92b499ac CV |
430 | fprintf (stderr, "%s: cannot create short name of %s\n", |
431 | prog_name, filename); | |
6a344609 CF |
432 | exit (2); |
433 | } | |
0a23799a | 434 | len = my_wcstombs (NULL, buf, 0) + 1; |
26fb7ef5 | 435 | sbuf = (char *) malloc (len); |
45b80bb4 | 436 | if (sbuf == NULL) |
6a344609 CF |
437 | { |
438 | fprintf (stderr, "%s: out of memory\n", prog_name); | |
439 | exit (1); | |
440 | } | |
0a23799a | 441 | my_wcstombs (sbuf, buf, len); |
26fb7ef5 | 442 | return sbuf; |
5bb52de4 CV |
443 | } |
444 | ||
5bb52de4 | 445 | static char * |
cf157504 | 446 | get_long_name (const char *filename, DWORD& len) |
5bb52de4 | 447 | { |
26fb7ef5 CV |
448 | char *sbuf; |
449 | wchar_t buf[32768]; | |
26fb7ef5 | 450 | wide_path wpath (filename); |
acc31d1a | 451 | |
71148bfc CV |
452 | if (!GetLongPathNameW (wpath, buf, 32768)) |
453 | wcscpy (buf, wpath); | |
0a23799a | 454 | len = my_wcstombs (NULL, buf, 0); |
cf157504 CF |
455 | sbuf = (char *) malloc (len + 1); |
456 | if (!sbuf) | |
5bb52de4 CV |
457 | { |
458 | fprintf (stderr, "%s: out of memory\n", prog_name); | |
459 | exit (1); | |
460 | } | |
0a23799a | 461 | my_wcstombs (sbuf, buf, len + 1); |
26fb7ef5 | 462 | return sbuf; |
5bb52de4 CV |
463 | } |
464 | ||
465 | static char * | |
cf157504 | 466 | get_long_paths (char *path) |
5bb52de4 | 467 | { |
cf157504 CF |
468 | char *sbuf; |
469 | char *ptr; | |
470 | int n = 1; | |
471 | ||
472 | ptr = path; | |
473 | while ((ptr = strchr (ptr, ';'))) | |
6a344609 | 474 | { |
cf157504 CF |
475 | ptr++; |
476 | n++; | |
6a344609 | 477 | } |
cf157504 CF |
478 | |
479 | char *paths[n]; | |
480 | DWORD acc = 0; | |
481 | int i; | |
482 | if (!n) | |
483 | return strdup (""); | |
484 | ||
485 | for (i = 0, ptr = path; ptr; i++) | |
486 | { | |
487 | DWORD len; | |
488 | char *next = ptr; | |
489 | ptr = strchr (ptr, ';'); | |
490 | if (ptr) | |
491 | *ptr++ = 0; | |
492 | paths[i] = get_long_name (next, len); | |
493 | acc += len + 1; | |
494 | } | |
495 | ||
496 | sbuf = (char *) malloc (acc + 1); | |
5bb52de4 CV |
497 | if (sbuf == NULL) |
498 | { | |
499 | fprintf (stderr, "%s: out of memory\n", prog_name); | |
500 | exit (1); | |
501 | } | |
cf157504 CF |
502 | |
503 | sbuf[0] = '\0'; | |
504 | for (i = 0; i < n; i++) | |
505 | { | |
506 | strcat (strcat (sbuf, paths[i]), ";"); | |
507 | free (paths[i]); | |
508 | } | |
509 | ||
510 | strchr (sbuf, '\0')[-1] = '\0'; | |
511 | return sbuf; | |
5bb52de4 CV |
512 | } |
513 | ||
33bd2d12 CF |
514 | static void |
515 | convert_slashes (char* name) | |
516 | { | |
517 | while ((name = strchr (name, '\\')) != NULL) | |
518 | { | |
519 | if (*name == '\\') | |
520 | *name = '/'; | |
521 | name++; | |
522 | } | |
523 | } | |
524 | ||
ca902991 | 525 | static bool |
71148bfc | 526 | get_special_folder (PWCHAR wpath, int id) |
ca902991 | 527 | { |
ca902991 CV |
528 | LPITEMIDLIST pidl = 0; |
529 | if (SHGetSpecialFolderLocation (NULL, id, &pidl) != S_OK) | |
530 | return false; | |
175e39bb | 531 | if (!SHGetPathFromIDListW (pidl, wpath) || !wpath[0]) |
ca902991 CV |
532 | return false; |
533 | return true; | |
534 | } | |
535 | ||
5bb52de4 | 536 | static void |
fc200025 | 537 | do_sysfolders (char option) |
5bb52de4 | 538 | { |
175e39bb | 539 | WCHAR wbuf[MAX_PATH]; |
71148bfc | 540 | char buf[PATH_MAX]; |
79b1b77b | 541 | BOOL iswow64 = FALSE; |
cf157504 | 542 | |
71148bfc | 543 | wbuf[0] = L'\0'; |
5bb52de4 CV |
544 | switch (option) |
545 | { | |
546 | case 'D': | |
71148bfc | 547 | get_special_folder (wbuf, allusers_flag ? CSIDL_COMMON_DESKTOPDIRECTORY |
175e39bb | 548 | : CSIDL_DESKTOPDIRECTORY); |
5bb52de4 CV |
549 | break; |
550 | ||
551 | case 'P': | |
71148bfc | 552 | get_special_folder (wbuf, allusers_flag ? CSIDL_COMMON_PROGRAMS |
175e39bb | 553 | : CSIDL_PROGRAMS); |
ca902991 CV |
554 | break; |
555 | ||
556 | case 'O': | |
71148bfc | 557 | get_special_folder (wbuf, allusers_flag ? CSIDL_COMMON_DOCUMENTS |
175e39bb | 558 | : CSIDL_PERSONAL); |
ca902991 CV |
559 | break; |
560 | ||
561 | case 'F': | |
562 | { | |
563 | int val = -1, len = -1; | |
564 | if (!(sscanf (output_arg, "%i%n", &val, &len) == 1 | |
565 | && len == (int) strlen (output_arg) && val >= 0)) | |
566 | { | |
567 | fprintf (stderr, "%s: syntax error in special folder ID %s\n", | |
568 | prog_name, output_arg); | |
569 | exit (1); | |
570 | } | |
71148bfc | 571 | get_special_folder (wbuf, val); |
ca902991 | 572 | } |
5bb52de4 CV |
573 | break; |
574 | ||
575 | case 'H': | |
71148bfc CV |
576 | { |
577 | DWORD len = MAX_PATH; | |
578 | GetProfilesDirectoryW (wbuf, &len); | |
579 | } | |
5bb52de4 CV |
580 | break; |
581 | ||
582 | case 'S': | |
e70dbe77 | 583 | GetSystemDirectoryW (wbuf, MAX_PATH); |
79b1b77b CV |
584 | if (!windows_flag |
585 | && IsWow64Process (GetCurrentProcess (), &iswow64) && iswow64) | |
586 | { | |
587 | /* When calling NtQueryInformationFile(FileNameInformation) on WOW64, | |
588 | the returned path will point to SysWOW64. This breaks path | |
589 | redirection to the network related files under device/etc. This | |
590 | here is a bad hack to make sure that the conversion will convert | |
591 | the case *and* stick to System32. */ | |
592 | PWCHAR last_bs = wcsrchr (wbuf, L'\\'); | |
593 | if (last_bs) | |
594 | wcpcpy (last_bs + 1, L"Sysnative"); | |
595 | } | |
5bb52de4 CV |
596 | break; |
597 | ||
598 | case 'W': | |
71148bfc | 599 | GetSystemWindowsDirectoryW (wbuf, MAX_PATH); |
5bb52de4 CV |
600 | break; |
601 | ||
602 | default: | |
603 | usage (stderr, 1); | |
604 | } | |
605 | ||
71148bfc | 606 | if (!wbuf[0]) |
ca902991 | 607 | { |
92b499ac CV |
608 | fprintf (stderr, "%s: failed to retrieve special folder path\n", |
609 | prog_name); | |
e70dbe77 | 610 | return; |
ca902991 CV |
611 | } |
612 | else if (!windows_flag) | |
5bb52de4 | 613 | { |
e70dbe77 CV |
614 | /* The system folders are not necessarily case-correct. To allow |
615 | case-sensitivity, try to correct the case. Note that this only | |
616 | works for local filesystems. */ | |
617 | if (iswalpha (wbuf[0]) && wbuf[1] == L':' && wbuf[2] == L'\\') | |
618 | { | |
619 | OBJECT_ATTRIBUTES attr; | |
620 | NTSTATUS status; | |
621 | HANDLE h; | |
622 | IO_STATUS_BLOCK io; | |
623 | UNICODE_STRING upath; | |
624 | const ULONG size = sizeof (FILE_NAME_INFORMATION) | |
625 | + PATH_MAX * sizeof (WCHAR); | |
626 | PFILE_NAME_INFORMATION pfni = (PFILE_NAME_INFORMATION) alloca (size); | |
627 | ||
628 | /* Avoid another buffer, reuse pfni. */ | |
629 | wcpcpy (wcpcpy (pfni->FileName, L"\\??\\"), wbuf); | |
630 | RtlInitUnicodeString (&upath, pfni->FileName); | |
631 | InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, | |
632 | NULL, NULL); | |
633 | status = NtOpenFile (&h, READ_CONTROL, &attr, &io, | |
634 | FILE_SHARE_VALID_FLAGS, FILE_OPEN_REPARSE_POINT); | |
635 | if (NT_SUCCESS (status)) | |
636 | { | |
637 | status = NtQueryInformationFile (h, &io, pfni, size, | |
638 | FileNameInformation); | |
639 | if (NT_SUCCESS (status)) | |
640 | { | |
641 | pfni->FileName[pfni->FileNameLength / sizeof (WCHAR)] = L'\0'; | |
642 | wcscpy (wbuf + 2, pfni->FileName); | |
643 | } | |
644 | NtClose (h); | |
645 | } | |
646 | } | |
5aa8817e CV |
647 | if (cygwin_conv_path (CCP_WIN_W_TO_POSIX | cygdrive_flag, |
648 | wbuf, buf, PATH_MAX)) | |
71148bfc CV |
649 | fprintf (stderr, "%s: error converting \"%ls\" - %s\n", |
650 | prog_name, wbuf, strerror (errno)); | |
5bb52de4 CV |
651 | } |
652 | else | |
653 | { | |
654 | if (shortname_flag) | |
71148bfc CV |
655 | /* System paths are never longer than MAX_PATH. The buffer pointers |
656 | in a call to GetShortPathNameW may point to the same buffer. */ | |
657 | GetShortPathNameW (wbuf, wbuf, MAX_PATH); | |
658 | my_wcstombs (buf, wbuf, MAX_PATH); | |
33bd2d12 | 659 | if (mixed_flag) |
1b526b48 | 660 | convert_slashes (buf); |
5bb52de4 CV |
661 | } |
662 | printf ("%s\n", buf); | |
1fd5e000 CF |
663 | } |
664 | ||
f135dd3e CF |
665 | static void |
666 | report_mode (char *filename) | |
667 | { | |
668 | switch (cygwin_internal (CW_GET_BINMODE, filename)) | |
669 | { | |
670 | case O_BINARY: | |
671 | printf ("%s: binary\n", filename); | |
672 | break; | |
673 | case O_TEXT: | |
674 | printf ("%s: text\n", filename); | |
675 | break; | |
676 | default: | |
92b499ac CV |
677 | fprintf (stderr, "%s: file '%s' - %s\n", prog_name, |
678 | filename, strerror (errno)); | |
f135dd3e CF |
679 | break; |
680 | } | |
681 | } | |
682 | ||
138d4f51 | 683 | static void |
fc200025 | 684 | do_pathconv (char *filename) |
138d4f51 | 685 | { |
bf4b8020 CV |
686 | char *buf = NULL, *tmp; |
687 | wchar_t *buf2 = NULL; | |
71148bfc | 688 | DWORD len = 32768; |
2b2b42cf | 689 | ssize_t err; |
80206d7f | 690 | bool print_tmp = false; |
2b2b42cf | 691 | cygwin_conv_path_t conv_func = |
71148bfc | 692 | (unix_flag ? CCP_WIN_W_TO_POSIX : CCP_POSIX_TO_WIN_W) |
5aa8817e | 693 | | absolute_flag | cygdrive_flag; |
138d4f51 | 694 | |
71148bfc | 695 | if (!filename || !filename[0]) |
c02e32c9 | 696 | { |
71148bfc CV |
697 | if (ignore_flag) |
698 | return; | |
699 | fprintf (stderr, "%s: can't convert empty path\n", prog_name); | |
700 | exit (1); | |
c02e32c9 | 701 | } |
138d4f51 CF |
702 | |
703 | buf = (char *) malloc (len); | |
71148bfc | 704 | if (!unix_flag) |
26fb7ef5 | 705 | buf2 = (wchar_t *) malloc (len * sizeof (wchar_t)); |
138d4f51 CF |
706 | if (buf == NULL) |
707 | { | |
708 | fprintf (stderr, "%s: out of memory\n", prog_name); | |
709 | exit (1); | |
710 | } | |
711 | ||
712 | if (path_flag) | |
713 | { | |
71148bfc CV |
714 | if (unix_flag) |
715 | { | |
733b554b | 716 | wide_path wpath (filename, false); |
71148bfc CV |
717 | err = cygwin_conv_path_list (conv_func, wpath, buf, len); |
718 | } | |
719 | else | |
720 | err = cygwin_conv_path_list (conv_func, filename, buf2, len); | |
721 | if (err) | |
722 | { | |
723 | fprintf (stderr, "%s: error converting \"%s\" - %s\n", | |
724 | prog_name, filename, strerror (errno)); | |
725 | exit (1); | |
726 | } | |
2b2b42cf | 727 | if (!unix_flag) |
6a344609 | 728 | { |
71148bfc | 729 | my_wcstombs (buf, buf2, 32768); |
bf4b8020 CV |
730 | buf = get_device_paths (tmp = buf); |
731 | free (tmp); | |
6a344609 | 732 | if (shortname_flag) |
bf4b8020 CV |
733 | { |
734 | buf = get_short_paths (tmp = buf); | |
735 | free (tmp); | |
736 | } | |
5bb52de4 | 737 | if (longname_flag) |
bf4b8020 CV |
738 | { |
739 | buf = get_long_paths (tmp = buf); | |
740 | free (tmp); | |
741 | } | |
2bd6505b | 742 | if (mixed_flag) |
1b526b48 | 743 | convert_slashes (buf); |
6a344609 | 744 | } |
138d4f51 CF |
745 | } |
746 | else | |
747 | { | |
71148bfc CV |
748 | if (unix_flag) |
749 | { | |
750 | wide_path wpath (filename); | |
751 | err = cygwin_conv_path (conv_func, wpath, (void *) buf, len); | |
752 | } | |
753 | else | |
754 | err = cygwin_conv_path (conv_func, filename, (void *) buf2, len); | |
7c03f799 | 755 | if (err) |
6a344609 | 756 | { |
7c03f799 CF |
757 | fprintf (stderr, "%s: error converting \"%s\" - %s\n", |
758 | prog_name, filename, strerror (errno)); | |
6a344609 CF |
759 | exit (1); |
760 | } | |
5bb52de4 CV |
761 | if (!unix_flag) |
762 | { | |
0a23799a | 763 | my_wcstombs (buf, buf2, 32768); |
bf4b8020 CV |
764 | buf = get_device_name (tmp = buf); |
765 | free (tmp); | |
7ca68b7e | 766 | if (shortname_flag) |
bf4b8020 CV |
767 | { |
768 | buf = get_short_name (tmp = buf); | |
769 | free (tmp); | |
770 | } | |
7ca68b7e | 771 | if (longname_flag) |
bf4b8020 CV |
772 | { |
773 | buf = get_long_name (tmp = buf, len); | |
774 | free (tmp); | |
775 | } | |
bf4b8020 | 776 | tmp = buf; |
8c3a79bb | 777 | if (strncmp (buf, "\\\\?\\", 4) == 0) |
26fb7ef5 | 778 | { |
d2cc418e CV |
779 | len = 0; |
780 | if (buf[5] == ':') | |
781 | len = 4; | |
782 | else if (!strncmp (buf + 4, "UNC\\", 4)) | |
8c3a79bb | 783 | len = 6; |
d2cc418e | 784 | if (len && strlen (buf) < MAX_PATH + len) |
8c3a79bb | 785 | { |
03ac74c1 | 786 | tmp += len; |
8c3a79bb | 787 | if (len == 6) |
03ac74c1 | 788 | *tmp = '\\'; |
80206d7f | 789 | print_tmp = true; |
8c3a79bb | 790 | } |
26fb7ef5 | 791 | } |
8c3a79bb | 792 | if (mixed_flag) |
03ac74c1 | 793 | convert_slashes (tmp); |
5bb52de4 | 794 | } |
138d4f51 CF |
795 | } |
796 | ||
80206d7f | 797 | puts (print_tmp ? tmp : buf); |
bf4b8020 CV |
798 | if (buf2) |
799 | free (buf2); | |
800 | if (buf) | |
03ac74c1 | 801 | free (buf); |
138d4f51 CF |
802 | } |
803 | ||
6a344609 CF |
804 | static void |
805 | print_version () | |
806 | { | |
92b499ac CV |
807 | printf ("cygpath (cygwin) %d.%d.%d\n" |
808 | "Path Conversion Utility\n" | |
6e623e93 | 809 | "Copyright (C) 1998 - %s Cygwin Authors\n" |
92b499ac CV |
810 | "This is free software; see the source for copying conditions. There is NO\n" |
811 | "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", | |
812 | CYGWIN_VERSION_DLL_MAJOR / 1000, | |
813 | CYGWIN_VERSION_DLL_MAJOR % 1000, | |
814 | CYGWIN_VERSION_DLL_MINOR, | |
815 | strrchr (__DATE__, ' ') + 1); | |
6a344609 CF |
816 | } |
817 | ||
fc200025 CV |
818 | static int |
819 | do_options (int argc, char **argv, int from_file) | |
1fd5e000 | 820 | { |
6a344609 | 821 | int c, o = 0; |
1fd5e000 | 822 | path_flag = 0; |
fc200025 | 823 | unix_flag = 0; |
1fd5e000 | 824 | windows_flag = 0; |
45b80bb4 | 825 | shortname_flag = 0; |
5bb52de4 | 826 | longname_flag = 0; |
2bd6505b | 827 | mixed_flag = 0; |
45b80bb4 | 828 | ignore_flag = 0; |
3cdacffc CV |
829 | allusers_flag = 0; |
830 | output_flag = 0; | |
f135dd3e | 831 | mode_flag = 0; |
0a23799a | 832 | codepage = 0; |
5aa8817e CV |
833 | cygdrive_flag = 0; |
834 | absolute_flag = CCP_RELATIVE; | |
fc200025 CV |
835 | if (!from_file) |
836 | options_from_file_flag = 0; | |
837 | optind = 0; | |
9b566b96 | 838 | while ((c = getopt_long (argc, argv, options, |
2bd6505b | 839 | long_options, (int *) NULL)) != EOF) |
1fd5e000 CF |
840 | { |
841 | switch (c) | |
842 | { | |
418068d4 | 843 | case 'a': |
5aa8817e | 844 | absolute_flag = CCP_ABSOLUTE; |
418068d4 CF |
845 | break; |
846 | ||
847 | case 'c': | |
fc200025 CV |
848 | if (!optarg) |
849 | usage (stderr, 1); | |
418068d4 CF |
850 | CloseHandle ((HANDLE) strtoul (optarg, NULL, 16)); |
851 | break; | |
852 | ||
1050e57c | 853 | case 'd': |
1050e57c CF |
854 | windows_flag = 1; |
855 | shortname_flag = 1; | |
856 | break; | |
857 | ||
138d4f51 | 858 | case 'f': |
fc200025 CV |
859 | if (from_file || !optarg) |
860 | usage (stderr, 1); | |
138d4f51 CF |
861 | file_arg = optarg; |
862 | break; | |
863 | ||
f135dd3e CF |
864 | case 'M': |
865 | mode_flag = 1; | |
866 | break; | |
867 | ||
418068d4 | 868 | case 'o': |
fc200025 CV |
869 | if (from_file) |
870 | usage (stderr, 1); | |
418068d4 CF |
871 | options_from_file_flag = 1; |
872 | break; | |
873 | ||
1fd5e000 CF |
874 | case 'p': |
875 | path_flag = 1; | |
876 | break; | |
877 | ||
878 | case 'u': | |
1fd5e000 CF |
879 | unix_flag = 1; |
880 | break; | |
881 | ||
882 | case 'w': | |
1fd5e000 CF |
883 | windows_flag = 1; |
884 | break; | |
885 | ||
1050e57c | 886 | case 'm': |
1050e57c CF |
887 | windows_flag = 1; |
888 | mixed_flag = 1; | |
889 | break; | |
890 | ||
5bb52de4 | 891 | case 'l': |
5bb52de4 CV |
892 | longname_flag = 1; |
893 | break; | |
894 | ||
45b80bb4 | 895 | case 's': |
45b80bb4 CF |
896 | shortname_flag = 1; |
897 | break; | |
898 | ||
fc200025 CV |
899 | case 't': |
900 | if (!optarg) | |
2bd6505b CF |
901 | usage (stderr, 1); |
902 | ||
1050e57c CF |
903 | format_type_arg = (*optarg == '=') ? (optarg + 1) : (optarg); |
904 | if (strcasecmp (format_type_arg, "dos") == 0) | |
cf157504 | 905 | { |
fc200025 CV |
906 | windows_flag = 1; |
907 | shortname_flag = 1; | |
cf157504 | 908 | } |
fc200025 | 909 | else if (!strcasecmp (format_type_arg, "mixed")) |
cf157504 | 910 | { |
fc200025 CV |
911 | windows_flag = 1; |
912 | mixed_flag = 1; | |
cf157504 | 913 | } |
fc200025 | 914 | else if (!strcasecmp (format_type_arg, "unix")) |
1050e57c | 915 | unix_flag = 1; |
fc200025 | 916 | else if (!strcasecmp (format_type_arg, "windows")) |
cf157504 | 917 | windows_flag = 1; |
2bd6505b CF |
918 | else |
919 | usage (stderr, 1); | |
920 | break; | |
921 | ||
3cdacffc CV |
922 | case 'A': |
923 | allusers_flag = 1; | |
924 | break; | |
925 | ||
5aa8817e CV |
926 | case 'U': |
927 | cygdrive_flag = CCP_PROC_CYGDRIVE; | |
928 | break; | |
929 | ||
0a23799a CV |
930 | case 'C': |
931 | if (!optarg) | |
932 | usage (stderr, 1); | |
933 | if (!strcasecmp (optarg, "ANSI")) | |
934 | codepage = GetACP (); | |
935 | else if (!strcasecmp (optarg, "OEM")) | |
936 | codepage = GetOEMCP (); | |
937 | else if (!strcasecmp (optarg, "UTF8") | |
938 | || !strcasecmp (optarg, "UTF-8")) | |
939 | codepage = CP_UTF8; | |
940 | else | |
941 | { | |
942 | char *c; | |
943 | codepage = (UINT) strtoul (optarg, &c, 10); | |
944 | if (*c) | |
945 | usage (stderr, 1); | |
946 | } | |
947 | break; | |
948 | ||
3cdacffc | 949 | case 'D': |
e355de81 | 950 | case 'H': |
ca902991 | 951 | case 'O': |
3cdacffc | 952 | case 'P': |
f00c1d2c | 953 | case 'S': |
3cdacffc | 954 | case 'W': |
fc200025 | 955 | ++output_flag; |
e355de81 | 956 | o = c; |
3cdacffc | 957 | break; |
f00c1d2c | 958 | |
ca902991 | 959 | case 'F': |
fc200025 | 960 | if (!optarg) |
ca902991 | 961 | usage (stderr, 1); |
fc200025 | 962 | ++output_flag; |
ca902991 CV |
963 | output_arg = optarg; |
964 | o = c; | |
965 | break; | |
966 | ||
45b80bb4 CF |
967 | case 'i': |
968 | ignore_flag = 1; | |
969 | break; | |
970 | ||
1fd5e000 CF |
971 | case 'h': |
972 | usage (stdout, 0); | |
1fd5e000 | 973 | |
92b499ac | 974 | case 'V': |
6a344609 | 975 | print_version (); |
1fd5e000 CF |
976 | exit (0); |
977 | ||
978 | default: | |
92b499ac CV |
979 | fprintf (stderr, "Try `%s --help' for more information.\n", |
980 | prog_name); | |
981 | exit (1); | |
1fd5e000 CF |
982 | } |
983 | } | |
984 | ||
fc200025 | 985 | /* If none of the "important" flags are set, -u is default. */ |
df1841c3 CV |
986 | if (!unix_flag && !windows_flag && !mode_flag |
987 | && (!from_file ? !options_from_file_flag : 1)) | |
fc200025 CV |
988 | unix_flag = 1; |
989 | ||
990 | /* Only one of ... */ | |
df1841c3 | 991 | if (unix_flag + windows_flag + mode_flag > 1 |
fc200025 | 992 | + (!from_file ? options_from_file_flag : 0)) |
418068d4 CF |
993 | usage (stderr, 1); |
994 | ||
fc200025 CV |
995 | /* options_from_file_flag requires a file. */ |
996 | if (!from_file && options_from_file_flag && !file_arg) | |
1050e57c CF |
997 | usage (stderr, 1); |
998 | ||
fc200025 CV |
999 | /* longname and shortname don't play well together. */ |
1000 | if (longname_flag && shortname_flag) | |
1050e57c CF |
1001 | usage (stderr, 1); |
1002 | ||
fc200025 CV |
1003 | /* longname and shortname only make sense with Windows paths. */ |
1004 | if ((longname_flag || shortname_flag) && !windows_flag) | |
1fd5e000 CF |
1005 | usage (stderr, 1); |
1006 | ||
fc200025 CV |
1007 | return o; |
1008 | } | |
1009 | ||
1010 | static void | |
1011 | action (int argc, char **argv, int opt) | |
1012 | { | |
1013 | if (output_flag) | |
1fd5e000 | 1014 | { |
fc200025 CV |
1015 | if (argv[optind]) |
1016 | usage (stderr, 1); | |
5bb52de4 | 1017 | |
fc200025 CV |
1018 | do_sysfolders (opt); |
1019 | } | |
1020 | else | |
1021 | { | |
0a5ea947 | 1022 | if (optind > argc - 1) |
138d4f51 | 1023 | usage (stderr, 1); |
1fd5e000 | 1024 | |
f135dd3e CF |
1025 | for (int i = optind; argv[i]; i++) |
1026 | if (mode_flag) | |
1027 | report_mode (argv[i]); | |
1028 | else | |
fc200025 | 1029 | do_pathconv (argv[i]); |
138d4f51 | 1030 | } |
fc200025 CV |
1031 | } |
1032 | ||
1033 | int | |
1034 | main (int argc, char **argv) | |
1035 | { | |
1036 | int o; | |
1037 | ||
73535010 | 1038 | setlocale (LC_CTYPE, ""); |
92b499ac | 1039 | prog_name = program_invocation_short_name; |
fc200025 CV |
1040 | |
1041 | o = do_options (argc, argv, 0); | |
1042 | ||
1043 | if (!file_arg) | |
1044 | action (argc, argv, o); | |
1fd5e000 CF |
1045 | else |
1046 | { | |
138d4f51 CF |
1047 | FILE *fp; |
1048 | char buf[PATH_MAX * 2 + 1]; | |
1fd5e000 | 1049 | |
138d4f51 CF |
1050 | if (argv[optind]) |
1051 | usage (stderr, 1); | |
1fd5e000 | 1052 | |
fc200025 CV |
1053 | if (strcmp (file_arg, "-")) |
1054 | { | |
1055 | if (!(fp = fopen (file_arg, "rt"))) | |
1056 | { | |
1057 | perror ("cygpath"); | |
1058 | exit (1); | |
1059 | } | |
1060 | } | |
1fd5e000 | 1061 | else |
138d4f51 CF |
1062 | { |
1063 | fp = stdin; | |
1064 | setmode (0, O_TEXT); | |
1065 | } | |
418068d4 | 1066 | setbuf (stdout, NULL); |
fc200025 CV |
1067 | |
1068 | while (fgets (buf, sizeof (buf), fp)) | |
138d4f51 | 1069 | { |
6004370b CV |
1070 | int ac = 0; |
1071 | char *av[4] = { NULL, NULL, NULL, NULL }; | |
fc200025 | 1072 | char *p = strchr (buf, '\n'); |
138d4f51 CF |
1073 | if (p) |
1074 | *p = '\0'; | |
6004370b CV |
1075 | p = buf; |
1076 | av[ac++] = prog_name; | |
1077 | av[ac++] = p; | |
1078 | if (options_from_file_flag && *p == '-') | |
fc200025 | 1079 | { |
6004370b CV |
1080 | while (*p && !isspace (*p)) |
1081 | ++p; | |
1082 | if (*p) | |
1083 | { | |
1084 | *p++ = '\0'; | |
1085 | while (*p && isspace (*p)) | |
1086 | ++p; | |
1087 | av[ac++] = p; | |
1088 | } | |
1089 | o = do_options (ac, av, 1); | |
fc200025 | 1090 | } |
6004370b | 1091 | else |
418068d4 | 1092 | { |
6004370b CV |
1093 | output_flag = 0; |
1094 | optind = 1; | |
418068d4 | 1095 | } |
fc200025 | 1096 | action (ac, av, o); |
138d4f51 CF |
1097 | } |
1098 | } | |
1fd5e000 CF |
1099 | exit (0); |
1100 | } |