|
|
/********************************************************************/ /** 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 * IsNumber() 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;
if (!IsNumber(msgid)) { ErrorExitInsTxt(APE_BAD_MSGID, msgid); }
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) { //
// Help file isn't Unicode
//
ErrorExit(APE_HelpFileError); } }
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 + 1] = {0}; PTCHAR pch;
//
// Get the fully qualified path name of where the exe lives
//
if (!GetModuleFileName(NULL, ExeFileName, DIMENSION(ExeFileName) - 1)) { 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); } }
|