Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

847 lines
20 KiB

  1. /********************************************************************/
  2. /** Microsoft LAN Manager **/
  3. /** Copyright(c) Microsoft Corp., 1987-1990 **/
  4. /********************************************************************/
  5. /***
  6. * help.c
  7. * Functions that give access to the text in the file net.hlp
  8. *
  9. * Format of the file net.hlp
  10. *
  11. * History
  12. * ??/??/??, stevero, initial code
  13. * 10/31/88, erichn, uses OS2.H instead of DOSCALLS
  14. * 01/04/89, erichn, filenames now MAX_PATH LONG
  15. * 05/02/89, erichn, NLS conversion
  16. * 06/08/89, erichn, canonicalization sweep
  17. * 02/20/91, danhi, change to use lm 16/32 mapping layer
  18. ***/
  19. /* Include files */
  20. #define INCL_ERRORS
  21. #define INCL_NOCOMMON
  22. #define INCL_DOSPROCESS
  23. #include <os2.h>
  24. #include <lmcons.h>
  25. #include <apperr.h>
  26. #include <apperr2.h>
  27. #include <lmerr.h>
  28. #include <stdio.h>
  29. #include <malloc.h>
  30. #include "lui.h"
  31. #include "netcmds.h"
  32. #include "msystem.h"
  33. /* Constants */
  34. #define ENTRY_NOT_FOUND -1
  35. #define NEXT_RECORD 0
  36. #define WHITE_SPACE TEXT("\t\n\x0B\x0C\r ")
  37. #define LINE_LEN 82
  38. #define OPTION_MAX_LEN 512
  39. #define DELS TEXT(":,\n")
  40. #define CNTRL (text[0] == DOT || text[0] == COLON || text[0] == POUND|| text[0] == DOLLAR)
  41. #define FCNTRL (text[0] == DOT || text[0] == COLON)
  42. #define HEADER (text[0] == PERCENT || text[0] == DOT || text[0] == BANG)
  43. #define ALIAS (text[0] == PERCENT)
  44. #define ADDCOM (text[0] == BANG)
  45. /* Static variables */
  46. TCHAR text[LINE_LEN+1];
  47. TCHAR *options; /* must be sure to malloc! */
  48. TCHAR *Arg_P[10];
  49. FILE *hfile;
  50. /* Forward declarations */
  51. int find_entry( int, int, HANDLE, int *);
  52. VOID print_syntax( HANDLE, int );
  53. VOID print_help( int );
  54. VOID print_options( int );
  55. VOID seek_data( int, int );
  56. LPWSTR skipwtspc( TCHAR FAR * );
  57. LPWSTR fgetsW(LPWSTR buf, int len, FILE *fh);
  58. DWORD GetHelpFileName(LPTSTR HelpFileName, DWORD BufferLength);
  59. DWORD GetFileName(LPTSTR FileName, DWORD BufferLength, LPTSTR FilePartName);
  60. /* help_help -
  61. */
  62. VOID NEAR pascal
  63. help_help( SHORT ali, SHORT amt)
  64. {
  65. DWORD err;
  66. int option_level = 1;
  67. int r;
  68. int found = 0;
  69. int out_len = 0;
  70. int offset;
  71. int arg_cnt;
  72. int k;
  73. SHORT pind = 0;
  74. TCHAR file_path[MAX_PATH];
  75. TCHAR str[10];
  76. TCHAR *Ap;
  77. TCHAR *tmp;
  78. TCHAR *stmp;
  79. TCHAR *t2;
  80. HANDLE outfile;
  81. if (!(options = malloc(OPTION_MAX_LEN + 1)))
  82. ErrorExit(ERROR_NOT_ENOUGH_MEMORY);
  83. *options = NULLC;
  84. Arg_P[0] = NET_KEYWORD;
  85. if (amt == USAGE_ONLY)
  86. {
  87. outfile = g_hStdErr;
  88. }
  89. else
  90. {
  91. outfile = g_hStdOut;
  92. }
  93. /* use offset to keep base of Arg_P relative to base of ArgList */
  94. offset = ali;
  95. /* increment ali in for loop so you can't get an ali of 0 */
  96. for (arg_cnt = 0; ArgList[ali++]; arg_cnt < 8 ? arg_cnt++ : 0)
  97. {
  98. str[arg_cnt] = (TCHAR)ali;
  99. }
  100. str[arg_cnt] = NULLC;
  101. str[arg_cnt+1] = NULLC; /* just in case the last argument is the first found */
  102. if (err = GetHelpFileName(file_path, MAX_PATH))
  103. {
  104. ErrorExit(err);
  105. }
  106. /*
  107. we need to open help files in binary mode
  108. because unicode text might contain 0x1a but
  109. it's not EOF.
  110. */
  111. if ( (hfile = _wfopen(file_path, L"rb")) == 0 )
  112. {
  113. ErrorExit(APE_HelpFileDoesNotExist);
  114. }
  115. if (!(fgetsW(text, LINE_LEN+1, hfile)))
  116. {
  117. ErrorExit(APE_HelpFileEmpty);
  118. }
  119. /* comment loop - read and ignore comments */
  120. while (!HEADER)
  121. {
  122. if (!fgetsW(text, LINE_LEN+1, hfile))
  123. {
  124. ErrorExit(APE_HelpFileError);
  125. }
  126. }
  127. /* get the list of commands that net help provides help for that are
  128. not specifically net commands
  129. */
  130. /* ALIAS Loop */
  131. while (ALIAS) {
  132. /* the first token read from text is the Real Object (the non alias) */
  133. tmp = skipwtspc(&text[2]);
  134. Ap = _tcstok(tmp, DELS);
  135. /* get each alias for the obove object and compare it to the arg_cnt
  136. number of args in ArgList */
  137. while ((tmp = _tcstok(NULL, DELS)) && arg_cnt) {
  138. tmp = skipwtspc(tmp);
  139. for (k = 0; k < arg_cnt; k++) {
  140. /* if there a match store the Objects real name in Arg_P */
  141. if (!_tcsicmp(tmp, ArgList[(int)(str[k]-1)])) {
  142. if (!(Arg_P[((int)str[k])-offset] = _tcsdup(Ap)))
  143. ErrorExit(APE_HelpFileError);
  144. /* delete the pointer to this argument from the list
  145. of pointers so the number of compares is reduced */
  146. stmp = &str[k];
  147. *stmp++ = NULLC;
  148. _tcscat(str, stmp);
  149. arg_cnt--;
  150. break;
  151. }
  152. }
  153. }
  154. if (!fgetsW(text, LINE_LEN+1, hfile))
  155. ErrorExit(APE_HelpFileError);
  156. }
  157. /* if there were any args that weren't aliased copy them into Arg_P */
  158. for (k = 0; k < arg_cnt; k++)
  159. Arg_P[((int)str[k])-offset] = ArgList[(int)(str[k]-1)];
  160. /* check for blank lines between alias declaration and command declarations */
  161. while (!HEADER) {
  162. if (!fgetsW(text, LINE_LEN+1, hfile))
  163. ErrorExit(APE_HelpFileError);
  164. }
  165. while (ADDCOM) {
  166. if ((arg_cnt) && (!found)) {
  167. tmp = skipwtspc(&text[2]);
  168. t2 = _tcschr(tmp, NEWLINE);
  169. *t2 = NULLC;
  170. if (!_tcsicmp(tmp, Arg_P[1])) {
  171. pind = 1;
  172. found = -1;
  173. }
  174. }
  175. if (!fgetsW(text, LINE_LEN+1, hfile))
  176. ErrorExit(APE_HelpFileError);
  177. }
  178. /* check for blank lines between command declarations and data */
  179. while (!FCNTRL) {
  180. if (!fgetsW(text, LINE_LEN+1, hfile))
  181. ErrorExit(APE_HelpFileError);
  182. }
  183. if (outfile == g_hStdOut) {
  184. if (amt == OPTIONS_ONLY)
  185. InfoPrint(APE_Options);
  186. else
  187. InfoPrint(APE_Syntax);
  188. }
  189. else {
  190. if (amt == OPTIONS_ONLY)
  191. InfoPrintInsHandle(APE_Options, 0, g_hStdErr);
  192. else
  193. InfoPrintInsHandle(APE_Syntax, 0, g_hStdErr);
  194. }
  195. ali = pind;
  196. GenOutput(outfile, TEXT("\r\n"));
  197. /* look for the specific entry (or path) and find its corresponding data */
  198. /* KKBUGFIX */
  199. /* U.S. bug. find_entry strcat's to options but options is
  200. uninitialized. The U.S. version is lucky that the malloc
  201. returns memory with mostly zeroes so this works. With recent
  202. changes things are a little different and a malloc returns
  203. memory with no zeroes so find_entry overwrites the buffer. */
  204. options[0] = '\0';
  205. while ((r = find_entry(option_level, ali, outfile, &out_len)) >= 0) {
  206. if (r) {
  207. options[0] = NULLC;
  208. if (Arg_P[++ali]) {
  209. option_level++;
  210. if (!fgetsW(text, LINE_LEN+1, hfile))
  211. ErrorExit(APE_HelpFileError);
  212. }
  213. else {
  214. seek_data(option_level, 1);
  215. break;
  216. }
  217. }
  218. }
  219. r = (r < 0) ? (option_level - 1) : r;
  220. switch(amt) {
  221. case ALL:
  222. /* print the syntax data that was found for this level */
  223. print_syntax(outfile, out_len);
  224. print_help(r);
  225. NetcmdExit(0);
  226. break;
  227. case USAGE_ONLY:
  228. print_syntax(outfile, out_len);
  229. GenOutput(outfile, TEXT("\r\n"));
  230. NetcmdExit(1);
  231. break;
  232. case OPTIONS_ONLY:
  233. //fflush( outfile );
  234. print_options(r);
  235. NetcmdExit(0);
  236. break;
  237. }
  238. }
  239. /* find_entry - each invocation of find_entry either finds a match at the
  240. specified level or advances through the file to the next entry at
  241. the specified level. If the level requested is greater than the
  242. next level read ENTRY_NOT_FOUND is returned. */
  243. int
  244. find_entry(
  245. int level,
  246. int ali,
  247. HANDLE out,
  248. int *out_len
  249. )
  250. {
  251. static TCHAR level_key[] = {TEXT(".0")};
  252. TCHAR *tmp;
  253. TCHAR *t2;
  254. level_key[1] = (TCHAR) (TEXT('0') + (TCHAR)level);
  255. if (level_key[1] > text[1])
  256. return (ENTRY_NOT_FOUND | ali);
  257. else {
  258. tmp = skipwtspc(&text[2]);
  259. t2 = _tcschr(tmp, NEWLINE);
  260. if (t2 == NULL)
  261. {
  262. //
  263. // A line in the help file is longer than LINE_LEN
  264. // so there's no newline character. Bail out.
  265. //
  266. ErrorExit(APE_HelpFileError);
  267. }
  268. *t2 = NULLC;
  269. if (!_tcsicmp(Arg_P[ali], tmp)) {
  270. *t2++ = BLANK;
  271. *t2 = NULLC;
  272. GenOutput1(out, TEXT("%s"), tmp);
  273. *out_len += _tcslen(tmp);
  274. return level;
  275. }
  276. else {
  277. *t2++ = BLANK;
  278. *t2 = NULLC;
  279. _tcscat(options, tmp);
  280. _tcscat(options, TEXT("| "));
  281. seek_data(level, 0);
  282. do {
  283. if (!fgetsW(text, LINE_LEN+1, hfile))
  284. ErrorExit(APE_HelpFileError);
  285. } while (!FCNTRL);
  286. return NEXT_RECORD;
  287. }
  288. }
  289. }
  290. VOID
  291. print_syntax(
  292. HANDLE out,
  293. int out_len
  294. )
  295. {
  296. TCHAR *tmp,
  297. *rtmp,
  298. *otmp,
  299. tchar;
  300. int off,
  301. pg_wdth = LINE_LEN - 14;
  302. tmp = skipwtspc(&text[2]);
  303. if (_tcslen(tmp) < 2)
  304. {
  305. //
  306. // Used only for syntax of NET (e.g., if user types
  307. // in "net foo")
  308. //
  309. if (_tcslen(options))
  310. {
  311. otmp = _tcsrchr(options, PIPE);
  312. if (otmp == NULL)
  313. {
  314. ErrorExit(APE_HelpFileError);
  315. }
  316. *otmp = NULLC;
  317. GenOutput(out, TEXT("[ "));
  318. out_len += 2;
  319. tmp = options;
  320. otmp = tmp;
  321. off = pg_wdth - out_len;
  322. while (((int)_tcslen(tmp) + out_len) > pg_wdth)
  323. {
  324. if ((tmp + off) > &options[OPTION_MAX_LEN])
  325. rtmp = (TCHAR*) (&options[OPTION_MAX_LEN]);
  326. else
  327. rtmp = (tmp + off);
  328. /* save TCHAR about to be stomped by null */
  329. tchar = *++rtmp;
  330. *rtmp = NULLC;
  331. /* use _tcsrchr to find last occurance of a space (kanji compatible) */
  332. if ( ! ( tmp = _tcsrchr(tmp, PIPE) ) ) {
  333. ErrorExit(APE_HelpFileError);
  334. }
  335. /* replace stomped TCHAR */
  336. *rtmp = tchar;
  337. rtmp = tmp;
  338. /* replace 'found space' with null for fprintf */
  339. *++rtmp = NULLC;
  340. rtmp++;
  341. GenOutput1(out, TEXT("%s\r\n"), otmp);
  342. /* indent next line */
  343. tmp = rtmp - out_len;
  344. otmp = tmp;
  345. while (rtmp != tmp)
  346. {
  347. *tmp++ = BLANK;
  348. }
  349. }
  350. GenOutput1(out, TEXT("%s]\r\n"), otmp);
  351. *tmp = NULLC;
  352. }
  353. }
  354. else
  355. {
  356. GenOutput(out, TEXT("\r\n"));
  357. }
  358. do
  359. {
  360. if (*tmp)
  361. GenOutput1(out, TEXT("%s"), tmp);
  362. if(!(tmp = fgetsW(text, LINE_LEN+1, hfile)))
  363. ErrorExit(APE_HelpFileError);
  364. if (_tcslen(tmp) > 3)
  365. tmp += 3;
  366. }
  367. while (!CNTRL);
  368. }
  369. VOID
  370. print_help(
  371. int level
  372. )
  373. {
  374. static TCHAR help_key[] = {TEXT("#0")};
  375. TCHAR *tmp;
  376. help_key[1] = (TCHAR)(level) + TEXT('0');
  377. while (!(text[0] == POUND))
  378. if(!fgetsW(text, LINE_LEN+1, hfile))
  379. ErrorExit(APE_HelpFileError);
  380. while (text[1] > help_key[1]) {
  381. help_key[1]--;
  382. seek_data(--level, 0);
  383. do {
  384. if (!fgetsW(text, LINE_LEN+1, hfile))
  385. ErrorExit(APE_HelpFileError);
  386. } while(!(text[0] == POUND));
  387. }
  388. tmp = &text[2];
  389. *tmp = NEWLINE;
  390. do {
  391. WriteToCon(TEXT("%s"), tmp);
  392. if (!(tmp = fgetsW(text, LINE_LEN+1, hfile)))
  393. ErrorExit(APE_HelpFileError);
  394. if (_tcslen(tmp) > 3)
  395. tmp = &text[3];
  396. } while (!CNTRL);
  397. }
  398. VOID
  399. print_options(int level)
  400. {
  401. static TCHAR help_key[] = {TEXT("$0")};
  402. TCHAR *tmp;
  403. help_key[1] = (TCHAR)(level) + TEXT('0');
  404. while (!(text[0] == DOLLAR))
  405. if(!fgetsW(text, LINE_LEN+1, hfile))
  406. ErrorExit(APE_HelpFileError);
  407. while (text[1] > help_key[1]) {
  408. help_key[1]--;
  409. seek_data(--level, 0);
  410. do {
  411. if (!fgetsW(text, LINE_LEN+1, hfile))
  412. ErrorExit(APE_HelpFileError);
  413. } while(!(text[0] == DOLLAR));
  414. }
  415. tmp = &text[2];
  416. *tmp = NEWLINE;
  417. do {
  418. WriteToCon(TEXT("%s"), tmp);
  419. if (!(tmp = fgetsW(text, LINE_LEN+1, hfile)))
  420. ErrorExit(APE_HelpFileError);
  421. if (_tcslen(tmp) > 3)
  422. tmp = &text[3];
  423. } while (!CNTRL);
  424. }
  425. VOID
  426. seek_data(int level, int opt_trace)
  427. {
  428. static TCHAR data_key[] = {TEXT(":0")};
  429. static TCHAR option_key[] = {TEXT(".0")};
  430. TCHAR *tmp;
  431. TCHAR *t2;
  432. data_key[1] = (TCHAR)(level) + TEXT('0');
  433. option_key[1] = (TCHAR)(level) + TEXT('1');
  434. do {
  435. if (!(fgetsW(text, LINE_LEN+1, hfile)))
  436. ErrorExit(APE_HelpFileError);
  437. if (opt_trace &&
  438. (!(_tcsncmp(option_key, text, DIMENSION(option_key)-1)))) {
  439. tmp = skipwtspc(&text[2]);
  440. t2 = _tcschr(tmp, NEWLINE);
  441. if (t2 == NULL)
  442. {
  443. //
  444. // A line in the help file is longer than LINE_LEN
  445. // so there's no newline character. Not good.
  446. //
  447. ErrorExit(APE_HelpFileError);
  448. }
  449. *t2++ = BLANK;
  450. *t2 = NULLC;
  451. _tcscat(options, tmp);
  452. _tcscat(options, TEXT("| "));
  453. }
  454. } while (_tcsncmp(data_key, text, DIMENSION(data_key)-1));
  455. }
  456. TCHAR FAR *
  457. skipwtspc(TCHAR FAR *s)
  458. {
  459. s += _tcsspn(s, WHITE_SPACE);
  460. return s;
  461. }
  462. /* help_helpmsg() -- front end for helpmsg utility
  463. *
  464. * This function acts as a front end for the OS/2 HELPMSG.EXE
  465. * utility for NET errors only. It takes as a parameter a string
  466. * that contains a VALID message id; i.e., of the form NETxxxx
  467. * or xxxx. The string is assumed to have been screened by the
  468. * IsNumber() function in grammar.c before coming here.
  469. JonN 3/31/00 98273: NETCMD: Need to fix the mapping of error 3521
  470. Before the checkin for 22391, NET1.EXE read errors
  471. NERR_BASE (2100) <= err < APPERR2_BASE (4300) from NETMSG.DLL,
  472. and all others from FORMAT_MESSAGE_FROM_SYSTEM.
  473. After the checkin for 22391, NET1.EXE read errors
  474. NERR_BASE (2100) < err < MAX_NERR (2999) from NETMSG.DLL,
  475. and all others from FORMAT_MESSAGE_FROM_SYSTEM.
  476. On closer examination, NETMSG.DLL currently appears to contain messages from
  477. 0x836 (2102) to 0x169F (5791).
  478. This is consistent with lmcons.h:
  479. #define MIN_LANMAN_MESSAGE_ID NERR_BASE
  480. #define MAX_LANMAN_MESSAGE_ID 5799
  481. It looks like we have a basic contradiction here:
  482. 3001:
  483. FORMAT_MESSAGE_FROM_SYSTEM: The specified printer driver is currently in use.
  484. NETMSG.DLL: *** errors were logged in the last *** minutes.
  485. 3521:
  486. FORMAT_MESSAGE_FROM_SYSTEM: not found
  487. NETMSG.DLL: The *** service is not started.
  488. So what do we do with the error messages in the range
  489. MAX_NERR (2999) < err <= MAX_LANMAN_MESSAGE_ID
  490. ? The best error message could be in either one.
  491. Perhaps we should try FORMAT_MESSAGE_FROM_SYSTEM, and if that fails
  492. fall back to NETMSG.DLL.
  493. */
  494. VOID NEAR pascal
  495. help_helpmsg(TCHAR *msgid)
  496. {
  497. USHORT err;
  498. TCHAR * temp = msgid;
  499. if (!IsNumber(msgid))
  500. {
  501. ErrorExitInsTxt(APE_BAD_MSGID, msgid);
  502. }
  503. if (n_atou(temp, &err))
  504. {
  505. ErrorExitInsTxt(APE_BAD_MSGID, msgid);
  506. }
  507. /* First try FORMAT_MESSAGE_FROM_SYSTEM unless the error is in the range
  508. NERR_BASE <= err <= MAX_NERR */
  509. if (err < NERR_BASE || err > MAX_NERR)
  510. {
  511. LPWSTR lpMessage = NULL ;
  512. if (!FormatMessageW(
  513. FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
  514. NULL,
  515. err,
  516. 0,
  517. (LPWSTR)&lpMessage,
  518. 1024,
  519. NULL))
  520. {
  521. // defer error message and fall back to NETMSG.DLL
  522. }
  523. else
  524. {
  525. WriteToCon(TEXT("\r\n%s\r\n"), lpMessage);
  526. (void) LocalFree((HLOCAL)lpMessage) ;
  527. return ;
  528. }
  529. }
  530. /* skip NETMSG.DLL if error message is way out of range */
  531. if (err < NERR_BASE || err > MAX_MSGID) {
  532. ErrorExitInsTxt(APE_BAD_MSGID, msgid);
  533. }
  534. /* read from NETMSG.DLL */
  535. PrintNL();
  536. //
  537. // If PrintMessage can't find the message id, don't try the expl
  538. //
  539. if (PrintMessage(g_hStdOut, MESSAGE_FILENAME, err, StarStrings, 9) == NO_ERROR)
  540. {
  541. PrintNL();
  542. PrintMessageIfFound(g_hStdOut, HELP_MSG_FILENAME, err, StarStrings, 9);
  543. }
  544. }
  545. /*
  546. * returns line from file (no CRLFs); returns NULL if EOF
  547. */
  548. LPWSTR
  549. fgetsW(
  550. LPWSTR buf,
  551. int len,
  552. FILE *fh
  553. )
  554. {
  555. int c = 0;
  556. TCHAR *pch;
  557. int cchline;
  558. DWORD cchRead;
  559. pch = buf;
  560. cchline = 0;
  561. if (ftell(fh) == 0)
  562. {
  563. fread(&c, sizeof(TCHAR), 1, fh);
  564. if (c != 0xfeff)
  565. {
  566. //
  567. // Help file isn't Unicode
  568. //
  569. ErrorExit(APE_HelpFileError);
  570. }
  571. }
  572. while (TRUE)
  573. {
  574. /*
  575. * for now read in the buffer in ANSI form until Unicode is more
  576. * widely accepted - dee
  577. *
  578. */
  579. cchRead = fread(&c, sizeof(TCHAR), 1, fh);
  580. //
  581. // if there are no more characters, end the line
  582. //
  583. if (cchRead < 1)
  584. {
  585. c = EOF;
  586. break;
  587. }
  588. //
  589. // if we see a \r, we ignore it
  590. //
  591. if (c == TEXT('\r'))
  592. continue;
  593. //
  594. // if we see a \n, we end the line
  595. //
  596. if (c == TEXT('\n')) {
  597. *pch++ = (TCHAR) c;
  598. break;
  599. }
  600. //
  601. // if the char is not a tab, store it
  602. //
  603. if (c != TEXT('\t'))
  604. {
  605. *pch = (TCHAR) c;
  606. pch++;
  607. cchline++;
  608. }
  609. //
  610. // if the line is too long, end it now
  611. //
  612. if (cchline >= len - 1) {
  613. break;
  614. }
  615. }
  616. //
  617. // end the line
  618. //
  619. *pch = (TCHAR) 0;
  620. //
  621. // return NULL at EOF with nothing read
  622. //
  623. return ((c == EOF) && (pch == buf)) ? NULL : buf;
  624. }
  625. //
  626. // Build the fully qualified path name of a file that lives with the exe
  627. // Used by LUI_GetHelpFileName
  628. //
  629. DWORD
  630. GetFileName(
  631. LPTSTR FileName,
  632. DWORD BufferLength,
  633. LPTSTR FilePartName
  634. )
  635. {
  636. TCHAR ExeFileName[MAX_PATH + 1] = {0};
  637. PTCHAR pch;
  638. //
  639. // Get the fully qualified path name of where the exe lives
  640. //
  641. if (!GetModuleFileName(NULL, ExeFileName, DIMENSION(ExeFileName) - 1))
  642. {
  643. return 1;
  644. }
  645. //
  646. // get rid of the file name part
  647. //
  648. pch = _tcsrchr(ExeFileName, '\\');
  649. if (!pch)
  650. {
  651. return 1;
  652. }
  653. *(pch+1) = NULLC;
  654. //
  655. // Copy the path name into the string and add the help filename part
  656. // but first make sure it's not too big for the user's buffer
  657. //
  658. if (_tcslen(ExeFileName) + _tcslen(FilePartName) + 1 > BufferLength)
  659. {
  660. return 1;
  661. }
  662. _tcscpy(FileName, ExeFileName);
  663. _tcscat(FileName, FilePartName);
  664. return 0;
  665. }
  666. //
  667. // Get the help file name
  668. //
  669. DWORD
  670. GetHelpFileName(
  671. LPTSTR HelpFileName,
  672. DWORD BufferLength
  673. )
  674. {
  675. TCHAR LocalizedFileName[MAX_PATH];
  676. DWORD LocalizedFileNameID;
  677. switch(GetConsoleOutputCP()) {
  678. case 932:
  679. case 936:
  680. case 949:
  681. case 950:
  682. LocalizedFileNameID = APE2_FE_NETCMD_HELP_FILE;
  683. break;
  684. default:
  685. LocalizedFileNameID = APE2_US_NETCMD_HELP_FILE;
  686. break;
  687. }
  688. if (LUI_GetMsg(LocalizedFileName, DIMENSION(LocalizedFileName),
  689. LocalizedFileNameID))
  690. {
  691. return GetFileName(HelpFileName, BufferLength, TEXT("NET.HLP"));
  692. }
  693. else
  694. {
  695. return GetFileName(HelpFileName, BufferLength, LocalizedFileName);
  696. }
  697. }