windows-nt/Source/XPSP1/NT/sdktools/restools/rltools/common/toktrans.c

1018 lines
24 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <tchar.h>
#ifdef RLDOS
#include "dosdefs.h"
#else
#include "windefs.h"
#endif
#include "restok.h"
#include "resread.h"
#include "toklist.h"
#include "commbase.h"
#define MAXLINE 1024
#define MAXTERM 512
extern UCHAR szDHW[];
extern PROJDATA gProj;
extern MSTRDATA gMstr;
#ifdef WIN32
extern HINSTANCE hInst; // Instance of the main window
#else
extern HWND hInst; // Instance of the main window
#endif
static fUnicodeGlossary = FALSE;
static long GetGlossaryIndex( FILE *, TCHAR, long []);
static void ParseGlossEntry( TCHAR *, TCHAR *, TCHAR[], TCHAR *, TCHAR[]);
static void ParseTextHotKeyToBuf( TCHAR *, TCHAR, TCHAR *);
static void ParseBufToTextHotKey( TCHAR *, TCHAR[], TCHAR *);
static WORD NormalizeIndex( TCHAR);
static int MyPutGlossStr( TCHAR *, FILE *);
static TCHAR *MyGetGlossStr( TCHAR *, int, FILE *);
static void BuildGlossEntry( TCHAR *, TCHAR *, TCHAR, TCHAR *, TCHAR);
static BOOL NotAMember( TRANSLIST *, TCHAR *);
FILE * OpenGlossary( CHAR *szGlossFile, CHAR chAccessType)
{
CHAR * szRW[4] = {"rb", "rt", "wb", "wt"};
int nRW = 0; // assume access type is 'r' (read)
FILE *fpRC = NULL;
if ( chAccessType == 'w' ) // is access type 'w' (write)?
{
nRW = fUnicodeGlossary ? 2 : 3; // yes (Unicode file or not?)
}
fpRC = fopen( szGlossFile, szRW[ nRW]);
if ( fpRC && chAccessType == 'r' )
{
USHORT usMark = GetWord( fpRC, NULL);
if ( usMark == 0xfeff )
{
fUnicodeGlossary = TRUE; // it's a Unicode text file
}
else if ( usMark == 0xfffe )
{
QuitA( IDS_WRONGENDIAN, szGlossFile, NULL);
}
else
{
fclose( fpRC);
fpRC = fopen( szGlossFile, szRW[ ++nRW]); // it's an ANSI text file
}
}
return( fpRC);
}
/**
*
*
* Function:
*
*
* Arguments:
*
* Returns:
*
* Errors Codes:
*
* History:
*
*
**/
int MakeGlossIndex( LONG * lFilePointer)
{
TCHAR szGlossEntry[MAXLINE] = TEXT("");
WORD iCurrent = 0;
LONG lFPointer = -1;
FILE *pFile = NULL;
pFile = OpenGlossary( gProj.szGlo, 'r');
if ( pFile == NULL )
{
return( 1);
}
// Glossaries some times have this bogus header at the begining.
// which we want to skip if it exists
if ( ! MyGetGlossStr( szGlossEntry, MAXLINE, pFile) )
{
// Error during first read from the glossary.
fclose( pFile);
return( 1);
}
lFPointer = ftell( pFile);
// check for glossary header
if ( lstrlen( szGlossEntry) >= 7 )
{
// lstrcpy( (TCHAR *)szDHW, szGlossEntry);
// szDHW[ MEMSIZE( 7)] = szDHW[ MEMSIZE( 7) + 1] = '\0';
// CharLower( (TCHAR *)szDHW);
//
// if ( lstrcmp( (TCHAR *)szDHW, TEXT("english")) == 0 )
if ( CompareStringW( MAKELCID( gMstr.wLanguageID, SORT_DEFAULT),
SORT_STRINGSORT | NORM_IGNORECASE,
szGlossEntry,
7,
TEXT("ENGLISH"),
7) == 2 )
{
lFPointer = ftell (pFile);
if ( ! MyGetGlossStr( szGlossEntry, MAXLINE, pFile) )
{
fclose( pFile);
return (1);
}
}
}
// now assume we are at the correct location in glossary
// file to begin generating the index, we want to save
// this location
lFilePointer[0] = lFPointer;
// glossary file is sorted so, any non letter items
// in the glossary would be first. Index into this location
// using the 1st position
// 1st lets make sure we have non letters items in
// the glossary
// now skip ( if any ) the non letter entries in the glossary
while( (WORD) szGlossEntry[0] < (WORD) TEXT('A' ) )
{
if ( ! MyGetGlossStr( szGlossEntry, MAXLINE, pFile) )
{
fclose( pFile);
return( 1);
}
}
// now position at alpha characters
iCurrent = NormalizeIndex( szGlossEntry[0] );
// now we read through the remaining glossary entries
// and save the offsets for each index as we go
do
{
if ( NormalizeIndex( szGlossEntry[0] ) > iCurrent )
{
// we passed the region for our current index
// so save the location, and move to the next index.
// note we may be skiping indexs,
lFilePointer[ iCurrent] = lFPointer;
iCurrent = NormalizeIndex( szGlossEntry[0] );
}
lFPointer = ftell( pFile );
// otherwise the current index is valied for this
// section of the glossary indexes, so just continue
} while ( MyGetGlossStr( szGlossEntry, MAXLINE, pFile) );
fclose( pFile);
return( 0);
}
/**
*
*
* Function: TransString
* Builds a circular linked list containing all translations of a string.
* The first entry in the list is the untranslated string.
*
* Arguments:
* fpGlossFile, handle to open glossary file
* szKeyText, string with the text to build translation table
* szCurrentText, text currently in the box.
* ppTransList, pointer to a pointer to a node in a circular linked list
* lFilePointer, pointer to index table for glossary file
*
* Returns:
* number of nodes in list
*
* Errors Codes:
*
* History:
* Recoded by SteveBl, 3/92
*
**/
/* Translate the string, if possible. */
int TransString(
TCHAR *szKeyText,
TCHAR *szCurrentText,
TRANSLIST **ppTransList,
LONG *lFilePointer)
{
int n = 0;
long lFileIndex;
TRANSLIST **ppCurrentPointer;
static TCHAR szGlossEntry[MAXLINE];
static TCHAR szEngText[260];
static TCHAR szIntlText[260];
TCHAR *szCurText = NULL;
TCHAR cEngHotKey = TEXT('\0');
TCHAR cIntlHotKey = TEXT('\0');
TCHAR cCurHotKey = TEXT('\0');
FILE *fpGlossFile = NULL;
// *Is* there a glossary file?
if ( (fpGlossFile = OpenGlossary( gProj.szGlo, 'r')) == NULL )
{
return( 0);
}
// FIRST let's erase the list
if ( *ppTransList )
{
(*ppTransList)->pPrev->pNext = NULL; // so we can find the end of the list
}
while ( *ppTransList )
{
TRANSLIST *pTemp;
pTemp = *ppTransList;
*ppTransList = pTemp->pNext;
RLFREE( pTemp->sz);
RLFREE( pTemp);
}
ppCurrentPointer = ppTransList;
// DONE removing the list
// Now make the first node (which is the untranslated string)
{
TCHAR * psz;
psz = (TCHAR *)FALLOC( MEMSIZE( lstrlen( szCurrentText) + 1));
lstrcpy( psz,szCurrentText);
*ppTransList = ( TRANSLIST *)FALLOC( sizeof( TRANSLIST));
(*ppTransList)->pPrev = (*ppTransList)->pNext = *ppTransList;
(*ppTransList)->sz = psz;
ppCurrentPointer = ppTransList;
n++;
}
szCurText = (TCHAR *)FALLOC( MEMSIZE( lstrlen( szKeyText) + 1) );
ParseBufToTextHotKey( szCurText, &cCurHotKey, szKeyText);
lFileIndex = GetGlossaryIndex( fpGlossFile, szCurText[0], lFilePointer);
fseek (fpGlossFile, lFileIndex, SEEK_SET);
while ( TRUE)
{
if ( ! MyGetGlossStr( szGlossEntry, MAXLINE, fpGlossFile) )
{
// Reached end of glossary file
RLFREE( szCurText);
fclose( fpGlossFile);
return n;
}
ParseGlossEntry( szGlossEntry,
szEngText,
&cEngHotKey,
szIntlText,
&cIntlHotKey);
// make comparision, using text, and hot keys
// if ( ( ! lstrcmp( szCurText, szEngText )) && cCurHotKey == cEngHotKey )
if ( CompareStringW( MAKELCID( gMstr.wLanguageID, SORT_DEFAULT),
SORT_STRINGSORT,
szCurText,
-1,
szEngText,
-1) == 2
&& cCurHotKey == cEngHotKey )
{
TCHAR * psz;
static TCHAR szTemp[ MAXINPUTBUFFER];
// we have a match, put translated text into token
if ( cIntlHotKey )
{
ParseTextHotKeyToBuf( szIntlText, cIntlHotKey, szTemp);
}
else
{
lstrcpy( szTemp, szIntlText);
}
if ( NotAMember( *ppTransList, szTemp) )
{
// add matched glossary text to circular list of matches
psz = (TCHAR *) FALLOC( MEMSIZE( lstrlen( szTemp) + 1));
lstrcpy( psz,szTemp);
(*ppCurrentPointer)->pNext = (TRANSLIST *)
FALLOC( sizeof( TRANSLIST));
((*ppCurrentPointer)->pNext)->pPrev = *ppCurrentPointer;
ppCurrentPointer = (TRANSLIST **)&((*ppCurrentPointer)->pNext);
(*ppCurrentPointer)->pPrev->pNext = *ppCurrentPointer;
(*ppCurrentPointer)->pNext = *ppTransList;
(*ppTransList)->pPrev = *ppCurrentPointer;
(*ppCurrentPointer)->sz = psz;
++n;
}
}
else
{
// can we terminate search?
// if( lstrcmpi( szEngText, szCurText ) > 0 )
if ( CompareStringW( MAKELCID( gMstr.wLanguageID, SORT_DEFAULT),
SORT_STRINGSORT,
szEngText,
-1,
szCurText,
-1) == 3 )
{
// went past index section
RLFREE( szCurText);
fclose( fpGlossFile);
return( n);
}
}
}
RLFREE( szCurText);
fclose( fpGlossFile);
return( n);
} // TransString
/**
*
*
* Function: NormalizeIndex
*
*
* Arguments:
*
* Returns:
*
* Errors Codes:
*
* History:
*
*
**/
static WORD NormalizeIndex( TCHAR chIndex )
{
TCHAR chTmp = chIndex;
CharLowerBuff( &chTmp, 1);
return( (chTmp != TEXT('"') && chTmp >= TEXT('a') && chTmp <= TEXT('z'))
? chTmp - TEXT('a') + 1
: 0);
}
/*
* Function:NotAMember
*
* Arguments:
* pList, pointer to a TRANSLIST node
* sz, string to find
*
* Returns:
* TRUE if not found in the list else FALSE
*
* History:
* 3/92, implemented SteveBl
**/
static BOOL NotAMember( TRANSLIST *pList, TCHAR *sz)
{
TRANSLIST *pCurrent = pList;
if ( ! pList )
{
return( TRUE); // empty list
}
do
{
// if ( lstrcmp( sz, pCurrent->sz) == 0 )
if ( CompareStringW( MAKELCID( gMstr.wLanguageID, SORT_DEFAULT),
SORT_STRINGSORT,
sz,
-1,
pCurrent->sz,
-1) == 2 )
{
return( FALSE); // found in list
}
pCurrent = pCurrent->pNext;
}while ( pList != pCurrent );
return( TRUE); // not found
}
/**
*
*
* Function:
*
*
* Arguments:
*
* Returns:
*
* Errors Codes:
*
* History:
*
*
**/
static void ParseGlossEntry(
TCHAR szGlossEntry[],
TCHAR szEngText[],
TCHAR cEngHotKey[1],
TCHAR szIntlText[],
TCHAR cIntlHotKey[1])
{
WORD wIndex, wIndex2;
// format is:
// <eng text><tab><eng hot key><tab><loc text><tab><loc hot key>
// Any field could be null and if there aren't the right amount of
// tabs we'll just assume that the remaining fields are empty.
wIndex=wIndex2=0;
// first get the english text
while ( szGlossEntry[wIndex2] != TEXT('\t')
&& szGlossEntry[wIndex2] != TEXT('\0') )
{
szEngText[ wIndex++] = szGlossEntry[ wIndex2++];
}
szEngText[wIndex]=TEXT('\0');
if ( szGlossEntry[ wIndex2] == TEXT('\t') )
{
++wIndex2; // skip the tab
}
// now get the eng hot key
if ( szGlossEntry[wIndex2] != TEXT('\t')
&& szGlossEntry[wIndex2] != TEXT('\0') )
{
*cEngHotKey = szGlossEntry[wIndex2++];
}
else
{
*cEngHotKey = TEXT('\0');
}
while ( szGlossEntry[ wIndex2] != TEXT('\t')
&& szGlossEntry[ wIndex2] != TEXT('\0') )
{
++wIndex2; // make sure the hot key field doesn't hold more than one char
}
if ( szGlossEntry[ wIndex2] == TEXT('\t') )
{
++wIndex2; // skip the tab
}
wIndex = 0;
// now get the intl text
while ( szGlossEntry[ wIndex2] != TEXT('\t')
&& szGlossEntry[ wIndex2] != TEXT('\0') )
{
szIntlText[wIndex++]=szGlossEntry[wIndex2++];
}
szIntlText[wIndex]='\0';
if ( szGlossEntry[ wIndex2] == TEXT('\t') )
{
++wIndex2; // skip the tab
}
// now get the intl hot key
if ( szGlossEntry[ wIndex2] != TEXT('\t')
&& szGlossEntry[ wIndex2] != TEXT('\0') )
{
*cIntlHotKey = szGlossEntry[ wIndex2++];
}
else
{
*cIntlHotKey = TEXT('\0');
}
}
/**
*
*
* Function:
*
*
* Arguments:
*
* Returns:
*
* Errors Codes:
*
* History:
*
*
**/
static void ParseBufToTextHotKey(
TCHAR *szText,
TCHAR cHotKey[1],
TCHAR *szBuf)
{
WORD wIndexBuf = 0;
WORD wIndexText = 0;
*cHotKey = TEXT('\0');
while( szBuf[ wIndexBuf] )
{
if ( szBuf[ wIndexBuf ] == TEXT('&') )
{
*cHotKey = szBuf[ ++wIndexBuf];
}
else
{
szText[ wIndexText++] = szBuf[ wIndexBuf++];
}
}
szText[ wIndexText] = TEXT('\0');
}
/**
*
*
* Function:
*
*
* Arguments:
*
* Returns:
*
* Errors Codes:
*
* History:
*
*
**/
static void ParseTextHotKeyToBuf(
TCHAR *szText,
TCHAR cHotKey,
TCHAR *szBuf )
{
WORD wIndexBuf = 0;
WORD wIndexText = 0;
// TCHAR cTmp;
while ( szText[ wIndexText] )
{
// cTmp = szText[ wIndexText];
//
// CharUpperBuff( &cTmp, 1);
//
// if ( cTmp == cHotKey )
if ( szText[ wIndexText] == cHotKey )
{
szBuf[ wIndexBuf++] = TEXT('&');
szBuf[ wIndexBuf++] = szText[ wIndexText++];
break;
}
else
{
szBuf[ wIndexBuf++] = szText[ wIndexText++];
}
}
// copy remaining string
while( szText[ wIndexText] )
{
szBuf[ wIndexBuf++] = szText[ wIndexText++];
}
szBuf[ wIndexBuf] = TEXT('\0');
}
static long GetGlossaryIndex(
FILE *fpGlossFile,
TCHAR c,
long *lGlossaryIndex )
{
int i = 0;
TCHAR cTmp = c;
CharLowerBuff( &cTmp, 1);
if ( cTmp >= TEXT('a')
&& cTmp <= TEXT('z') )
{
i = NormalizeIndex( c );
return( lGlossaryIndex[ i > 0 ? i - 1 : 0]);
}
else
{
return( 0);
}
}
/*******************************************************************************
* PROCEDURE: BuildGlossEntry
* Builds a glossary entry line.
*
* Parameters:
* sz, line buffer
* sz1, untranslated text
* c1, untranslated hot key (or 0 if no hot key)
* sz2, translated text
* c2, translated hot key (or 0 if no hot key)
*
* Returns:
* nothing. sz contains the line. (assumes there is room in the buffer)
*
* History:
* 3/93 - initial implementation - SteveBl
*******************************************************************************/
static void BuildGlossEntry(
TCHAR *sz,
TCHAR *sz1,
TCHAR c1,
TCHAR *sz2,
TCHAR c2)
{
*sz = TEXT('\0');
wsprintf( sz, TEXT("%s\t%c\t%s\t%c"), sz1, c1, sz2, c2);
}
/******************************************************************************
* PROCEDURE: AddTranslation
* Adds a translation to a glossary file.
*
* PARAMETERS:
* szGlossFile, path to the glossary
* szKey, untranslated text
* szTranslation, translated text
* lFilePointer, pointer to index hash table for glossary
*
* RETURNS:
* nothing. Key is added to glossary if no errors are encountered else
* file is left unchanged.
*
* COMMENTS:
* rebuilds the global pointer list lFilePointer
*
* HISTORY: *
* 3/92 - initial implementation - SteveBl
******************************************************************************/
void AddTranslation(
TCHAR *szKey,
TCHAR *szTranslation,
LONG *lFilePointer)
{
// DBCS begin
TCHAR szCurText [520];
TCHAR szTransText [520];
// DBCS end
TCHAR cTransHot = TEXT('\0');
TCHAR cCurHotKey = TEXT('\0');
CHAR szTempFileName [255];
FILE *fTemp = NULL;
FILE *fpGlossFile = NULL;
TCHAR szTempText [MAXLINE];
// DBCS begin
TCHAR szNewText [MAXLINE * 2];
// DBCS end
TCHAR *r = NULL;
TCHAR chTmp = TEXT('\0');
MyGetTempFileName( 0, "", 0, szTempFileName);
if ( (fTemp = OpenGlossary( szTempFileName, 'w')) != NULL )
{
if ( fUnicodeGlossary )
{
fprintf( fTemp, "%hu", 0xfeff); // Mark new one as Unicode
}
ParseBufToTextHotKey( szCurText, &cCurHotKey, szKey);
ParseBufToTextHotKey( szTransText, &cTransHot, szTranslation);
BuildGlossEntry( szNewText,
szCurText,
cCurHotKey,
szTransText,
cTransHot);
// If the glossary file exists, get its first
// line. If it doesn't exist, we'll create it
// (via CopyFile) at the end of this function.
if ( (fpGlossFile = OpenGlossary( gProj.szGlo, 'r')) != NULL )
{
if ( (r = MyGetGlossStr( szTempText,
TCHARSIN( sizeof( szTempText)),
fpGlossFile)) )
{
// lstrcpy( (TCHAR *)szDHW, szTempText);
// szDHW[ MEMSIZE( 7)] = szDHW[ MEMSIZE( 7) + 1] = '\0';
// CharLower( (TCHAR *)szDHW);
//
// if ( lstrcmpi( (TCHAR *)szDHW, TEXT("ENGLISH")) == 0 )
if ( CompareStringW( MAKELCID( gMstr.wLanguageID, SORT_DEFAULT),
SORT_STRINGSORT | NORM_IGNORECASE,
szTempText,
7,
TEXT("ENGLISH"),
7) == 2 )
{
// skip first line
MyPutGlossStr( szTempText, fTemp);
r = MyGetGlossStr( szTempText, TCHARSIN( sizeof( szTempText)), fpGlossFile);
}
}
}
else
{
r = NULL;
}
// if ( r )
// {
// chTmp = szTempText[0];
// CharLowerBuff( &chTmp, 1);
// }
// else
// {
// chTmp = szTempText[0] = TEXT('\0');
// }
// // Does the new text begin with a letter?
//
// if ( chTmp >= TEXT('a') )
// {
// // begins with a letter, we need to find where to put it
//
// while ( r && chTmp < TEXT('a') )
while ( r && CompareStringW( MAKELCID( gMstr.wLanguageID, SORT_DEFAULT),
SORT_STRINGSORT,
szTempText,
-1,
szNewText,
-1) == 1 )
{
// skip the non letter section
MyPutGlossStr( szTempText, fTemp);
r = MyGetGlossStr( szTempText,
TCHARSIN( sizeof( szTempText)),
fpGlossFile);
// if ( (r = MyGetGlossStr( szTempText,
// TCHARSIN( sizeof( szTempText)),
// fpGlossFile)) )
// {
// chTmp = szTempText[0];
// CharLowerBuff( &chTmp, 1);
// }
}
// while ( r && _tcsicmp( szTempText, szNewText) < 0 )
// {
// // skip anything smaller than me
//
// MyPutGlossStr( szTempText, fTemp);
// r = MyGetGlossStr( szTempText, TCHARSIN( sizeof( szTempText)), fpGlossFile);
// }
// }
// else
// {
// // doesn't begin with a letter, we need to insert it before
// // the letter sections begin but it still must be sorted
//
// while ( r
// && chTmp < TEXT('a')
// && _tcsicmp( szTempText, szNewText) < 0 )
// {
// MyPutGlossStr( szTempText, fTemp);
//
// if ( (r = MyGetGlossStr( szTempText,
// TCHARSIN( sizeof( szTempText)),
// fpGlossFile)) )
// {
// chTmp = szTempText[0];
// CharLowerBuff( &chTmp, 1);
// }
// }
// }
MyPutGlossStr( szNewText, fTemp);
while ( r )
{
MyPutGlossStr( szTempText,fTemp);
r = MyGetGlossStr( szTempText, TCHARSIN( sizeof( szTempText)), fpGlossFile);
}
fclose( fTemp);
if ( fpGlossFile )
{
fclose( fpGlossFile);
}
// This call will create the glossary file
// if it didn't already exist.
if ( ! CopyFileA( szTempFileName, gProj.szGlo, FALSE) )
{
QuitA( IDS_COPYFILE_FAILED, szTempFileName, gProj.szGlo);
}
remove( szTempFileName);
MakeGlossIndex( lFilePointer);
}
else
{
QuitA( IDS_NO_TMP_GLOSS, szTempFileName, NULL);
}
}
/**
*
*
* Function: MyGetGlossStr
* Replaces C runtime fgets function.
*
* History:
* 5/92, Implemented. TerryRu.
*
*
**/
static TCHAR *MyGetGlossStr( TCHAR * ptszStr, int nCount, FILE * fIn)
{
int i = 0;
#ifdef RLRES32
// It this a Unicode glossary file?
TCHAR tCh = TEXT('\0');
if ( fUnicodeGlossary )
{
do // Yes
{
tCh = ptszStr[ i++] = (TCHAR)GetWord( fIn, NULL);
} while ( i < nCount && tCh != TEXT('\n') );
if ( tCh == TEXT('\0') || feof( fIn) )
{
return( NULL);
}
ptszStr[i] = TEXT('\0');
StripNewLineW( ptszStr);
}
else // No, it's an ANSI glossary file
{
if ( fgets( szDHW, DHWSIZE, fIn) != NULL )
{
StripNewLineA( szDHW);
_MBSTOWCS( ptszStr, szDHW, nCount, (UINT)-1);
}
else
{
return( NULL);
}
}
return( ptszStr);
#else //RLRES32
if ( fgets( ptszStr, nCount, fIn) )
{
StripNewLineA( ptszStr);
}
else
{
return( NULL);
}
#endif //RLRES32
}
/**
*
*
* Function: MyPutGlossStr
* Replaces C runtime fputs function.
* History:
* 6/92, Implemented. TerryRu.
*
*
**/
static int MyPutGlossStr( TCHAR * ptszStr, FILE * fOut)
{
#ifdef RLRES32
int i = 0;
// It this a Unicode glossary file?
if ( fUnicodeGlossary )
{
do // Yes
{
PutWord( fOut, ptszStr[i], NULL);
} while ( ptszStr[ i++] );
PutWord( fOut, TEXT('\r'), NULL);
PutWord( fOut, TEXT('\n'), NULL);
i += 2;
}
else // No, it's an ANSI glossary file
{
_WCSTOMBS( szDHW, ptszStr, DHWSIZE, lstrlen( ptszStr) + 1);
i = fputs( szDHW, fOut);
fputs( "\n", fOut);
}
#else //RLRES32
i = fputs( ptszStr, fOut);
fputs( "\n", fOut);
#endif //RLRES32
return(i);
}