winhelp: Added ability to locate information within a page (and to store it inside...
[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 };
39
40 static const char progname[] = "winepath";
41
42 /*
43  * handle an option
44  */
45 static int option(int shortopt, const WCHAR *longopt)
46 {
47     static const char helpmsg[] =
48     "Convert PATH(s) to Unix or Windows long or short paths.\n"
49     "\n"
50     "  -u, --unix    converts a Windows path to a Unix path\n"
51     "  -w, --windows converts a Unix path to a long Windows path\n"
52     "  -l, --long    converts the short Windows path of an existing file or\n"
53     "                directory to the long format\n"
54     "  -s, --short   converts the long Windows path of an existing file or\n"
55     "                directory to the short format\n"
56     "  -h, --help    output this help message and exit\n"
57     "  -v, --version output version information and exit\n"
58     "\n"
59     "If more than one option is given then the input paths are output in\n"
60     "all formats specified, in the order long, short, Unix, Windows.\n"
61     "If no option is given the default is Unix format.\n";
62
63     switch (shortopt) {
64         case 'h':
65             printf("Usage: %s [OPTION] [PATH]...\n", progname);
66             printf(helpmsg);
67             exit(0);
68         case 'v':
69             printf("%s version " PACKAGE_VERSION "\n", progname);
70             exit(0);
71         case 'l':
72             return LONGFORMAT;
73         case 's':
74             return SHORTFORMAT;
75         case 'u':
76             return UNIXFORMAT;
77         case 'w':
78             return WINDOWSFORMAT;
79     }
80
81     fprintf(stderr, "%s: invalid option ", progname);
82     if (longopt)
83         fprintf(stderr, "%s\n", wine_dbgstr_w(longopt));
84     else
85         fprintf(stderr, "'-%c'\n", shortopt);
86     fprintf(stderr, "Try '%s --help' for help\n", progname);
87     exit(2);
88 }
89
90 /*
91  * Parse command line options
92  */
93 static int parse_options(const WCHAR *argv[])
94 {
95     static const WCHAR longW[] = { 'l','o','n','g',0 };
96     static const WCHAR shortW[] = { 's','h','o','r','t',0 };
97     static const WCHAR unixW[] = { 'u','n','i','x',0 };
98     static const WCHAR windowsW[] = { 'w','i','n','d','o','w','s',0 };
99     static const WCHAR helpW[] = { 'h','e','l','p',0 };
100     static const WCHAR versionW[] = { 'v','e','r','s','i','o','n',0 };
101     static const WCHAR nullW[] = { 0 };
102     static const WCHAR *longopts[] = { longW, shortW, unixW, windowsW, helpW, versionW, nullW };
103     int outputformats = 0;
104     int done = 0;
105     int i, j;
106
107     for (i = 1; argv[i] && !done; )
108     {
109         if (argv[i][0] != '-') {
110             /* not an option */
111             i++;
112             continue;
113         }
114
115         if (argv[i][1] == '-') {
116             if (argv[i][2] == 0) {
117                 /* '--' end of options */
118                 done = 1;
119             } else {
120                 /* long option */
121                 for (j = 0; longopts[j][0]; j++)
122                     if (!lstrcmpiW(argv[i]+2, longopts[j]))
123                         break;
124                 outputformats |= option(longopts[j][0], argv[i]);
125             }
126         } else {
127             /* short options */
128             for (j = 1; argv[i][j]; j++)
129                 outputformats |= option(argv[i][j], NULL);
130         }
131
132         /* remove option */
133         for (j = i + 1; argv[j - 1]; j++)
134             argv[j - 1] = argv[j];
135     }
136
137     return outputformats;
138 }
139
140 /*
141  * Main function
142  */
143 int wmain(int argc, const WCHAR *argv[])
144 {
145     LPSTR (*wine_get_unix_file_name_ptr)(LPCWSTR) = NULL;
146     LPWSTR (*wine_get_dos_file_name_ptr)(LPCSTR) = NULL;
147     WCHAR dos_pathW[MAX_PATH];
148     char path[MAX_PATH];
149     int outputformats;
150     int i;
151
152     outputformats = parse_options(argv);
153     if (outputformats == 0)
154         outputformats = UNIXFORMAT;
155
156     if (outputformats & UNIXFORMAT) {
157         wine_get_unix_file_name_ptr = (void*)
158             GetProcAddress(GetModuleHandle("KERNEL32"),
159                            "wine_get_unix_file_name");
160         if (wine_get_unix_file_name_ptr == NULL) {
161             fprintf(stderr, "%s: cannot get the address of "
162                             "'wine_get_unix_file_name'\n", progname);
163             exit(3);
164         }
165     }
166
167     if (outputformats & WINDOWSFORMAT) {
168         wine_get_dos_file_name_ptr = (void*)
169             GetProcAddress(GetModuleHandle("KERNEL32"),
170                            "wine_get_dos_file_name");
171         if (wine_get_dos_file_name_ptr == NULL) {
172             fprintf(stderr, "%s: cannot get the address of "
173                             "'wine_get_dos_file_name'\n", progname);
174             exit(3);
175         }
176     }
177
178     for (i = 1; argv[i]; i++)
179     {
180         *path='\0';
181         if (outputformats & LONGFORMAT) {
182             if (GetLongPathNameW(argv[i], dos_pathW, MAX_PATH))
183                 WideCharToMultiByte(CP_UNIXCP, 0, dos_pathW, -1, path, MAX_PATH, NULL, NULL);
184             printf("%s\n", path);
185         }
186         if (outputformats & SHORTFORMAT) {
187             if (GetShortPathNameW(argv[i], dos_pathW, MAX_PATH))
188                 WideCharToMultiByte(CP_UNIXCP, 0, dos_pathW, -1, path, MAX_PATH, NULL, NULL);
189             printf("%s\n", path);
190         }
191         if (outputformats & UNIXFORMAT) {
192             WCHAR *ntpath, *tail;
193             int ntpathlen=lstrlenW(argv[i]);
194             ntpath=HeapAlloc(GetProcessHeap(), 0, sizeof(*ntpath)*(ntpathlen+1));
195             lstrcpyW(ntpath, argv[i]);
196             tail=NULL;
197             while (1)
198             {
199                 char *unix_name;
200                 WCHAR *slash, *c;
201
202                 unix_name = wine_get_unix_file_name_ptr(ntpath);
203                 if (unix_name)
204                 {
205                     if (tail)
206                     {
207                         WideCharToMultiByte(CP_UNIXCP, 0, tail+1, -1, path, MAX_PATH, NULL, NULL);
208                         printf("%s/%s\n", unix_name, path);
209                     }
210                     else
211                     {
212                         printf("%s\n", unix_name);
213                     }
214                     HeapFree( GetProcessHeap(), 0, unix_name );
215                     break;
216                 }
217
218                 slash=(tail ? tail : ntpath+ntpathlen);
219                 while (slash != ntpath && *slash != '/' && *slash != '\\')
220                     slash--;
221                 if (slash == ntpath)
222                 {
223                     /* This is a complete path conversion failure.
224                      * It would typically happen if ntpath == "".
225                      */
226                     printf("\n");
227                     break;
228                 }
229                 c=slash+1;
230                 while (*c != '\0' && *c != '*' && *c != '?' &&
231                        *c != '<' && *c != '>' && *c != '|' && *c != '"')
232                     c++;
233                 if (*c != '\0')
234                 {
235                     /* If this is not a valid NT path to start with,
236                      * then obviously we cannot convert it.
237                      */
238                     printf("\n");
239                     break;
240                 }
241                 if (tail)
242                     *tail='/';
243                 tail=slash;
244                 *tail='\0';
245             }
246             HeapFree(GetProcessHeap(), 0, ntpath);
247         }
248         if (outputformats & WINDOWSFORMAT) {
249             WCHAR* windows_name;
250             char* unix_name;
251             DWORD size;
252
253             size=WideCharToMultiByte(CP_UNIXCP, 0, argv[i], -1, NULL, 0, NULL, NULL);
254             unix_name=HeapAlloc(GetProcessHeap(), 0, size);
255             WideCharToMultiByte(CP_UNIXCP, 0, argv[i], -1, unix_name, size, NULL, NULL);
256
257             if ((windows_name = wine_get_dos_file_name_ptr(unix_name)))
258             {
259                 WideCharToMultiByte(CP_UNIXCP, 0, windows_name, -1, path, MAX_PATH, NULL, NULL);
260                 printf("%s\n", path);
261                 HeapFree( GetProcessHeap(), 0, windows_name );
262             }
263             else printf( "\n" );
264             HeapFree( GetProcessHeap(), 0, unix_name );
265         }
266     }
267
268     exit(0);
269 }