/*** variable.c - Variable Manager * * Microsoft Confidential * Copyright (C) Microsoft Corporation 1993-1994 * All Rights Reserved. * * Author: * Benjamin W. Slivka * * History: * 10-Aug-1993 bens Initial version * 20-Aug-1993 bens Use MemStrDup to simplify VarCreate, VarSet * 21-Aug-1993 bens Support multiple lists (no static data!) * 08-Feb-1994 bens Set var.pvlist! Fix error cleanup in VarCreate. * 03-Jun-1994 bens Add vflDEFINE support; Get/SetFlags * * Exported Functions: * VarCloneList - Create an exact copy of a variable list * VarCreate - Create a variable * VarCreateList - Create a list of variables * VarDelete - Delete existing variable * VarDestroyList - Destroy a list of variables * VarFind - See if variable exists * VarFirstVar - Get first variable from list * VarGetBool - Get value of boolean variable * VarGetFlags - Get variable flags * VarGetInt - Get value of int variable * VarGetLong - Get value of long variable * VarGetName - Get name of variable * VarGetString - Get value of string variable * VarNextVar - Get next variable * VarSet - Set value of a variable (create if necessary) * VarSetLong - Set long variable value (create if necessary) * VarSetFlags - Set variable flags * * Internal Functions: * findVar - See if variable exists * isValidVarName - Checks validity of variable name * setVarValue - Validate value, then update variable */ #include #include #include "types.h" #include "asrt.h" #include "error.h" #include "mem.h" #include "message.h" #include "variable.h" #include "variable.msg" //** Empty definition, to avoid "chicken and the egg" problem typedef struct VARLIST_t VARLIST; /* var */ typedef VARLIST *PVARLIST; /* vlist */ typedef struct VARIABLE_t { #ifdef ASSERT SIGNATURE sig; // structure signature sigVARIABLE #endif char *pszName; // variable name char *pszValue; // current value VARTYPE vtype; // variable type VARFLAGS vfl; // special flags PFNVCVALIDATE pfnvcv; // validation function struct VARIABLE_t *pvarNext; // next variable struct VARIABLE_t *pvarPrev; // previous variable PVARLIST pvlist; // List containing this variable } VARIABLE; /* var */ typedef VARIABLE *PVARIABLE; /* pvar */ #ifdef ASSERT #define sigVARIABLE MAKESIG('V','A','R','$') // VARIABLE signature #define AssertVar(pvar) AssertStructure(pvar,sigVARIABLE); #else // !ASSERT #define AssertVar(pvar) #endif // !ASSERT typedef struct VARLIST_t { #ifdef ASSERT SIGNATURE sig; // structure signature sigVARLIST #endif PVARIABLE pvarHead; PVARIABLE pvarTail; } VARLIST; /* vlist */ //typedef VARLIST *PVARLIST; /* pvlist */ #ifdef ASSERT #define sigVARLIST MAKESIG('V','L','S','T') // VARLIST signature #define AssertVList(pv) AssertStructure(pv,sigVARLIST); #else // !ASSERT #define AssertVList(pv) #endif // !ASSERT #define HVARfromPVAR(h) ((PVARIABLE)(h)) #define PVARfromHVAR(p) ((HVARIABLE)(p)) #define HVLfromPVL(h) ((PVARLIST)(h)) #define PVLfromHVL(p) ((HVARLIST)(p)) //** Function Prototypes PVARIABLE findVar(PVARLIST pvlist, char *pszName, PERROR perr); BOOL isValidVarName(char *pszName, PERROR perr); BOOL setVarValue(PVARIABLE pvar, char *pszValue, PERROR perr); //*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* // // Exported Functions // //*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* /*** VarCreate - Create a variable * * NOTE: See variable.h for entry/exit conditions. */ HVARIABLE VarCreate(HVARLIST hvlist, char *pszName, char *pszValue, VARTYPE vtype, VARFLAGS vfl, PFNVCVALIDATE pfnvcv, PERROR perr) { char ach[cbMSG_MAX]; // message formatting buffer PVARIABLE pvar; PVARLIST pvlist; pvlist = PVLfromHVL(hvlist); AssertVList(pvlist); //** Make sure variable name is legal if (!isValidVarName(pszName,perr)) { // Use error message from isValidVarName return NULL; } //** Make sure variable does not already exist if (findVar(pvlist,pszName, perr)) { ErrSet(perr,pszPARERR_ALREADY_CREATED,"%s",pszName); return NULL; } //** Create VARIABLE ErrClear(perr); // Reset error state caused by findVar() failing above! if (!(pvar = MemAlloc(sizeof(VARIABLE)))) goto error; SetAssertSignature(pvar,sigVARIABLE); pvar->pszName = NULL; // Make sure not to free garbage! pvar->pszValue = NULL; // Make sure not to free garbage! pvar->vtype = vtype; pvar->vfl = vfl; pvar->pfnvcv = pfnvcv; //** Make copy of name if (!(pvar->pszName = MemStrDup(pszName))) goto error; //** Validate and copy value if (!setVarValue(pvar,pszValue,perr)) goto error; //** Link variable into list pvar->pvarNext = NULL; // Always last on list pvar->pvarPrev = pvlist->pvarTail; // Always points to last variable on list if (pvlist->pvarHead == NULL) { pvlist->pvarHead = pvar; pvlist->pvarTail = pvar; } else { AssertVar(pvlist->pvarTail); pvlist->pvarTail->pvarNext = pvar; // Add to end of list pvlist->pvarTail = pvar; // New tail } //** Remember which list we are on! pvar->pvlist = pvlist; //** Success return HVARfromPVAR(pvar); error: if (!pvar) { if (!(pvar->pszName)) MemFree(pvar->pszName); if (!(pvar->pszValue)) MemFree(pvar->pszValue); MemFree(pvar); } if (!ErrIsError(perr)) { // Only create error message if not already present MsgSet(ach,pszPARERR_CREATING_VARIABLE,"%s",pszName); ErrSet(perr,pszPARERR_OUT_OF_MEMORY,"%s",ach); } return NULL; } /* VarCreate */ /*** VarDelete - Delete existing variable * * NOTE: See variable.h for entry/exit conditions. */ void VarDelete(HVARIABLE hvar) { PVARIABLE pvar; PVARLIST pvlist; pvar = PVARfromHVAR(hvar); AssertVar(pvar); pvlist = pvar->pvlist; AssertVList(pvlist); AssertVar(pvlist->pvarHead); AssertVar(pvlist->pvarTail); //** Free memory for variable name and value if (pvar->pszName) MemFree(pvar->pszName); if (pvar->pszValue) MemFree(pvar->pszValue); //** Adjust forward list pointers if (pvar->pvarPrev == NULL) { // At head of list pvlist->pvarHead = pvar->pvarNext; // Remove from forward chain } else { // At middle or end of list AssertVar(pvar->pvarPrev); pvar->pvarPrev->pvarNext = pvar->pvarNext; // Remove from forward chain } //** Adjust backward list pointers if (pvar->pvarNext == NULL) { // At tail of list pvlist->pvarTail = pvar->pvarPrev; // Remove from backward chain } else { AssertVar(pvar->pvarNext); pvar->pvarNext->pvarPrev = pvar->pvarPrev; // Remove from backward chain } ClearAssertSignature(pvar); MemFree(pvar); } /* VarDelete * /*** VarCreateList - Create a list of variables * * NOTE: See variable.h for entry/exit conditions. */ HVARLIST VarCreateList(PERROR perr) { PVARLIST pvlist; if (!(pvlist = MemAlloc(sizeof(VARLIST)))) { ErrSet(perr,pszPARERR_OUT_OF_MEMORY,"%s",pszPARERR_CREATING_VAR_LIST); return NULL; } SetAssertSignature(pvlist,sigVARLIST); pvlist->pvarHead = NULL; // Empty list pvlist->pvarTail = NULL; // Empty list return HVLfromPVL(pvlist); } /* VarCreateList */ /*** VarCloneList - Create an exact copy of a variable list * * NOTE: See variable.h for entry/exit conditions. */ HVARLIST VarCloneList(HVARLIST hvlist, PERROR perr) { PVARIABLE pvar; PVARLIST pvlistClone; PVARLIST pvlist; ERROR errDummy; // Don't care about result pvlist = PVLfromHVL(hvlist); AssertVList(pvlist); //** Create list if (!(pvlistClone = PVLfromHVL(VarCreateList(perr)))) { return NULL; } //** Clone variables one at a time for (pvar=pvlist->pvarHead; pvar != NULL; pvar = pvar->pvarNext) { AssertVar(pvar); if (!VarCreate(HVLfromPVL(pvlistClone), pvar->pszName, pvar->pszValue, pvar->vtype, pvar->vfl, pvar->pfnvcv, perr)) { //** Variable create failed // VarDestroyList(HVLfromPVL(pvlistClone),&errDummy); // Toss partial clone return NULL; // Failure } } //** Clone was succesfull! return HVLfromPVL(pvlistClone); // Success } /* VarCloneList */ /*** VarDestroyList - Destroy a list of variables * * NOTE: See variable.h for entry/exit conditions. */ BOOL VarDestroyList(HVARLIST hvlist, PERROR perr) { PVARIABLE pvar; PVARIABLE pvarNext; PVARLIST pvlist; pvlist = PVLfromHVL(hvlist); AssertVList(pvlist); //NOTE: // // Calling VarDelete() is simple, but induces a great deal of // overhead for all of the list management. A speedier solution // would be to have both VarDelete() and this routine call a bare-bones // worker routine to delete the VARIABLE. However, this routine is // lightly used by Diamond, so this optimization is not important. // //** Free all of the variables for (pvar=pvlist->pvarHead; pvar != NULL; ) { AssertVar(pvar); pvarNext = pvar->pvarNext; // Save next pvar before we free pvar! VarDelete(HVARfromPVAR(pvar)); pvar = pvarNext; // Use it } ClearAssertSignature(pvlist); //** Free the list itself MemFree(pvlist); return TRUE; } /* VarDestroyList */ /*** VarSet - Set value of a variable (create if necessary) * * NOTE: See variable.h for entry/exit conditions. */ HVARIABLE VarSet(HVARLIST hvlist, char *pszName, char *pszValue, PERROR perr) { HVARIABLE hvar; PVARIABLE pvar; hvar = VarFind(hvlist,pszName,perr); //** If variable does not exist, create a simple string variable if (hvar == NULL) { // Have to create it ourselves hvar = VarCreate(hvlist, // list pszName, // var name "", // default value vtypeSTR, // var type vflNONE, // No flags NULL, // No validation function perr); if (hvar == NULL) { return FALSE; // Could not create variable } } //** Set new value pvar = PVARfromHVAR(hvar); AssertVar(pvar); if (!setVarValue(pvar,pszValue,perr)) { return FALSE; } //** Success return HVARfromPVAR(pvar); // Success, return hvar } /* VarSet */ /*** VarSetLong - Set long variable value (create if necessary) * * NOTE: See variable.h for entry/exit conditions. */ BOOL VarSetLong(HVARLIST hvlist, char *pszName, long lValue, PERROR perr) { char ach[20]; // Longest long is: 123456789012 // -1234567890. _ltoa(lValue,ach,10); // Create a string version return VarSet(hvlist,pszName,ach,perr) != NULL; } /* VarSetLong() */ /*** VarFind - See if variable exists * * NOTE: See variable.h for entry/exit conditions. */ HVARIABLE VarFind(HVARLIST hvlist, char *pszName, PERROR perr) { PVARLIST pvlist; pvlist = PVLfromHVL(hvlist); AssertVList(pvlist); //** Make sure variable name is legal if (!isValidVarName(pszName,perr)) { return NULL; // isValidVarName sets perr } //** Find variable return HVARfromPVAR(findVar(pvlist, pszName, perr)); } /*** VarGetBool - Get value of boolean variable * * NOTE: See variable.h for entry/exit conditions. */ BOOL VarGetBool(HVARIABLE hvar) { PVARIABLE pvar; pvar = PVARfromHVAR(hvar); AssertVar(pvar); return atoi(pvar->pszValue); } /* VarFind */ /*** VarGetInt - Get value of int variable * * NOTE: See variable.h for entry/exit conditions. */ int VarGetInt(HVARIABLE hvar) { PVARIABLE pvar; pvar = PVARfromHVAR(hvar); AssertVar(pvar); return atoi(pvar->pszValue); } /*** VarGetLong - Get value of long variable * * NOTE: See variable.h for entry/exit conditions. */ long VarGetLong(HVARIABLE hvar) { PVARIABLE pvar; pvar = PVARfromHVAR(hvar); AssertVar(pvar); return atol(pvar->pszValue); } /*** VarGetString - Get value of string variable * * NOTE: See variable.h for entry/exit conditions. */ char *VarGetString(HVARIABLE hvar) { PVARIABLE pvar; pvar = PVARfromHVAR(hvar); AssertVar(pvar); return pvar->pszValue; } /*** VarSetFlags - Set variable flags * * NOTE: See variable.h for entry/exit conditions. */ void VarSetFlags(HVARIABLE hvar, VARFLAGS vfl) { PVARIABLE pvar; pvar = PVARfromHVAR(hvar); AssertVar(pvar); pvar->vfl = vfl; } /* VarSetFlags() */ /*** VarGetFlags - Get variable flags * * NOTE: See variable.h for entry/exit conditions. */ VARFLAGS VarGetFlags(HVARIABLE hvar) { PVARIABLE pvar; pvar = PVARfromHVAR(hvar); AssertVar(pvar); return pvar->vfl; } /* VarGetFlags() */ /*** VarFirstVar - Get first variable from list * * NOTE: See variable.h for entry/exit conditions. */ HVARIABLE VarFirstVar(HVARLIST hvlist) { PVARLIST pvlist; pvlist = PVLfromHVL(hvlist); AssertVList(pvlist); return HVARfromPVAR(pvlist->pvarHead); } /* VarFirstVar() */ /*** VarNextVar - Get next variable * * NOTE: See variable.h for entry/exit conditions. */ HVARIABLE VarNextVar(HVARIABLE hvar) { PVARIABLE pvar; pvar = PVARfromHVAR(hvar); AssertVar(pvar); return HVARfromPVAR(pvar->pvarNext); } /* VarNextVar() */ /*** VarGetName - Get name of variable * * NOTE: See variable.h for entry/exit conditions. */ char *VarGetName(HVARIABLE hvar) { PVARIABLE pvar; pvar = PVARfromHVAR(hvar); AssertVar(pvar); return pvar->pszName; } /* VarGetName() */ //*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* // // Private Functions // //*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* /*** isValidVarName - Checks validity of variable name * * Entry: * pszName - Variable name to check * perr - ERROR structure * * Exit-Success: * Returns TRUE. * * Exit-Failure: * Returns FALSE; perr filled in with error. */ BOOL isValidVarName(char *pszName, PERROR perr) { //** Check name length if (strlen(pszName) >= cbVAR_NAME_MAX) { ErrSet(perr,pszPARERR_VAR_NAME_TOO_LONG,"%d%s",cbVAR_NAME_MAX,pszName); return FALSE; } //** Check for invalid characters, especially chVAR! //BUGBUG 10-Aug-1993 bens isValidVarName is incomplete return TRUE; } /*** findVar - See if variable exists * * Entry: * pvlist - Variable list * pszName - Variable name to look for * perr - ERROR structure * * Exit-Success: * Returns PVARIABLE, if variable exists. * * Exit-Failure: * Returns NULL, variable does not exist. * ERROR structure filled in with details of error. */ PVARIABLE findVar(PVARLIST pvlist, char *pszName, PERROR perr) { PVARIABLE pvar; AssertVList(pvlist); for (pvar=pvlist->pvarHead; pvar != NULL; pvar = pvar->pvarNext) { AssertVar(pvar); if (!_stricmp(pvar->pszName,pszName)) { // Got a match! return pvar; // Return variable pointer } } //** Did not find variable ErrSet(perr,pszPARERR_VARIABLE_NOT_FOUND,"%s",pszName); return NULL; } /*** setVarValue - Validate value, then update variable * * Entry: * pvar - Variable to update * pszValue - New value * perr - ERROR structure * * Exit-Success: * Returns TRUE; variable updated * * Exit-Failure: * Returns FALSE, variable not updated. * ERROR structure filled in with details of error. */ BOOL setVarValue(PVARIABLE pvar, char *pszValue, PERROR perr) { char achValue[cbVAR_VALUE_MAX]; char achMsg[cbMSG_MAX]; char *psz; AssertVar(pvar); //** Check value length if (strlen(pszValue) >= cbVAR_VALUE_MAX) { ErrSet(perr,pszPARERR_VALUE_TOO_LONG,"%d%s", cbVAR_VALUE_MAX,pvar->pszName); return FALSE; } //** Check if new value is OK if (pvar->pfnvcv == NULL) { // No validation function strcpy(achValue,pszValue); // Value is fine } else if (!(pvar->pfnvcv)(HVLfromPVL(pvar->pvlist), pvar->pszName, pszValue, achValue, perr)) { //** Something wrong with value; validation function set perr return FALSE; } //** Set new value psz = pvar->pszValue; // Remember original value if (!(pvar->pszValue = MemStrDup(achValue))) { pvar->pszValue = psz; // Restore original value MsgSet(achMsg,pszPARERR_SETTING_VARIABLE,"%s",pvar->pszName); ErrSet(perr,pszPARERR_OUT_OF_MEMORY,"%s",achMsg); return FALSE; } //** Free old value if (psz != NULL) // If old value exists MemFree(psz); // Free old value return TRUE; } /* setVarValue() */