844 lines
19 KiB
C
844 lines
19 KiB
C
|
/********************************************************************/
|
||
|
/** Microsoft LAN Manager **/
|
||
|
/** Copyright(c) Microsoft Corp., 1987-1990 **/
|
||
|
/********************************************************************/
|
||
|
|
||
|
/***
|
||
|
* help.c
|
||
|
* Functions that give access to the text in the file net.hlp
|
||
|
*
|
||
|
* Format of the file net.hlp
|
||
|
*
|
||
|
* History
|
||
|
* ??/??/??, stevero, initial code
|
||
|
* 10/31/88, erichn, uses OS2.H instead of DOSCALLS
|
||
|
* 01/04/89, erichn, filenames now MAX_PATH LONG
|
||
|
* 05/02/89, erichn, NLS conversion
|
||
|
* 06/08/89, erichn, canonicalization sweep
|
||
|
* 02/20/91, danhi, change to use lm 16/32 mapping layer
|
||
|
***/
|
||
|
|
||
|
/* Include files */
|
||
|
|
||
|
#define INCL_ERRORS
|
||
|
#define INCL_NOCOMMON
|
||
|
#define INCL_DOSPROCESS
|
||
|
#include <os2.h>
|
||
|
#include <lmcons.h>
|
||
|
#include <apperr.h>
|
||
|
#include <apperr2.h>
|
||
|
#include <lmerr.h>
|
||
|
#include <stdio.h>
|
||
|
#include <malloc.h>
|
||
|
#include "lui.h"
|
||
|
#include "netcmds.h"
|
||
|
#include "msystem.h"
|
||
|
|
||
|
|
||
|
/* Constants */
|
||
|
|
||
|
#define ENTRY_NOT_FOUND -1
|
||
|
#define NEXT_RECORD 0
|
||
|
#define WHITE_SPACE TEXT("\t\n\x0B\x0C\r ")
|
||
|
|
||
|
#define LINE_LEN 82
|
||
|
#define OPTION_MAX_LEN 512
|
||
|
#define DELS TEXT(":,\n")
|
||
|
|
||
|
#define CNTRL (text[0] == DOT || text[0] == COLON || text[0] == POUND|| text[0] == DOLLAR)
|
||
|
#define FCNTRL (text[0] == DOT || text[0] == COLON)
|
||
|
#define HEADER (text[0] == PERCENT || text[0] == DOT || text[0] == BANG)
|
||
|
#define ALIAS (text[0] == PERCENT)
|
||
|
#define ADDCOM (text[0] == BANG)
|
||
|
|
||
|
/* Static variables */
|
||
|
|
||
|
TCHAR text[LINE_LEN+1];
|
||
|
TCHAR *options; /* must be sure to malloc! */
|
||
|
TCHAR *Arg_P[10];
|
||
|
FILE *hfile;
|
||
|
|
||
|
|
||
|
/* Forward declarations */
|
||
|
|
||
|
int find_entry( int, int, HANDLE, int *);
|
||
|
VOID print_syntax( HANDLE, int );
|
||
|
VOID print_help( int );
|
||
|
VOID print_options( int );
|
||
|
VOID seek_data( int, int );
|
||
|
LPWSTR skipwtspc( TCHAR FAR * );
|
||
|
LPWSTR fgetsW(LPWSTR buf, int len, FILE *fh);
|
||
|
DWORD GetHelpFileName(LPTSTR HelpFileName, DWORD BufferLength);
|
||
|
DWORD GetFileName(LPTSTR FileName, DWORD BufferLength, LPTSTR FilePartName);
|
||
|
|
||
|
|
||
|
/* help_help -
|
||
|
*/
|
||
|
VOID NEAR pascal
|
||
|
help_help( SHORT ali, SHORT amt)
|
||
|
{
|
||
|
DWORD err;
|
||
|
int option_level = 1;
|
||
|
int r;
|
||
|
int found = 0;
|
||
|
int out_len = 0;
|
||
|
int offset;
|
||
|
int arg_cnt;
|
||
|
int k;
|
||
|
SHORT pind = 0;
|
||
|
TCHAR file_path[MAX_PATH];
|
||
|
TCHAR str[10];
|
||
|
TCHAR *Ap;
|
||
|
TCHAR *tmp;
|
||
|
TCHAR *stmp;
|
||
|
TCHAR *t2;
|
||
|
HANDLE outfile;
|
||
|
|
||
|
if (!(options = malloc(OPTION_MAX_LEN + 1)))
|
||
|
ErrorExit(ERROR_NOT_ENOUGH_MEMORY);
|
||
|
*options = NULLC;
|
||
|
|
||
|
Arg_P[0] = NET_KEYWORD;
|
||
|
|
||
|
if (amt == USAGE_ONLY)
|
||
|
{
|
||
|
outfile = g_hStdErr;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
outfile = g_hStdOut;
|
||
|
}
|
||
|
|
||
|
/* use offset to keep base of Arg_P relative to base of ArgList */
|
||
|
offset = ali;
|
||
|
|
||
|
/* increment ali in for loop so you can't get an ali of 0 */
|
||
|
for (arg_cnt = 0; ArgList[ali++]; arg_cnt < 8 ? arg_cnt++ : 0)
|
||
|
{
|
||
|
str[arg_cnt] = (TCHAR)ali;
|
||
|
}
|
||
|
|
||
|
str[arg_cnt] = NULLC;
|
||
|
str[arg_cnt+1] = NULLC; /* just in case the last argument is the first found */
|
||
|
|
||
|
|
||
|
if (err = GetHelpFileName(file_path, MAX_PATH))
|
||
|
{
|
||
|
ErrorExit(err);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
we need to open help files in binary mode
|
||
|
because unicode text might contain 0x1a but
|
||
|
it's not EOF.
|
||
|
*/
|
||
|
if ( (hfile = _wfopen(file_path, L"rb")) == 0 )
|
||
|
{
|
||
|
ErrorExit(APE_HelpFileDoesNotExist);
|
||
|
}
|
||
|
|
||
|
if (!(fgetsW(text, LINE_LEN+1, hfile)))
|
||
|
{
|
||
|
ErrorExit(APE_HelpFileEmpty);
|
||
|
}
|
||
|
|
||
|
/* comment loop - read and ignore comments */
|
||
|
while (!HEADER)
|
||
|
{
|
||
|
if (!fgetsW(text, LINE_LEN+1, hfile))
|
||
|
{
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
}
|
||
|
}
|
||
|
/* get the list of commands that net help provides help for that are
|
||
|
not specifically net commands
|
||
|
*/
|
||
|
/* ALIAS Loop */
|
||
|
while (ALIAS) {
|
||
|
/* the first token read from text is the Real Object (the non alias) */
|
||
|
tmp = skipwtspc(&text[2]);
|
||
|
Ap = _tcstok(tmp, DELS);
|
||
|
|
||
|
/* get each alias for the obove object and compare it to the arg_cnt
|
||
|
number of args in ArgList */
|
||
|
while ((tmp = _tcstok(NULL, DELS)) && arg_cnt) {
|
||
|
tmp = skipwtspc(tmp);
|
||
|
|
||
|
for (k = 0; k < arg_cnt; k++) {
|
||
|
/* if there a match store the Objects real name in Arg_P */
|
||
|
if (!_tcsicmp(tmp, ArgList[(int)(str[k]-1)])) {
|
||
|
if (!(Arg_P[((int)str[k])-offset] = _tcsdup(Ap)))
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
|
||
|
/* delete the pointer to this argument from the list
|
||
|
of pointers so the number of compares is reduced */
|
||
|
stmp = &str[k];
|
||
|
*stmp++ = NULLC;
|
||
|
_tcscat(str, stmp);
|
||
|
arg_cnt--;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!fgetsW(text, LINE_LEN+1, hfile))
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
|
||
|
}
|
||
|
|
||
|
/* if there were any args that weren't aliased copy them into Arg_P */
|
||
|
for (k = 0; k < arg_cnt; k++)
|
||
|
Arg_P[((int)str[k])-offset] = ArgList[(int)(str[k]-1)];
|
||
|
|
||
|
/* check for blank lines between alias declaration and command declarations */
|
||
|
while (!HEADER) {
|
||
|
if (!fgetsW(text, LINE_LEN+1, hfile))
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
}
|
||
|
|
||
|
while (ADDCOM) {
|
||
|
if ((arg_cnt) && (!found)) {
|
||
|
tmp = skipwtspc(&text[2]);
|
||
|
t2 = _tcschr(tmp, NEWLINE);
|
||
|
*t2 = NULLC;
|
||
|
if (!_tcsicmp(tmp, Arg_P[1])) {
|
||
|
pind = 1;
|
||
|
found = -1;
|
||
|
}
|
||
|
}
|
||
|
if (!fgetsW(text, LINE_LEN+1, hfile))
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
}
|
||
|
|
||
|
/* check for blank lines between command declarations and data */
|
||
|
while (!FCNTRL) {
|
||
|
if (!fgetsW(text, LINE_LEN+1, hfile))
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
}
|
||
|
|
||
|
if (outfile == g_hStdOut) {
|
||
|
if (amt == OPTIONS_ONLY)
|
||
|
InfoPrint(APE_Options);
|
||
|
else
|
||
|
InfoPrint(APE_Syntax);
|
||
|
}
|
||
|
else {
|
||
|
if (amt == OPTIONS_ONLY)
|
||
|
InfoPrintInsHandle(APE_Options, 0, g_hStdErr);
|
||
|
else
|
||
|
InfoPrintInsHandle(APE_Syntax, 0, g_hStdErr);
|
||
|
}
|
||
|
|
||
|
ali = pind;
|
||
|
GenOutput(outfile, TEXT("\r\n"));
|
||
|
/* look for the specific entry (or path) and find its corresponding data */
|
||
|
|
||
|
/* KKBUGFIX */
|
||
|
/* U.S. bug. find_entry strcat's to options but options is
|
||
|
uninitialized. The U.S. version is lucky that the malloc
|
||
|
returns memory with mostly zeroes so this works. With recent
|
||
|
changes things are a little different and a malloc returns
|
||
|
memory with no zeroes so find_entry overwrites the buffer. */
|
||
|
|
||
|
options[0] = '\0';
|
||
|
|
||
|
while ((r = find_entry(option_level, ali, outfile, &out_len)) >= 0) {
|
||
|
if (r) {
|
||
|
options[0] = NULLC;
|
||
|
if (Arg_P[++ali]) {
|
||
|
option_level++;
|
||
|
if (!fgetsW(text, LINE_LEN+1, hfile))
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
}
|
||
|
else {
|
||
|
seek_data(option_level, 1);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
r = (r < 0) ? (option_level - 1) : r;
|
||
|
|
||
|
switch(amt) {
|
||
|
case ALL:
|
||
|
/* print the syntax data that was found for this level */
|
||
|
print_syntax(outfile, out_len);
|
||
|
|
||
|
print_help(r);
|
||
|
NetcmdExit(0);
|
||
|
break;
|
||
|
case USAGE_ONLY:
|
||
|
print_syntax(outfile, out_len);
|
||
|
GenOutput(outfile, TEXT("\r\n"));
|
||
|
NetcmdExit(1);
|
||
|
break;
|
||
|
case OPTIONS_ONLY:
|
||
|
//fflush( outfile );
|
||
|
print_options(r);
|
||
|
NetcmdExit(0);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
/* find_entry - each invocation of find_entry either finds a match at the
|
||
|
specified level or advances through the file to the next entry at
|
||
|
the specified level. If the level requested is greater than the
|
||
|
next level read ENTRY_NOT_FOUND is returned. */
|
||
|
|
||
|
int
|
||
|
find_entry(
|
||
|
int level,
|
||
|
int ali,
|
||
|
HANDLE out,
|
||
|
int *out_len
|
||
|
)
|
||
|
{
|
||
|
static TCHAR level_key[] = {TEXT(".0")};
|
||
|
TCHAR *tmp;
|
||
|
TCHAR *t2;
|
||
|
|
||
|
level_key[1] = (TCHAR) (TEXT('0') + (TCHAR)level);
|
||
|
if (level_key[1] > text[1])
|
||
|
return (ENTRY_NOT_FOUND | ali);
|
||
|
else {
|
||
|
tmp = skipwtspc(&text[2]);
|
||
|
t2 = _tcschr(tmp, NEWLINE);
|
||
|
|
||
|
if (t2 == NULL)
|
||
|
{
|
||
|
//
|
||
|
// A line in the help file is longer than LINE_LEN
|
||
|
// so there's no newline character. Bail out.
|
||
|
//
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
}
|
||
|
|
||
|
*t2 = NULLC;
|
||
|
|
||
|
if (!_tcsicmp(Arg_P[ali], tmp)) {
|
||
|
*t2++ = BLANK;
|
||
|
*t2 = NULLC;
|
||
|
GenOutput1(out, TEXT("%s"), tmp);
|
||
|
*out_len += _tcslen(tmp);
|
||
|
return level;
|
||
|
}
|
||
|
else {
|
||
|
*t2++ = BLANK;
|
||
|
*t2 = NULLC;
|
||
|
_tcscat(options, tmp);
|
||
|
_tcscat(options, TEXT("| "));
|
||
|
seek_data(level, 0);
|
||
|
do {
|
||
|
|
||
|
if (!fgetsW(text, LINE_LEN+1, hfile))
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
|
||
|
} while (!FCNTRL);
|
||
|
return NEXT_RECORD;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
print_syntax(
|
||
|
HANDLE out,
|
||
|
int out_len
|
||
|
)
|
||
|
{
|
||
|
TCHAR *tmp,
|
||
|
*rtmp,
|
||
|
*otmp,
|
||
|
tchar;
|
||
|
|
||
|
int off,
|
||
|
pg_wdth = LINE_LEN - 14;
|
||
|
|
||
|
tmp = skipwtspc(&text[2]);
|
||
|
|
||
|
if (_tcslen(tmp) < 2)
|
||
|
{
|
||
|
//
|
||
|
// Used only for syntax of NET (e.g., if user types
|
||
|
// in "net foo")
|
||
|
//
|
||
|
if (_tcslen(options))
|
||
|
{
|
||
|
otmp = _tcsrchr(options, PIPE);
|
||
|
|
||
|
if (otmp == NULL)
|
||
|
{
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
}
|
||
|
|
||
|
*otmp = NULLC;
|
||
|
GenOutput(out, TEXT("[ "));
|
||
|
out_len += 2;
|
||
|
tmp = options;
|
||
|
otmp = tmp;
|
||
|
off = pg_wdth - out_len;
|
||
|
|
||
|
while (((int)_tcslen(tmp) + out_len) > pg_wdth)
|
||
|
{
|
||
|
if ((tmp + off) > &options[OPTION_MAX_LEN])
|
||
|
rtmp = (TCHAR*) (&options[OPTION_MAX_LEN]);
|
||
|
else
|
||
|
rtmp = (tmp + off);
|
||
|
|
||
|
/* save TCHAR about to be stomped by null */
|
||
|
tchar = *++rtmp;
|
||
|
*rtmp = NULLC;
|
||
|
|
||
|
/* use _tcsrchr to find last occurance of a space (kanji compatible) */
|
||
|
if ( ! ( tmp = _tcsrchr(tmp, PIPE) ) ) {
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
}
|
||
|
|
||
|
/* replace stomped TCHAR */
|
||
|
*rtmp = tchar;
|
||
|
rtmp = tmp;
|
||
|
|
||
|
/* replace 'found space' with null for fprintf */
|
||
|
*++rtmp = NULLC;
|
||
|
rtmp++;
|
||
|
GenOutput1(out, TEXT("%s\r\n"), otmp);
|
||
|
|
||
|
/* indent next line */
|
||
|
tmp = rtmp - out_len;
|
||
|
otmp = tmp;
|
||
|
|
||
|
while (rtmp != tmp)
|
||
|
{
|
||
|
*tmp++ = BLANK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
GenOutput1(out, TEXT("%s]\r\n"), otmp);
|
||
|
*tmp = NULLC;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GenOutput(out, TEXT("\r\n"));
|
||
|
}
|
||
|
|
||
|
do
|
||
|
{
|
||
|
if (*tmp)
|
||
|
GenOutput1(out, TEXT("%s"), tmp);
|
||
|
if(!(tmp = fgetsW(text, LINE_LEN+1, hfile)))
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
if (_tcslen(tmp) > 3)
|
||
|
tmp += 3;
|
||
|
}
|
||
|
while (!CNTRL);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
print_help(
|
||
|
int level
|
||
|
)
|
||
|
{
|
||
|
|
||
|
static TCHAR help_key[] = {TEXT("#0")};
|
||
|
TCHAR *tmp;
|
||
|
|
||
|
help_key[1] = (TCHAR)(level) + TEXT('0');
|
||
|
while (!(text[0] == POUND))
|
||
|
if(!fgetsW(text, LINE_LEN+1, hfile))
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
|
||
|
while (text[1] > help_key[1]) {
|
||
|
help_key[1]--;
|
||
|
seek_data(--level, 0);
|
||
|
do {
|
||
|
if (!fgetsW(text, LINE_LEN+1, hfile))
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
} while(!(text[0] == POUND));
|
||
|
}
|
||
|
|
||
|
tmp = &text[2];
|
||
|
*tmp = NEWLINE;
|
||
|
do {
|
||
|
WriteToCon(TEXT("%s"), tmp);
|
||
|
if (!(tmp = fgetsW(text, LINE_LEN+1, hfile)))
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
|
||
|
if (_tcslen(tmp) > 3)
|
||
|
tmp = &text[3];
|
||
|
|
||
|
} while (!CNTRL);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
print_options(int level)
|
||
|
{
|
||
|
|
||
|
static TCHAR help_key[] = {TEXT("$0")};
|
||
|
TCHAR *tmp;
|
||
|
|
||
|
help_key[1] = (TCHAR)(level) + TEXT('0');
|
||
|
while (!(text[0] == DOLLAR))
|
||
|
if(!fgetsW(text, LINE_LEN+1, hfile))
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
|
||
|
while (text[1] > help_key[1]) {
|
||
|
help_key[1]--;
|
||
|
seek_data(--level, 0);
|
||
|
do {
|
||
|
if (!fgetsW(text, LINE_LEN+1, hfile))
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
} while(!(text[0] == DOLLAR));
|
||
|
}
|
||
|
|
||
|
tmp = &text[2];
|
||
|
*tmp = NEWLINE;
|
||
|
do {
|
||
|
WriteToCon(TEXT("%s"), tmp);
|
||
|
if (!(tmp = fgetsW(text, LINE_LEN+1, hfile)))
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
|
||
|
if (_tcslen(tmp) > 3)
|
||
|
tmp = &text[3];
|
||
|
|
||
|
} while (!CNTRL);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
seek_data(int level, int opt_trace)
|
||
|
{
|
||
|
static TCHAR data_key[] = {TEXT(":0")};
|
||
|
static TCHAR option_key[] = {TEXT(".0")};
|
||
|
|
||
|
TCHAR *tmp;
|
||
|
TCHAR *t2;
|
||
|
|
||
|
data_key[1] = (TCHAR)(level) + TEXT('0');
|
||
|
option_key[1] = (TCHAR)(level) + TEXT('1');
|
||
|
|
||
|
do {
|
||
|
if (!(fgetsW(text, LINE_LEN+1, hfile)))
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
|
||
|
if (opt_trace &&
|
||
|
(!(_tcsncmp(option_key, text, DIMENSION(option_key)-1)))) {
|
||
|
tmp = skipwtspc(&text[2]);
|
||
|
t2 = _tcschr(tmp, NEWLINE);
|
||
|
|
||
|
if (t2 == NULL)
|
||
|
{
|
||
|
//
|
||
|
// A line in the help file is longer than LINE_LEN
|
||
|
// so there's no newline character. Not good.
|
||
|
//
|
||
|
ErrorExit(APE_HelpFileError);
|
||
|
}
|
||
|
|
||
|
*t2++ = BLANK;
|
||
|
*t2 = NULLC;
|
||
|
_tcscat(options, tmp);
|
||
|
_tcscat(options, TEXT("| "));
|
||
|
}
|
||
|
|
||
|
} while (_tcsncmp(data_key, text, DIMENSION(data_key)-1));
|
||
|
}
|
||
|
|
||
|
TCHAR FAR *
|
||
|
skipwtspc(TCHAR FAR *s)
|
||
|
{
|
||
|
s += _tcsspn(s, WHITE_SPACE);
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
/* help_helpmsg() -- front end for helpmsg utility
|
||
|
*
|
||
|
* This function acts as a front end for the OS/2 HELPMSG.EXE
|
||
|
* utility for NET errors only. It takes as a parameter a string
|
||
|
* that contains a VALID message id; i.e., of the form NETxxxx
|
||
|
* or xxxx. The string is assumed to have been screened by the
|
||
|
* IsMsgid() function in grammar.c before coming here.
|
||
|
|
||
|
JonN 3/31/00 98273: NETCMD: Need to fix the mapping of error 3521
|
||
|
|
||
|
Before the checkin for 22391, NET1.EXE read errors
|
||
|
NERR_BASE (2100) <= err < APPERR2_BASE (4300) from NETMSG.DLL,
|
||
|
and all others from FORMAT_MESSAGE_FROM_SYSTEM.
|
||
|
After the checkin for 22391, NET1.EXE read errors
|
||
|
NERR_BASE (2100) < err < MAX_NERR (2999) from NETMSG.DLL,
|
||
|
and all others from FORMAT_MESSAGE_FROM_SYSTEM.
|
||
|
|
||
|
On closer examination, NETMSG.DLL currently appears to contain messages from
|
||
|
0x836 (2102) to 0x169F (5791).
|
||
|
This is consistent with lmcons.h:
|
||
|
#define MIN_LANMAN_MESSAGE_ID NERR_BASE
|
||
|
#define MAX_LANMAN_MESSAGE_ID 5799
|
||
|
|
||
|
It looks like we have a basic contradiction here:
|
||
|
|
||
|
3001:
|
||
|
FORMAT_MESSAGE_FROM_SYSTEM: The specified printer driver is currently in use.
|
||
|
NETMSG.DLL: *** errors were logged in the last *** minutes.
|
||
|
|
||
|
3521:
|
||
|
FORMAT_MESSAGE_FROM_SYSTEM: not found
|
||
|
NETMSG.DLL: The *** service is not started.
|
||
|
|
||
|
So what do we do with the error messages in the range
|
||
|
MAX_NERR (2999) < err <= MAX_LANMAN_MESSAGE_ID
|
||
|
? The best error message could be in either one.
|
||
|
Perhaps we should try FORMAT_MESSAGE_FROM_SYSTEM, and if that fails
|
||
|
fall back to NETMSG.DLL.
|
||
|
|
||
|
*/
|
||
|
VOID NEAR pascal
|
||
|
help_helpmsg(TCHAR *msgid)
|
||
|
{
|
||
|
USHORT err;
|
||
|
TCHAR * temp = msgid;
|
||
|
|
||
|
/* first, filter out non-NET error msgs */
|
||
|
|
||
|
/* if msgid begins with a string */
|
||
|
if (!IsNumber(msgid)) { /* compare it against NET */
|
||
|
if (_tcsnicmp(msgid, NET_KEYWORD, NET_KEYWORD_SIZE)) {
|
||
|
ErrorExitInsTxt(APE_BAD_MSGID, msgid);
|
||
|
}
|
||
|
else
|
||
|
temp += NET_KEYWORD_SIZE;
|
||
|
}
|
||
|
|
||
|
if (n_atou(temp, &err))
|
||
|
ErrorExitInsTxt(APE_BAD_MSGID, msgid);
|
||
|
|
||
|
/* First try FORMAT_MESSAGE_FROM_SYSTEM unless the error is in the range
|
||
|
NERR_BASE <= err <= MAX_NERR */
|
||
|
if (err < NERR_BASE || err > MAX_NERR)
|
||
|
{
|
||
|
LPWSTR lpMessage = NULL ;
|
||
|
|
||
|
if (!FormatMessageW(
|
||
|
FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
|
||
|
NULL,
|
||
|
err,
|
||
|
0,
|
||
|
(LPWSTR)&lpMessage,
|
||
|
1024,
|
||
|
NULL))
|
||
|
{
|
||
|
// defer error message and fall back to NETMSG.DLL
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
WriteToCon(TEXT("\r\n%s\r\n"), lpMessage);
|
||
|
(void) LocalFree((HLOCAL)lpMessage) ;
|
||
|
return ;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* skip NETMSG.DLL if error message is way out of range */
|
||
|
if (err < NERR_BASE || err > MAX_MSGID) {
|
||
|
ErrorExitInsTxt(APE_BAD_MSGID, msgid);
|
||
|
}
|
||
|
|
||
|
/* read from NETMSG.DLL */
|
||
|
PrintNL();
|
||
|
|
||
|
//
|
||
|
// If PrintMessage can't find the message id, don't try the expl
|
||
|
//
|
||
|
|
||
|
if (PrintMessage(g_hStdOut, MESSAGE_FILENAME, err, StarStrings, 9) == NO_ERROR)
|
||
|
{
|
||
|
PrintNL();
|
||
|
|
||
|
PrintMessageIfFound(g_hStdOut, HELP_MSG_FILENAME, err, StarStrings, 9);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* returns line from file (no CRLFs); returns NULL if EOF
|
||
|
*/
|
||
|
|
||
|
LPWSTR
|
||
|
fgetsW(
|
||
|
LPWSTR buf,
|
||
|
int len,
|
||
|
FILE *fh
|
||
|
)
|
||
|
{
|
||
|
int c = 0;
|
||
|
TCHAR *pch;
|
||
|
int cchline;
|
||
|
DWORD cchRead;
|
||
|
|
||
|
pch = buf;
|
||
|
cchline = 0;
|
||
|
|
||
|
if (ftell(fh) == 0) {
|
||
|
fread(&c, sizeof(TCHAR), 1, fh);
|
||
|
if (c != 0xfeff)
|
||
|
GenOutput(g_hStdErr, TEXT("help file not Unicode\r\n"));
|
||
|
}
|
||
|
|
||
|
while (TRUE)
|
||
|
{
|
||
|
/*
|
||
|
* for now read in the buffer in ANSI form until Unicode is more
|
||
|
* widely accepted - dee
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
cchRead = fread(&c, sizeof(TCHAR), 1, fh);
|
||
|
|
||
|
//
|
||
|
// if there are no more characters, end the line
|
||
|
//
|
||
|
|
||
|
if (cchRead < 1)
|
||
|
{
|
||
|
c = EOF;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// if we see a \r, we ignore it
|
||
|
//
|
||
|
|
||
|
if (c == TEXT('\r'))
|
||
|
continue;
|
||
|
|
||
|
//
|
||
|
// if we see a \n, we end the line
|
||
|
//
|
||
|
|
||
|
if (c == TEXT('\n')) {
|
||
|
*pch++ = (TCHAR) c;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// if the char is not a tab, store it
|
||
|
//
|
||
|
|
||
|
if (c != TEXT('\t'))
|
||
|
{
|
||
|
*pch = (TCHAR) c;
|
||
|
pch++;
|
||
|
cchline++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// if the line is too long, end it now
|
||
|
//
|
||
|
|
||
|
if (cchline >= len - 1) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// end the line
|
||
|
//
|
||
|
|
||
|
*pch = (TCHAR) 0;
|
||
|
|
||
|
//
|
||
|
// return NULL at EOF with nothing read
|
||
|
//
|
||
|
|
||
|
return ((c == EOF) && (pch == buf)) ? NULL : buf;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Build the fully qualified path name of a file that lives with the exe
|
||
|
// Used by LUI_GetHelpFileName
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
GetFileName(
|
||
|
LPTSTR FileName,
|
||
|
DWORD BufferLength,
|
||
|
LPTSTR FilePartName
|
||
|
)
|
||
|
{
|
||
|
|
||
|
TCHAR ExeFileName[MAX_PATH];
|
||
|
PTCHAR pch;
|
||
|
|
||
|
//
|
||
|
// Get the fully qualified path name of where the exe lives
|
||
|
//
|
||
|
|
||
|
if (!GetModuleFileName(NULL, ExeFileName, DIMENSION(ExeFileName)))
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// get rid of the file name part
|
||
|
//
|
||
|
|
||
|
pch = _tcsrchr(ExeFileName, '\\');
|
||
|
|
||
|
if (!pch)
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
*(pch+1) = NULLC;
|
||
|
|
||
|
//
|
||
|
// Copy the path name into the string and add the help filename part
|
||
|
// but first make sure it's not too big for the user's buffer
|
||
|
//
|
||
|
|
||
|
if (_tcslen(ExeFileName) + _tcslen(FilePartName) + 1 > BufferLength)
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
_tcscpy(FileName, ExeFileName);
|
||
|
_tcscat(FileName, FilePartName);
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the help file name
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
GetHelpFileName(
|
||
|
LPTSTR HelpFileName,
|
||
|
DWORD BufferLength
|
||
|
)
|
||
|
{
|
||
|
|
||
|
TCHAR LocalizedFileName[MAX_PATH];
|
||
|
DWORD LocalizedFileNameID;
|
||
|
switch(GetConsoleOutputCP()) {
|
||
|
case 932:
|
||
|
case 936:
|
||
|
case 949:
|
||
|
case 950:
|
||
|
LocalizedFileNameID = APE2_FE_NETCMD_HELP_FILE;
|
||
|
break;
|
||
|
default:
|
||
|
LocalizedFileNameID = APE2_US_NETCMD_HELP_FILE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (LUI_GetMsg(LocalizedFileName, DIMENSION(LocalizedFileName),
|
||
|
LocalizedFileNameID))
|
||
|
{
|
||
|
return GetFileName(HelpFileName, BufferLength, TEXT("NET.HLP"));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return GetFileName(HelpFileName, BufferLength, LocalizedFileName);
|
||
|
}
|
||
|
}
|