winedbg: Complete the Thumb disassembler.
[wine] / programs / winepath / winepath.c
1 /*
2  * Translate between Windows and Unix paths formats
3  *
4  * Copyright 2002 Mike Wetherell
5  * Copyright 2005 Dmitry Timoshkov
6  * Copyright 2005 Francois Gouget
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #define WIN32_LEAN_AND_MEAN
24
25 #include "config.h"
26
27 #include <windows.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30
31 #include "wine/debug.h"
32
33 enum {
34     SHORTFORMAT   = 1,
35     LONGFORMAT    = 2,
36     UNIXFORMAT    = 4,
37     WINDOWSFORMAT = 8,
38     PRINT0        = 16,
39 };
40
41 static const char progname[] = "winepath";
42
43 /*
44  * handle an option
45  */
46 static int option(int shortopt, const WCHAR *longopt)
47 {
48     static const char helpmsg[] =
49     "Convert PATH(s) to Unix or Windows long or short paths.\n"
50     "\n"
51     "  -u, --unix    converts a Windows path to a Unix path\n"
52     "  -w, --windows converts a Unix path to a long Windows path\n"
53     "  -l, --long    converts the short Windows path of an existing file or\n"
54     "                directory to the long format\n"
55     "  -s, --short   converts the long Windows path of an existing file or\n"
56     "                directory to the short format\n"
57     "  -0            separate output with \\0 character, instead of a newline\n"
58     "  -h, --help    output this help message and exit\n"
59     "  -v, --version output version information and exit\n"
60     "\n"
61     "If more than one option is given then the input paths are output in\n"
62     "all formats specified, in the order long, short, Unix, Windows.\n"
63     "If no option is given the default is Unix format.\n";
64
65     switch (shortopt) {
66         case 'h':
67             printf("Usage: %s [OPTION] [PATH]...\n", progname);
68             printf(helpmsg);
69             exit(0);
70         case 'v':
71             printf("%s version " PACKAGE_VERSION "\n", progname);
72             exit(0);
73         case 'l':
74             return LONGFORMAT;
75         case 's':
76             return SHORTFORMAT;
77         case 'u':
78             return UNIXFORMAT;
79         case 'w':
80             return WINDOWSFORMAT;
81         case '0':
82             return PRINT0;
83     }
84
85     fprintf(stderr, "%s: invalid option ", progname);
86     if (longopt)
87         fprintf(stderr, "%s\n", wine_dbgstr_w(longopt));
88     else
89         fprintf(stderr, "'-%c'\n", shortopt);
90     fprintf(stderr, "Try '%s --help' for help\n", progname);
91     exit(2);
92 }
93
94 /*
95  * Parse command line options
96  */
97 static int parse_options(WCHAR *argv[])
98 {
99     static const WCHAR longW[] = { 'l','o','n','g',0 };
100     static const WCHAR shortW[] = { 's','h','o','r','t',0 };
101     static const WCHAR unixW[] = { 'u','n','i','x',0 };
102     static const WCHAR windowsW[] = { 'w','i','n','d','o','w','s',0 };
103     static const WCHAR helpW[] = { 'h','e','l','p',0 };
104     static const WCHAR versionW[] = { 'v','e','r','s','i','o','n',0 };
105     static const WCHAR nullW[] = { 0 };
106     static const WCHAR *longopts[] = { longW, shortW, unixW, windowsW, helpW, versionW, nullW };
107     int outputformats = 0;
108     int done = 0;
109     int i, j;
110
111     for (i = 1; argv[i] && !done; )
112     {
113         if (argv[i][0] != '-') {
114             /* not an option */
115             i++;
116             continue;
117         }
118
119         if (argv[i][1] == '-') {
120             if (argv[i][2] == 0) {
121                 /* '--' end of options */
122                 done = 1;
123             } else {
124                 /* long option */
125                 for (j = 0; longopts[j][0]; j++)
126                     if (!lstrcmpiW(argv[i]+2, longopts[j]))
127                         break;
128                 outputformats |= option(longopts[j][0], argv[i]);
129             }
130         } else {
131             /* short options */
132             for (j = 1; argv[i][j]; j++)
133                 outputformats |= option(argv[i][j], NULL);
134         }
135
136         /* remove option */
137         for (j = i + 1; argv[j - 1]; j++)
138             argv[j - 1] = argv[j];
139     }
140
141     return outputformats;
142 }
143
144 /*
145  * Main function
146  */
147 int wmain(int argc, WCHAR *argv[])
148 {
149     LPSTR (*CDECL wine_get_unix_file_name_ptr)(LPCWSTR) = NULL;
150     LPWSTR (*CDECL wine_get_dos_file_name_ptr)(LPCSTR) = NULL;
151     WCHAR dos_pathW[MAX_PATH];
152     char path[MAX_PATH];
153     int outputformats;
154     int i;
155     int separator;
156
157     outputformats = parse_options(argv);
158
159     if (outputformats & PRINT0)
160     {
161         separator = '\0';
162         outputformats ^= PRINT0;
163     }
164     else
165         separator = '\n';
166
167     if (outputformats == 0)
168         outputformats = UNIXFORMAT;
169
170     if (outputformats & UNIXFORMAT) {
171         wine_get_unix_file_name_ptr = (void*)
172             GetProcAddress(GetModuleHandleA("KERNEL32"),
173                            "wine_get_unix_file_name");
174         if (wine_get_unix_file_name_ptr == NULL) {
175             fprintf(stderr, "%s: cannot get the address of "
176                             "'wine_get_unix_file_name'\n", progname);
177             exit(3);
178         }
179     }
180
181     if (outputformats & WINDOWSFORMAT) {
182         wine_get_dos_file_name_ptr = (void*)
183             GetProcAddress(GetModuleHandleA("KERNEL32"),
184                            "wine_get_dos_file_name");
185         if (wine_get_dos_file_name_ptr == NULL) {
186             fprintf(stderr, "%s: cannot get the address of "
187                             "'wine_get_dos_file_name'\n", progname);
188             exit(3);
189         }
190     }
191
192     for (i = 1; argv[i]; i++)
193     {
194         *path='\0';
195         if (outputformats & LONGFORMAT) {
196             if (GetLongPathNameW(argv[i], dos_pathW, MAX_PATH))
197                 WideCharToMultiByte(CP_UNIXCP, 0, dos_pathW, -1, path, MAX_PATH, NULL, NULL);
198             printf("%s%c", path, separator);
199         }
200         if (outputformats & SHORTFORMAT) {
201             if (GetShortPathNameW(argv[i], dos_pathW, MAX_PATH))
202                 WideCharToMultiByte(CP_UNIXCP, 0, dos_pathW, -1, path, MAX_PATH, NULL, NULL);
203             printf("%s%c", path, separator);
204         }
205         if (outputformats & UNIXFORMAT) {
206             WCHAR *ntpath, *tail;
207             int ntpathlen=lstrlenW(argv[i]);
208             ntpath=HeapAlloc(GetProcessHeap(), 0, sizeof(*ntpath)*(ntpathlen+1));
209             lstrcpyW(ntpath, argv[i]);
210             tail=NULL;
211             while (1)
212             {
213                 char *unix_name;
214                 WCHAR *slash, *c;
215
216                 unix_name = wine_get_unix_file_name_ptr(ntpath);
217                 if (unix_name)
218                 {
219                     if (tail)
220                     {
221                         WideCharToMultiByte(CP_UNIXCP, 0, tail+1, -1, path, MAX_PATH, NULL, NULL);
222                         printf("%s/%s%c", unix_name, path, separator);
223                     }
224                     else
225                     {
226                         printf("%s%c", unix_name, separator);
227                     }
228                     HeapFree( GetProcessHeap(), 0, unix_name );
229                     break;
230                 }
231
232                 slash=(tail ? tail : ntpath+ntpathlen);
233                 while (slash != ntpath && *slash != '/' && *slash != '\\')
234                     slash--;
235                 if (slash == ntpath)
236                 {
237                     /* This is a complete path conversion failure.
238                      * It would typically happen if ntpath == "".
239                      */
240                     printf("%c", separator);
241                     break;
242                 }
243                 c=slash+1;
244                 while (*c != '\0' && *c != '*' && *c != '?' &&
245                        *c != '<' && *c != '>' && *c != '|' && *c != '"')
246                     c++;
247                 if (*c != '\0')
248                 {
249                     /* If this is not a valid NT path to start with,
250                      * then obviously we cannot convert it.
251                      */
252                     printf("%c", separator);
253                     break;
254                 }
255                 if (tail)
256                     *tail='/';
257                 tail=slash;
258                 *tail='\0';
259             }
260             HeapFree(GetProcessHeap(), 0, ntpath);
261         }
262         if (outputformats & WINDOWSFORMAT) {
263             WCHAR* windows_name;
264             char* unix_name;
265             DWORD size;
266
267             size=WideCharToMultiByte(CP_UNIXCP, 0, argv[i], -1, NULL, 0, NULL, NULL);
268             unix_name=HeapAlloc(GetProcessHeap(), 0, size);
269             WideCharToMultiByte(CP_UNIXCP, 0, argv[i], -1, unix_name, size, NULL, NULL);
270
271             if ((windows_name = wine_get_dos_file_name_ptr(unix_name)))
272             {
273                 WideCharToMultiByte(CP_UNIXCP, 0, windows_name, -1, path, MAX_PATH, NULL, NULL);
274                 printf("%s%c", path, separator);
275                 HeapFree( GetProcessHeap(), 0, windows_name );
276             }
277             else printf("%c", separator);
278             HeapFree( GetProcessHeap(), 0, unix_name );
279         }
280     }
281
282     exit(0);
283 }