879 lines
20 KiB
C
879 lines
20 KiB
C
/*++
|
||
|
||
Copyright (c) 1994 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
StrUtils.C
|
||
|
||
Abstract:
|
||
|
||
String utility functions
|
||
|
||
Author:
|
||
|
||
Bob Watson (a-robw)
|
||
|
||
Revision History:
|
||
|
||
24 Jun 94 Written
|
||
|
||
--*/
|
||
//
|
||
// Windows Include Files
|
||
//
|
||
|
||
#include <windows.h>
|
||
#include <stdio.h>
|
||
#include <malloc.h>
|
||
#include <tchar.h> // unicode macros
|
||
#include <stdlib.h> // string to number conversions
|
||
//
|
||
// app include files
|
||
//
|
||
#include "otnboot.h"
|
||
#include "otnbtdlg.h"
|
||
//
|
||
// Local constants
|
||
//
|
||
#define NUM_BUFS 8
|
||
|
||
BOOL
|
||
MatchFirst (
|
||
IN LPCTSTR szStringA,
|
||
IN LPCTSTR szStringB
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
performs a case in-sensitive comparison of the two strings to
|
||
the extent of the shortest string. If, up to the length
|
||
of the shortest string, the strings match then TRUE is
|
||
returned otherwise FALSE is returned.
|
||
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szStringA,
|
||
pointer to first string
|
||
|
||
IN LPCTSTR szStringB
|
||
pointer to second string
|
||
|
||
Return Value:
|
||
|
||
TRUE if match found
|
||
FALSE if not
|
||
|
||
--*/
|
||
{
|
||
LPTSTR szAptr; // pointer to char in szStringA to compare
|
||
LPTSTR szBptr; // pointer to char in szStringB to compare
|
||
|
||
if ((szStringA != NULL) && (szStringB != NULL)) {
|
||
szAptr = (LPTSTR)szStringA;
|
||
szBptr = (LPTSTR)szStringB;
|
||
while ((*szBptr != 0) && (*szAptr != 0)) {
|
||
if (_totlower(*szBptr) != _totlower(*szAptr)) break;
|
||
szBptr++;
|
||
szAptr++;
|
||
}
|
||
if (((*szAptr == 0) && ((*szBptr == 0) || (*szBptr == cBackslash))) ||
|
||
((*szBptr == 0) && ((*szAptr == 0) || (*szAptr == cBackslash)))) {
|
||
// then a matched directoryto the end of the shortest string
|
||
return TRUE;
|
||
} else {
|
||
return FALSE;
|
||
}
|
||
} else {
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
DWORD
|
||
GetSizeFromInfString (
|
||
IN LPCTSTR szString
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads the estimated size of the directory tree as stored in the
|
||
inf file. The format of the INF string is:
|
||
|
||
key=entry
|
||
where:
|
||
key = subdir name
|
||
entry = NumberOfFiles,TotalBytes
|
||
|
||
value must be less than 2**32
|
||
|
||
Arguments:
|
||
|
||
"entry" string read from INF file
|
||
|
||
|
||
Return Value:
|
||
|
||
DWORD value of TotalBytes in entry
|
||
|
||
--*/
|
||
{
|
||
LPTSTR szSize; // size string parsed from input string
|
||
LPTSTR szLastChar; // beginning of size value in string
|
||
|
||
// size is second param in comma separated list
|
||
// go to first comma
|
||
szSize = (LPTSTR)szString;
|
||
while ((*szSize != cComma) && (*szSize != 0)) szSize++;
|
||
szSize++; // go to first char after comma
|
||
return _tcstoul (szSize, &szLastChar, 10);
|
||
}
|
||
|
||
BOOL
|
||
SavePathToRegistry (
|
||
LPCTSTR szPath,
|
||
LPCTSTR szServerKey,
|
||
LPCTSTR szShareKey
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
splits the path (which must be a UNC path) into server & sharepoint
|
||
for loading into the system registry. The key used is the
|
||
\HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Network
|
||
and the NCAdmin key is created (if it doesn't exist) under which the
|
||
Server is stored in the szServerKey value and the share point is
|
||
stored under the szShareKey value
|
||
|
||
Arguments:
|
||
|
||
LPCTSTR szPath
|
||
UNC path to store
|
||
|
||
LPCTSTR szServerKey
|
||
name of registry value to store server under
|
||
|
||
LPCTSTR szShareKey
|
||
name of registry value to store share under
|
||
|
||
Return Value:
|
||
|
||
TRUE values stored OK
|
||
FALSE values not stored
|
||
|
||
--*/
|
||
{
|
||
TCHAR szMachine[MAX_COMPUTERNAME_LENGTH+1]; // computer name buffer
|
||
LPTSTR szShare; // share name buffer
|
||
HKEY hkeyUserInfo; // registry key
|
||
HKEY hkeyAppInfo; // registry key
|
||
|
||
LONG lStatus; // local function status
|
||
BOOL bReturn; // return value of this fn
|
||
DWORD dwAppKeyDisp; // create/existing value
|
||
|
||
szShare = GlobalAlloc (GPTR, MAX_PATH_BYTES);
|
||
if (szShare == NULL) {
|
||
// unable to alloc memory.
|
||
return FALSE;
|
||
}
|
||
|
||
if (IsUncPath (szPath)) {
|
||
// open registry key containing net apps
|
||
|
||
lStatus = RegOpenKeyEx (
|
||
HKEY_CURRENT_USER,
|
||
cszUserInfoKey,
|
||
0L,
|
||
KEY_READ,
|
||
&hkeyUserInfo);
|
||
|
||
if (lStatus != ERROR_SUCCESS) {
|
||
// unable to open key so return error
|
||
bReturn = FALSE;
|
||
} else {
|
||
// open registry key containing this app's info
|
||
lStatus = RegCreateKeyEx (
|
||
hkeyUserInfo,
|
||
szAppName,
|
||
0L,
|
||
(LPTSTR)cszEmptyString,
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_WRITE,
|
||
NULL,
|
||
&hkeyAppInfo,
|
||
&dwAppKeyDisp);
|
||
|
||
if (lStatus != ERROR_SUCCESS) {
|
||
// unable to open key so return false
|
||
bReturn = FALSE;
|
||
} else {
|
||
if (!GetServerFromUnc (szPath, szMachine)) {
|
||
// unable to read share so clear value
|
||
szMachine[0] = 0;
|
||
}
|
||
// get server name from registry
|
||
lStatus = RegSetValueEx (
|
||
hkeyAppInfo,
|
||
(LPTSTR)szServerKey,
|
||
0L,
|
||
REG_SZ,
|
||
(LPBYTE)&szMachine[0],
|
||
(DWORD)(lstrlen(szMachine)*sizeof(TCHAR)));
|
||
|
||
if (lStatus == ERROR_SUCCESS) {
|
||
if (!GetShareFromUnc (szPath, szShare)) {
|
||
szShare[0] = 0;
|
||
}
|
||
|
||
lStatus = RegSetValueEx (
|
||
hkeyAppInfo,
|
||
(LPTSTR)szShareKey,
|
||
0L,
|
||
REG_SZ,
|
||
(LPBYTE)&szShare[0],
|
||
(DWORD)(lstrlen(szShare)*sizeof(TCHAR)));
|
||
|
||
if (lStatus == ERROR_SUCCESS) {
|
||
bReturn = TRUE;
|
||
} else {
|
||
bReturn = FALSE;
|
||
}
|
||
} else {
|
||
bReturn = FALSE;
|
||
}
|
||
|
||
RegCloseKey (hkeyAppInfo);
|
||
}
|
||
RegCloseKey (hkeyUserInfo);
|
||
}
|
||
|
||
bReturn = TRUE;
|
||
} else {
|
||
// not a UNC path so return error
|
||
bReturn = FALSE;
|
||
}
|
||
|
||
FREE_IF_ALLOC (szShare);
|
||
return bReturn;
|
||
|
||
}
|
||
|
||
DWORD
|
||
QuietGetPrivateProfileString (
|
||
IN LPCTSTR lpszSection, /* address of section name */
|
||
IN LPCTSTR lpszKey, /* address of key name */
|
||
IN LPCTSTR lpszDefault, /* address of default string */
|
||
OUT LPTSTR lpszReturnBuffer, /* address of destination buffer */
|
||
IN DWORD cchReturnBuffer, /* size of destination buffer */
|
||
IN LPCTSTR lpszFile /* address of initialization filename */
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads data from profile file without triggering OS error message if
|
||
unable to access file.
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR lpszSection
|
||
address of section name
|
||
IN LPCTSTR lpszKey
|
||
address of key name
|
||
IN LPCTSTR lpszDefault
|
||
address of default string
|
||
OUT LPTSTR lpszReturnBuffer
|
||
address of destination buffer
|
||
IN DWORD cchReturnBuffer
|
||
size of destination buffer (in characters)
|
||
IN LPCTSTR lpszFile
|
||
address of initialization filename
|
||
|
||
See HELP on GetPrivateProfileString for details on using these arguments.
|
||
|
||
Return Value:
|
||
|
||
number of characters copied into lpszReturnBuffer.
|
||
|
||
--*/
|
||
{
|
||
DWORD dwReturn;
|
||
UINT nErrorMode;
|
||
|
||
// disable windows error message popup
|
||
nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
|
||
|
||
// call function
|
||
dwReturn = GetPrivateProfileString (
|
||
lpszSection, lpszKey, lpszDefault, lpszReturnBuffer,
|
||
cchReturnBuffer, lpszFile);
|
||
|
||
SetErrorMode (nErrorMode); // restore old error mode
|
||
|
||
return dwReturn;
|
||
}
|
||
|
||
LPCTSTR
|
||
GetKeyFromEntry (
|
||
IN LPCTSTR szEntry
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
copys the "key" from an INF string of the format:
|
||
Key=Value. All text up to, but not including the "="
|
||
is returned.
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szEntry
|
||
line from INF file to process. must be in the format referenced
|
||
above.
|
||
|
||
Return Value:
|
||
|
||
pointer to a read only string that contains the resulting key string.
|
||
|
||
NOTE: this is stored in a static variable and should be copied to a
|
||
local variable for further processing OR before calling this routine
|
||
again.
|
||
|
||
--*/
|
||
{
|
||
static TCHAR szReturnBuffer[MAX_PATH];
|
||
LPTSTR szSource, szDest;
|
||
|
||
szSource = (LPTSTR)szEntry;
|
||
szDest = &szReturnBuffer[0];
|
||
|
||
*szDest = 0;
|
||
|
||
if (*szSource != 0) {
|
||
// copy all chars from start to the equal sign
|
||
// (or the end of the string)
|
||
while ((*szSource != cEqual) && (*szSource != 0)) {
|
||
*szDest++ = *szSource++;
|
||
}
|
||
*szDest = 0; //terminate destination string (key)
|
||
}
|
||
return szReturnBuffer;
|
||
}
|
||
|
||
LPCTSTR
|
||
GetItemFromEntry (
|
||
IN LPCTSTR szEntry,
|
||
IN DWORD dwItem
|
||
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
returns nth item from comma separated list returned from
|
||
inf file. leaves (double)quoted strings intact.
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szEntry
|
||
entry string returned from INF file
|
||
|
||
IN DWORD dwItem
|
||
1-based index indicating which item to return. (i.e. 1= first item
|
||
in list, 2= second, etc.)
|
||
|
||
|
||
Return Value:
|
||
|
||
pointer to buffer containing desired entry in string. Note, this
|
||
routine may only be called 4 times before the string
|
||
buffer is re-used. (i.e. don't use this function more than
|
||
4 times in another function call!!)
|
||
|
||
--*/
|
||
{
|
||
static TCHAR szReturnBuffer[4][MAX_PATH];
|
||
LPTSTR szSource, szDest;
|
||
DWORD dwThisItem;
|
||
static DWORD dwBuff;
|
||
|
||
dwBuff = ++dwBuff % 4; // wrap buffer index
|
||
|
||
szSource = (LPTSTR)szEntry;
|
||
szDest = &szReturnBuffer[dwBuff][0];
|
||
|
||
*szDest = 0;
|
||
|
||
// go past ini key
|
||
while ((*szSource != cEqual) && (*szSource != 0)) szSource++;
|
||
if (*szSource == 0){
|
||
// no equals found so start at beginning
|
||
// presumably this is just the "value"
|
||
szSource = (LPTSTR)szEntry;
|
||
} else {
|
||
szSource++;
|
||
}
|
||
dwThisItem = 1;
|
||
while (dwThisItem < dwItem) {
|
||
if (*szSource != 0) {
|
||
while ((*szSource != cComma) && (*szSource != 0)) {
|
||
if (*szSource == cDoubleQuote) {
|
||
// if this is a quote, then go to the close quote
|
||
szSource++;
|
||
while ((*szSource != cDoubleQuote) && (*szSource != 0)) szSource++;
|
||
}
|
||
if (*szSource != 0) szSource++;
|
||
}
|
||
}
|
||
dwThisItem++;
|
||
if (*szSource != 0) szSource++;
|
||
}
|
||
// copy this entry to the return buffer
|
||
if (*szSource != 0) {
|
||
while ((*szSource != cComma) && (*szSource != 0)) {
|
||
if (*szSource == cDoubleQuote) {
|
||
// if this is a quote, then go to the close quote
|
||
// don't copy quotes!
|
||
szSource++;
|
||
while ((*szSource != cDoubleQuote) && (*szSource != 0)) {
|
||
*szDest++ = *szSource++;
|
||
}
|
||
if (*szSource != 0) szSource++;
|
||
} else {
|
||
*szDest++ = *szSource++;
|
||
}
|
||
}
|
||
*szDest = 0;
|
||
}
|
||
|
||
return &szReturnBuffer[dwBuff][0];
|
||
}
|
||
|
||
LPCTSTR
|
||
GetFileNameFromEntry (
|
||
IN LPCTSTR szEntry
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
returns pointer into szEntry where file name is found.
|
||
first character after the ":"
|
||
|
||
Arguments:
|
||
|
||
string containing filename in format of:
|
||
nn:filename.ext
|
||
|
||
Return Value:
|
||
|
||
returns pointer into szEntry where file name is found.
|
||
first character after the ":"
|
||
returns an empty string if no ":" char was found.
|
||
|
||
--*/
|
||
{
|
||
LPTSTR szReturn;
|
||
szReturn = (LPTSTR)szEntry;
|
||
// go to COLON character
|
||
while ((*szReturn != cColon) && (*szReturn != 0)) szReturn++;
|
||
// scoot to next char
|
||
if (*szReturn != 0) szReturn++;
|
||
return szReturn;
|
||
}
|
||
|
||
BOOL
|
||
TrimSpaces (
|
||
IN OUT LPTSTR szString
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Trims leading and trailing spaces from szString argument, modifying
|
||
the buffer passed in
|
||
|
||
Arguments:
|
||
|
||
IN OUT LPTSTR szString
|
||
buffer to process
|
||
|
||
Return Value:
|
||
|
||
TRUE if string was modified
|
||
FALSE if not
|
||
|
||
--*/
|
||
{
|
||
LPTSTR szSource;
|
||
LPTSTR szDest;
|
||
LPTSTR szLast;
|
||
BOOL bChars;
|
||
|
||
szLast = szSource = szDest = szString;
|
||
bChars = FALSE;
|
||
|
||
while (*szSource != 0) {
|
||
// skip leading non-space chars
|
||
if (*szSource > cSpace) {
|
||
szLast = szDest;
|
||
bChars = TRUE;
|
||
}
|
||
if (bChars) {
|
||
// remember last non-space character
|
||
// copy source to destination & increment both
|
||
*szDest++ = *szSource++;
|
||
} else {
|
||
szSource++;
|
||
}
|
||
}
|
||
|
||
if (bChars) {
|
||
*++szLast = 0; // terminate after last non-space char
|
||
} else {
|
||
// string was all spaces so return an empty (0-len) string
|
||
*szString = 0;
|
||
}
|
||
|
||
return (szLast != szSource);
|
||
}
|
||
|
||
BOOL
|
||
IsUncPath (
|
||
IN LPCTSTR szPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
examines path as a string looking for "tell-tale" double
|
||
backslash indicating the machine name syntax of a UNC path
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szPath
|
||
path to examine
|
||
|
||
Return Value:
|
||
|
||
TRUE if \\ found at start of string
|
||
FALSE if not
|
||
|
||
--*/
|
||
{
|
||
LPTSTR szPtChar;
|
||
|
||
szPtChar = (LPTSTR)szPath;
|
||
if (*szPtChar == cBackslash) {
|
||
if (*++szPtChar == cBackslash) {
|
||
return TRUE;
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
LPCTSTR
|
||
GetEntryInMultiSz (
|
||
IN LPCTSTR mszList,
|
||
IN DWORD dwEntry
|
||
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Searches for the specified element in the mszList and returns the pointer
|
||
to that element in the list.
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR mszList Multi-SZ list to search
|
||
IN DWORD dwEntry 1-based index of entry to return
|
||
|
||
ReturnValue:
|
||
|
||
!=cszEmptyString pointer to matching element in list
|
||
cszEmptyString (pointer to 0-length string) entry is not in list
|
||
--*/
|
||
{
|
||
LPCTSTR szThisString;
|
||
DWORD dwIndex=0;
|
||
|
||
if (mszList == NULL) return (LPCTSTR)cszEmptyString; // no list to process
|
||
if (dwEntry == 0) return (LPCTSTR)cszEmptyString; // no string to find
|
||
|
||
for (szThisString = mszList;
|
||
*szThisString;
|
||
szThisString += (lstrlen(szThisString)+ 1)) {
|
||
dwIndex++;
|
||
if (dwIndex == dwEntry) {
|
||
return szThisString;
|
||
}
|
||
}
|
||
|
||
return (LPCTSTR)cszEmptyString;
|
||
}
|
||
|
||
DWORD
|
||
AddStringToMultiSz (
|
||
LPTSTR OUT mszDest,
|
||
LPCTSTR IN szSource
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
appends the source string to the end of the destination MULTI_SZ
|
||
string. Assumes that the destination is large enough!
|
||
|
||
Arguments:
|
||
|
||
LPTSTR OUT mszDest multi-sz string to be appended
|
||
LPTSTR IN szSource ASCIZ string to be added to the end of the dest
|
||
string
|
||
|
||
ReturnValue:
|
||
|
||
1
|
||
|
||
--*/
|
||
{
|
||
LPTSTR szDestElem;
|
||
|
||
// check function arguments
|
||
|
||
if ((mszDest == NULL) || (szSource == NULL)) return 0; // invalid buffers
|
||
if (*szSource == '\0') return 0; // no string to add
|
||
|
||
// go to end of dest string
|
||
//
|
||
|
||
for (szDestElem = mszDest;
|
||
*szDestElem;
|
||
szDestElem += (lstrlen(szDestElem)+1));
|
||
|
||
// if here, then add string
|
||
// szDestElem is at end of list
|
||
|
||
lstrcpy (szDestElem, szSource);
|
||
szDestElem += (lstrlen(szDestElem) + 1);
|
||
*szDestElem = '\0'; // add second NULL
|
||
|
||
return 1;
|
||
}
|
||
|
||
DWORD
|
||
StringInMultiSz (
|
||
IN LPCTSTR szString,
|
||
IN LPCTSTR mszList
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Searches each element in the mszList and does a case-insensitive
|
||
comparison with the szString argument.
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szString string to find in list
|
||
IN LPCTSTR mszList list to search
|
||
|
||
ReturnValue:
|
||
|
||
>0 szString was found in the list, # returned is the
|
||
index of the matching entry (1= first)
|
||
0 szString was NOT found
|
||
--*/
|
||
{
|
||
LPTSTR szThisString;
|
||
DWORD dwIndex=0;
|
||
|
||
// check input arguments
|
||
|
||
if ((szString == NULL) || (mszList == NULL)) return 0; // invalid buffer
|
||
if (*szString == 0) return 0; // no string to find
|
||
|
||
for (szThisString = (LPTSTR)mszList;
|
||
*szThisString;
|
||
szThisString += (lstrlen(szThisString)+ 1)) {
|
||
dwIndex++;
|
||
if (lstrcmpi(szThisString, szString) == 0) {
|
||
return dwIndex;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
LPCTSTR
|
||
GetStringResource (
|
||
IN UINT nId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
look up string resource and return string
|
||
|
||
Arguments:
|
||
|
||
IN UINT nId
|
||
Resource ID of string to look up
|
||
|
||
Return Value:
|
||
|
||
pointer to string referenced by ID in arg list
|
||
|
||
--*/
|
||
{
|
||
static TCHAR szBufArray[NUM_BUFS][SMALL_BUFFER_SIZE];
|
||
static DWORD dwIndex;
|
||
LPTSTR szBuffer;
|
||
DWORD dwLength;
|
||
|
||
dwIndex++;
|
||
dwIndex %= NUM_BUFS;
|
||
szBuffer = &szBufArray[dwIndex][0];
|
||
|
||
dwLength = LoadString (
|
||
GetModuleHandle (NULL),
|
||
nId,
|
||
szBuffer,
|
||
SMALL_BUFFER_SIZE);
|
||
|
||
return (LPCTSTR)szBuffer;
|
||
}
|
||
|
||
DWORD
|
||
GetMultiSzLen (
|
||
IN LPCTSTR mszInString
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Counts the number of characters in the multi-sz string (including
|
||
NULL's between strings and terminating NULL char)
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR mszInString
|
||
multi-sz string to count
|
||
|
||
Return Value:
|
||
|
||
number of characters in string
|
||
|
||
--*/
|
||
{
|
||
LPCTSTR szEndChar = mszInString;
|
||
BOOL bEnd = FALSE;
|
||
DWORD dwCharsInString = 0;
|
||
|
||
while (!bEnd) {
|
||
if (*szEndChar == 0) {
|
||
// this is the end of a line so adjust the count to
|
||
// account for the crlf being 2 chars
|
||
szEndChar++;
|
||
dwCharsInString += 2;
|
||
|
||
if (*szEndChar == 0) {
|
||
// this is the end of the MSZ
|
||
dwCharsInString++; // for the CTRL-Z
|
||
bEnd = TRUE;
|
||
}
|
||
} else {
|
||
szEndChar++;
|
||
dwCharsInString++;
|
||
}
|
||
}
|
||
|
||
return dwCharsInString;
|
||
}
|
||
|
||
DWORD
|
||
TranslateEscapeChars (
|
||
IN LPTSTR szNewString,
|
||
IN LPTSTR szString
|
||
)
|
||
/*++
|
||
|
||
Translates the following escape sequences if found in the string.
|
||
The translation is performed on szString and written to szNewString.
|
||
|
||
The return value is the length of the resulting string in characters;
|
||
|
||
--*/
|
||
{
|
||
LPTSTR szSource;
|
||
LPTSTR szDest;
|
||
|
||
szSource = szString;
|
||
szDest = szNewString;
|
||
|
||
while (*szSource != 0) {
|
||
if (*szSource == '\\') {
|
||
// this is an escape sequence so go to the next char
|
||
// and see which one.
|
||
szSource++;
|
||
switch (*szSource) {
|
||
case _T('b'):
|
||
*szDest = _T('\b');
|
||
break;
|
||
|
||
case _T('f'):
|
||
*szDest = _T('\f');
|
||
break;
|
||
|
||
case _T('n'):
|
||
*szDest = _T('\n');
|
||
break;
|
||
|
||
case _T('r'):
|
||
*szDest = _T('\r');
|
||
break;
|
||
|
||
case _T('t'):
|
||
*szDest = _T('\t');
|
||
break;
|
||
|
||
case _T('v'):
|
||
*szDest = _T('\v');
|
||
break;
|
||
|
||
case _T('?'):
|
||
*szDest = _T('\?');
|
||
break;
|
||
|
||
case _T('\''):
|
||
*szDest = _T('\'');
|
||
break;
|
||
|
||
case _T('\"'):
|
||
*szDest = _T('\"');
|
||
break;
|
||
|
||
case _T('\\'):
|
||
*szDest = _T('\\');
|
||
break;
|
||
|
||
default:
|
||
*szDest = *szSource;
|
||
break;
|
||
}
|
||
szDest++;
|
||
szSource++;
|
||
} else {
|
||
// just a plain old character so copy it
|
||
*szDest++ = *szSource++;
|
||
}
|
||
}
|
||
return (DWORD)(szDest - szNewString);
|
||
|
||
}
|