source: trunk/dll/pathutil.c@ 1750

Last change on this file since 1750 was 1750, checked in by John Small, 11 years ago

Ticket #524: Made "searchapath" thread-safe. Function names and signatures were changed.

So calls to these functions, direct and indirect, had to be changed.

  • Property svn:keywords set to Author Date Id Revision
File size: 11.7 KB
Line 
1
2/***********************************************************************
3
4 $Id: pathutil.c 1750 2014-03-01 13:55:57Z jbs $
5
6 Path handling utility functions
7
8 Copyright (c) 1993-98 M. Kimes
9 Copyright (c) 2001, 2009 Steven H. Levine
10
11 05 Jan 08 SHL Move from arccnrs.c and comp.c to here
12 06 Jan 08 GKY Add NormalizeCmdLine to check program strings on entry
13 29 Feb 08 GKY Changes to enable user settable command line length
14 15 Oct 08 GKY Fix NormalizeCmdLine to check all 5 executable extensions when no extension provided;
15 use searchapath to check for existance of file types not checked by DosQAppType;
16 close DosFind.
17 28 Jun 09 GKY Added AddBackslashToPath() to remove repeatative code
18 12 Jul 09 GKY Add xDosQueryAppType and xDosAlloc... to allow FM/2 to load in high memory
19 23 Oct 10 GKY Add ForwardslashToBackslash function to streamline code
20 17 Sep 11 GKY Fix commandline quoting issues
21 01 Mar 14 JBS Ticket #524: Made "searchapath" thread-safe. Function names and signatures were changed.
22 So calls to these functions had to be changed.
23
24***********************************************************************/
25
26#include <stdlib.h>
27#include <string.h>
28
29#define INCL_WIN
30#define INCL_DOS
31#define INCL_LONGLONG
32
33#include "fm3dll.h" // needs_quoting
34#include "notebook.h" // Data declaration(s)
35#include "init.h" // Data declaration(s)
36#include "fm3str.h"
37#include "srchpath.h" // Search*Path*ForFile
38#include "pathutil.h"
39#include "strips.h" // remove_first_occurence_of_character
40#include "valid.h" // needs_quoting
41#include "errutil.h" // Dos_Error...
42#include "strutil.h" // GetPString
43#include "wrappers.h" // xmalloc
44#include "fortify.h"
45#include "stristr.h" //stristr
46
47static PSZ pszSrcFile = __FILE__;
48
49PSZ ForwardslashToBackslash(PSZ pszPathName)
50{
51 CHAR *p;
52
53 p = pszPathName;
54 while (*p) {
55 if (*p == '/')
56 *p = '\\';
57 p++;
58 }
59 return pszPathName;
60}
61
62PSZ AddBackslashToPath(PSZ pszPathName)
63{
64 if (pszPathName[strlen(pszPathName) - 1] != '\\')
65 strcat(pszPathName, PCSZ_BACKSLASH);
66 return pszPathName;
67}
68
69// #pragma data_seg(DATA1)
70
71/**
72 * Build full path name in callers buffer given directory
73 * name and filename
74 * @param pszPathName points to drive/directory if not NULL
75 * @returns pointer to full path name in caller's buffer
76 * @note OK for pszFullPathName and pszPathName to point to same buffer
77 *
78 */
79
80PSZ BldFullPathName(PSZ pszFullPathName, PCSZ pszPathName, PCSZ pszFileName)
81{
82 UINT c = pszPathName ? strlen(pszPathName) : 0;
83 if (c > 0) {
84 if (pszFullPathName != pszPathName)
85 memcpy(pszFullPathName, pszPathName, c);
86 if (pszFullPathName[c - 1] != '\\')
87 pszFullPathName[c++] = '\\';
88 }
89 strcpy(pszFullPathName + c, pszFileName);
90 return pszFullPathName;
91}
92
93/**
94 * Build quoted full path name in callers buffer given
95 * directory name and filename
96 * @param pszPathName points to drive/directory if not NULL
97 * @returns pointer to quoted path name in caller's buffer
98 */
99
100PSZ BldQuotedFullPathName(PSZ pszFullPathName, PCSZ pszPathName, PCSZ pszFileName)
101{
102 UINT c = pszPathName ? strlen(pszPathName) : 0;
103 BOOL q = needs_quoting(pszPathName) || needs_quoting(pszFileName);
104 PSZ psz = pszFullPathName;
105
106 if (q)
107 *psz++ = '"';
108 if (c > 0) {
109 memcpy(psz, pszPathName, c);
110 psz += c;
111 if (*(psz - 1) != '\\')
112 *psz++ = '\\';
113 }
114 strcpy(psz, pszFileName);
115 if (q) {
116 psz += strlen(psz);
117 *psz++ = '"';
118 *psz = 0;
119 }
120 return pszFullPathName;
121}
122
123/**
124 * Build quoted full path name in callers buffer given a filename
125 * @returns pointer to quoted file name in caller's buffer
126 */
127
128PSZ BldQuotedFileName(PSZ pszQuotedFileName, PCSZ pszFileName)
129{
130 BOOL q = needs_quoting(pszFileName);
131 PSZ psz = pszQuotedFileName;
132
133 if (q)
134 *psz++ = '"';
135 strcpy(psz, pszFileName);
136 if (q) {
137 psz += strlen(psz);
138 *psz++ = '"';
139 *psz = 0;
140 }
141 return pszQuotedFileName;
142}
143
144/** NormalizeCmdLine
145 * Checks a command line for common errors (missing quotes, missing extension,
146 * no space between exe and args etc) Also check for the existance of the file
147 * and checks .com and .exe file headers.
148 * Command line passed as pszCmdLine_
149 * A pointer to a buffer of the size MaxComLineStrg should be supplied in
150 * pszWorkBuf. This is where the quoted etc as necessary command
151 * line string will be returned.
152 */
153
154PCSZ NormalizeCmdLine(PSZ pszWorkBuf, PSZ pszCmdLine_)
155{
156 char *szCmdLine, *szArgs;
157 char *offset = '\0', *offsetexe, *offsetcom, *offsetcmd, *offsetbtm, *offsetbat;
158 APIRET ret;
159 ULONG ulAppType;
160 char *pszChar;
161 PSZ pszNewCmdLine = pszWorkBuf;
162
163 szCmdLine = xmalloc(MaxComLineStrg, pszSrcFile, __LINE__);
164 if (!szCmdLine)
165 return pszCmdLine_; //already complained
166 szArgs = xmalloc(MaxComLineStrg, pszSrcFile, __LINE__);
167 if (!szArgs) {
168 free(szCmdLine);
169 return pszCmdLine_; //already complained
170 }
171 bstrip(pszCmdLine_);
172 memset(pszWorkBuf, 0, MaxComLineStrg);
173 strcpy(szCmdLine, pszCmdLine_);
174 if (szCmdLine[0] != '\0') {
175 offsetexe = stristr(pszCmdLine_, PCSZ_DOTEXE);
176 offsetcmd = stristr(pszCmdLine_, PCSZ_DOTCMD);
177 offsetcom = stristr(pszCmdLine_, PCSZ_DOTCOM);
178 offsetbtm = stristr(pszCmdLine_, PCSZ_DOTBTM);
179 offsetbat = stristr(pszCmdLine_, PCSZ_DOTBAT);
180 if (offsetexe)
181 offset = offsetexe;
182 else {
183 if (offsetcom)
184 offset = offsetcom;
185 else {
186 if (offsetcmd)
187 offset = offsetcmd;
188 else {
189 if (offsetbtm)
190 offset = offsetbtm;
191 else {
192 if (offsetbat)
193 offset = offsetexe;
194 }
195 }
196 }
197 }
198 if (offset) {
199 szCmdLine[offset + 4 - pszCmdLine_] = '\0';
200 strcpy(szArgs, &pszCmdLine_[offset + 4 - pszCmdLine_]);
201 while (strchr(szCmdLine, '\"'))
202 remove_first_occurence_of_character("\"", szCmdLine);
203 if ((szArgs[0] == '\"' && szArgs[1] == ' ') ||
204 (!strstr(pszCmdLine_, "\\:") && strchr(szArgs, '\"') &&
205 strchr(szArgs, '\"') == strrchr(szArgs, '\"')))
206 remove_first_occurence_of_character("\"", szArgs);
207 if (strchr(szArgs, '\"') != strrchr(szArgs, '\"'))
208 saymsg(MB_OK, HWND_DESKTOP,
209 NullStr,
210 GetPString(IDS_QUOTESINARGSTEXT),
211 pszCmdLine_);
212 if (!offsetexe && !offsetcom) {
213 if (!SearchPathForFile(PCSZ_PATH, szCmdLine, NULL))
214 ret = 0;
215 }
216 else
217 ret = xDosQueryAppType(szCmdLine, &ulAppType);
218 BldQuotedFileName(pszNewCmdLine, szCmdLine);
219 if (ret) {
220 ret = saymsg(MB_YESNO,
221 HWND_DESKTOP,
222 NullStr,
223 GetPString(IDS_PROGRAMNOTFOUNDTEXT),
224 pszCmdLine_);
225 if (ret == MBID_YES){
226 if (szArgs[0] != ' ')
227 strcat(pszNewCmdLine, " ");
228 strcat(pszNewCmdLine, szArgs);
229 }
230 else{
231 fCancelAction = TRUE;
232 pszNewCmdLine = pszCmdLine_;
233 }
234 }
235 else{
236 if (szArgs[0] != ' ')
237 strcat(pszNewCmdLine, " ");
238 strcat(pszNewCmdLine, szArgs);
239 }
240
241 }
242 // if it doesn't have an extension try it with all the standard ones and add if found
243 else if (szCmdLine && (!strchr(szCmdLine, '.') ||
244 strrchr(szCmdLine, '.' ) < strrchr(szCmdLine, '\\'))) {
245 if (!strchr(szCmdLine, ' ')) {
246 // strip quotes readded by BuildQuotedFileName
247 while (strchr(szCmdLine, '\"'))
248 remove_first_occurence_of_character("\"", szCmdLine);
249 ret = xDosQueryAppType(szCmdLine, &ulAppType); // exe automatically appended
250 if (!ret)
251 strcat(szCmdLine, PCSZ_DOTEXE);
252 else {
253 strcat(szCmdLine, PCSZ_DOTCOM);
254 ret = xDosQueryAppType(szCmdLine, &ulAppType);
255 if (ret) {
256 offset = strrchr(szCmdLine, '.' );
257 *offset = 0;
258 strcat(szCmdLine, PCSZ_DOTCMD);
259 if (!SearchPathForFile(PCSZ_PATH, szCmdLine, NULL))
260 ret = 0;
261 else {
262 *offset = 0;
263 strcat(szCmdLine, PCSZ_DOTBAT);
264 if (!SearchPathForFile(PCSZ_PATH, szCmdLine, NULL))
265 ret = 0;
266 else {
267 *offset = 0;
268 strcat(szCmdLine, PCSZ_DOTBTM);
269 if (!SearchPathForFile(PCSZ_PATH, szCmdLine, NULL))
270 ret = 0;
271 }
272 }
273 }
274 }
275 }
276 else {
277 pszChar = szCmdLine;
278 while (pszChar) {
279 while (strchr(szCmdLine, '\"'))
280 remove_first_occurence_of_character("\"", szCmdLine);
281 if (*pszChar == ' ') { //test at every space for the end of the filename
282 *pszChar = '\0';
283 ret = xDosQueryAppType(szCmdLine, &ulAppType);
284 if (!ret) {
285 strcat(szCmdLine, PCSZ_DOTEXE);
286 break;
287 }
288 else {
289 strcat(szCmdLine, PCSZ_DOTCOM);
290 ret = xDosQueryAppType(szCmdLine, &ulAppType);
291 if (ret) {
292 offset = strrchr(szCmdLine, '.' );
293 *offset = 0;
294 strcat(szCmdLine, PCSZ_DOTCMD);
295 if (!SearchPathForFile(PCSZ_PATH, szCmdLine, NULL)) {
296 ret = 0;
297 break;
298 }
299 else {
300 *offset = 0;
301 strcat(szCmdLine, PCSZ_DOTBAT);
302 if (!SearchPathForFile(PCSZ_PATH, szCmdLine, NULL)) {
303 ret = 0;
304 break;
305 }
306 else {
307 *offset = 0;
308 strcat(szCmdLine, PCSZ_DOTBTM);
309 if (!SearchPathForFile(PCSZ_PATH, szCmdLine, NULL)) {
310 ret = 0;
311 break;
312 }
313 }
314 }
315 }
316 else
317 break;
318 }
319 }
320 strcpy(szCmdLine, pszCmdLine_);
321 pszChar++;
322 }
323 }
324 if (!ret){
325 BldQuotedFileName(pszNewCmdLine, szCmdLine);
326 strcpy(szArgs, pszCmdLine_ + strlen(szCmdLine) - 3);
327 if ((szArgs[0] == '\"' && szArgs[1] == ' ') ||
328 !strstr(pszCmdLine_, "\\:" ) ||
329 strchr(szArgs, '\"') == strrchr(szArgs, '\"'))
330 remove_first_occurence_of_character("\"", szArgs);
331 if (strchr(szArgs, '\"') != strrchr(szArgs, '\"'))
332 saymsg(MB_OK, HWND_DESKTOP,
333 NullStr,
334 GetPString(IDS_QUOTESINARGSTEXT),
335 pszCmdLine_);
336 if (szArgs[0] != ' ')
337 strcat(pszNewCmdLine, " ");
338 strcat(pszNewCmdLine, szArgs);
339 }
340 else { // fail if no extension can be found runemf2 requires one
341 ret = saymsg(MB_OK,
342 HWND_DESKTOP,
343 NullStr,
344 GetPString(IDS_PROGRAMNOTEXE2TEXT),
345 pszCmdLine_);
346 fCancelAction = TRUE;
347 pszNewCmdLine = pszCmdLine_;
348 }
349 }
350 else { // file has a nonstandard extension for executable
351 pszChar = strrchr(szCmdLine, '.');
352 while (pszChar && *pszChar !=' ') {
353 pszChar++;
354 }
355 *pszChar = '\0';
356 strcpy (szArgs, pszCmdLine_ + strlen(szCmdLine));
357 while (strchr(szCmdLine, '\"'))
358 remove_first_occurence_of_character("\"", szCmdLine);
359 if ((szArgs[0] == '\"' && szArgs[1] == ' ') ||
360 !strstr(pszCmdLine_, "\\:")||
361 strchr(szArgs, '\"') == strrchr(szArgs, '\"'))
362 remove_first_occurence_of_character("\"", szArgs);
363 if (strchr(szArgs, '\"') != strrchr(szArgs, '\"'))
364 saymsg(MB_OK, HWND_DESKTOP,
365 NullStr,
366 GetPString(IDS_QUOTESINARGSTEXT),
367 pszCmdLine_);
368 BldQuotedFileName(pszNewCmdLine, szCmdLine);
369 if (SearchPathForFile(PCSZ_PATH, szCmdLine, NULL)) {
370 ret = saymsg(MB_YESNO,
371 HWND_DESKTOP,
372 NullStr,
373 GetPString(IDS_PROGRAMNOTFOUNDTEXT),
374 pszCmdLine_);
375 if (ret == MBID_YES) {
376 if (szArgs[0] != ' ')
377 strcat(pszNewCmdLine, " ");
378 strcat(pszNewCmdLine, szArgs);
379 }
380 else {
381 fCancelAction = TRUE;
382 pszWorkBuf = pszCmdLine_;
383 }
384 }
385 else {
386 ret = saymsg(MB_YESNOCANCEL,
387 HWND_DESKTOP,
388 NullStr,
389 GetPString(IDS_PROGRAMNOTEXE3TEXT),
390 pszCmdLine_, pszNewCmdLine);
391 if (ret == MBID_YES){
392 if (szArgs[0] != ' ')
393 strcat(pszNewCmdLine, " ");
394 strcat(pszNewCmdLine, szArgs);
395 }
396 if (ret == MBID_CANCEL){
397 fCancelAction = TRUE;
398 pszNewCmdLine = pszCmdLine_;
399 }
400 }
401 }
402 }
403 free(szArgs);
404 free(szCmdLine);
405 return pszWorkBuf;
406}
407
408#pragma alloc_text(PATHUTIL,BldFullPathName)
409#pragma alloc_text(PATHUTIL,BldQuotedFileName)
410#pragma alloc_text(PATHUTIL,BldQuotedFullPathName)
411#pragma alloc_text(PATHUTIL,NormalizeCmdLine)
Note: See TracBrowser for help on using the repository browser.