windows-nt/Source/XPSP1/NT/ds/nw/convert/nwconv/utils.c
2020-09-26 16:20:57 +08:00

831 lines
18 KiB
C

/*++
Copyright (c) 1993-1995 Microsoft Corporation
Module Name:
nwconv.c
Abstract:
Author:
Arthur Hanson (arth) 27-Jul-1994
Revision History:
--*/
#include "globals.h"
LPTSTR alpsz[TOTAL_STRINGS]; // String resource array cache.
static UINT cswitch = 0;
static HCURSOR hCursor;
/////////////////////////////////////////////////////////////////////////
LPTSTR
Lids(
WORD idsStr
)
/*++
Routine Description:
Returns the requested string from the string table. Caches the
strings in an internal buffer. Will return a NULL string if the
string can't be loaded.
Arguments:
Return Value:
--*/
{
WORD idsString;
static TCHAR szEmpty[] = TEXT("");
TCHAR Buffer[MAX_STRING_SIZE];
WORD nLen;
LPTSTR lpsz;
idsString = idsStr - IDS_STRINGBASE;
if ((idsString == 0) ||( idsString > TOTAL_STRINGS))
return(szEmpty);
// -1 index as table is 0 based and 0 is not a valid string ID.
if (alpsz[idsString-1])
return((LPTSTR)alpsz[idsString-1]);
if (!(nLen = (WORD) LoadString(hInst, idsStr, (LPTSTR) Buffer, MAX_STRING_SIZE)))
return(szEmpty);
if (!(lpsz = AllocMemory((nLen+1) * sizeof(TCHAR))))
return(szEmpty);
lstrcpy((LPTSTR)lpsz, (LPTSTR) Buffer);
return (alpsz[idsString-1] = lpsz);
} // Lids
/////////////////////////////////////////////////////////////////////////
VOID
StringTableDestroy()
/*++
Routine Description:
Frees up all the memory allocated in the string table.
Arguments:
Return Value:
--*/
{
int i;
for (i=0; i < TOTAL_STRINGS ; i++ ) {
if (alpsz[i]) {
FreeMemory(alpsz[i]);
alpsz[i]=NULL;
}
}
} // StringTableDestroy
/////////////////////////////////////////////////////////////////////////
VOID
CursorHourGlass()
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
if (!cswitch) {
hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
ShowCursor(TRUE);
}
cswitch++;
} // CursorHourGlass
/////////////////////////////////////////////////////////////////////////
VOID
CursorNormal()
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
if (cswitch == 0)
return;
cswitch--;
if (!cswitch) {
ShowCursor(FALSE);
SetCursor(hCursor);
}
} // Cursor Normal
/////////////////////////////////////////////////////////////////////////
BOOL
BitTest(
int Bit,
BYTE *Bits
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
int i, j;
i = Bit / 8;
j = Bit % 8;
if ((Bits[i] >> j) & 0x01)
return TRUE;
else
return FALSE;
} // BitTest
/////////////////////////////////////////////////////////////////////////
BOOL
CenterWindow(
HWND hwndChild,
HWND hwndParent
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
RECT rChild, rParent;
int wChild, hChild, wParent, hParent;
int wScreen, hScreen, xNew, yNew;
HDC hdc;
// Get the Height and Width of the child window
GetWindowRect (hwndChild, &rChild);
wChild = rChild.right - rChild.left;
hChild = rChild.bottom - rChild.top;
// Get the Height and Width of the parent window
GetWindowRect (hwndParent, &rParent);
wParent = rParent.right - rParent.left;
hParent = rParent.bottom - rParent.top;
// Get the display limits
hdc = GetDC (hwndChild);
wScreen = GetDeviceCaps (hdc, HORZRES);
hScreen = GetDeviceCaps (hdc, VERTRES);
ReleaseDC (hwndChild, hdc);
// Calculate new X position, then adjust for screen
xNew = rParent.left + ((wParent - wChild) /2);
if (xNew < 0)
xNew = 0;
else if ((xNew+wChild) > wScreen)
xNew = wScreen - wChild;
// Calculate new Y position, then adjust for screen
yNew = rParent.top + ((hParent - hChild) /2);
if (yNew < 0)
yNew = 0;
else if ((yNew+hChild) > hScreen)
yNew = hScreen - hChild;
// Set it, and return
return SetWindowPos (hwndChild, NULL, xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
} // CenterWindow
/////////////////////////////////////////////////////////////////////////
TCHAR *
lstrchr(
LPTSTR String,
TCHAR c
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
TCHAR *ptrChar = String;
BOOL Found = FALSE;
while(*ptrChar && !Found) {
if (*ptrChar == c)
Found = TRUE;
else
ptrChar++;
}
if (Found)
return ptrChar;
else
return NULL;
} // lstrchr
/////////////////////////////////////////////////////////////////////////
BOOL
IsPath(
LPTSTR Path
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
ULONG len;
LPTSTR ptr;
len = lstrlen(Path);
if (len < 2) // must have a slash and character
return FALSE;
// now know path is at least 2 characters long
ptr = Path;
// if slash anywhere then it has to be a path
while (*ptr)
if (*ptr == TEXT('\\'))
return TRUE;
else
ptr++;
// no slash - unless this is a drive then it aint no path.
if (Path[1] == TEXT(':'))
return TRUE;
return FALSE;
} // IsPath
/////////////////////////////////////////////////////////////////////////
LPTSTR
lToStr(
ULONG Number
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
static TCHAR String[15];
TCHAR tString[15];
LPTSTR sptr, dptr;
ULONG Count;
sptr = String;
dptr = tString;
wsprintf(tString, TEXT("%lu"), Number);
Count = lstrlen(tString);
*sptr++ = *dptr++;
Count--;
while (*dptr) {
if (!(Count % 3))
*sptr++ = TEXT(',');
*sptr++ = *dptr++;
Count--;
}
*sptr = TEXT('\0');
return String;
} // lToStr;
/////////////////////////////////////////////////////////////////////////
LPTSTR
TimeToStr(
ULONG TotTime
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
static TCHAR String[10];
ULONG Hours, Minutes, Seconds;
Hours = TotTime / 3600;
TotTime -= (Hours * 3600);
Minutes = TotTime / 60;
Seconds = TotTime - (Minutes * 60);
wsprintf(String, TEXT("%3lu:%2lu:%2lu"), Hours, Minutes, Seconds);
return String;
} // TimeToStr;
/////////////////////////////////////////////////////////////////////////
LPTSTR
DateToStr(
ULONG TotTime
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
static TCHAR String[10];
ULONG Hours, Minutes, Seconds;
Hours = TotTime / 3600;
TotTime -= (Hours * 3600);
Minutes = TotTime / 60;
Seconds = TotTime - (Minutes * 60);
wsprintf(String, TEXT("%3lu:%2lu:%2lu"), Hours, Minutes, Seconds);
return String;
} // DateToStr;
/*+-----------------------------------------------------------------------+
| Took the _splitpath and _makepath routines and converted them to |
| be NT (long file name) and Unicode friendly. |
+-----------------------------------------------------------------------+*/
/////////////////////////////////////////////////////////////////////////
VOID
lsplitpath(
const TCHAR *path,
TCHAR *drive,
TCHAR *dir,
TCHAR *fname,
TCHAR *ext
)
/*++
Routine Description:
Splits a path name into its individual components
Arguments:
path - pointer to path name to be parsed
drive - pointer to buffer for drive component, if any
dir - pointer to buffer for subdirectory component, if any
fname - pointer to buffer for file base name component, if any
ext - pointer to buffer for file name extension component, if any
Return Value:
drive - pointer to drive string. Includes ':' if a drive was given.
dir - pointer to subdirectory string. Includes leading and
trailing '/' or '\', if any.
fname - pointer to file base name
ext - pointer to file extension, if any. Includes leading '.'.
--*/
{
TCHAR *p;
TCHAR *last_slash = NULL, *dot = NULL;
unsigned len;
// init these so we don't exit with bogus values
drive[0] = TEXT('\0');
dir[0] = TEXT('\0');
fname[0] = TEXT('\0');
ext[0] = TEXT('\0');
if (path[0] == TEXT('\0'))
return;
/*+---------------------------------------------------------------------+
| Assume that the path argument has the following form, where any or |
| all of the components may be missing. |
| |
| <drive><dir><fname><ext> |
| |
| drive: |
| 0 to MAX_DRIVE-1 characters, the last of which, if any, is a |
| ':' or a '\' in the case of a UNC path. |
| dir: |
| 0 to _MAX_DIR-1 characters in the form of an absolute path |
| (leading '/' or '\') or relative path, the last of which, if |
| any, must be a '/' or '\'. E.g - |
| |
| absolute path: |
| \top\next\last\ ; or |
| /top/next/last/ |
| relative path: |
| top\next\last\ ; or |
| top/next/last/ |
| Mixed use of '/' and '\' within a path is also tolerated |
| fname: |
| 0 to _MAX_FNAME-1 characters not including the '.' character |
| ext: |
| 0 to _MAX_EXT-1 characters where, if any, the first must be a |
| '.' |
+---------------------------------------------------------------------+*/
// extract drive letter and :, if any
if ( path[0] && (path[1] == TEXT(':')) ) {
if (drive) {
drive[0] = path[0];
drive[1] = path[1];
drive[2] = TEXT('\0');
}
path += 2;
}
// if no drive then check for UNC pathname
if (drive[0] == TEXT('\0'))
if ((path[0] == TEXT('\\')) && (path[1] == TEXT('\\'))) {
// got a UNC path so put server-sharename into drive
drive[0] = path[0];
drive[1] = path[1];
path += 2;
p = &drive[2];
while ((*path != TEXT('\0')) && (*path != TEXT('\\')))
*p++ = *path++;
if (*path == TEXT('\0'))
return;
// now sitting at the share - copy this as well (copy slash first)
*p++ = *path++;
while ((*path != TEXT('\0')) && (*path != TEXT('\\')))
*p++ = *path++;
// tack on terminating NULL
*p = TEXT('\0');
}
/*+---------------------------------------------------------------------+
| extract path string, if any. Path now points to the first character|
| of the path, if any, or the filename or extension, if no path was |
| specified. Scan ahead for the last occurence, if any, of a '/' or |
| '\' path separator character. If none is found, there is no path. |
| We will also note the last '.' character found, if any, to aid in |
| handling the extension. |
+---------------------------------------------------------------------+*/
for (last_slash = NULL, p = (TCHAR *)path; *p; p++) {
if (*p == TEXT('/') || *p == TEXT('\\'))
// point to one beyond for later copy
last_slash = p + 1;
else if (*p == TEXT('.'))
dot = p;
}
if (last_slash) {
// found a path - copy up through last_slash or max. characters allowed,
// whichever is smaller
if (dir) {
len = (USHORT) __min((last_slash - path), (_MAX_DIR - 1));
lstrcpyn(dir, path, len + 1);
dir[len] = TEXT('\0');
}
path = last_slash;
}
/*+---------------------------------------------------------------------+
| extract file name and extension, if any. Path now points to the |
| first character of the file name, if any, or the extension if no |
| file name was given. Dot points to the '.' beginning the extension,|
| if any. |
+---------------------------------------------------------------------+*/
if (dot && (dot >= path)) {
// found the marker for an extension - copy the file name up to the
// '.'.
if (fname) {
len = (USHORT) __min((dot - path), (_MAX_FNAME - 1));
lstrcpyn(fname, path, len + 1);
*(fname + len) = TEXT('\0');
}
// now we can get the extension - remember that p still points to the
// terminating nul character of path.
if (ext) {
len = (USHORT) __min((p - dot), (_MAX_EXT - 1));
lstrcpyn(ext, dot, len + 1);
ext[len] = TEXT('\0');
}
}
else {
// found no extension, give empty extension and copy rest of string
// into fname.
if (fname) {
len = (USHORT) __min((p - path), (_MAX_FNAME - 1));
lstrcpyn(fname, path, len + 1);
fname[len] = TEXT('\0');
}
if (ext) {
*ext = TEXT('\0');
}
}
} // lsplitpath
/////////////////////////////////////////////////////////////////////////
VOID
lmakepath(
TCHAR *path,
const TCHAR *drive,
const TCHAR *dir,
const TCHAR *fname,
const TCHAR *ext
)
/*++
Routine Description:
create a path name from its individual components.
Arguments:
char *path - pointer to buffer for constructed path
char *drive - pointer to drive component, may or may not contain
trailing ':'
char *dir - pointer to subdirectory component, may or may not include
leading and/or trailing '/' or '\' characters
char *fname - pointer to file base name component
char *ext - pointer to extension component, may or may not contain
a leading '.'.
Return Value:
path - pointer to constructed path name
--*/
{
const TCHAR *p;
/*+---------------------------------------------------------------------+
| we assume that the arguments are in the following form (although we |
| do not diagnose invalid arguments or illegal filenames (such as |
| names longer than 8.3 or with illegal characters in them) |
| |
| drive: |
| A or A: |
| dir: |
| \top\next\last\ ; or |
| /top/next/last/ ; or |
| |
| either of the above forms with either/both the leading and |
| trailing / or \ removed. Mixed use of '/' and '\' is also |
| tolerated |
| fname: |
| any valid file name |
| ext: |
| any valid extension (none if empty or null ) |
+---------------------------------------------------------------------+*/
// copy drive
if (drive && *drive)
while (*drive)
*path++ = *drive++;
// copy dir
if ((p = dir) && *p) {
do {
*path++ = *p++;
}
while (*p);
if ((*(p-1) != TEXT('/')) && (*(p-1) != TEXT('\\'))) {
*path++ = TEXT('\\');
}
}
// copy fname
if (p = fname) {
while (*p) {
*path++ = *p++;
}
}
// copy ext, including 0-terminator - check to see if a '.' needs to be
// inserted.
if (p = ext) {
if (*p && *p != TEXT('.')) {
*path++ = TEXT('.');
}
while (*path++ = *p++)
;
}
else {
// better add the 0-terminator
*path = TEXT('\0');
}
} // lmakepath
#ifndef _UNICODE
#error "Function below not DBCS safe"
#endif
VOID
EscapeFormattingChars(
LPTSTR String,
ULONG BufferLength
)
/*++
Routine Description:
Escapes any formatting chars (ie. % chars) in the string so
if you sprintf it, you dont trap out as a result of trying to
access bogus stack data.
Arguments:
String - String to fix up. Escaping is done IN PLACE.
BufferLength - Size of the buffer the string is in. We need to know
this since we are inserting characters. BufferLength is in
characters, not bytes.
Return Value:
None
--*/
{
ULONG Length; LONG Avail ;
LPTSTR End, Tmp = String ;
if (!Tmp)
return ;
Length = lstrlen(String) ;
//
// Point past end of string. We use this to figure out
// via pointer substraction how much needs to be shifted
// down as we insert chars.
//
End = Tmp + Length + 1 ;
//
// How much is avail for escape chars
//
Avail = BufferLength - (Length+1) ;
while (*Tmp) {
if (*Tmp == TEXT('%')) {
//
// If no more space, just change to '_'.
//
if (Avail <= 0) {
*Tmp = TEXT('_') ;
}
else {
//
// Move string over and add escape character.
// This is not very efficient but we assume
// that this is not common.
//
--Avail ;
memmove(Tmp+1,
Tmp,
(UINT) (End - Tmp)) ;
*Tmp = TEXT('%') ;
Tmp++ ;
}
}
++Tmp ;
}
}