303 lines
7 KiB
C
303 lines
7 KiB
C
|
/* UTILS.C
|
||
|
Resident Code Segment // Tweak: make non-resident?
|
||
|
|
||
|
NoMem string utility routines
|
||
|
String utility routines
|
||
|
|
||
|
Frosting: Master Theme Selector for Windows '95
|
||
|
Copyright (c) 1994-1999 Microsoft Corporation. All rights reserved.
|
||
|
*/
|
||
|
|
||
|
// ---------------------------------------------
|
||
|
// Brief file history:
|
||
|
// Alpha:
|
||
|
// Beta:
|
||
|
// Bug fixes
|
||
|
// ---------
|
||
|
//
|
||
|
// ---------------------------------------------
|
||
|
|
||
|
#include "windows.h"
|
||
|
#include "frost.h"
|
||
|
#include "global.h"
|
||
|
|
||
|
// Local Routines
|
||
|
|
||
|
// Local global vars
|
||
|
TCHAR szNoMem[NUM_NOMEM_STRS][MAX_STRLEN+1];
|
||
|
|
||
|
|
||
|
// InitNoMem
|
||
|
//
|
||
|
// Stores all the no/low memory error messages in the data segment,
|
||
|
// so you're guaranteed to have them when you need them.
|
||
|
//
|
||
|
// Called at init, when we are assured these loads succeed.
|
||
|
//
|
||
|
// Note that this loop shows why the string IDs for the low mem
|
||
|
// messages need to be consecutive and starting with STR_NOT_ENUF,
|
||
|
// as noted in the .H file.
|
||
|
//
|
||
|
|
||
|
void FAR InitNoMem(hinst)
|
||
|
HANDLE hinst;
|
||
|
{
|
||
|
int iter;
|
||
|
|
||
|
for (iter = 0; iter < NUM_NOMEM_STRS; iter++)
|
||
|
LoadString(hinst, STR_NOT_ENUF+iter,
|
||
|
&(szNoMem[iter][0]), MAX_STRLEN);
|
||
|
}
|
||
|
|
||
|
|
||
|
// NoMemMsg
|
||
|
//
|
||
|
// Takes the low memory error string suffix, creates the full string, posts
|
||
|
// a messagebox. We are assured of being able to get a messagebox in low
|
||
|
// memory situations with at least a hand icon.
|
||
|
//
|
||
|
// Note that the second line shows why the string IDs for the low mem
|
||
|
// messages need to be consecutive and starting with STR_NOT_ENUF,
|
||
|
// as noted in the .H file.
|
||
|
//
|
||
|
|
||
|
void FAR NoMemMsg(istr)
|
||
|
int istr;
|
||
|
{
|
||
|
lstrcpy( (LPTSTR)szMsg, (LPCTSTR)&(szNoMem[0][0]) );
|
||
|
lstrcat( (LPTSTR)szMsg, (LPCTSTR)&(szNoMem[istr-STR_NOT_ENUF][0]) );
|
||
|
|
||
|
MessageBox((HWND)hWndApp, (LPCTSTR)szMsg, (LPCTSTR)szAppName,
|
||
|
MB_OK | MB_ICONSTOP | MB_SYSTEMMODAL);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*=============================================================================
|
||
|
FILEFROMPATH returns the filename of given filename which may include path.
|
||
|
Q: International: always same chars for \ and :, or should we do a string
|
||
|
compare with a resource string for each?
|
||
|
Q: International: does lstrlen return chars or bytes to make the first line
|
||
|
work or not?
|
||
|
=============================================================================*/
|
||
|
LPTSTR FAR FileFromPath(lpsz)
|
||
|
LPCTSTR lpsz;
|
||
|
{
|
||
|
LPTSTR lpch;
|
||
|
|
||
|
/* Strip path/drive specification from name if there is one */
|
||
|
lpch = CharPrev((LPCTSTR)lpsz, (LPCTSTR)(lpsz + lstrlen(lpsz)));
|
||
|
while (lpch > lpsz) {
|
||
|
lpch = CharPrev((LPCTSTR)lpsz, (LPCTSTR)lpch);
|
||
|
if (*lpch == TEXT('\\') || *lpch == TEXT(':')) {
|
||
|
lpch = CharNext((LPCTSTR)lpch);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return(lpch);
|
||
|
|
||
|
} /* end FileFromPath */ // JUST FOR INIT DEBUG
|
||
|
|
||
|
// TruncateExt
|
||
|
//
|
||
|
// Utility routine that removes extension from filename
|
||
|
// See International questions above routine.
|
||
|
//
|
||
|
void FAR TruncateExt(LPCTSTR lpstr)
|
||
|
{
|
||
|
LPTSTR lpch;
|
||
|
|
||
|
// find the dot before the extension, truncate from there if found
|
||
|
lpch = CharPrev((LPCTSTR)lpstr, (LPCTSTR)(lpstr + lstrlen(lpstr)));
|
||
|
while (lpch > lpstr) {
|
||
|
lpch = CharPrev((LPCTSTR)lpstr, (LPCTSTR)lpch);
|
||
|
if (*lpch == TEXT('.')) {
|
||
|
*lpch = 0; // null terminate
|
||
|
break; // you're done now EXIT loop
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// FindChar
|
||
|
//
|
||
|
// Subset of a substring search. Just looks for first instance of a single
|
||
|
// character in a string.
|
||
|
//
|
||
|
// Returns: pointer into string you passed, or to its null term if not found
|
||
|
//
|
||
|
LPTSTR FAR FindChar(LPTSTR lpszStr, TCHAR chSearch)
|
||
|
{
|
||
|
LPTSTR lpszScan;
|
||
|
|
||
|
for (lpszScan = lpszStr;
|
||
|
*lpszScan && (*lpszScan != chSearch); // ***DEBUG*** char compare in intl?
|
||
|
lpszScan = CharNext(lpszScan))
|
||
|
{ }
|
||
|
|
||
|
// cleanup
|
||
|
return (lpszScan); // either points to null term or search char
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// ascii to integer conversion routine
|
||
|
//
|
||
|
|
||
|
// ***DEBUG*** int'l: is this true?
|
||
|
// These don't need to be UNICODE/international ready, since they
|
||
|
// *only* deal with strings from the Registry and our own private
|
||
|
// INI files.
|
||
|
|
||
|
/* CAREFUL!! This atoi just IGNORES non-numerics like decimal points!!! */
|
||
|
/* checks for (>=1) leading negative sign */
|
||
|
int FAR latoi( s )
|
||
|
LPSTR s;
|
||
|
{
|
||
|
int n;
|
||
|
LPSTR pS;
|
||
|
BOOL bSeenNum;
|
||
|
BOOL bNeg;
|
||
|
|
||
|
n=0;
|
||
|
bSeenNum = bNeg = FALSE;
|
||
|
|
||
|
for (pS=s; *pS; pS++) {
|
||
|
if ((*pS >= '0') && (*pS <= '9')) {
|
||
|
bSeenNum = TRUE;
|
||
|
n = n*10 + (*pS - '0');
|
||
|
}
|
||
|
if (!bSeenNum && (*pS == '-')) {
|
||
|
bNeg = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (bNeg) {
|
||
|
n = -n;
|
||
|
}
|
||
|
|
||
|
return(n);
|
||
|
}
|
||
|
|
||
|
|
||
|
void lreverse( s )
|
||
|
LPSTR s;
|
||
|
{
|
||
|
LPSTR p1, p2;
|
||
|
char c;
|
||
|
|
||
|
p1 = s;
|
||
|
p2 = (LPSTR)(p1+ lstrlenA((LPSTR) p1 ) - 1 );
|
||
|
|
||
|
while( p1 < p2 ) {
|
||
|
c = *p1;
|
||
|
*p1++ = *p2;
|
||
|
*p2-- = c;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID FAR litoa( n, s )
|
||
|
int n;
|
||
|
LPSTR s;
|
||
|
{
|
||
|
LPSTR pS;
|
||
|
BOOL bNeg = FALSE;
|
||
|
|
||
|
if (n < 0) {
|
||
|
n = -n;
|
||
|
bNeg = TRUE;
|
||
|
}
|
||
|
pS = s;
|
||
|
do {
|
||
|
*pS = n % 10 + '0';
|
||
|
pS++;
|
||
|
} while ( (n /= 10) != 0 );
|
||
|
|
||
|
if (bNeg) {
|
||
|
*pS = '-';
|
||
|
pS++;
|
||
|
}
|
||
|
*pS = '\0';
|
||
|
lreverse( s );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// LongToShortToLong
|
||
|
//
|
||
|
// Can take either as input (?).
|
||
|
// Output string has to be long enough (14 or MAX_PATH)
|
||
|
//
|
||
|
// OK for input and output to be the same string.
|
||
|
//
|
||
|
// Returns: success in finding file
|
||
|
|
||
|
BOOL FAR FilenameToShort(LPTSTR lpszInput, LPTSTR lpszShort)
|
||
|
{
|
||
|
WIN32_FIND_DATA wfdFind;
|
||
|
HANDLE hFind;
|
||
|
|
||
|
// init
|
||
|
hFind = FindFirstFile(lpszInput, (LPWIN32_FIND_DATA)&wfdFind);
|
||
|
if (INVALID_HANDLE_VALUE == hFind) {
|
||
|
*lpszShort = 0; // error null return
|
||
|
return (FALSE); // couldn't find file EXIT
|
||
|
}
|
||
|
|
||
|
// meat
|
||
|
if (wfdFind.cAlternateFileName[0])
|
||
|
lstrcpy(lpszShort, (LPTSTR)wfdFind.cAlternateFileName);
|
||
|
else
|
||
|
// sometimes no alternate given; e.g. if short == long
|
||
|
lstrcpy(lpszShort, (LPTSTR)wfdFind.cFileName);
|
||
|
|
||
|
// cleanup
|
||
|
FindClose(hFind);
|
||
|
Assert(*lpszShort, TEXT("no short filename constructed!\n"))
|
||
|
return (*lpszShort);
|
||
|
}
|
||
|
|
||
|
BOOL FAR FilenameToLong(LPTSTR lpszInput, LPTSTR lpszLong)
|
||
|
{
|
||
|
WIN32_FIND_DATA wfdFind;
|
||
|
HANDLE hFind;
|
||
|
|
||
|
// init
|
||
|
hFind = FindFirstFile(lpszInput, (LPWIN32_FIND_DATA)&wfdFind);
|
||
|
if (INVALID_HANDLE_VALUE == hFind) {
|
||
|
*lpszLong = 0; // error null return
|
||
|
return (FALSE); // couldn't find file EXIT
|
||
|
}
|
||
|
|
||
|
// meat
|
||
|
if (wfdFind.cFileName[0])
|
||
|
lstrcpy(lpszLong, (LPTSTR)wfdFind.cFileName);
|
||
|
else
|
||
|
// sometimes no long name given; e.g. if funny old file
|
||
|
lstrcpy(lpszLong, (LPTSTR)wfdFind.cAlternateFileName);
|
||
|
|
||
|
// cleanup
|
||
|
FindClose(hFind);
|
||
|
Assert(*lpszLong, TEXT("no long filename constructed!\n"))
|
||
|
return (*lpszLong);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// IsValidThemeFile
|
||
|
//
|
||
|
// Answers the question.
|
||
|
//
|
||
|
BOOL FAR IsValidThemeFile(LPTSTR lpTest)
|
||
|
{
|
||
|
extern TCHAR szFrostSection[], szMagic[], szVerify[];
|
||
|
|
||
|
GetPrivateProfileString((LPTSTR)szFrostSection,
|
||
|
(LPTSTR)szMagic,
|
||
|
(LPTSTR)szNULL,
|
||
|
(LPTSTR)szMsg, MAX_MSGLEN,
|
||
|
(LPTSTR)lpTest);
|
||
|
|
||
|
return (!lstrcmp((LPTSTR)szMsg, (LPTSTR)szVerify));
|
||
|
}
|