2739 lines
77 KiB
C
2739 lines
77 KiB
C
/*** inf.c - Diamond INF generation routines
|
|
*
|
|
* Microsoft Confidential
|
|
* Copyright (C) Microsoft Corporation 1994
|
|
* All Rights Reserved.
|
|
*
|
|
* Author:
|
|
* Benjamin W. Slivka
|
|
*
|
|
* History:
|
|
* 23-Feb-1994 bens Initial version
|
|
* 24-Feb-1994 bens Use new tempfile routines
|
|
* 01-Mar-1994 bens Generate header and footer
|
|
* 02-Mar-1994 bens Add function header comments
|
|
* 02-May-1994 bens Add customizable INF stuff
|
|
* 04-Jun-1994 bens Add Version/Language support
|
|
* 12-Jul-1994 bens InfHeader/Footer are now customizable; support
|
|
* overriding disk/cabinet/file formats for
|
|
* specific disk/cabinet/file numbers.
|
|
* 28-Mar-1995 jeffwe Add ChecksumWidth variable
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <malloc.h>
|
|
#include <fcntl.h>
|
|
#include <sys\types.h>
|
|
#include <sys\stat.h>
|
|
#include <io.h>
|
|
#include <dos.h> // Get file attribute definitions
|
|
#include <errno.h>
|
|
#include <direct.h>
|
|
#include <time.h>
|
|
|
|
#include "types.h"
|
|
#include "asrt.h"
|
|
#include "error.h"
|
|
#include "mem.h"
|
|
#include "message.h"
|
|
#include "fileutil.h"
|
|
#include "variable.h"
|
|
#include "misc.h"
|
|
#include "format.h"
|
|
|
|
#include "inf.h"
|
|
#include "inf.msg"
|
|
|
|
#include "dfparse.msg"
|
|
|
|
|
|
/*****************************/
|
|
/*** DEFINITIONS and TYPES ***/
|
|
/*****************************/
|
|
|
|
|
|
#define cbINF_IO_BUFFER 2048 // INF I/O buffer size
|
|
|
|
|
|
//** Don't redefine definitions in Win16 WINDOWS.H (_INC_WINDOWS)
|
|
// or Win32 WINDOWS.H (_WINDOWS_)
|
|
//
|
|
#if !defined(_INC_WINDOWS) && !defined(_WINDOWS_)
|
|
#define HIWORD(l) ((WORD)(l>>16))
|
|
#define LOWORD(l) ((WORD)(l&0xFFFF))
|
|
#endif // _INC_WINDOWS
|
|
|
|
|
|
/*** yearFAT_DATE_MIN/MAX - minimum and maximum FAT Date years
|
|
*
|
|
*/
|
|
#define yearFAT_DATE_MIN 1980
|
|
#define yearFAT_DATE_MAX 2107
|
|
|
|
|
|
/** INF definitions
|
|
*
|
|
*/
|
|
typedef enum {
|
|
itmpDISKS, // Disk list tempfile
|
|
itmpCABINETS, // Cabinet list tempfile
|
|
itmpFILES, // File list tempfile
|
|
cTMP_FILES // Count of tempfiles
|
|
} ETMPFILES; /* etmp */
|
|
|
|
|
|
#ifdef ASSERT
|
|
#define sigINF MAKESIG('I','N','F','$') // INF signature
|
|
#define AssertInf(pinf) AssertStructure(pinf,sigINF);
|
|
#else // !ASSERT
|
|
#define AssertInf(pinf)
|
|
#endif // !ASSERT
|
|
|
|
typedef struct { /* inf */
|
|
#ifdef ASSERT
|
|
SIGNATURE sig; // structure signature sigINF
|
|
#endif
|
|
HTEMPFILE ahtmp[cTMP_FILES]; // Temporary files
|
|
char achLine[cbINF_LINE_MAX]; // Line output formatting buffer
|
|
} INF;
|
|
typedef INF *PINF; /* pinf */
|
|
|
|
#define PINFfromHINF(hinf) ((PINF)(hinf))
|
|
#define HINFfromPINF(pinf) ((HINF)(pinf))
|
|
|
|
|
|
/*** TMPFILEINIT - info used to initialize INF temporary files
|
|
*
|
|
*/
|
|
typedef struct {
|
|
char *pszDesc; // Description of tempfile
|
|
char *pszHeaderVar; // Header line variable
|
|
char *pszHeaderVarTemplate; // Header line variable template
|
|
} TMPFILEINIT; /* tfi */
|
|
|
|
|
|
/*
|
|
* Avoid chicken & egg definition problem!
|
|
*/
|
|
typedef struct SASCONTEXT_t *PSASCONTEXT; /* psascon */
|
|
|
|
|
|
/*** PFNFPFORMAT - Function type for FILEPARM formatting
|
|
*** FNFPFORMAT - Macro to help define FILEPARM formatting function
|
|
*
|
|
* Entry:
|
|
* psess - Session
|
|
* pszDst - Buffer to receive formatted string
|
|
* cbDst - Size of pszDst buffer
|
|
* pszName - Parameter Name
|
|
* psascon - SASCONTEXT pointer
|
|
* perr - ERROR structure
|
|
*
|
|
* Exit-Success:
|
|
* Returns length of string written to pszDst (excluding NUL byte)
|
|
*
|
|
* Exit-Failure:
|
|
* Returns -1; perr filled in.
|
|
*/
|
|
typedef BOOL (*PFNFPFORMAT)(PSESSION psess,
|
|
char *pszDst,
|
|
int cbDst,
|
|
char *pszName,
|
|
PSASCONTEXT psascon,
|
|
PERROR perr); /* pfnfpf */
|
|
#define FNFPFORMAT(fn) BOOL fn(PSESSION psess, \
|
|
char *pszDst, \
|
|
int cbDst, \
|
|
char *pszName, \
|
|
PSASCONTEXT psascon, \
|
|
PERROR perr)
|
|
|
|
|
|
/*** PFNFPVALIDATE - Function type for FILEPARM validation
|
|
*** FNFPVALIDATE - macro to help define FILEPARM validation function
|
|
*
|
|
* Entry:
|
|
* psess - Session
|
|
* pszName - Parameter Name
|
|
* pszValue - Value to check for validity;
|
|
* pv - Parameter-specific context
|
|
* perr - ERROR structure
|
|
*
|
|
* Exit-Success:
|
|
* Returns TRUE, value is valid.
|
|
* pv updated with interpreted value, if appropriate.
|
|
*
|
|
* Exit-Failure:
|
|
* Returns FALSE, perr filled in.
|
|
*/
|
|
typedef BOOL (*PFNFPVALIDATE)(PSESSION psess,
|
|
char *pszName,
|
|
char *pszValue,
|
|
void *pv,
|
|
PERROR perr); /* pfnfpv */
|
|
#define FNFPVALIDATE(fn) BOOL fn(PSESSION psess, \
|
|
char *pszName, \
|
|
char *pszValue, \
|
|
void *pv, \
|
|
PERROR perr)
|
|
|
|
|
|
/*** VALIDATEFILEPARM - validate file parameter
|
|
*
|
|
*/
|
|
typedef struct {
|
|
char *pszName; // Parameter Name
|
|
PFNFPVALIDATE pfnfpv; // Validation function
|
|
} VALIDATEFILEPARM; /* vfp */
|
|
typedef VALIDATEFILEPARM *PVALIDATEFILEPARM; /* pvfp */
|
|
|
|
|
|
/*** FORMATFILEPARM - Format file parameter
|
|
*
|
|
*/
|
|
typedef struct {
|
|
char *pszName; // Parameter Name
|
|
PFNFPFORMAT pfnfpf; // Validation function
|
|
} FORMATFILEPARM; /* ffp */
|
|
typedef FORMATFILEPARM *PFORMATFILEPARM; /* pffp */
|
|
|
|
|
|
/*** SASCONTEXT - Subcontext for formatting INF file lines
|
|
*
|
|
*/
|
|
#ifdef ASSERT
|
|
#define sigSASCONTEXT MAKESIG('S','A','S','C') // SASCONTEXT signature
|
|
#define AssertSascon(p) AssertStructure(p,sigSASCONTEXT);
|
|
#else // !ASSERT
|
|
#define AssertSascon(p)
|
|
#endif // !ASSERT
|
|
|
|
typedef struct SASCONTEXT_t {
|
|
#ifdef ASSERT
|
|
SIGNATURE sig; // structure signature sigSASCONTEXT
|
|
#endif
|
|
PSESSION psess; // Session
|
|
HGENLIST hglistParm; // Parameter list (if any)
|
|
PFORMATFILEPARM pffp; // Parm->function mapping table
|
|
void *pv; // Type-specific context pointer
|
|
} SASCONTEXT; /* sascon */
|
|
typedef SASCONTEXT *PSASCONTEXT; /* psascon */
|
|
|
|
|
|
/*** FILECONTEXT - Subcontext for formatting INF file lines
|
|
*
|
|
*/
|
|
#ifdef ASSERT
|
|
#define sigFILECONTEXT MAKESIG('F','C','O','N') // FILECONTEXT signature
|
|
#define AssertFilecon(p) AssertStructure(p,sigFILECONTEXT);
|
|
#else // !ASSERT
|
|
#define AssertFilecon(p)
|
|
#endif // !ASSERT
|
|
|
|
typedef struct {
|
|
#ifdef ASSERT
|
|
SIGNATURE sig; // structure signature sigFILECONTEXT
|
|
#endif
|
|
char *pszFile; // destination file name
|
|
PFILEINFO pfinfo; // file info
|
|
} FILECONTEXT; /* filecon */
|
|
typedef FILECONTEXT *PFILECONTEXT; /* pfilecon */
|
|
|
|
|
|
/*** CABCONTEXT - Subcontext for formatting INF cabinet lines
|
|
*
|
|
*/
|
|
#ifdef ASSERT
|
|
#define sigCABCONTEXT MAKESIG('C','C','O','N') // CABCONTEXT signature
|
|
#define AssertCabcon(p) AssertStructure(p,sigCABCONTEXT);
|
|
#else // !ASSERT
|
|
#define AssertCabcon(p)
|
|
#endif // !ASSERT
|
|
|
|
typedef struct {
|
|
#ifdef ASSERT
|
|
SIGNATURE sig; // structure signature sigCABCONTEXT
|
|
#endif
|
|
int iDisk; // Disk where cabinet resides
|
|
int iCabinet; // Cabinet number
|
|
char *pszCab; // Cabinet file name
|
|
} CABCONTEXT; /* cabcon */
|
|
typedef CABCONTEXT *PCABCONTEXT; /* pcabcon */
|
|
|
|
|
|
/*** DISKCONTEXT - Subcontext for formatting INF DISK lines
|
|
*
|
|
*/
|
|
#ifdef ASSERT
|
|
#define sigDISKCONTEXT MAKESIG('D','C','O','N') // DISKCONTEXT signature
|
|
#define AssertDiskcon(p) AssertStructure(p,sigDISKCONTEXT);
|
|
#else // !ASSERT
|
|
#define AssertDiskcon(p)
|
|
#endif // !ASSERT
|
|
|
|
typedef struct {
|
|
#ifdef ASSERT
|
|
SIGNATURE sig; // structure signature sigDISKCONTEXT
|
|
#endif
|
|
int iDisk; // Disk number
|
|
char *pszDisk; // Disk label
|
|
} DISKCONTEXT; /* diskcon */
|
|
typedef DISKCONTEXT *PDISKCONTEXT; /* pdiskcon */
|
|
|
|
|
|
|
|
/******************/
|
|
/*** PROTOTYPES ***/
|
|
/******************/
|
|
|
|
BOOL catTempFile(FILE * pfileDst,
|
|
char * pszFile,
|
|
HTEMPFILE htmp,
|
|
char * pszMode,
|
|
PERROR perr);
|
|
BOOL checkInfLineFormats(PSESSION psess, PERROR perr);
|
|
BOOL doHeaderFooter(PSESSION psess,
|
|
FILE *pfileInf,
|
|
char *pszInfFile,
|
|
char *pszVarMain,
|
|
char *pszVarTemplate,
|
|
char *pszComment,
|
|
char *pszTime,
|
|
char *pszVer,
|
|
PERROR perr);
|
|
HVARIABLE GetInfCustomVar(PSESSION psess,char *pszParm,BOOL fCopy,PERROR perr);
|
|
char * getLineFormat(PSESSION psess,
|
|
char *pszVarMain,
|
|
char *pszVarTemplate,
|
|
int i);
|
|
BOOL infClose(HINF hinf, PERROR perr);
|
|
|
|
WORD FATAttrFromPsz(char *pszAttr, PERROR perr);
|
|
WORD FATDateFromPsz(char *pszDate, PERROR perr);
|
|
WORD FATTimeFromPsz(char *pszTime, PERROR perr);
|
|
int pszFromFATAttr(char *pszDst, int cbDst, WORD attr);
|
|
int pszFromFATDate(char *pszDst, int cbDst, WORD date, BOOL fMMDDYY);
|
|
int pszFromFATTime(char *pszDst, int cbDst, WORD time);
|
|
|
|
FNFORMATPARM(fnfpInfLine);
|
|
|
|
FNFPFORMAT(fnfpfCabinetFileName);
|
|
FNFPFORMAT(fnfpfCabinetNumber);
|
|
FNFPFORMAT(fnfpfDiskNumber);
|
|
FNFPFORMAT(fnfpfDiskLabel);
|
|
FNFPFORMAT(fnfpfFileChecksum);
|
|
FNFPFORMAT(fnfpfFileAttr);
|
|
FNFPFORMAT(fnfpfFileDate);
|
|
FNFPFORMAT(fnfpfFileLanguage);
|
|
FNFPFORMAT(fnfpfFileName);
|
|
FNFPFORMAT(fnfpfFileNumber);
|
|
FNFPFORMAT(fnfpfFileSize);
|
|
FNFPFORMAT(fnfpfFileTime);
|
|
FNFPFORMAT(fnfpfFileVerNum);
|
|
FNFPFORMAT(fnfpfFileVerString);
|
|
|
|
FNFPVALIDATE(fnfpvBOOL);
|
|
FNFPVALIDATE(fnfpvFileAttr);
|
|
FNFPVALIDATE(fnfpvFileDate);
|
|
FNFPVALIDATE(fnfpvFileTime);
|
|
FNFPVALIDATE(fnfpvLong);
|
|
FNFPVALIDATE(fnfpvShort);
|
|
FNFPVALIDATE(fnfpvString);
|
|
|
|
|
|
/*****************/
|
|
/*** VARIABLES ***/
|
|
/*****************/
|
|
|
|
|
|
/*** atfi - array of INF temporary file information
|
|
*
|
|
* NOTE: Must be in same order as ETMPFILES enumeration!
|
|
*/
|
|
TMPFILEINIT atfi[] = {
|
|
{pszINF_TMP_FILED,pszVAR_INF_DISK_HEADER,pszPATTERN_VAR_INF_DISK_HEADER}, // itmpDISKS
|
|
{pszINF_TMP_FILEC,pszVAR_INF_CAB_HEADER ,pszPATTERN_VAR_INF_CAB_HEADER }, // itmpCABINETS
|
|
{pszINF_TMP_FILEF,pszVAR_INF_FILE_HEADER,pszPATTERN_VAR_INF_FILE_HEADER}, // itmpFILES
|
|
};
|
|
|
|
|
|
/*** avfpInfVar - InfXxx variable validation mapping
|
|
*
|
|
* NOTE: This table is used by CheckForInfVarOverrides() to pick up
|
|
* an InfXxx variable overrides.
|
|
*/
|
|
VALIDATEFILEPARM avfpInfVar[] = {
|
|
{pszPARM_FILEATTR , fnfpvFileAttr }, // File attributes
|
|
{pszPARM_FILEDATE , fnfpvFileDate }, // File date
|
|
{pszPARM_FILETIME , fnfpvFileTime }, // File time
|
|
{NULL , NULL } // end-of-list
|
|
};
|
|
|
|
|
|
/*** avfpFile - File Parm validation mapping
|
|
*
|
|
*/
|
|
VALIDATEFILEPARM avfpFile[] = {
|
|
{pszPARM_CAB_NUMBER , fnfpvShort }, // Cabinet number
|
|
{pszPARM_CHECKSUM , fnfpvLong }, // Checksum
|
|
{pszPARM_DISK_NUMBER, fnfpvShort }, // Disk number
|
|
{pszPARM_FILEATTR , fnfpvFileAttr }, // File attributes
|
|
{pszPARM_FILEDATE , fnfpvFileDate }, // File date
|
|
{pszPARM_FILENAME , fnfpvString }, // File name
|
|
{pszPARM_FILE_NUMBER, fnfpvLong }, // File number
|
|
{pszPARM_FILESIZE , fnfpvLong }, // File size
|
|
{pszPARM_FILETIME , fnfpvFileTime }, // File time
|
|
{pszPARM_INF , fnfpvBOOL }, // /INF=YES|NO
|
|
{pszPARM_LANG , fnfpvString }, // VER.DLL language code
|
|
{pszPARM_UNIQUE , fnfpvBOOL }, // /UNIQUE=YES|NO
|
|
{pszPARM_VERNUM , fnfpvString }, // VER.DLL version *number*
|
|
{pszPARM_VERSTR , fnfpvString }, // VER.DLL version *string*
|
|
{NULL , NULL } // end-of-list
|
|
};
|
|
|
|
|
|
/*** affpFile - File Parm formatting mapping
|
|
*
|
|
*/
|
|
FORMATFILEPARM affpFile[] = {
|
|
{pszPARM_CAB_NUMBER , fnfpfCabinetNumber}, // Cabinet number
|
|
{pszPARM_CHECKSUM , fnfpfFileChecksum }, // Checksum
|
|
{pszPARM_DISK_NUMBER, fnfpfDiskNumber }, // Disk number
|
|
{pszPARM_FILEATTR , fnfpfFileAttr }, // File attributes
|
|
{pszPARM_FILEDATE , fnfpfFileDate }, // File date
|
|
{pszPARM_FILENAME , fnfpfFileName }, // File name
|
|
{pszPARM_FILE_NUMBER, fnfpfFileNumber }, // File number
|
|
{pszPARM_FILESIZE , fnfpfFileSize }, // File size
|
|
{pszPARM_FILETIME , fnfpfFileTime }, // File time
|
|
{pszPARM_LANG , fnfpfFileLanguage }, // VER.DLL language code
|
|
{pszPARM_VERNUM , fnfpfFileVerNum }, // VER.DLL version *number*
|
|
{pszPARM_VERSTR , fnfpfFileVerString}, // VER.DLL version *string*
|
|
{NULL , NULL } // end-of-list
|
|
};
|
|
|
|
|
|
/*** affpDisk - Disk Parm formatting mapping
|
|
*
|
|
*/
|
|
FORMATFILEPARM affpDisk[] = {
|
|
{pszPARM_DISK_NUMBER, fnfpfDiskNumber }, // Disk number
|
|
{pszPARM_LABEL , fnfpfDiskLabel }, // Disk label
|
|
{NULL , NULL } // end-of-list
|
|
};
|
|
|
|
|
|
/*** affpCabinet - Cabinet Parm formatting mapping
|
|
*
|
|
*/
|
|
FORMATFILEPARM affpCabinet[] = {
|
|
{pszPARM_CAB_NUMBER , fnfpfCabinetNumber }, // Cabinet number
|
|
{pszPARM_CAB_FILE , fnfpfCabinetFileName}, // Cabinet file name
|
|
{pszPARM_DISK_NUMBER, fnfpfDiskNumber }, // Disk number
|
|
{NULL , NULL } // end-of-list
|
|
};
|
|
|
|
|
|
|
|
/*****************/
|
|
/*** FUNCTIONS ***/
|
|
/*****************/
|
|
|
|
|
|
/*** infCreate - Create INF context
|
|
*
|
|
* NOTE: See inf.h for entry/exit conditions.
|
|
*/
|
|
HINF infCreate (PSESSION psess,PERROR perr)
|
|
{
|
|
char achVar[cbVAR_NAME_MAX]; // Header line variable names
|
|
char ch;
|
|
HVARIABLE hvar;
|
|
int itmp;
|
|
int iLine;
|
|
PINF pinf;
|
|
FILE *pfile;
|
|
char *pszLine;
|
|
char *pszOrder;
|
|
|
|
AssertSess(psess);
|
|
|
|
//** Create INF structure
|
|
if (!(pinf = MemAlloc(sizeof(INF)))) {
|
|
ErrSet(perr,pszINFERR_OUT_OF_MEMORY);
|
|
return NULL;
|
|
}
|
|
|
|
//** Initialize so error cleanup is simple
|
|
for (itmp=0; itmp<cTMP_FILES; itmp++) {
|
|
pinf->ahtmp[itmp] = NULL;
|
|
}
|
|
SetAssertSignature(pinf,sigINF); // Set so we can use infDestroy()
|
|
psess->hinf = HINFfromPINF(pinf); // Set for checkInfLineFormat
|
|
|
|
//** Make sure there are no undefined parameters in any of the
|
|
// InfXxxLineFormat variables!
|
|
if (!checkInfLineFormats(psess,perr)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//** Create temp files
|
|
hvar = VarFind(psess->hvlist,pszVAR_INF_SECTION_ORDER,perr);
|
|
Assert(!perr->fError); // Must be defined
|
|
pszOrder = VarGetString(hvar); // Section order string
|
|
Assert(strlen(pszOrder) <= cTMP_FILES);
|
|
for ( ; *pszOrder; pszOrder++) {
|
|
//** Pick temp file
|
|
ch = toupper(*pszOrder);
|
|
switch (ch) {
|
|
case pszISO_DISK: itmp = itmpDISKS; break;
|
|
case pszISO_CABINET: itmp = itmpCABINETS; break;
|
|
case pszISO_FILE: itmp = itmpFILES; break;
|
|
|
|
default:
|
|
Assert(0);
|
|
return FALSE;
|
|
}
|
|
|
|
//** Get required header line
|
|
hvar = VarFind(psess->hvlist,atfi[itmp].pszHeaderVar,perr);
|
|
Assert(!perr->fError); // Must be defined
|
|
pszLine = VarGetString(hvar);
|
|
|
|
//** Create temp file
|
|
pinf->ahtmp[itmp] = TmpCreate(atfi[itmp].pszDesc, // description
|
|
pszINF_TMP_PREFIX, // filename prefix
|
|
"wt", // write text mode
|
|
perr);
|
|
if (!pinf->ahtmp[itmp]) {
|
|
goto error;
|
|
}
|
|
|
|
//** Add header line(s)
|
|
pfile = TmpGetStream(pinf->ahtmp[itmp],perr);
|
|
Assert(pfile!=NULL);
|
|
iLine = 1;
|
|
while (pszLine) {
|
|
if (fprintf(pfile,"%s\n",pszLine) < 0) { // Add header line
|
|
goto error;
|
|
}
|
|
|
|
//** Get next header line (if any)
|
|
if (!nameFromTemplate(achVar,
|
|
sizeof(achVar),
|
|
atfi[itmp].pszHeaderVarTemplate,
|
|
iLine,
|
|
pszINF_HEADER_TEMPLATE,
|
|
perr)) {
|
|
goto error;
|
|
}
|
|
hvar = VarFind(psess->hvlist,achVar,perr);
|
|
if (hvar) { // Get line
|
|
pszLine = VarGetString(hvar);
|
|
iLine++; // Next variable to get
|
|
}
|
|
else { // Done
|
|
ErrClear(perr); // Not an error
|
|
pszLine = NULL; // End loop
|
|
}
|
|
}
|
|
}
|
|
|
|
//** Success
|
|
psess->fGenerateInf = TRUE; // Remember we are creating INF
|
|
return HINFfromPINF(pinf);
|
|
|
|
error:
|
|
infDestroy(pinf,perr);
|
|
return NULL;
|
|
} /* infCreate() */
|
|
|
|
|
|
/*** infAddLine - Add a line to an INF area
|
|
*
|
|
* NOTE: See inf.h for entry/exit conditions.
|
|
*/
|
|
BOOL infAddLine(HINF hinf, INFAREA inf, char *pszLine, PERROR perr)
|
|
{
|
|
FILE *pfile;
|
|
PINF pinf;
|
|
int itmp;
|
|
|
|
pinf = PINFfromHINF(hinf);
|
|
AssertInf(pinf);
|
|
|
|
//** Select correct temp file
|
|
switch (inf) {
|
|
case infDISK: itmp = itmpDISKS; break;
|
|
case infCABINET: itmp = itmpCABINETS; break;
|
|
case infFILE: itmp = itmpFILES; break;
|
|
|
|
default:
|
|
Assert(0);
|
|
return FALSE;
|
|
}
|
|
|
|
//** Write line to temp file
|
|
pfile = TmpGetStream(pinf->ahtmp[itmp],perr);
|
|
Assert(pfile!=NULL);
|
|
return fprintf(pfile,"%s\n",pszLine) > 0;
|
|
} /* infAddLine() */
|
|
|
|
|
|
/*** infDestroy - Destroy INF context
|
|
*
|
|
* NOTE: See inf.h for entry/exit conditions.
|
|
*/
|
|
BOOL infDestroy(HINF hinf, PERROR perr)
|
|
{
|
|
int i;
|
|
PINF pinf;
|
|
|
|
pinf = PINFfromHINF(hinf);
|
|
AssertInf(pinf);
|
|
|
|
//** Make sure files are closed
|
|
if (!infClose(pinf,perr)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//** Get rid of tempfiles
|
|
for (i=0; i<cTMP_FILES; i++) {
|
|
if (pinf->ahtmp[i]) {
|
|
if (!TmpDestroy(pinf->ahtmp[i],perr)) {
|
|
return FALSE;
|
|
}
|
|
pinf->ahtmp[i] = NULL;
|
|
}
|
|
}
|
|
|
|
//** Free INF structure
|
|
ClearAssertSignature(pinf);
|
|
MemFree(pinf);
|
|
return TRUE;
|
|
} /* infDestroy() */
|
|
|
|
|
|
/*** infClose - Close file handles in INF context
|
|
*
|
|
* NOTE: See inf.h for entry/exit conditions.
|
|
*/
|
|
BOOL infClose(HINF hinf, PERROR perr)
|
|
{
|
|
int i;
|
|
PINF pinf;
|
|
|
|
pinf = PINFfromHINF(hinf);
|
|
AssertInf(pinf);
|
|
|
|
//** Close all temp files
|
|
for (i=0; i<cTMP_FILES; i++) {
|
|
if (pinf->ahtmp[i]) {
|
|
if (!TmpClose(pinf->ahtmp[i],perr)) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
} /* infClose() */
|
|
|
|
|
|
/*** infGenerate - Generate INF file
|
|
*
|
|
* NOTE: See inf.h for entry/exit conditions.
|
|
*/
|
|
BOOL infGenerate(PSESSION psess,
|
|
char *pszInfFile,
|
|
time_t *ptime,
|
|
char *pszVer,
|
|
PERROR perr)
|
|
{
|
|
char achTime[50];
|
|
char ch;
|
|
HVARIABLE hvar;
|
|
int itmp;
|
|
FILE *pfileInf;
|
|
PINF pinf;
|
|
char *pszOrder;
|
|
char *pszComment;
|
|
|
|
AssertSess(psess);
|
|
pinf = PINFfromHINF(psess->hinf);
|
|
AssertInf(pinf);
|
|
|
|
//** Flush temporary files
|
|
if (!infClose(pinf,perr)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//** Create final output file
|
|
pfileInf = fopen(pszInfFile,"wb");
|
|
if (!pfileInf) {
|
|
ErrSet(perr,pszINFERR_CANT_CREATE_INF,"%s",pszInfFile);
|
|
return FALSE;
|
|
}
|
|
|
|
//** Get INF line comment prefix
|
|
hvar = VarFind(psess->hvlist,pszVAR_INF_COMMENT_STRING,perr);
|
|
Assert(!perr->fError); // Must be defined
|
|
pszComment = VarGetString(hvar);
|
|
|
|
//** Trim off trailing new-line in time
|
|
strcpy(achTime,ctime(ptime));
|
|
achTime[strlen(achTime)-1] = '\0';
|
|
|
|
//** Add header
|
|
if (!doHeaderFooter(psess,
|
|
pfileInf,
|
|
pszInfFile,
|
|
pszVAR_INF_HEADER,
|
|
pszPATTERN_VAR_INF_HEADER,
|
|
pszComment,
|
|
achTime,
|
|
pszVer,
|
|
perr)) {
|
|
goto error;
|
|
}
|
|
|
|
//** Concatenate intermediate files
|
|
hvar = VarFind(psess->hvlist,pszVAR_INF_SECTION_ORDER,perr);
|
|
Assert(!perr->fError); // Must be defined
|
|
pszOrder = VarGetString(hvar); // Section order string
|
|
Assert(strlen(pszOrder) <= cTMP_FILES);
|
|
for ( ; *pszOrder; pszOrder++) {
|
|
//** Pick temp file
|
|
ch = toupper(*pszOrder);
|
|
switch (ch) {
|
|
case pszISO_DISK: itmp = itmpDISKS; break;
|
|
case pszISO_CABINET: itmp = itmpCABINETS; break;
|
|
case pszISO_FILE: itmp = itmpFILES; break;
|
|
|
|
default:
|
|
Assert(0);
|
|
return FALSE;
|
|
}
|
|
//** Concatenate it
|
|
Assert(pinf->ahtmp[itmp] != NULL);
|
|
if (!catTempFile(pfileInf,pszInfFile,pinf->ahtmp[itmp],"rb",perr)) {
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
//** Add footer
|
|
if (!doHeaderFooter(psess,
|
|
pfileInf,
|
|
pszInfFile,
|
|
pszVAR_INF_FOOTER,
|
|
pszPATTERN_VAR_INF_FOOTER,
|
|
pszComment,
|
|
achTime,
|
|
pszVer,
|
|
perr)) {
|
|
goto error;
|
|
}
|
|
|
|
//** Success
|
|
fclose(pfileInf);
|
|
return TRUE;
|
|
|
|
error:
|
|
fclose(pfileInf);
|
|
return FALSE;
|
|
} /* infGenerate() */
|
|
|
|
|
|
/*** doHeaderFooter - Add header or footer to INF file
|
|
*
|
|
* Entry:
|
|
* psess - SESSION
|
|
* pfileInf - File pointer for INF file (opened in mode "rb", so
|
|
* we have to do \r\n for newline).
|
|
* pszInfFile - INF file name (for error messages)
|
|
* pszVarMain - Main variable name (InfHeader or InfFooter)
|
|
* pszVarTemplate - Template for other variables (InfHeader* or InfFooter*)
|
|
* pszComment - Line comment string (usually ";")
|
|
* pszTime - Time string
|
|
* pszVer - Diamond version string
|
|
* perr - ERROR
|
|
* Exit-Success:
|
|
* Returns TRUE, lines added to INF file
|
|
*
|
|
* Exit-Failure:
|
|
* Returns FALSE, perr filled in.
|
|
*
|
|
* NOTE: If the variable pszVarMain has the empty string value, no lines
|
|
* are added to the INF file.
|
|
*/
|
|
BOOL doHeaderFooter(PSESSION psess,
|
|
FILE *pfileInf,
|
|
char *pszInfFile,
|
|
char *pszVarMain,
|
|
char *pszVarTemplate,
|
|
char *pszComment,
|
|
char *pszTime,
|
|
char *pszVer,
|
|
PERROR perr)
|
|
{
|
|
char achVar[cbVAR_NAME_MAX]; // Header line variable names
|
|
HVARIABLE hvar;
|
|
int iLine;
|
|
PINF pinf;
|
|
char *psz;
|
|
char *pszVar;
|
|
|
|
AssertSess(psess);
|
|
|
|
//** See if we're supposed to add lines to file
|
|
hvar = VarFind(psess->hvlist,pszVarMain,perr);
|
|
Assert(!perr->fError); // Must be defined
|
|
psz = VarGetString(hvar); // Get value
|
|
if (strlen(psz) == 0) { // Main variable empty
|
|
return TRUE; // Skip writing to INF
|
|
}
|
|
|
|
//** Add lines to INF file
|
|
pinf = PINFfromHINF(psess->hinf);
|
|
AssertInf(pinf);
|
|
iLine = 1;
|
|
pszVar = pszVarMain;
|
|
while (psz) {
|
|
//** Do substitution of comment string, time, and version
|
|
MsgSet(pinf->achLine,psz,"%s%s%s",pszComment,pszTime,pszVer);
|
|
|
|
//** Add line to INF file (opened in BINARY, so need \r\n!)
|
|
if (fprintf(pfileInf,"%s\r\n",pinf->achLine) < 0) {
|
|
ErrSet(perr,pszINFERR_INF_WRITE,"%s%s",pszVar,pszInfFile);
|
|
return FALSE;
|
|
}
|
|
|
|
//** Get next header line (if any)
|
|
if (!nameFromTemplate(achVar,
|
|
sizeof(achVar),
|
|
pszVarTemplate,
|
|
iLine,
|
|
pszINF_HEADER_TEMPLATE,
|
|
perr)) {
|
|
return FALSE; // perr already filled in
|
|
}
|
|
hvar = VarFind(psess->hvlist,achVar,perr);
|
|
if (hvar) { // Get line
|
|
psz = VarGetString(hvar);
|
|
iLine++; // Next variable to get
|
|
}
|
|
else { // Done
|
|
ErrClear(perr); // Not an error
|
|
psz = NULL; // End loop
|
|
}
|
|
}
|
|
|
|
//** Success
|
|
return TRUE;
|
|
} /* doHeaderFooter() */
|
|
|
|
|
|
/*** infAddDisk - Add information for a new disk to the INF context
|
|
*
|
|
* NOTE: See inf.h for entry/exit conditions.
|
|
*/
|
|
BOOL infAddDisk(PSESSION psess, int iDisk, char *pszDisk, PERROR perr)
|
|
{
|
|
DISKCONTEXT diskcon;
|
|
FILE *pfile;
|
|
PINF pinf;
|
|
char *pszFmt;
|
|
SASCONTEXT sascon;
|
|
|
|
AssertSess(psess);
|
|
pinf = PINFfromHINF(psess->hinf);
|
|
AssertInf(pinf);
|
|
|
|
//** Quick out if not generating this INF area
|
|
if (!pinf->ahtmp[itmpDISKS]) {
|
|
return TRUE;
|
|
}
|
|
|
|
Assert(iDisk != idiskBAD);
|
|
|
|
//** Get line format
|
|
pszFmt = getLineFormat(psess,
|
|
pszVAR_INF_DISK_LINE_FMT,
|
|
pszPATTERN_VAR_INF_DISK_LINE_FMT,
|
|
iDisk);
|
|
|
|
//** Format and write line to file
|
|
SetAssertSignature((&diskcon),sigDISKCONTEXT);
|
|
diskcon.iDisk = iDisk;
|
|
diskcon.pszDisk = pszDisk;
|
|
|
|
SetAssertSignature((&sascon),sigSASCONTEXT);
|
|
sascon.psess = psess;
|
|
sascon.hglistParm = NULL;
|
|
sascon.pffp = affpDisk;
|
|
sascon.pv = &diskcon;
|
|
|
|
if (!SubstituteFormatString(pinf->achLine,
|
|
sizeof(pinf->achLine),
|
|
pszFmt,
|
|
fnfpInfLine,
|
|
&sascon,
|
|
perr)) {
|
|
return FALSE;
|
|
}
|
|
|
|
pfile = TmpGetStream(pinf->ahtmp[itmpDISKS],perr);
|
|
Assert(pfile!=NULL);
|
|
if (fprintf(pfile,"%s\n",pinf->achLine) < 0) {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
} /* infAddDisk() */
|
|
|
|
|
|
/*** infAddCabinet - Add information for a new cabinet to the INF context
|
|
*
|
|
* NOTE: See inf.h for entry/exit conditions.
|
|
*/
|
|
BOOL infAddCabinet(PSESSION psess,
|
|
int iCabinet,
|
|
int iDisk,
|
|
char *pszCab,
|
|
PERROR perr)
|
|
{
|
|
CABCONTEXT cabcon;
|
|
FILE *pfile;
|
|
PINF pinf;
|
|
char *pszFmt;
|
|
SASCONTEXT sascon;
|
|
|
|
AssertSess(psess);
|
|
pinf = PINFfromHINF(psess->hinf);
|
|
AssertInf(pinf);
|
|
|
|
//** Quick out if not generating this INF area
|
|
if (!pinf->ahtmp[itmpCABINETS]) {
|
|
return TRUE;
|
|
}
|
|
|
|
Assert(iCabinet != icabBAD);
|
|
Assert(iDisk != idiskBAD);
|
|
|
|
//** Get line format
|
|
pszFmt = getLineFormat(psess,
|
|
pszVAR_INF_CAB_LINE_FMT,
|
|
pszPATTERN_VAR_INF_CAB_LINE_FMT,
|
|
iCabinet);
|
|
|
|
//** Format and write line to file
|
|
SetAssertSignature((&cabcon),sigCABCONTEXT);
|
|
cabcon.iCabinet = iCabinet;
|
|
cabcon.iDisk = iDisk;
|
|
cabcon.pszCab = pszCab;
|
|
|
|
SetAssertSignature((&sascon),sigSASCONTEXT);
|
|
sascon.psess = psess;
|
|
sascon.hglistParm = NULL;
|
|
sascon.pffp = affpCabinet;
|
|
sascon.pv = &cabcon;
|
|
|
|
if (!SubstituteFormatString(pinf->achLine,
|
|
sizeof(pinf->achLine),
|
|
pszFmt,
|
|
fnfpInfLine,
|
|
&sascon,
|
|
perr)) {
|
|
return FALSE;
|
|
}
|
|
|
|
pfile = TmpGetStream(pinf->ahtmp[itmpCABINETS],perr);
|
|
Assert(pfile!=NULL);
|
|
if (fprintf(pfile,"%s\n",pinf->achLine) < 0) {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
} /* infAddCabinet() */
|
|
|
|
|
|
/*** infAddFile - Add information for a new file to the INF context
|
|
*
|
|
* NOTE: See inf.h for entry/exit conditions.
|
|
*/
|
|
BOOL infAddFile(PSESSION psess,
|
|
char *pszFile,
|
|
PFILEINFO pfinfo,
|
|
HGENLIST hglistParm,
|
|
PERROR perr)
|
|
{
|
|
FILECONTEXT filecon;
|
|
HGENERIC hgen;
|
|
FILE *pfile;
|
|
PINF pinf;
|
|
PLINEINFO plinfo;
|
|
char *pszFmt;
|
|
SASCONTEXT sascon;
|
|
|
|
AssertSess(psess);
|
|
pinf = PINFfromHINF(psess->hinf);
|
|
AssertInf(pinf);
|
|
|
|
AssertFinfo(pfinfo);
|
|
Assert(pfinfo->iDisk != idiskBAD);
|
|
Assert(pfinfo->iCabinet != icabBAD);
|
|
|
|
//** Quick out if not generating this INF area
|
|
if (!pinf->ahtmp[itmpFILES]) {
|
|
return TRUE;
|
|
}
|
|
|
|
//** Get line format
|
|
pszFmt = getLineFormat(psess,
|
|
pszVAR_INF_FILE_LINE_FMT,
|
|
pszPATTERN_VAR_INF_FILE_LINE_FMT,
|
|
pfinfo->iFile);
|
|
|
|
//** Format and write line to file
|
|
SetAssertSignature((&filecon),sigFILECONTEXT);
|
|
filecon.pszFile = pszFile;
|
|
filecon.pfinfo = pfinfo;
|
|
|
|
SetAssertSignature((&sascon),sigSASCONTEXT);
|
|
sascon.psess = psess;
|
|
sascon.hglistParm = hglistParm;
|
|
sascon.pffp = affpFile;
|
|
sascon.pv = &filecon;
|
|
|
|
if (!SubstituteFormatString(pinf->achLine,
|
|
sizeof(pinf->achLine),
|
|
pszFmt,
|
|
fnfpInfLine,
|
|
&sascon,
|
|
perr)) {
|
|
return FALSE;
|
|
}
|
|
pfile = TmpGetStream(pinf->ahtmp[itmpFILES],perr);
|
|
Assert(pfile!=NULL);
|
|
if (fprintf(pfile,"%s\n",pinf->achLine) < 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
//** Remember that we added file to inf
|
|
Assert((psess->ddfmode == ddfmodeRELATIONAL) || // Relational mode -or-
|
|
!(pfinfo->flags & fifWRITTEN_TO_INF)); // Not yet written to INF
|
|
pfinfo->flags |= fifWRITTEN_TO_INF;
|
|
|
|
//** Print out any additional INF lines
|
|
if (!pfinfo->hglistInfLines) { // No additional lines
|
|
return TRUE;
|
|
}
|
|
for (hgen = GLFirstItem(pfinfo->hglistInfLines);
|
|
hgen;
|
|
hgen = GLNextItem(hgen)) {
|
|
|
|
plinfo = GLGetValue(hgen); // Get line info
|
|
AssertLinfo(plinfo);
|
|
if (!infAddLine(psess->hinf,plinfo->inf,plinfo->pszLine,perr)) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//** Free the INF lines, to conserve space
|
|
GLDestroyList(pfinfo->hglistInfLines);
|
|
pfinfo->hglistInfLines = NULL; // Remember they are gone
|
|
|
|
return TRUE;
|
|
} /* infAddFile() */
|
|
|
|
|
|
/*** getLineFormat - Get line format for INF detail line
|
|
*
|
|
* Entry:
|
|
* psess - SESSION
|
|
* pszVarMain - Main variable name (InfXxxLineFormat)
|
|
* pszVarTemplate - Template for override var (InfXxxLineFormat*)
|
|
* i - Variable number to search for (replaces * above)
|
|
*
|
|
* Exit:
|
|
* Returns pointer to line format string.
|
|
*/
|
|
char *getLineFormat(PSESSION psess,
|
|
char *pszVarMain,
|
|
char *pszVarTemplate,
|
|
int i)
|
|
{
|
|
char achVar[cbVAR_NAME_MAX];
|
|
ERROR err;
|
|
HVARIABLE hvar;
|
|
|
|
AssertSess(psess);
|
|
|
|
//** See if override format exists
|
|
if (!nameFromTemplate(achVar, // Couldn't build template
|
|
sizeof(achVar),
|
|
pszVarTemplate,
|
|
i,
|
|
"",
|
|
&err) ||
|
|
!(hvar = VarFind(psess->hvlist,achVar,&err))) // Override not defined
|
|
{
|
|
//** Use standard format
|
|
ErrClear(&err); // Ignore error from above
|
|
hvar = VarFind(psess->hvlist,pszVarMain,&err);
|
|
Assert(!err.fError); // Must be defined
|
|
}
|
|
|
|
//** Return the format string
|
|
return VarGetString(hvar);
|
|
} /* getLineFormat() */
|
|
|
|
|
|
/*** catTempFile - Append a tempfile to an open FILE* stream
|
|
*
|
|
* Entry:
|
|
* pfileDst - file stream to receive temp file
|
|
* pszFile - name of pfileDst (for error reporting)
|
|
* htmp - tempfile
|
|
* pszMode - mode to pass to fopen for tempfile
|
|
* perr - ERROR structure
|
|
*
|
|
* Exit-Success:
|
|
* Returns TRUE; files concatenated, pfileDst still open and at EOF
|
|
*
|
|
* Exit-Failure:
|
|
* Returns FALSE; perr is filled in.
|
|
*/
|
|
BOOL catTempFile(FILE * pfileDst,
|
|
char * pszFile,
|
|
HTEMPFILE htmp,
|
|
char * pszMode,
|
|
PERROR perr)
|
|
{
|
|
int cbRead;
|
|
int cbWrite;
|
|
ERROR errTmp;
|
|
char *pbuf=NULL;
|
|
FILE *pfileSrc=NULL;
|
|
char *pszDesc;
|
|
char *pszTmpName;
|
|
|
|
Assert(pfileDst != NULL);
|
|
Assert(htmp != NULL);
|
|
Assert(TmpGetStream(htmp,perr) == NULL); // Should be closed
|
|
|
|
//** Get strings for error messages
|
|
pszDesc = TmpGetDescription(htmp,&errTmp);
|
|
pszTmpName= TmpGetFileName(htmp,&errTmp);
|
|
|
|
//** Get I/O buffer
|
|
if (!(pbuf = MemAlloc(cbINF_IO_BUFFER))) {
|
|
ErrSet(perr,pszINFERR_NO_MEM_CATING_FILE,"%s%s%s",
|
|
pszDesc,pszTmpName,pszFile);
|
|
return FALSE;
|
|
}
|
|
|
|
//** Open file to copy from
|
|
if (!TmpOpen(htmp,pszMode,perr)) {
|
|
goto error;
|
|
}
|
|
pfileSrc = TmpGetStream(htmp,perr);
|
|
Assert(pfileSrc != NULL); // Should be open now
|
|
|
|
//** Copy source to destination
|
|
while (!feof(pfileSrc)) {
|
|
cbRead = fread(pbuf,1,cbINF_IO_BUFFER,pfileSrc);
|
|
if (ferror(pfileSrc)) {
|
|
ErrSet(perr,pszINFERR_READING,"%s%s%s",pszDesc,pszTmpName,pszFile);
|
|
goto error;
|
|
}
|
|
if (cbRead > 0) {
|
|
cbWrite = fwrite(pbuf,1,cbRead,pfileDst);
|
|
if (ferror(pfileDst)) {
|
|
ErrSet(perr,pszINFERR_WRITING,"%s%s%s",
|
|
pszDesc,pszTmpName,pszFile);
|
|
goto error;
|
|
}
|
|
}
|
|
}
|
|
|
|
//** Clean up
|
|
TmpClose(htmp,perr);
|
|
MemFree(pbuf);
|
|
return TRUE; // Success
|
|
|
|
error:
|
|
if (!pbuf) {
|
|
MemFree(pbuf);
|
|
}
|
|
if (!pfileSrc) {
|
|
fclose(pfileSrc);
|
|
}
|
|
return FALSE;
|
|
} /* catTempFile() */
|
|
|
|
|
|
/*** DestroyFileInfo - Destroy a file info structure
|
|
*
|
|
* NOTE: see inf.h for entry/exit conditions.
|
|
*/
|
|
FNGLDESTROYVALUE(DestroyFileInfo)
|
|
{
|
|
PFILEINFO pfinfo;
|
|
|
|
//** Quick out
|
|
if (pv == NULL) {
|
|
return;
|
|
}
|
|
pfinfo = pv;
|
|
AssertFinfo(pfinfo);
|
|
|
|
//** Free DDF file name
|
|
if (pfinfo->pszDDF) {
|
|
MemFree(pfinfo->pszDDF);
|
|
}
|
|
|
|
//** Free parameter list
|
|
if (pfinfo->hglistParm != NULL) {
|
|
GLDestroyList(pfinfo->hglistParm);
|
|
}
|
|
|
|
//** Free INF line list
|
|
if (pfinfo->hglistInfLines != NULL) {
|
|
GLDestroyList(pfinfo->hglistInfLines);
|
|
}
|
|
|
|
//** Free structure
|
|
ClearAssertSignature(pfinfo);
|
|
MemFree(pfinfo);
|
|
} /* DestroyFileInfo() */
|
|
|
|
|
|
/*** DestroyLineInfo - Destroy a line info structure
|
|
*
|
|
* NOTE: see inf.h for entry/exit conditions.
|
|
*/
|
|
FNGLDESTROYVALUE(DestroyLineInfo)
|
|
{
|
|
PLINEINFO plinfo;
|
|
|
|
//** Quick out
|
|
if (pv == NULL) {
|
|
return;
|
|
}
|
|
plinfo = pv;
|
|
AssertLinfo(plinfo);
|
|
|
|
//** Free line
|
|
if (plinfo->pszLine) {
|
|
MemFree(plinfo->pszLine);
|
|
}
|
|
|
|
//** Free structure
|
|
ClearAssertSignature(plinfo);
|
|
MemFree(plinfo);
|
|
} /* DestroyLineInfo() */
|
|
|
|
|
|
|
|
|
|
/*** CheckForInfVarOverrides - Apply any InfXxxx overrides to FILEINFO
|
|
*
|
|
* NOTE: See inf.h for entry/exit conditions.
|
|
*/
|
|
BOOL CheckForInfVarOverrides(PSESSION psess,
|
|
PFILEINFO pfinfo,
|
|
PERROR perr)
|
|
{
|
|
HVARIABLE hvar;
|
|
char *pszValue;
|
|
PVALIDATEFILEPARM pvfp;
|
|
|
|
AssertSess(psess);
|
|
AssertFinfo(pfinfo);
|
|
|
|
//** See if any overrides are defined for standard parameters
|
|
for (pvfp=avfpInfVar; pvfp->pszName; pvfp++) {
|
|
//** See if variable is defined (don't clone to pass 2 var list)
|
|
hvar = GetInfCustomVar(psess,pvfp->pszName,FALSE,perr);
|
|
if (hvar) { // Variable is defined
|
|
pszValue = VarGetString(hvar);
|
|
Assert(pszValue != NULL);
|
|
//** Validate value
|
|
// Note: Validation functions will update *pfinfo *only* if
|
|
// a file copy parameter has not already done so!
|
|
if (!(*pvfp->pfnfpv)(psess,
|
|
pvfp->pszName,
|
|
pszValue,
|
|
pfinfo,
|
|
perr)) {
|
|
return FALSE; // perr already filled in
|
|
}
|
|
}
|
|
}
|
|
//** Success
|
|
return TRUE;
|
|
} /* CheckForInfVarOverrides() */
|
|
|
|
|
|
/*** validateParms - Validate list of file/reference parameters
|
|
*
|
|
* NOTE: See inf.h for entry/exit conditions.
|
|
*/
|
|
BOOL ValidateParms(PSESSION psess,
|
|
HGENLIST hglist,
|
|
PFILEINFO pfinfo,
|
|
PERROR perr)
|
|
{
|
|
HGENERIC hgen;
|
|
HVARIABLE hvar;
|
|
char *pszParm;
|
|
char *pszValue;
|
|
PFILEPARM pfparm;
|
|
PVALIDATEFILEPARM pvfp;
|
|
|
|
//** Quick out if list is empty
|
|
if (!hglist) {
|
|
return TRUE;
|
|
}
|
|
|
|
AssertSess(psess);
|
|
AssertFinfo(pfinfo);
|
|
|
|
//** Test parameters
|
|
for (hgen=GLFirstItem(hglist); hgen; hgen=GLNextItem(hgen)) {
|
|
pszParm = GLGetKey(hgen);
|
|
Assert(pszParm != NULL);
|
|
pfparm = GLGetValue(hgen);
|
|
AssertFparm(pfparm);
|
|
pszValue = pfparm->pszValue;
|
|
Assert(pszValue != NULL);
|
|
for (pvfp=avfpFile; pvfp->pszName; pvfp++) {
|
|
if (!_stricmp(pvfp->pszName,pszParm)) { // Found the parm
|
|
break; // Exit loop
|
|
}
|
|
}
|
|
if (pvfp->pszName) { // A standard parameter
|
|
//** Validate param
|
|
if (!(*pvfp->pfnfpv)(psess,
|
|
pszParm,
|
|
pszValue,
|
|
pfinfo,
|
|
perr)) {
|
|
return FALSE; // perr already filled in
|
|
}
|
|
}
|
|
else { // Might be a custom parameter
|
|
hvar = GetInfCustomVar(psess,pszParm,FALSE,perr);
|
|
if (!hvar) {
|
|
ErrSet(perr,pszINFERR_UNDECLARED_PARM,"%s",pszParm);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
//** Success
|
|
return TRUE;
|
|
} /* validateParms() */
|
|
|
|
|
|
/*** fnfpvBOOL - Validate a BOOLEAN value
|
|
*
|
|
*/
|
|
FNFPVALIDATE(fnfpvBOOL)
|
|
{
|
|
BOOL f;
|
|
|
|
f = BOOLfromPSZ(pszValue,perr);
|
|
if (f == -1) {
|
|
return FALSE; // perr already filled in
|
|
}
|
|
|
|
//** Success, no need to update pv
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*** fnfpvFileAttr - Validate FAT file attributes
|
|
*
|
|
*/
|
|
FNFPVALIDATE(fnfpvFileAttr)
|
|
{
|
|
WORD attr;
|
|
PFILEINFO pfinfo;
|
|
|
|
pfinfo = pv;
|
|
AssertFinfo(pfinfo);
|
|
|
|
//** Parse attr
|
|
attr = FATAttrFromPsz(pszValue,perr);
|
|
if (ErrIsError(perr)) {
|
|
return FALSE; // perr already filled in
|
|
}
|
|
|
|
//** Set attr in fileinfo, if not already set
|
|
if (!(pfinfo->flags & fifATTR_SET)) {
|
|
pfinfo->fta.attr = attr;
|
|
pfinfo->flags |= fifATTR_SET; // Override file date
|
|
}
|
|
|
|
return TRUE;
|
|
} /* fnfpvFileAttr() */
|
|
|
|
|
|
/*** fnfpvFileDate - Validate a FAT file date
|
|
*
|
|
*/
|
|
FNFPVALIDATE(fnfpvFileDate)
|
|
{
|
|
WORD date;
|
|
PFILEINFO pfinfo;
|
|
|
|
pfinfo = pv;
|
|
AssertFinfo(pfinfo);
|
|
|
|
//** Parse date
|
|
date = FATDateFromPsz(pszValue,perr);
|
|
if (ErrIsError(perr)) {
|
|
return FALSE; // perr already filled in
|
|
}
|
|
|
|
//** Set date in fileinfo, if not already set
|
|
if (!(pfinfo->flags & fifDATE_SET)) {
|
|
pfinfo->fta.date = date;
|
|
pfinfo->flags |= fifDATE_SET; // Override file date
|
|
}
|
|
|
|
return TRUE;
|
|
} /* fnfpvFileDate() */
|
|
|
|
|
|
/*** fnfpvFileTime - Validate a FAT file time
|
|
*
|
|
*/
|
|
FNFPVALIDATE(fnfpvFileTime)
|
|
{
|
|
WORD time;
|
|
PFILEINFO pfinfo;
|
|
|
|
pfinfo = pv;
|
|
AssertFinfo(pfinfo);
|
|
|
|
//** Parse time
|
|
time = FATTimeFromPsz(pszValue,perr);
|
|
if (ErrIsError(perr)) {
|
|
return FALSE; // perr already filled in
|
|
}
|
|
|
|
//** Set date in fileinfo, if not already set
|
|
if (!(pfinfo->flags & fifTIME_SET)) {
|
|
pfinfo->fta.time = time;
|
|
pfinfo->flags |= fifTIME_SET; // Override file date
|
|
}
|
|
|
|
return TRUE;
|
|
} /* fnfpvFileTime() */
|
|
|
|
|
|
/*** fnfpvLong - Validate a 32-bit integer
|
|
*
|
|
*/
|
|
FNFPVALIDATE(fnfpvLong)
|
|
{
|
|
char *psz;
|
|
|
|
for (psz=pszValue; *psz && isdigit(*psz); psz++) {
|
|
; //** Make sure entire value is digits
|
|
}
|
|
if (*psz != '\0') {
|
|
ErrSet(perr,pszINFERR_NOT_A_NUMBER,"%s%s",pszName,pszValue);
|
|
return FALSE;
|
|
}
|
|
|
|
//BUGBUG 04-Jun-1994 bens Should we verify number fits in 32-bits?
|
|
|
|
//** Success
|
|
return TRUE;
|
|
} /* fnfpvLong() */
|
|
|
|
|
|
/*** fnfpvShort - Validate a 16-bit integer
|
|
*
|
|
*/
|
|
FNFPVALIDATE(fnfpvShort)
|
|
{
|
|
char *psz;
|
|
long l;
|
|
|
|
for (psz=pszValue; *psz && isdigit(*psz); psz++) {
|
|
; //** Make sure entire value is digits
|
|
}
|
|
if (*psz != '\0') {
|
|
ErrSet(perr,pszINFERR_NOT_A_NUMBER,"%s%s",pszName,pszValue);
|
|
return FALSE;
|
|
}
|
|
|
|
//** Make sure it is in the range of a short
|
|
l = atol(pszValue);
|
|
if ((l < -32768) || (32767 < l)) {
|
|
ErrSet(perr,pszINFERR_NOT_A_SHORT,"%s%s",pszName,pszValue);
|
|
return FALSE;
|
|
}
|
|
|
|
//** Success
|
|
return TRUE;
|
|
} /* fnfpvShort() */
|
|
|
|
|
|
/*** fnfpvString - Validate an arbitrary string
|
|
*
|
|
*/
|
|
FNFPVALIDATE(fnfpvString)
|
|
{
|
|
//** Nothing to check
|
|
return TRUE;
|
|
} /* fnfpvString() */
|
|
|
|
|
|
/*** fnfpfFileName - Format destination file name
|
|
*
|
|
* NOTE: See FNFPFORMAT for entry/exit conditions.
|
|
*/
|
|
FNFPFORMAT(fnfpfFileName)
|
|
{
|
|
int cb;
|
|
PFILECONTEXT pfilecon;
|
|
|
|
AssertSascon(psascon);
|
|
Assert(psascon->pffp == affpFile);
|
|
|
|
pfilecon = psascon->pv;
|
|
AssertFilecon(pfilecon);
|
|
cb = strlen(pfilecon->pszFile);
|
|
if (cb >= cbDst) {
|
|
ErrSet(perr,pszINFERR_BUFFER_OVERFLOW,"%s%s",pszName,pfilecon->pszFile);
|
|
return -1;
|
|
}
|
|
strcpy(pszDst,pfilecon->pszFile); // Copy to output buffer
|
|
return cb; // Return size
|
|
} /* fnfpfFileName() */
|
|
|
|
|
|
/*** fnfpfDiskNumber - Format disk number
|
|
*
|
|
* NOTE: See FNFPFORMAT for entry/exit conditions.
|
|
*/
|
|
FNFPFORMAT(fnfpfDiskNumber)
|
|
{
|
|
char ach[10];
|
|
int cb;
|
|
int iDisk;
|
|
PCABCONTEXT pcabcon;
|
|
PDISKCONTEXT pdiskcon;
|
|
PFILECONTEXT pfilecon;
|
|
PFILEINFO pfinfo;
|
|
|
|
AssertSascon(psascon);
|
|
|
|
if (psascon->pffp == affpCabinet) {
|
|
pcabcon = psascon->pv;
|
|
AssertCabcon(pcabcon);
|
|
iDisk = pcabcon->iDisk;
|
|
}
|
|
else if (psascon->pffp == affpDisk) {
|
|
pdiskcon = psascon->pv;
|
|
AssertDiskcon(pdiskcon);
|
|
iDisk = pdiskcon->iDisk;
|
|
}
|
|
else if (psascon->pffp == affpFile) {
|
|
pfilecon = psascon->pv;
|
|
AssertFilecon(pfilecon);
|
|
|
|
pfinfo = pfilecon->pfinfo;
|
|
AssertFinfo(pfinfo);
|
|
iDisk = pfinfo->iDisk;
|
|
}
|
|
else {
|
|
//** Didn't get expected type
|
|
Assert(0);
|
|
}
|
|
|
|
sprintf(ach,"%d",iDisk);
|
|
cb = strlen(ach);
|
|
if (cb >= cbDst) {
|
|
ErrSet(perr,pszINFERR_BUFFER_OVERFLOW,"%s%s",pszName,ach);
|
|
return -1;
|
|
}
|
|
strcpy(pszDst,ach); // Copy to output buffer
|
|
return cb; // Return size
|
|
} /* fnfpfDiskNumber() */
|
|
|
|
|
|
/*** fnfpfCabinetNumber - Format cabinet number
|
|
*
|
|
* NOTE: See FNFPFORMAT for entry/exit conditions.
|
|
*/
|
|
FNFPFORMAT(fnfpfCabinetNumber)
|
|
{
|
|
char ach[10];
|
|
int cb;
|
|
int iCabinet;
|
|
PCABCONTEXT pcabcon;
|
|
PFILECONTEXT pfilecon;
|
|
PFILEINFO pfinfo;
|
|
|
|
AssertSascon(psascon);
|
|
|
|
if (psascon->pffp == affpCabinet) {
|
|
pcabcon = psascon->pv;
|
|
AssertCabcon(pcabcon);
|
|
iCabinet = pcabcon->iCabinet;
|
|
}
|
|
else if (psascon->pffp == affpFile) {
|
|
pfilecon = psascon->pv;
|
|
AssertFilecon(pfilecon);
|
|
|
|
pfinfo = pfilecon->pfinfo;
|
|
AssertFinfo(pfinfo);
|
|
iCabinet = pfinfo->iCabinet;
|
|
}
|
|
else {
|
|
//** Didn't get expected type
|
|
Assert(0);
|
|
}
|
|
|
|
sprintf(ach,"%d",iCabinet);
|
|
cb = strlen(ach);
|
|
if (cb >= cbDst) {
|
|
ErrSet(perr,pszINFERR_BUFFER_OVERFLOW,"%s%s",pszName,ach);
|
|
return -1;
|
|
}
|
|
strcpy(pszDst,ach); // Copy to output buffer
|
|
return cb; // Return size
|
|
} /* fnfpfCabinetNumber() */
|
|
|
|
|
|
/*** fnfpfFileNumber - Format file number
|
|
*
|
|
* NOTE: See FNFPFORMAT for entry/exit conditions.
|
|
*/
|
|
FNFPFORMAT(fnfpfFileNumber)
|
|
{
|
|
char ach[10];
|
|
int cb;
|
|
PFILECONTEXT pfilecon;
|
|
PFILEINFO pfinfo;
|
|
|
|
AssertSascon(psascon);
|
|
Assert(psascon->pffp == affpFile);
|
|
|
|
pfilecon = psascon->pv;
|
|
AssertFilecon(pfilecon);
|
|
|
|
pfinfo = pfilecon->pfinfo;
|
|
AssertFinfo(pfinfo);
|
|
|
|
sprintf(ach,"%d",pfinfo->iFile);
|
|
cb = strlen(ach);
|
|
if (cb >= cbDst) {
|
|
ErrSet(perr,pszINFERR_BUFFER_OVERFLOW,"%s%s",pszName,ach);
|
|
return -1;
|
|
}
|
|
strcpy(pszDst,ach); // Copy to output buffer
|
|
return cb; // Return size
|
|
} /* fnfpfFileNumber() */
|
|
|
|
|
|
/*** fnfpfFileSize - Format file size
|
|
*
|
|
* NOTE: See FNFPFORMAT for entry/exit conditions.
|
|
*/
|
|
FNFPFORMAT(fnfpfFileSize)
|
|
{
|
|
char ach[10];
|
|
int cb;
|
|
PFILECONTEXT pfilecon;
|
|
PFILEINFO pfinfo;
|
|
|
|
AssertSascon(psascon);
|
|
Assert(psascon->pffp == affpFile);
|
|
|
|
pfilecon = psascon->pv;
|
|
AssertFilecon(pfilecon);
|
|
|
|
pfinfo = pfilecon->pfinfo;
|
|
AssertFinfo(pfinfo);
|
|
|
|
sprintf(ach,"%ld",pfinfo->cbFile);
|
|
cb = strlen(ach);
|
|
if (cb >= cbDst) {
|
|
ErrSet(perr,pszINFERR_BUFFER_OVERFLOW,"%s%s",pszName,ach);
|
|
return -1;
|
|
}
|
|
strcpy(pszDst,ach); // Copy to output buffer
|
|
return cb; // Return size
|
|
} /* fnfpfFileSize() */
|
|
|
|
|
|
/*** fnfpfFileAttr - Format file attr
|
|
*
|
|
* NOTE: See FNFPFORMAT for entry/exit conditions.
|
|
*/
|
|
FNFPFORMAT(fnfpfFileAttr)
|
|
{
|
|
PFILECONTEXT pfilecon;
|
|
PFILEINFO pfinfo;
|
|
|
|
AssertSascon(psascon);
|
|
Assert(psascon->pffp == affpFile);
|
|
|
|
pfilecon = psascon->pv;
|
|
AssertFilecon(pfilecon);
|
|
|
|
pfinfo = pfilecon->pfinfo;
|
|
AssertFinfo(pfinfo);
|
|
|
|
//** NOTE: pszFromFATAttr checks for buffer overflow
|
|
return pszFromFATAttr(pszDst,cbDst,pfinfo->fta.attr);
|
|
} /* fnfpfFileAttr() */
|
|
|
|
|
|
/*** fnfpfFileDate - Format file date
|
|
*
|
|
* NOTE: See FNFPFORMAT for entry/exit conditions.
|
|
*/
|
|
FNFPFORMAT(fnfpfFileDate)
|
|
{
|
|
ERROR err;
|
|
BOOL fMMDDYY;
|
|
HVARIABLE hvar;
|
|
PFILECONTEXT pfilecon;
|
|
PFILEINFO pfinfo;
|
|
char *pszDateFmt;
|
|
|
|
AssertSascon(psascon);
|
|
Assert(psascon->pffp == affpFile);
|
|
|
|
pfilecon = psascon->pv;
|
|
AssertFilecon(pfilecon);
|
|
|
|
pfinfo = pfilecon->pfinfo;
|
|
AssertFinfo(pfinfo);
|
|
|
|
//** Get date format
|
|
AssertSess(psess);
|
|
ErrClear(&err);
|
|
hvar = VarFind(psess->hvlist,pszVAR_INF_DATE_FMT,&err);
|
|
Assert(!err.fError); // Must be defined
|
|
pszDateFmt = VarGetString(hvar);
|
|
fMMDDYY = (_stricmp(pszDateFmt,pszIDF_MMDDYY) == 0);
|
|
|
|
//** NOTE: pszFromFATDate checks for buffer overflow
|
|
return pszFromFATDate(pszDst,cbDst,pfinfo->fta.date,fMMDDYY);
|
|
} /* fnfpfFileDate() */
|
|
|
|
|
|
/*** fnfpfFileTime - Format file time
|
|
*
|
|
* NOTE: See FNFPFORMAT for entry/exit conditions.
|
|
*/
|
|
FNFPFORMAT(fnfpfFileTime)
|
|
{
|
|
PFILECONTEXT pfilecon;
|
|
PFILEINFO pfinfo;
|
|
|
|
AssertSascon(psascon);
|
|
Assert(psascon->pffp == affpFile);
|
|
|
|
pfilecon = psascon->pv;
|
|
AssertFilecon(pfilecon);
|
|
|
|
pfinfo = pfilecon->pfinfo;
|
|
AssertFinfo(pfinfo);
|
|
|
|
//** NOTE: pszFromFATTime checks for buffer overflow
|
|
return pszFromFATTime(pszDst,cbDst,pfinfo->fta.time);
|
|
} /* fnfpfFileTime() */
|
|
|
|
|
|
/*** fnfpfCabinetFileName - Format cabinet file name
|
|
*
|
|
* NOTE: See FNFPFORMAT for entry/exit conditions.
|
|
*/
|
|
FNFPFORMAT(fnfpfCabinetFileName)
|
|
{
|
|
int cb;
|
|
PCABCONTEXT pcabcon;
|
|
|
|
AssertSascon(psascon);
|
|
Assert(psascon->pffp == affpCabinet);
|
|
|
|
pcabcon = psascon->pv;
|
|
AssertCabcon(pcabcon);
|
|
|
|
cb = strlen(pcabcon->pszCab);
|
|
if (cb >= cbDst) {
|
|
ErrSet(perr,pszINFERR_BUFFER_OVERFLOW,"%s%s",pszName,pcabcon->pszCab);
|
|
return -1;
|
|
}
|
|
strcpy(pszDst,pcabcon->pszCab); // Copy to output buffer
|
|
return cb; // Return size
|
|
} /* fnfpfCabinetFileName() */
|
|
|
|
|
|
/*** fnfpfDiskLabel - Format disk label
|
|
*
|
|
* NOTE: See FNFPFORMAT for entry/exit conditions.
|
|
*/
|
|
FNFPFORMAT(fnfpfDiskLabel)
|
|
{
|
|
int cb;
|
|
PDISKCONTEXT pdiskcon;
|
|
|
|
AssertSascon(psascon);
|
|
Assert(psascon->pffp == affpDisk);
|
|
|
|
pdiskcon = psascon->pv;
|
|
AssertDiskcon(pdiskcon);
|
|
|
|
cb = strlen(pdiskcon->pszDisk);
|
|
if (cb >= cbDst) {
|
|
ErrSet(perr,pszINFERR_BUFFER_OVERFLOW,"%s%s",pszName,pdiskcon->pszDisk);
|
|
return -1;
|
|
}
|
|
strcpy(pszDst,pdiskcon->pszDisk); // Copy to output buffer
|
|
return cb; // Return size
|
|
} /* fnfpfDiskLabel() */
|
|
|
|
|
|
/*** fnfpfFileVerNum - Format file version *number*
|
|
*
|
|
* NOTE: See FNFPFORMAT for entry/exit conditions.
|
|
*/
|
|
FNFPFORMAT(fnfpfFileVerNum)
|
|
{
|
|
int cb;
|
|
PFILECONTEXT pfilecon;
|
|
PFILEINFO pfinfo;
|
|
|
|
AssertSess(psess);
|
|
psess->fGetVerInfo = TRUE; // Have to get file version info
|
|
|
|
AssertSascon(psascon);
|
|
Assert(psascon->pffp == affpFile);
|
|
|
|
pfilecon = psascon->pv;
|
|
AssertFilecon(pfilecon);
|
|
|
|
pfinfo = pfilecon->pfinfo;
|
|
AssertFinfo(pfinfo);
|
|
|
|
//** Check for no version number (all zeros)
|
|
if ((pfinfo->verMS == 0) && (pfinfo->verLS == 0)) {
|
|
return 0; // Nothing copied to output buffer
|
|
}
|
|
|
|
//** Format version number
|
|
cb = sprintf(psess->achMsg,"%d.%d.%d.%d",
|
|
HIWORD(pfinfo->verMS),
|
|
LOWORD(pfinfo->verMS),
|
|
HIWORD(pfinfo->verLS),
|
|
LOWORD(pfinfo->verLS));
|
|
|
|
//** Check for buffer overflow
|
|
if (cb >= cbDst) {
|
|
ErrSet(perr,pszINFERR_BUFFER_OVERFLOW,"%s%s",pszName,psess->achMsg);
|
|
return -1;
|
|
}
|
|
strcpy(pszDst,psess->achMsg); // Copy to output buffer
|
|
return cb; // Return size
|
|
} /* fnfpfFileVerNum() */
|
|
|
|
|
|
/*** fnfpfFileVerString - Format file version *string*
|
|
*
|
|
* NOTE: See FNFPFORMAT for entry/exit conditions.
|
|
*/
|
|
FNFPFORMAT(fnfpfFileVerString)
|
|
{
|
|
int cb;
|
|
PFILECONTEXT pfilecon;
|
|
PFILEINFO pfinfo;
|
|
|
|
AssertSess(psess);
|
|
psess->fGetVerInfo = TRUE; // Have to get file version info
|
|
|
|
AssertSascon(psascon);
|
|
Assert(psascon->pffp == affpFile);
|
|
|
|
pfilecon = psascon->pv;
|
|
AssertFilecon(pfilecon);
|
|
|
|
pfinfo = pfilecon->pfinfo;
|
|
AssertFinfo(pfinfo);
|
|
|
|
//** Check for undefined version string
|
|
if (pfinfo->pszVersion == NULL) {
|
|
return 0; // No version string copied
|
|
}
|
|
|
|
//** Check length and store string in buffer
|
|
cb = strlen(pfinfo->pszVersion);
|
|
if (cb >= cbDst) {
|
|
ErrSet(perr,pszINFERR_BUFFER_OVERFLOW,"%s%s",
|
|
pszName,pfinfo->pszVersion);
|
|
return -1;
|
|
}
|
|
strcpy(pszDst,pfinfo->pszVersion); // Copy to output buffer
|
|
return cb; // Return size
|
|
} /* fnfpfFileVerString() */
|
|
|
|
|
|
/*** fnfpfFileChecksum - Format file checksum
|
|
*
|
|
* NOTE: See FNFPFORMAT for entry/exit conditions.
|
|
*/
|
|
FNFPFORMAT(fnfpfFileChecksum)
|
|
{
|
|
char ach[10];
|
|
int cb;
|
|
int cHexDigits;
|
|
ULONG csum;
|
|
ULONG mask;
|
|
PFILECONTEXT pfilecon;
|
|
PFILEINFO pfinfo;
|
|
HVARIABLE hvar;
|
|
|
|
AssertSess(psess);
|
|
psess->fGetFileChecksum = TRUE; // Have to compute file checksums
|
|
|
|
AssertSascon(psascon);
|
|
Assert(psascon->pffp == affpFile);
|
|
|
|
pfilecon = psascon->pv;
|
|
AssertFilecon(pfilecon);
|
|
|
|
pfinfo = pfilecon->pfinfo;
|
|
AssertFinfo(pfinfo);
|
|
|
|
//** Get the ChecksumWidth value, and mask off any undesired bits
|
|
// NOTE: By ensuring the upper bits are zero, we effectively bound
|
|
// the width of the checksum that is printed.
|
|
// Why would we throw away this valuable info, you ask? Because
|
|
// the Windows 95 setup program runs as a Win16 application, and
|
|
// is limited to 64Kb INF files. While the US English version does
|
|
// not exceed this limit, the Far East versions have many more
|
|
// files, and they do. So, there you have it!
|
|
//
|
|
hvar = VarFind(psess->hvlist,pszVAR_CHECKSUM_WIDTH,perr);
|
|
Assert(!perr->fError); // Must be defined
|
|
cHexDigits = (int)VarGetLong(hvar); // Get desired width
|
|
csum = pfinfo->checksum; // Get full checksum value
|
|
Assert(cHexDigits >= 1);
|
|
Assert(cHexDigits <= 8);
|
|
if (cHexDigits != 8) { // Need to mask off high-order bits
|
|
mask = (1L << (cHexDigits*4)) - 1; // Construct mask
|
|
csum &= mask; // Keep desired bits
|
|
}
|
|
|
|
//** Use hex format to minimize INF file size
|
|
sprintf(ach,"%lx", csum);
|
|
cb = strlen(ach);
|
|
if (cb >= cbDst) {
|
|
ErrSet(perr,pszINFERR_BUFFER_OVERFLOW,"%s%s",pszName,ach);
|
|
return -1;
|
|
}
|
|
strcpy(pszDst,ach); // Copy to output buffer
|
|
return cb; // Return size
|
|
} /* fnfpfFileChecksum() */
|
|
|
|
|
|
/*** fnfpfFileLanguage - Format file language code(s)
|
|
*
|
|
* NOTE: See FNFPFORMAT for entry/exit conditions.
|
|
*/
|
|
FNFPFORMAT(fnfpfFileLanguage)
|
|
{
|
|
int cb;
|
|
PFILECONTEXT pfilecon;
|
|
PFILEINFO pfinfo;
|
|
|
|
AssertSess(psess);
|
|
psess->fGetVerInfo = TRUE; // Only for checkInfLineFormats()
|
|
|
|
AssertSascon(psascon);
|
|
Assert(psascon->pffp == affpFile);
|
|
|
|
pfilecon = psascon->pv;
|
|
AssertFilecon(pfilecon);
|
|
|
|
pfinfo = pfilecon->pfinfo;
|
|
AssertFinfo(pfinfo);
|
|
|
|
//** Check for undefined string
|
|
if (pfinfo->pszLang == NULL) {
|
|
return 0; // No string copied
|
|
}
|
|
|
|
//** Check length and store string in buffer
|
|
cb = strlen(pfinfo->pszLang);
|
|
if (cb >= cbDst) {
|
|
ErrSet(perr,pszINFERR_BUFFER_OVERFLOW,"%s%s",
|
|
pszName,pfinfo->pszLang);
|
|
return -1;
|
|
}
|
|
strcpy(pszDst,pfinfo->pszLang); // Copy to output buffer
|
|
return cb; // Return size
|
|
} /* fnfpfFileLanguage() */
|
|
|
|
|
|
/*** checkInfLineFormats - Check validity of InfXxxLineFormat variables
|
|
*
|
|
* We do this by crofting up fake data for one disk, one cabinet, and one
|
|
* file line, and trying to format each of these with the the same code that
|
|
* does it at INF generation time. If these all succeed, we must be OK!
|
|
*
|
|
* We also have code in each of the ver info formatting routines to set the
|
|
* psess->fGetVerInfo flag, so we can tell that we have to spend the extra
|
|
* time extracting version information from every file!
|
|
*
|
|
* We also have code in the file checksum formatting routine to set the
|
|
* psess->fGetFileChecksum flag, so we can tell that we have to spend the
|
|
* extra time computing source file checksums for every file!
|
|
*
|
|
* Entry:
|
|
* psess - Session
|
|
* perr - ERROR
|
|
*
|
|
* Exit-Success:
|
|
* Returns TRUE; formats are OK.
|
|
* psess->fGetVerInfo set if any of the parameters *ver*, *vers*, or
|
|
* *lang* were referenced.
|
|
* psess->fGetFileChecksum set if *csum* parameter is referenced.
|
|
*
|
|
* Exit-Failure:
|
|
* Returns FALSE; perr filled in
|
|
*/
|
|
BOOL checkInfLineFormats(PSESSION psess,PERROR perr)
|
|
{
|
|
CABCONTEXT cabcon;
|
|
DISKCONTEXT diskcon;
|
|
FILECONTEXT filecon;
|
|
HVARIABLE hvar;
|
|
PINF pinf;
|
|
FILEINFO finfo;
|
|
char *pszFmt;
|
|
SASCONTEXT sascon;
|
|
|
|
AssertSess(psess);
|
|
pinf = PINFfromHINF(psess->hinf);
|
|
AssertInf(pinf);
|
|
|
|
SetAssertSignature((&sascon),sigSASCONTEXT);
|
|
sascon.psess = psess;
|
|
sascon.hglistParm = NULL;
|
|
|
|
/*
|
|
** Check InfDiskLineFormat
|
|
*/
|
|
//** Get disk line format
|
|
hvar = VarFind(psess->hvlist,pszVAR_INF_DISK_LINE_FMT,perr);
|
|
Assert(!perr->fError); // Must be defined
|
|
pszFmt = VarGetString(hvar); // Disk line format
|
|
|
|
//** Format and write line to file
|
|
SetAssertSignature((&diskcon),sigDISKCONTEXT);
|
|
diskcon.iDisk = 1;
|
|
diskcon.pszDisk = "test";
|
|
|
|
sascon.pffp = affpDisk;
|
|
sascon.pv = &diskcon;
|
|
|
|
if (!SubstituteFormatString(pinf->achLine,
|
|
sizeof(pinf->achLine),
|
|
pszFmt,
|
|
fnfpInfLine,
|
|
&sascon,
|
|
perr)) {
|
|
strcpy(pinf->achLine,perr->ach); // Save details
|
|
ErrSet(perr,pszINFERR_BAD_FMT,"%s%s",
|
|
pszVAR_INF_DISK_LINE_FMT, pinf->achLine);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
** Check InfCabinetLineFormat
|
|
*/
|
|
//** Get cabinet line format
|
|
hvar = VarFind(psess->hvlist,pszVAR_INF_CAB_LINE_FMT,perr);
|
|
Assert(!perr->fError); // Must be defined
|
|
pszFmt = VarGetString(hvar); // Cabinet line format
|
|
|
|
//** Format and write line to file
|
|
SetAssertSignature((&cabcon),sigCABCONTEXT);
|
|
cabcon.iCabinet = 1;
|
|
cabcon.iDisk = 1;
|
|
cabcon.pszCab = "test";
|
|
|
|
sascon.pffp = affpCabinet;
|
|
sascon.pv = &cabcon;
|
|
|
|
if (!SubstituteFormatString(pinf->achLine,
|
|
sizeof(pinf->achLine),
|
|
pszFmt,
|
|
fnfpInfLine,
|
|
&sascon,
|
|
perr)) {
|
|
strcpy(pinf->achLine,perr->ach); // Save details
|
|
ErrSet(perr,pszINFERR_BAD_FMT,"%s%s",
|
|
pszVAR_INF_CAB_LINE_FMT, pinf->achLine);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
** Check InfFileLineFormat
|
|
*/
|
|
//** Fill in dummy FILEINFO structure
|
|
SetAssertSignature((&finfo),sigFILEINFO);
|
|
finfo.pszDDF = "test";
|
|
finfo.ilineDDF = 1;
|
|
finfo.cbFile = 1;
|
|
finfo.iDisk = 1;
|
|
finfo.iCabinet = 1;
|
|
finfo.fta.date = 0;
|
|
finfo.fta.time = 0;
|
|
finfo.fta.attr = 0;
|
|
finfo.hglistInfLines = NULL;
|
|
finfo.flags = 0;
|
|
finfo.hglistParm = NULL;
|
|
finfo.checksum = 0;
|
|
finfo.verMS = 0;
|
|
finfo.verLS = 0;
|
|
finfo.pszVersion = NULL;
|
|
finfo.pszLang = NULL;
|
|
|
|
//** Get line format
|
|
hvar = VarFind(psess->hvlist,pszVAR_INF_FILE_LINE_FMT,perr);
|
|
Assert(!perr->fError); // Must be defined
|
|
pszFmt = VarGetString(hvar); // File line format
|
|
|
|
//** Format and write line to file
|
|
SetAssertSignature((&filecon),sigFILECONTEXT);
|
|
filecon.pszFile = "a test";
|
|
filecon.pfinfo = &finfo;
|
|
|
|
sascon.pffp = affpFile;
|
|
sascon.pv = &filecon;
|
|
|
|
if (!SubstituteFormatString(pinf->achLine,
|
|
sizeof(pinf->achLine),
|
|
pszFmt,
|
|
fnfpInfLine,
|
|
&sascon,
|
|
perr)) {
|
|
strcpy(pinf->achLine,perr->ach); // Save details
|
|
ErrSet(perr,pszINFERR_BAD_FMT,"%s%s",
|
|
pszVAR_INF_FILE_LINE_FMT, pinf->achLine);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
** SUCCESS
|
|
*/
|
|
return TRUE;
|
|
} /* checkInfLineFormats() */
|
|
|
|
|
|
/*** fnfpInfLine - Format parameter in an INF File, Disk, or Cab line
|
|
*
|
|
* NOTE: See format.h for entry/exit conditions.
|
|
*
|
|
* Strategy:
|
|
* Determine where to get value from, according to this priority:
|
|
* (1) Parameter list
|
|
* (2) InfXxxx variable
|
|
* (3) Standard parameter
|
|
*
|
|
* Error checking:
|
|
* As this is called from pass 2, we can rely upon pass 1 to catch
|
|
* certain errors (like /x=y on a file copy/reference command without
|
|
* the variable InfX being defined). We will wait and catch truly
|
|
* undefined parameters in the InfXxxLineFormat variables until now,
|
|
* because it is easier than writing another routine to scan through
|
|
* and look for undefined parms.
|
|
*/
|
|
FNFORMATPARM(fnfpInfLine)
|
|
{
|
|
char achDate[20];
|
|
int cb;
|
|
WORD date;
|
|
BOOL fMMDDYY; // TRUE => use MM/DD/YY format
|
|
HVARIABLE hvar;
|
|
PSASCONTEXT psascon;
|
|
PFORMATFILEPARM pffp=NULL;
|
|
PFILEPARM pfparm;
|
|
PSESSION psess;
|
|
char *pszDateFmt;
|
|
char *pszValue;
|
|
|
|
psascon = pv;
|
|
AssertSascon(psascon);
|
|
psess = psascon->psess;
|
|
AssertSess(psess);
|
|
|
|
//** (1) Look on parm list
|
|
pfparm = GLFindAndGetValue(psascon->hglistParm,pszParm);
|
|
|
|
//** (2) Look for InfXxxxx variable (copy to pass 2 list if pass 1)
|
|
hvar = GetInfCustomVar(psess,pszParm,TRUE,perr);
|
|
|
|
//** (3) Look for a standard parameter if we didn't find a variable
|
|
if (!hvar) {
|
|
for (pffp=psascon->pffp; pffp->pszName; pffp++) {
|
|
if (!_stricmp(pffp->pszName,pszParm)) { // Found the parm
|
|
break; // Exit loop
|
|
}
|
|
}
|
|
if (!pffp->pszName) { // No match
|
|
pffp = NULL; // Indicate failure for below
|
|
}
|
|
}
|
|
|
|
/*
|
|
* OK, now we have the following state:
|
|
* pfparm - non-null if value is on parm list
|
|
* hvar - non-null if InfXxxx variable is defined for parm
|
|
* pffp - non-null if hvar==NULL *and* standard parm
|
|
*/
|
|
|
|
if (pfparm || hvar) { // Use parm list or variable value
|
|
if (pfparm && !(hvar || pffp)) {
|
|
//** Pass 1 should catch /x=y without InfX variable definition!
|
|
Assert(0);
|
|
return -1;
|
|
}
|
|
else if (pfparm) { // Use parm list value
|
|
AssertFparm(pfparm);
|
|
pszValue = pfparm->pszValue;
|
|
}
|
|
else {
|
|
Assert(hvar != NULL); // Use variable value
|
|
pszValue = VarGetString(hvar);
|
|
Assert(pszValue != NULL);
|
|
}
|
|
|
|
//** See if we have to normalize date format
|
|
if (!_stricmp(pszParm,pszPARM_FILEDATE)) {
|
|
date = FATDateFromPsz(pszValue,perr); // Convert to date
|
|
Assert(!perr->fError); // Was already validated
|
|
hvar = VarFind(psess->hvlist,pszVAR_INF_DATE_FMT,perr);
|
|
Assert(!perr->fError); // Must be defined
|
|
pszDateFmt = VarGetString(hvar);
|
|
fMMDDYY = (_stricmp(pszDateFmt,pszIDF_MMDDYY) == 0);
|
|
if (-1 == pszFromFATDate(achDate,sizeof(achDate),date,fMMDDYY)) {
|
|
return -1;
|
|
}
|
|
pszValue = achDate; // Use reformated date string
|
|
}
|
|
|
|
//** copy value
|
|
cb = strlen(pszValue);
|
|
if (cb >= cbOut) {
|
|
ErrSet(perr,pszINFERR_BUFFER_OVERFLOW,"%s%s",pszParm,pszValue);
|
|
return -1;
|
|
}
|
|
strcpy(pszOut,pszValue);
|
|
return cb;
|
|
}
|
|
else if (pffp) {
|
|
//** Format a standard parameter
|
|
return (*pffp->pfnfpf)(psascon->psess, // Session
|
|
pszOut, // Output buffer
|
|
cbOut, // Output buffer size
|
|
pszParm, // Parameter name
|
|
psascon, // SAS Context
|
|
perr);
|
|
}
|
|
else {
|
|
//** Parameter name was never defined at all! No InfX variable,
|
|
// no /X on a file copy or reference command, and it is not a
|
|
// standard parameter.
|
|
ErrSet(perr,pszINFERR_UNDEFINED_PARM,"%s",pszParm);
|
|
return -1;
|
|
}
|
|
Assert(0);
|
|
} /* fnfpInfLine() */
|
|
|
|
|
|
/*** pszFromFATDate - Convert MS-DOS file date to string
|
|
*
|
|
* Entry:
|
|
* pszDst - Buffer to receive formatted date
|
|
* cbDst - Length of psz buffer
|
|
* date - MS-DOS FAT file system date format (see below)
|
|
* fMMDDYY - TRUE => use mm/dd/yy; FALSE => use yyyy-mm-dd
|
|
*
|
|
* Exit-Success:
|
|
* Returns length of string stored in *psz (not counting NUL byte)
|
|
*
|
|
* Exit-Failure:
|
|
* Returns -1; buffer too small
|
|
*
|
|
* NOTE: This is the interpretation of the MS-DOS date value:
|
|
*
|
|
* Date Bits cBits Meaning
|
|
* --------- ----- ----------------------------------------
|
|
* 0 - 4 5 Day (1 - 31)
|
|
* 5 - 8 4 Month (1 - 12)
|
|
* 9 - 15 7 Year since 1980 (for example, 1994 is stored as 14)
|
|
*/
|
|
int pszFromFATDate(char *pszDst, int cbDst, WORD date, BOOL fMMDDYY)
|
|
{
|
|
char ach[50];
|
|
int cb;
|
|
int day;
|
|
int month;
|
|
int year;
|
|
|
|
day = (date & 0x1f);
|
|
month = (date >> 5) & 0x0f;
|
|
year = ((date >> 9) & 0x7f) + yearFAT_DATE_MIN;
|
|
|
|
if (fMMDDYY) {
|
|
//** Adjust year to two digits, if appropriate
|
|
if (year < 2000) { // 1980..1999 -> 80..99
|
|
year -= 1900;
|
|
}
|
|
else if (year < 2080) { // 2000..2079 -> 00..79
|
|
year -= 2000;
|
|
}
|
|
//** Format mm/dd/yy
|
|
MsgSet(ach,pszINF_DATE_FMT,"%02d%02d%02d",month,day,year);
|
|
}
|
|
else {
|
|
//** Format yyyy-mm-dd
|
|
MsgSet(ach,pszINF_DATE_FMT2,"%04d%02d%02d",year,month,day);
|
|
}
|
|
|
|
cb = strlen(ach);
|
|
if (cb >= cbDst) {
|
|
return -1; // Buffer too small
|
|
}
|
|
strcpy(pszDst,ach);
|
|
return cb;
|
|
} /* pszFromFATDate() */
|
|
|
|
|
|
/*** FATDateFromPsz - Convert string to MS-DOS file date
|
|
*
|
|
* Entry:
|
|
* pszDate - String with MM/DD/YY or YYYY-MM-DD date
|
|
* perr - ERROR structure
|
|
*
|
|
* Exit-Success:
|
|
* Returns FAT file system date;
|
|
* perr is clear (ErrIsError(perr) is FALSE).
|
|
*
|
|
* Exit-Failure:
|
|
* Returns 0; perr is filled with an error
|
|
*
|
|
* NOTE: This is the interpretation of the MS-DOS date value:
|
|
*
|
|
* Date Bits cBits Meaning
|
|
* --------- ----- ----------------------------------------
|
|
* 0 - 4 5 Day (1 - 31)
|
|
* 5 - 8 4 Month (1 - 12)
|
|
* 9 - 15 7 Year since 1980 (for example, 1994 is stored as 14)
|
|
* (1980..2107)
|
|
*/
|
|
WORD FATDateFromPsz(char *pszDate, PERROR perr)
|
|
{
|
|
char chSep;
|
|
WORD date;
|
|
int day;
|
|
int month;
|
|
char *psz;
|
|
int t;
|
|
int year;
|
|
|
|
//** Make sure date is long enough to include first separator
|
|
if (strlen(pszDate) < 5) { // Check for minimum length
|
|
ErrSet(perr,pszINFERR_INVALID_DATE_FORMAT,"%s",pszDate);
|
|
return 0;
|
|
}
|
|
|
|
//** Choose between two date formats
|
|
if (pszDate[2] == chINF_DATE_SEP) {
|
|
chSep = pszDate[2]; // Remember separator ('/')
|
|
}
|
|
else if (pszDate[4] == chINF_DATE_SEP2) {
|
|
chSep = pszDate[4]; // Remember separator ('-')
|
|
}
|
|
else {
|
|
ErrSet(perr,pszINFERR_INVALID_DATE_FORMAT,"%s",pszDate);
|
|
return 0;
|
|
}
|
|
|
|
//** Parse off month (or year)
|
|
month = atoi(pszDate);
|
|
if (!(psz = strchr(pszDate,chSep))) {
|
|
ErrSet(perr,pszINFERR_MISSING_DATE_SEPARATOR,"%c%s",chSep,pszDate);
|
|
return 0;
|
|
}
|
|
psz++; // Skip over separator
|
|
|
|
//** Parse off day (or month)
|
|
day = atoi(psz);
|
|
if (!(psz = strchr(psz,chSep))) {
|
|
ErrSet(perr,pszINFERR_MISSING_DATE_SEPARATOR,"%c%s",chSep,pszDate);
|
|
return 0;
|
|
}
|
|
psz++; // Skip over separator
|
|
|
|
//** Parse off year (or day)
|
|
year = atoi(psz);
|
|
|
|
//** Shuffle around numbers if YYYY-MM-DD format
|
|
if (chSep == chINF_DATE_SEP2) {
|
|
t = day; // save month
|
|
day = year;
|
|
year = month;
|
|
month = t;
|
|
}
|
|
|
|
//** Check ranges (but not invalid dates!)
|
|
if ((day < 1) || (day > 31) || ((month == 2) && (day > 29))) {
|
|
ErrSet(perr,pszINFERR_BAD_DAY_IN_DATE,"%d%s",day,pszDate);
|
|
return 0;
|
|
}
|
|
if ((month < 1) || (month > 12)) {
|
|
ErrSet(perr,pszINFERR_BAD_MONTH_IN_DATE,"%d%s",day,pszDate);
|
|
return 0;
|
|
}
|
|
|
|
//** Permit both two digit (94) and 4 digit (1994) dates
|
|
if (year < 100) { // Convert to 4-digit date
|
|
if (year < 80) { // Must be 20xx
|
|
year += 2000;
|
|
}
|
|
else { // Must be 19xx
|
|
year += 1900;
|
|
}
|
|
}
|
|
|
|
if (year < yearFAT_DATE_MIN) {
|
|
ErrSet(perr,pszINFERR_LO_YEAR_IN_DATE,"%d%d%s",
|
|
year,yearFAT_DATE_MIN,pszDate);
|
|
return 0;
|
|
}
|
|
if (year > yearFAT_DATE_MAX) {
|
|
ErrSet(perr,pszINFERR_HI_YEAR_IN_DATE,"%d%d%s",
|
|
year,yearFAT_DATE_MAX,pszDate);
|
|
return 0;
|
|
}
|
|
|
|
//** Combine year, month, and day
|
|
date = (year-1980)<<9 | month<<5 | day;
|
|
ErrClear(perr); // Make sure error is clear
|
|
return date;
|
|
} /* FATDateFromPsz() */
|
|
|
|
|
|
/*** pszFromFATTime - Convert MS-DOS file time to string
|
|
*
|
|
* Entry:
|
|
* pszDst - Buffer to receive formatted time
|
|
* cbDst - Length of psz buffer
|
|
* time - MS-DOS FAT file system time format (see below)
|
|
*
|
|
* Exit-Success:
|
|
* Returns length of string stored in *psz (not counting NUL byte)
|
|
*
|
|
* Exit-Failure:
|
|
* Returns -1; buffer too small
|
|
*
|
|
* NOTE: This is the interpretation of the MS-DOS time value:
|
|
*
|
|
* Time Bits cBits Meaning
|
|
* --------- ----- ----------------------------------------
|
|
* 0 - 4 5 Number of two-second increments (0 - 29)
|
|
* 5 - 10 6 Minutes (0 - 59)
|
|
* 11 - 15 5 Hours (0 - 23)
|
|
*/
|
|
int pszFromFATTime(char *pszDst, int cbDst, WORD time)
|
|
{
|
|
char ach[50];
|
|
int cb;
|
|
int sec;
|
|
int min;
|
|
int hour;
|
|
char chAMPM; // AM/PM string
|
|
|
|
sec = (time & 0x1f) << 1;
|
|
min = (time >> 5) & 0x3f;
|
|
hour = (time >> 11) & 0x1f;
|
|
|
|
//** Get am/pm extension, and map 0 to 12
|
|
if (hour >= 12) {
|
|
chAMPM = chINF_TIME_PM;
|
|
hour -= 12;
|
|
}
|
|
else {
|
|
chAMPM = chINF_TIME_AM;
|
|
}
|
|
if (hour == 0) {
|
|
hour = 12;
|
|
}
|
|
|
|
MsgSet(ach,pszINF_TIME_FMT,"%02d%02d%02d%c",hour,min,sec,chAMPM);
|
|
cb = strlen(ach);
|
|
if (cb >= cbDst) {
|
|
return -1; // Buffer too small
|
|
}
|
|
strcpy(pszDst,ach);
|
|
return cb;
|
|
} /* pszFromFATTime() */
|
|
|
|
|
|
/*** FATTimeFromPsz - Convert string to MS-DOS file date
|
|
*
|
|
* Entry:
|
|
* pszTime - String with HH:MM:SSa|p format
|
|
* perr - ERROR structure
|
|
*
|
|
* Exit-Success:
|
|
* Returns FAT file system time;
|
|
* perr is clear (ErrIsError(perr) is FALSE).
|
|
*
|
|
* Exit-Failure:
|
|
* Returns 0; perr is filled with an error
|
|
*
|
|
* NOTE: This is the interpretation of the MS-DOS time value:
|
|
*
|
|
* Time Bits cBits Meaning
|
|
* --------- ----- ----------------------------------------
|
|
* 0 - 4 5 Number of two-second increments (0 - 29)
|
|
* 5 - 10 6 Minutes (0 - 59)
|
|
* 11 - 15 5 Hours (0 - 23)
|
|
*/
|
|
WORD FATTimeFromPsz(char *pszTime, PERROR perr)
|
|
{
|
|
char ch;
|
|
int hour;
|
|
int min;
|
|
char *psz;
|
|
int sec;
|
|
WORD time;
|
|
|
|
//** Parse off hour
|
|
hour = atoi(pszTime);
|
|
if (!(psz = strchr(pszTime,chINF_TIME_SEP))) {
|
|
ErrSet(perr,pszINFERR_MISSING_TIME_SEPARATOR,"%c%s",
|
|
chINF_TIME_SEP,pszTime);
|
|
return 0;
|
|
}
|
|
psz++; // Skip over separator
|
|
|
|
//** Parse off minute
|
|
min = atoi(psz);
|
|
if (!(psz = strchr(psz,chINF_TIME_SEP))) {
|
|
ErrSet(perr,pszINFERR_MISSING_TIME_SEPARATOR,"%c%s",
|
|
chINF_TIME_SEP,pszTime);
|
|
return 0;
|
|
}
|
|
psz++; // Skip over separator
|
|
|
|
//** Parse off seconds
|
|
sec = atoi(psz);
|
|
|
|
//** Parse off a/p
|
|
ch = tolower(psz[2]); // Require 2 digits for seconds
|
|
switch (ch) {
|
|
case chINF_TIME_AM:
|
|
case chINF_TIME_PM:
|
|
//** Check range
|
|
if ((hour < 1) || (hour > 12)) {
|
|
ErrSet(perr,pszINFERR_BAD_HOUR_IN_TIME,"%d%s",hour,pszTime);
|
|
return 0;
|
|
}
|
|
//** Convert to 24-hour clock
|
|
//** 12:xx AM -> 0
|
|
//** 1:xx AM -> 1
|
|
//** ...
|
|
//** 11:xx AM -> 11
|
|
//** 12:xx PM -> 12
|
|
//** 1:xx PM -> 13
|
|
//** ...
|
|
//** 11:xx PM -> 23
|
|
|
|
if (hour == 12) { // Move 12 back to 0
|
|
hour = 0;
|
|
}
|
|
if (ch == chINF_TIME_PM) {
|
|
hour += 12; // Swing PM times up
|
|
}
|
|
break;
|
|
|
|
case '\0': // Assume 24-hour clock
|
|
break;
|
|
|
|
default:
|
|
ErrSet(perr,pszINFERR_BAD_TIME_AM_PM,"%c%s",ch,pszTime);
|
|
return 0;
|
|
}
|
|
|
|
//** Check ranges
|
|
if ((sec < 0) || (sec > 59)) {
|
|
ErrSet(perr,pszINFERR_BAD_SEC_IN_TIME,"%d%s",sec,pszTime);
|
|
return 0;
|
|
}
|
|
if (sec % 2) { // Only permit even seconds
|
|
ErrSet(perr,pszINFERR_ODD_SEC_IN_TIME,"%d%s",sec,pszTime);
|
|
return 0;
|
|
}
|
|
if ((min < 0) || (min > 59)) {
|
|
ErrSet(perr,pszINFERR_BAD_MINUTE_IN_TIME,"%d%s",min,pszTime);
|
|
return 0;
|
|
}
|
|
if ((hour < 0) || (hour > 23)) {
|
|
ErrSet(perr,pszINFERR_BAD_HOUR_IN_TIME,"%d%s",hour,pszTime);
|
|
return 0;
|
|
}
|
|
|
|
//** Combine hour, minute, and second
|
|
time = hour<<11 | min<<5 | sec>>1;
|
|
ErrClear(perr); // Make sure error is clear
|
|
return time;
|
|
} /* FATTimeFromPsz() */
|
|
|
|
|
|
/*** pszFromFATAttr - Convert MS-DOS file date to string
|
|
*
|
|
* Entry:
|
|
* pszDst - Buffer to receive formatted date
|
|
* cbDst - Length of psz buffer
|
|
* date - MS-DOS FAT file system date format (see below)
|
|
*
|
|
* Exit-Success:
|
|
* Returns length of string stored in *psz (not counting NUL byte)
|
|
*
|
|
* Exit-Failure:
|
|
* Returns -1; buffer too small
|
|
*/
|
|
int pszFromFATAttr(char *pszDst, int cbDst, WORD attr)
|
|
{
|
|
char *psz;
|
|
|
|
Assert(pszDst != NULL);
|
|
psz = pszDst;
|
|
|
|
//** Require worst-case buffer size
|
|
if (cbDst < 5) {
|
|
return -1;
|
|
}
|
|
|
|
//** Create string representation
|
|
if (attr & _A_ARCH ) *psz++ = chINF_ATTR_ARCHIVE;
|
|
if (attr & _A_HIDDEN) *psz++ = chINF_ATTR_HIDDEN;
|
|
if (attr & _A_RDONLY) *psz++ = chINF_ATTR_READONLY;
|
|
if (attr & _A_SYSTEM) *psz++ = chINF_ATTR_SYSTEM;
|
|
|
|
//** Terminate string
|
|
*psz = '\0';
|
|
|
|
//** Return length (not counting NUL byte)
|
|
return psz-pszDst;
|
|
} /* pszFromFATAttr() */
|
|
|
|
|
|
/*** FATAttrFromPsz - Convert string to MS-DOS file attributes
|
|
*
|
|
* Entry:
|
|
* pszAttr - String composed of letters from {R,H,S,A}
|
|
* perr - ERROR structure
|
|
*
|
|
* Exit-Success:
|
|
* Returns FAT file system attributes;
|
|
* perr is clear (ErrIsError(perr) is FALSE).
|
|
*
|
|
* Exit-Failure:
|
|
* Returns 0; perr is filled with an error
|
|
*/
|
|
WORD FATAttrFromPsz(char *pszAttr, PERROR perr)
|
|
{
|
|
WORD attr;
|
|
char ch;
|
|
char *psz;
|
|
|
|
Assert(pszAttr != NULL);
|
|
attr = 0; // No attributes, yet
|
|
for (psz=pszAttr; *psz; psz++) {
|
|
ch = toupper(*psz);
|
|
switch (ch) {
|
|
case chINF_ATTR_ARCHIVE: attr |= _A_ARCH; break;
|
|
case chINF_ATTR_HIDDEN: attr |= _A_HIDDEN; break;
|
|
case chINF_ATTR_READONLY: attr |= _A_RDONLY; break;
|
|
case chINF_ATTR_SYSTEM: attr |= _A_SYSTEM; break;
|
|
|
|
default:
|
|
ErrSet(perr,pszERRINF_BAD_ATTR,"%c%s",*psz,pszAttr);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//** Success
|
|
return attr;
|
|
} /* FATAttrFromPsz() */
|
|
|
|
|
|
/*** GetInfCustomVar - See if InfXxxx variable exists
|
|
*
|
|
* Entry:
|
|
* psess - Session
|
|
* pszParm - Parameter name (suffix for Inf)
|
|
* fCopy - TRUE => Copy to pass 2 list if exists and this is pass 1
|
|
* perr - ERROR structure
|
|
*
|
|
* Exit-Success:
|
|
* Returns HVARIABLE;
|
|
*
|
|
* Exit-Failure:
|
|
* Returns NULL; variable not found *or* error occured (use
|
|
* ErrIsError(perr) to determine what happened).
|
|
*/
|
|
HVARIABLE GetInfCustomVar(PSESSION psess,char *pszParm,BOOL fCopy,PERROR perr)
|
|
{
|
|
char achVar[cbVAR_NAME_MAX];
|
|
ERROR errIgnore;
|
|
HVARIABLE hvar;
|
|
char *pszValue;
|
|
|
|
//** Construct InfXxxx variable name
|
|
Assert(sizeof(achVar) > strlen(pszPREFIX_INF_VARS));
|
|
strcpy(achVar,pszPREFIX_INF_VARS); // Get prefix
|
|
if (strlen(pszParm)+strlen(achVar) >= sizeof(achVar)) {
|
|
ErrSet(perr,pszINFERR_PARM_NAME_TOO_LONG,"%d%s",
|
|
sizeof(achVar)-1,pszParm);
|
|
return NULL;
|
|
}
|
|
strcat(achVar,pszParm); // Append parameter name
|
|
|
|
//** Discard error message from VarFind
|
|
hvar = VarFind(psess->hvlist,achVar,&errIgnore);
|
|
|
|
//** If this is pass 1, and we are checking the InfXxxxLineFormat
|
|
// variables, so we need to carry over this variable to the pass 2
|
|
// variable list so that it will be available when the Disk and Cabinet
|
|
// lines get generated. For *relational-mode* DDFs, this allows the
|
|
// DDF author to put *all* INF-related variables in the *INF* area --
|
|
// after all of the file layout!
|
|
//
|
|
if (fCopy && hvar && !psess->fPass2) {
|
|
Assert(psess->hvlistPass2 != NULL); // Must have been cloned already
|
|
pszValue = VarGetString(hvar); // Get value
|
|
if (!VarSet(psess->hvlistPass2,achVar,pszValue,perr)) {
|
|
return NULL; // Error
|
|
}
|
|
}
|
|
|
|
//** Return result
|
|
return hvar;
|
|
} /* GetInfCustomVar() */
|