From 7fb581fc0bd13bf11800e1206eb31863fb6b8f04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9=20van=20Geldorp?= Date: Wed, 12 Jan 2005 09:31:44 +0000 Subject: [PATCH] Sync to Wine-20050111: Vitaly Lipatov - Get real screen properties. - Add description for MsiGetMode, MSIRUNMODE constants. - Add ScreenX, ScreenY, ColorBits installer properties. Mike McCormack - Add a simple test case for MSI databases. - Remove unneeded whitespace, indent correctly. - Remove more fixed length buffers, rewrite functions to return malloc'ed memory. - Remove a lot of fixed length buffers. - Implement thread safety for records. - Fix selecting string columns and matching against a wildcard. - Implement MsiRecordSetStreamA/W and add tests for records containing streams. - Fix records according to test cases. - Fix transposition of 4 byte values when reading in table data from storage. - MsiCloseAllHandles only closes handles allocated in the calling thread. Francois Gouget - Assorted spelling fixes. Aric Stewart - Make all custom type 1 actions happen in a seperate thread and close all handles for that thread when it exits. Honors the concept of temporary MSI handles for custom actions. - Properly deformat keys written to the registry. - Because directory mappings can change between the CostFinalize step and the InstallFiles step we need to do a final resolution of the target file name before installing. - When checking for an existing .lnk shortcut extension on the filename do not just search for '.' but actually verify it is '.lnk'. - CustomAction 35 should call SetTargetPath not just set the property. - TARGETDIR and SOURCEDIR may not be entries 0 in the directory tables. So when resolving the folder we need to seek them out. - When we handle SetTargetPath we need to be sure to recalculate the resulting paths as things with the now set Directory as the parent will change. - Change how we install files so that we extract files as we need them, cuts down on extraction time and unused files. - Improve progress bar tracking. - Be sure that set paths are terminated with a backslash. - Free allocated buffers. - Parse out the full features by using the ',' character and do comparisons based on the full feature names. - Continue when a duplicate component is found and loaded. - Rework how we handle Feature and Component States. I have confirmed from testing that, although documented nowhere, having ADDLOCAL on the install line overrides INSTALLLEVEL. - Track all files extracted from cabinents as tempfiles so they can be removed at the end of the install to not leave uninstalled but uncabbed files laying around. - Move Install Features selection and evaluation into CostFinalize. - Allow for end of install actions. - Create the shortcut directory if it does not exist. - Set the INSTALLLEVEL in CostFinalize if it is not set. - Eliminate some fixed length buffers. - Enable asynchronous dll custom action calls. - Make sure to include trailing backslash in path. - Move around and rename some functions. - Fix incorrect return code check. - Fix folder resolution. - Let negative number be parsed correctly. Needed for accessing actions with sequences such as -1. - Added MsiSetExternalUIW. - Include a System16Folder definition. - Free allocated buffers. - Blank the property buffers even if the property is not found. - Include the trailing backslash on the Windows volume. - Fix folder resolution. Eric Pouech - Fixed some errors in function prototypes. Steven Edwards - Add and fix some stubs. Ulrich Czekalla - Set the out buffer count to zero on read error. Michael Stefaniuc - Add missing HeapFree's (found by smatch). Paul Vriens - Use Interlocked* functions in AddRef and Release. svn path=/trunk/; revision=12948 --- reactos/include/wine/msiquery.h | 44 +- reactos/lib/msi/Makefile.in | 4 +- reactos/lib/msi/action.c | 1942 ++++++++----- reactos/lib/msi/handle.c | 70 +- reactos/lib/msi/msi.c | 52 +- reactos/lib/msi/msi.spec | 10 +- reactos/lib/msi/msipriv.h | 5 + reactos/lib/msi/package.c | 65 +- reactos/lib/msi/query.h | 1 + reactos/lib/msi/record.c | 227 +- reactos/lib/msi/sql.tab.c | 4676 +++++++++++++++++-------------- reactos/lib/msi/sql.tab.h | 512 ++-- reactos/lib/msi/sql.y | 12 +- reactos/lib/msi/table.c | 2 +- reactos/lib/msi/where.c | 23 +- 15 files changed, 4505 insertions(+), 3140 deletions(-) diff --git a/reactos/include/wine/msiquery.h b/reactos/include/wine/msiquery.h index cfd07b9a875..9b61ae6acd4 100644 --- a/reactos/include/wine/msiquery.h +++ b/reactos/include/wine/msiquery.h @@ -59,7 +59,30 @@ typedef enum tagMSIMODIFY #define MSIDBOPEN_TRANSACT (LPCTSTR)1 #define MSIDBOPEN_DIRECT (LPCTSTR)2 #define MSIDBOPEN_CREATE (LPCTSTR)3 +#define MSIDBOPEN_CREATEDIRECT (LPCTSTR)4 +typedef enum tagMSIRUNMODE +{ + MSIRUNMODE_ADMIN = 0, + MSIRUNMODE_ADVERTISE = 1, + MSIRUNMODE_MAINTENANCE = 2, + MSIRUNMODE_ROLLBACKENABLED = 3, + MSIRUNMODE_LOGENABLED = 4, + MSIRUNMODE_OPERATIONS = 5, + MSIRUNMODE_REBOOTATEND = 6, + MSIRUNMODE_REBOOTNOW = 7, + MSIRUNMODE_CABINET = 8, + MSIRUNMODE_SOURCESHORTNAMES = 9, + MSIRUNMODE_TARGETSHORTNAMES = 10, + MSIRUNMODE_RESERVED11 = 11, + MSIRUNMODE_WINDOWS9X = 12, + MSIRUNMODE_ZAWENABLED = 13, + MSIRUNMODE_RESERVED14 = 14, + MSIRUNMODE_RESERVED15 = 15, + MSIRUNMODE_SCHEDULED = 16, + MSIRUNMODE_ROLLBACK = 17, + MSIRUNMODE_COMMIT = 18 +} MSIRUNMODE; /* view manipulation */ UINT WINAPI MsiViewFetch(MSIHANDLE,MSIHANDLE*); @@ -123,15 +146,12 @@ MSICONDITION WINAPI MsiEvaluateConditionW(MSIHANDLE,LPCWSTR); #define MsiEvaluateCondition WINELIB_NAME_AW(MsiEvaluateCondition) /* property functions */ -UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, - LPSTR szValueBuf, DWORD* pchValueBuf); -UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, - LPWSTR szValueBuf, DWORD* pchValueBuf); +UINT WINAPI MsiGetPropertyA(MSIHANDLE, LPCSTR, LPSTR, DWORD*); +UINT WINAPI MsiGetPropertyW(MSIHANDLE, LPCWSTR, LPWSTR, DWORD*); #define MsiGetProperty WINELIB_NAME_AW(MsiGetProperty) -UINT WINAPI MsiSetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue); -UINT WINAPI MsiSetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, - LPCWSTR szValue); +UINT WINAPI MsiSetPropertyA(MSIHANDLE, LPCSTR, LPCSTR); +UINT WINAPI MsiSetPropertyW(MSIHANDLE, LPCWSTR, LPCWSTR); #define MsiSetProperty WINELIB_NAME_AW(MsiSetProperty) UINT WINAPI MsiGetTargetPathA(MSIHANDLE,LPCSTR,LPSTR,DWORD*); @@ -148,11 +168,13 @@ UINT WINAPI MsiGetSourcePathW(MSIHANDLE,LPCWSTR,LPWSTR,DWORD*); MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE); -UINT WINAPI MsiViewGetColumnInfo( MSIHANDLE, MSICOLINFO, MSIHANDLE*); -INT WINAPI MsiProcessMessage( MSIHANDLE, INSTALLMESSAGE, MSIHANDLE); +UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE, MSICOLINFO, MSIHANDLE*); +INT WINAPI MsiProcessMessage(MSIHANDLE, INSTALLMESSAGE, MSIHANDLE); -UINT WINAPI MsiSetFeatureStateA( MSIHANDLE, LPCSTR, INSTALLSTATE); -UINT WINAPI MsiSetFeatureStateW( MSIHANDLE, LPCWSTR, INSTALLSTATE); +UINT WINAPI MsiSetFeatureStateA(MSIHANDLE, LPCSTR, INSTALLSTATE); +UINT WINAPI MsiSetFeatureStateW(MSIHANDLE, LPCWSTR, INSTALLSTATE); #define MsiSetFeatureState WINELIB_NAME_AW(MsiSetFeatureState) +BOOL WINAPI MsiGetMode(MSIHANDLE, MSIRUNMODE); + #endif /* __WINE_MSIQUERY_H */ diff --git a/reactos/lib/msi/Makefile.in b/reactos/lib/msi/Makefile.in index 95f3ecd5b4f..df2489801a5 100644 --- a/reactos/lib/msi/Makefile.in +++ b/reactos/lib/msi/Makefile.in @@ -3,7 +3,7 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = msi.dll -IMPORTS = shell32 cabinet oleaut32 ole32 version user32 advapi32 kernel32 +IMPORTS = shell32 cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32 EXTRALIBS = -luuid $(LIBUNICODE) C_SRCS = \ @@ -31,6 +31,8 @@ RC_SRCS = version.rc EXTRA_SRCS = sql.y cond.y EXTRA_OBJS = sql.tab.o cond.tab.o +SUBDIRS = tests + @MAKE_DLL_RULES@ sql.tab.c sql.tab.h: sql.y diff --git a/reactos/lib/msi/action.c b/reactos/lib/msi/action.c index e32e1f9b6dd..ec066ac054b 100644 --- a/reactos/lib/msi/action.c +++ b/reactos/lib/msi/action.c @@ -51,6 +51,8 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/stand #include "ver.h" #define CUSTOM_ACTION_TYPE_MASK 0x3F +#define REG_PROGRESS_VALUE 13200 +#define COMPONENT_PROGRESS_VALUE 24000 WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -65,8 +67,10 @@ typedef struct tagMSIFEATURE WCHAR Directory[96]; INT Attributes; - INSTALLSTATE State; - BOOL Enabled; + INSTALLSTATE Installed; + INSTALLSTATE ActionRequest; + INSTALLSTATE Action; + INT ComponentCount; INT Components[1024]; /* yes hardcoded limit.... I am bad */ INT Cost; @@ -81,21 +85,23 @@ typedef struct tagMSICOMPONENT WCHAR Condition[0x100]; WCHAR KeyPath[96]; - INSTALLSTATE State; - BOOL FeatureState; + INSTALLSTATE Installed; + INSTALLSTATE ActionRequest; + INSTALLSTATE Action; + BOOL Enabled; INT Cost; } MSICOMPONENT; typedef struct tagMSIFOLDER { - WCHAR Directory[96]; - WCHAR TargetDefault[96]; - WCHAR SourceDefault[96]; + LPWSTR Directory; + LPWSTR TargetDefault; + LPWSTR SourceDefault; - WCHAR ResolvedTarget[MAX_PATH]; - WCHAR ResolvedSource[MAX_PATH]; - WCHAR Property[MAX_PATH]; /* initially set property */ + LPWSTR ResolvedTarget; + LPWSTR ResolvedSource; + LPWSTR Property; /* initially set property */ INT ParentIndex; INT State; /* 0 = uninitialized */ @@ -108,12 +114,12 @@ typedef struct tagMSIFOLDER typedef struct tagMSIFILE { - WCHAR File[72]; + LPWSTR File; INT ComponentIndex; - WCHAR FileName[MAX_PATH]; + LPWSTR FileName; INT FileSize; - WCHAR Version[72]; - WCHAR Language[20]; + LPWSTR Version; + LPWSTR Language; INT Attributes; INT Sequence; @@ -123,8 +129,8 @@ typedef struct tagMSIFILE /* 2 = present but replace */ /* 3 = present do not replace */ /* 4 = Installed */ - WCHAR SourcePath[MAX_PATH]; - WCHAR TargetPath[MAX_PATH]; + LPWSTR SourcePath; + LPWSTR TargetPath; BOOL Temporary; }MSIFILE; @@ -134,6 +140,7 @@ typedef struct tagMSIFILE static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran); static UINT ACTION_ProcessUISequence(MSIPACKAGE *package); +static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq); UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action); static UINT ACTION_LaunchConditions(MSIPACKAGE *package); @@ -158,15 +165,15 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source, const LPWSTR target, const INT type); static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source, const LPWSTR target, const INT type); -static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source, +static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source, const LPWSTR target, const INT type); -static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source, +static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source, const LPWSTR target, const INT type); -static UINT HANDLE_CustomType34(MSIPACKAGE *package, const LPWSTR source, +static UINT HANDLE_CustomType34(MSIPACKAGE *package, const LPWSTR source, const LPWSTR target, const INT type); static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data); -static UINT resolve_folder(MSIPACKAGE *package, LPCWSTR name, LPWSTR path, +static LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, BOOL set_prop, MSIFOLDER **folder); static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path); @@ -223,12 +230,9 @@ const static WCHAR szPublishProduct[] = ********************************************************/ inline static void reduce_to_longfilename(WCHAR* filename) { - if (strchrW(filename,'|')) - { - WCHAR newname[MAX_PATH]; - strcpyW(newname,strchrW(filename,'|')+1); - strcpyW(filename,newname); - } + LPWSTR p = strchrW(filename,'|'); + if (p) + memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR)); } inline static char *strdupWtoA( const WCHAR *str ) @@ -256,6 +260,15 @@ inline static WCHAR *strdupAtoW( const char *str ) return ret; } +static LPWSTR dupstrW(LPCWSTR src) +{ + LPWSTR dest; + if (!src) return NULL; + dest = HeapAlloc(GetProcessHeap(), 0, (strlenW(src)+1)*sizeof(WCHAR)); + strcpyW(dest, src); + return dest; +} + inline static WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index) { UINT rc; @@ -263,16 +276,58 @@ inline static WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index) LPWSTR ret; sz = 0; - rc = MSI_RecordGetStringW(row,index,NULL,&sz); - if (sz <= 0) + if (MSI_RecordIsNull(row,index)) return NULL; + rc = MSI_RecordGetStringW(row,index,NULL,&sz); + + /* having an empty string is different than NULL */ + if (sz == 0) + { + ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)); + ret[0] = 0; + return ret; + } + sz ++; ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR)); rc = MSI_RecordGetStringW(row,index,ret,&sz); + if (rc!=ERROR_SUCCESS) + { + ERR("Unable to load dynamic string\n"); + HeapFree(GetProcessHeap(), 0, ret); + ret = NULL; + } return ret; } +inline static LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, + UINT* rc) +{ + DWORD sz = 0; + LPWSTR str; + UINT r; + + r = MSI_GetPropertyW(package, prop, NULL, &sz); + if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA) + { + if (rc) + *rc = r; + return NULL; + } + sz++; + str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR)); + r = MSI_GetPropertyW(package, prop, str, &sz); + if (r != ERROR_SUCCESS) + { + HeapFree(GetProcessHeap(),0,str); + str = NULL; + } + if (rc) + *rc = r; + return str; +} + inline static int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component ) { int rc = -1; @@ -321,6 +376,7 @@ inline static int get_loaded_file(MSIPACKAGE* package, LPCWSTR file) return rc; } + static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path) { DWORD i; @@ -343,8 +399,8 @@ static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path) memset(&package->files[index],0,sizeof(MSIFILE)); - strcpyW(package->files[index].File,name); - strcpyW(package->files[index].TargetPath,path); + package->files[index].File = dupstrW(name); + package->files[index].TargetPath = dupstrW(path); package->files[index].Temporary = TRUE; TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File)); @@ -362,11 +418,103 @@ void ACTION_remove_tracked_tempfiles(MSIPACKAGE* package) for (i = 0; i < package->loaded_files; i++) { if (package->files[i].Temporary) + { + TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath)); DeleteFileW(package->files[i].TargetPath); + } } } +/* Called when the package is being closed */ +extern void ACTION_free_package_structures( MSIPACKAGE* package) +{ + INT i; + + TRACE("Freeing package action data\n"); + + /* No dynamic buffers in features */ + if (package->features && package->loaded_features > 0) + HeapFree(GetProcessHeap(),0,package->features); + + for (i = 0; i < package->loaded_folders; i++) + { + HeapFree(GetProcessHeap(),0,package->folders[i].Directory); + HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault); + HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault); + HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget); + HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource); + HeapFree(GetProcessHeap(),0,package->folders[i].Property); + } + if (package->folders && package->loaded_folders > 0) + HeapFree(GetProcessHeap(),0,package->folders); + + /* no dynamic buffers in components */ + if (package->components && package->loaded_components > 0) + HeapFree(GetProcessHeap(),0,package->components); + + for (i = 0; i < package->loaded_files; i++) + { + HeapFree(GetProcessHeap(),0,package->files[i].File); + HeapFree(GetProcessHeap(),0,package->files[i].FileName); + HeapFree(GetProcessHeap(),0,package->files[i].Version); + HeapFree(GetProcessHeap(),0,package->files[i].Language); + HeapFree(GetProcessHeap(),0,package->files[i].SourcePath); + HeapFree(GetProcessHeap(),0,package->files[i].TargetPath); + } + + if (package->files && package->loaded_files > 0) + HeapFree(GetProcessHeap(),0,package->files); +} + +static UINT ACTION_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) +{ + LPWSTR szQuery; + LPCWSTR p; + UINT sz, rc; + va_list va; + + /* figure out how much space we need to allocate */ + va_start(va, fmt); + sz = strlenW(fmt) + 1; + p = fmt; + while (*p) + { + p = strchrW(p, '%'); + if (!p) + break; + p++; + switch (*p) + { + case 's': /* a string */ + sz += strlenW(va_arg(va,LPCWSTR)); + break; + case 'd': + case 'i': /* an integer -2147483648 seems to be longest */ + sz += 3*sizeof(int); + (void)va_arg(va,int); + break; + case '%': /* a single % - leave it alone */ + break; + default: + FIXME("Unhandled character type %c\n",*p); + } + p++; + } + va_end(va); + + /* construct the string */ + szQuery = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR)); + va_start(va, fmt); + vsnprintfW(szQuery, sz, fmt, va); + va_end(va); + + /* perform the query */ + rc = MSI_DatabaseOpenViewW(db, szQuery, view); + HeapFree(GetProcessHeap(), 0, szQuery); + return rc; +} + static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d ) { MSIRECORD * row; @@ -390,17 +538,14 @@ static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * recor UINT rc; MSIQUERY * view; MSIRECORD * row = 0; - static WCHAR *ActionFormat=NULL; - static WCHAR LastAction[0x100] = {0}; - WCHAR Query[1024]; LPWSTR ptr; - if (strcmpW(LastAction,action)!=0) + if (!package->LastAction || strcmpW(package->LastAction,action)) { - sprintfW(Query,Query_t,action); - rc = MSI_DatabaseOpenViewW(package->db, Query, &view); + rc = ACTION_OpenQuery(package->db, &view, Query_t, action); if (rc != ERROR_SUCCESS) return; + rc = MSI_ViewExecute(view, 0); if (rc != ERROR_SUCCESS) { @@ -422,18 +567,22 @@ static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * recor return; } - if (ActionFormat) - HeapFree(GetProcessHeap(),0,ActionFormat); + /* update the cached actionformat */ + if (package->ActionFormat) + HeapFree(GetProcessHeap(),0,package->ActionFormat); + package->ActionFormat = load_dynamic_stringW(row,3); + + if (package->LastAction) + HeapFree(GetProcessHeap(),0,package->LastAction); + package->LastAction = dupstrW(action); - ActionFormat = load_dynamic_stringW(row,3); - strcpyW(LastAction,action); msiobj_release(&row->hdr); MSI_ViewClose(view); msiobj_release(&view->hdr); } message[0]=0; - ptr = ActionFormat; + ptr = package->ActionFormat; while (*ptr) { LPWSTR ptr2; @@ -489,12 +638,10 @@ static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action) MSIQUERY * view; MSIRECORD * row = 0; WCHAR *ActionText=NULL; - WCHAR Query[1024]; GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100); - sprintfW(Query,Query_t,action); - rc = MSI_DatabaseOpenViewW(package->db, Query, &view); + rc = ACTION_OpenQuery(package->db, &view, Query_t, action); if (rc != ERROR_SUCCESS) return; rc = MSI_ViewExecute(view, 0); @@ -555,6 +702,58 @@ static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, msiobj_release(&row->hdr); } +/* + * build_directory_name() + * + * This function is to save messing round with directory names + * It handles adding backslashes between path segments, + * and can add \ at the end of the directory name if told to. + * + * It takes a variable number of arguments. + * It always allocates a new string for the result, so make sure + * to free the return value when finished with it. + * + * The first arg is the number of path segments that follow. + * The arguments following count are a list of path segments. + * A path segment may be NULL. + * + * Path segments will be added with a \ separating them. + * A \ will not be added after the last segment, however if the + * last segment is NULL, then the last character will be a \ + * + */ +static LPWSTR build_directory_name(DWORD count, ...) +{ + DWORD sz = 1, i; + LPWSTR dir; + va_list va; + + va_start(va,count); + for(i=0; i 0) { - TRACE("Found commandline property (%s) = (%s)\n", debugstr_w(prop), debugstr_w(val)); + TRACE("Found commandline property (%s) = (%s)\n", + debugstr_w(prop), debugstr_w(val)); MSI_SetPropertyW(package,prop,val); } + HeapFree(GetProcessHeap(),0,val); + HeapFree(GetProcessHeap(),0,prop); } ptr++; } @@ -653,9 +859,92 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath, else rc = ACTION_ProcessExecSequence(package,FALSE); + /* process the ending type action */ + if (rc == ERROR_SUCCESS) + rc = ACTION_PerformActionSequence(package,-1); + else if (rc == ERROR_FUNCTION_FAILED) + rc = ACTION_PerformActionSequence(package,-3); + return rc; } +static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq) +{ + MSIQUERY * view; + UINT rc; + WCHAR buffer[0x100]; + DWORD sz = 0x100; + MSIRECORD * row = 0; + static const WCHAR ExecSeqQuery[] = { + 's','e','l','e','c','t',' ','*',' ', + 'f','r','o','m',' ', + 'I','n','s','t','a','l','l','E','x','e','c','u','t','e', + 'S','e','q','u','e','n','c','e',' ', + 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', + '=',' ','%','i',0}; + + rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, seq); + + if (rc == ERROR_SUCCESS) + { + rc = MSI_ViewExecute(view, 0); + + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + msiobj_release(&view->hdr); + goto end; + } + + TRACE("Running the actions\n"); + + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + rc = ERROR_SUCCESS; + goto end; + } + + /* check conditions */ + if (!MSI_RecordIsNull(row,2)) + { + LPWSTR cond = NULL; + cond = load_dynamic_stringW(row,2); + + if (cond) + { + /* this is a hack to skip errors in the condition code */ + if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE) + { + HeapFree(GetProcessHeap(),0,cond); + msiobj_release(&row->hdr); + goto end; + } + else + HeapFree(GetProcessHeap(),0,cond); + } + } + + sz=0x100; + rc = MSI_RecordGetStringW(row,1,buffer,&sz); + if (rc != ERROR_SUCCESS) + { + ERR("Error is %x\n",rc); + msiobj_release(&row->hdr); + goto end; + } + + rc = ACTION_PerformAction(package,buffer); + msiobj_release(&row->hdr); +end: + MSI_ViewClose(view); + msiobj_release(&view->hdr); + } + else + rc = ERROR_SUCCESS; + + return rc; +} static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran) { @@ -669,7 +958,6 @@ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran) 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', '>',' ','%','i',' ','o','r','d','e','r',' ', 'b','y',' ','S','e','q','u','e','n','c','e',0 }; - WCHAR Query[1024]; MSIRECORD * row = 0; static const WCHAR IVQuery[] = { 's','e','l','e','c','t',' ','S','e','q','u','e','n','c','e',' ', @@ -678,11 +966,11 @@ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran) 'w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',' ', '`','I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','`', 0}; + INT seq = 0; + /* get the sequence number */ if (UIran) { - INT seq = 0; - rc = MSI_DatabaseOpenViewW(package->db, IVQuery, &view); if (rc != ERROR_SUCCESS) return rc; @@ -704,12 +992,9 @@ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran) msiobj_release(&row->hdr); MSI_ViewClose(view); msiobj_release(&view->hdr); - sprintfW(Query,ExecSeqQuery,seq); } - else - sprintfW(Query,ExecSeqQuery,0); - - rc = MSI_DatabaseOpenViewW(package->db, Query, &view); + + rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, seq); if (rc == ERROR_SUCCESS) { rc = MSI_ViewExecute(view, 0); @@ -721,7 +1006,7 @@ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran) goto end; } - TRACE("Running the actions \n"); + TRACE("Running the actions\n"); while (1) { @@ -900,7 +1185,6 @@ UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action) TRACE("Performing action (%s)\n",debugstr_w(action)); ui_actioninfo(package, action, TRUE, 0); ui_actionstart(package, action); - ui_progress(package,2,1,0,0); /* pre install, setup and configuration block */ if (strcmpW(action,szLaunchConditions)==0) @@ -961,21 +1245,16 @@ static UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action) UINT rc = ERROR_SUCCESS; MSIQUERY * view; MSIRECORD * row = 0; - WCHAR ExecSeqQuery[1024] = + static const WCHAR ExecSeqQuery[] = {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','C','u','s','t','o' -,'m','A','c','t','i','o','n',' ','w','h','e','r','e',' ','`','A','c','t','i' -,'o','n','`',' ','=',' ','`',0}; - static const WCHAR end[]={'`',0}; + ,'m','A','c','t','i','o','n',' ','w','h','e','r','e',' ','`','A','c','t','i' + ,'o','n','`',' ','=',' ','`','%','s','`',0}; UINT type; LPWSTR source; LPWSTR target; WCHAR *deformated=NULL; - strcatW(ExecSeqQuery,action); - strcatW(ExecSeqQuery,end); - - rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); - + rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, action); if (rc != ERROR_SUCCESS) return rc; @@ -1022,6 +1301,10 @@ static UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action) rc = HANDLE_CustomType34(package,source,target,type); break; case 35: /* Directory set with formatted text. */ + deformat_string(package,target,&deformated); + MSI_SetTargetPathW(package, source, deformated); + HeapFree(GetProcessHeap(),0,deformated); + break; case 51: /* Property set with formatted text. */ deformat_string(package,target,&deformated); rc = MSI_SetPropertyW(package,source,deformated); @@ -1063,10 +1346,9 @@ static UINT store_binary_to_temp(MSIPACKAGE *package, const LPWSTR source, UINT rc; MSIQUERY * view; MSIRECORD * row = 0; - WCHAR Query[1024] = + static const WCHAR fmt[] = {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','B','i' -,'n','a','r','y',' ','w','h','e','r','e',' ','N','a','m','e','=','`',0}; - static const WCHAR end[]={'`',0}; +,'n','a','r','y',' ','w','h','e','r','e',' ','N','a','m','e','=','`','%','s','`',0}; HANDLE the_file; CHAR buffer[1024]; @@ -1079,10 +1361,7 @@ static UINT store_binary_to_temp(MSIPACKAGE *package, const LPWSTR source, if (the_file == INVALID_HANDLE_VALUE) return ERROR_FUNCTION_FAILED; - strcatW(Query,source); - strcatW(Query,end); - - rc = MSI_DatabaseOpenViewW( package->db, Query, &view); + rc = ACTION_OpenQuery(package->db, &view, fmt, source); if (rc != ERROR_SUCCESS) return rc; @@ -1127,66 +1406,82 @@ static UINT store_binary_to_temp(MSIPACKAGE *package, const LPWSTR source, return ERROR_SUCCESS; } - typedef UINT __stdcall CustomEntry(MSIHANDLE); typedef struct { MSIPACKAGE *package; - WCHAR target[MAX_PATH]; - WCHAR source[MAX_PATH]; + WCHAR *target; + WCHAR *source; } thread_struct; -#if 0 -static DWORD WINAPI DllThread(LPVOID info) +static DWORD WINAPI ACTION_CallDllFunction(thread_struct *stuff) { - HANDLE DLL; + HANDLE hModule; LPSTR proc; - thread_struct *stuff; CustomEntry *fn; - - stuff = (thread_struct*)info; - TRACE("Asynchronous start (%s, %s) \n", debugstr_w(stuff->source), + TRACE("calling function (%s, %s) \n", debugstr_w(stuff->source), debugstr_w(stuff->target)); - DLL = LoadLibraryW(stuff->source); - if (DLL) + hModule = LoadLibraryW(stuff->source); + if (hModule) { proc = strdupWtoA( stuff->target ); - fn = (CustomEntry*)GetProcAddress(DLL,proc); + fn = (CustomEntry*)GetProcAddress(hModule,proc); if (fn) { MSIHANDLE hPackage; MSIPACKAGE *package = stuff->package; - TRACE("Calling function\n"); + TRACE("Calling function %s\n", proc); hPackage = msiobj_findhandle( &package->hdr ); - if( !hPackage ) + if (hPackage ) + { + fn(hPackage); + msiobj_release( &package->hdr ); + } + else ERR("Handle for object %p not found\n", package ); - fn(hPackage); - msiobj_release( &package->hdr ); } else ERR("Cannot load functon\n"); HeapFree(GetProcessHeap(),0,proc); - FreeLibrary(DLL); + FreeLibrary(hModule); } else ERR("Unable to load library\n"); msiobj_release( &stuff->package->hdr ); - HeapFree( GetProcessHeap(), 0, info ); + HeapFree(GetProcessHeap(),0,stuff->source); + HeapFree(GetProcessHeap(),0,stuff->target); + HeapFree(GetProcessHeap(), 0, stuff); return 0; } -#endif + +static DWORD WINAPI DllThread(LPVOID info) +{ + thread_struct *stuff; + DWORD rc = 0; + + TRACE("MSI Thread (0x%lx) started for custom action\n", + GetCurrentThreadId()); + + stuff = (thread_struct*)info; + rc = ACTION_CallDllFunction(stuff); + + TRACE("MSI Thread (0x%lx) finished\n",GetCurrentThreadId()); + /* clse all handles for this thread */ + MsiCloseAllHandles(); + return rc; +} static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source, const LPWSTR target, const INT type) { WCHAR tmp_file[MAX_PATH]; - CustomEntry *fn; - HANDLE DLL; - LPSTR proc; + thread_struct *info; + DWORD ThreadId; + HANDLE ThreadHandle; store_binary_to_temp(package, source, tmp_file); @@ -1199,76 +1494,57 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source, strcatW(tmp_file,dot); } - if (type & 0xc0) - { - /* DWORD ThreadId; */ - thread_struct *info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) ); + info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) ); + msiobj_addref( &package->hdr ); + info->package = package; + info->target = dupstrW(target); + info->source = dupstrW(tmp_file); - /* msiobj_addref( &package->hdr ); */ - info->package = package; - strcpyW(info->target,target); - strcpyW(info->source,tmp_file); - TRACE("Start Asynchronous execution\n"); - FIXME("DATABASE NOT THREADSAFE... not starting\n"); - /* CreateThread(NULL,0,DllThread,(LPVOID)&info,0,&ThreadId); */ - /* FIXME: release the package if the CreateThread fails */ - HeapFree( GetProcessHeap(), 0, info ); - return ERROR_SUCCESS; - } + ThreadHandle = CreateThread(NULL,0,DllThread,(LPVOID)info,0,&ThreadId); + + if (!(type & 0xc0)) + WaitForSingleObject(ThreadHandle,INFINITE); + + CloseHandle(ThreadHandle); - DLL = LoadLibraryW(tmp_file); - if (DLL) - { - proc = strdupWtoA( target ); - fn = (CustomEntry*)GetProcAddress(DLL,proc); - if (fn) - { - MSIHANDLE hPackage; - - TRACE("Calling function\n"); - hPackage = msiobj_findhandle( &package->hdr ); - if( !hPackage ) - ERR("Handle for object %p not found\n", package ); - fn(hPackage); - msiobj_release( &package->hdr ); - } - else - ERR("Cannot load functon\n"); - - HeapFree(GetProcessHeap(),0,proc); - FreeLibrary(DLL); - } - else - ERR("Unable to load library\n"); - return ERROR_SUCCESS; } static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source, const LPWSTR target, const INT type) { - WCHAR tmp_file[MAX_PATH*2]; + WCHAR tmp_file[MAX_PATH]; STARTUPINFOW si; PROCESS_INFORMATION info; BOOL rc; + INT len; WCHAR *deformated; + WCHAR *cmd; static const WCHAR spc[] = {' ',0}; memset(&si,0,sizeof(STARTUPINFOW)); store_binary_to_temp(package, source, tmp_file); - strcatW(tmp_file,spc); deformat_string(package,target,&deformated); - strcatW(tmp_file,deformated); + + len = strlenW(tmp_file) + strlenW(deformated) + 2; + + cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*len); + + strcpyW(cmd,tmp_file); + strcatW(cmd,spc); + strcatW(cmd,deformated); HeapFree(GetProcessHeap(),0,deformated); - TRACE("executing exe %s \n",debugstr_w(tmp_file)); + TRACE("executing exe %s \n",debugstr_w(cmd)); - rc = CreateProcessW(NULL, tmp_file, NULL, NULL, FALSE, 0, NULL, + rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL, c_collen, &si, &info); + HeapFree(GetProcessHeap(),0,cmd); + if ( !rc ) { ERR("Unable to execute command\n"); @@ -1283,33 +1559,43 @@ static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source, return ERROR_SUCCESS; } -static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source, +static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source, const LPWSTR target, const INT type) { - WCHAR filename[MAX_PATH*2]; STARTUPINFOW si; PROCESS_INFORMATION info; BOOL rc; WCHAR *deformated; + WCHAR *cmd; + INT len; static const WCHAR spc[] = {' ',0}; int index; memset(&si,0,sizeof(STARTUPINFOW)); index = get_loaded_file(package,source); - strcpyW(filename,package->files[index].TargetPath); - strcatW(filename,spc); + len = strlenW(package->files[index].TargetPath); + deformat_string(package,target,&deformated); - strcatW(filename,deformated); + len += strlenW(deformated); + len += 2; + + cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,len * sizeof(WCHAR)); + + strcpyW(cmd, package->files[index].TargetPath); + strcatW(cmd, spc); + strcatW(cmd, deformated); HeapFree(GetProcessHeap(),0,deformated); - TRACE("executing exe %s \n",debugstr_w(filename)); + TRACE("executing exe %s \n",debugstr_w(cmd)); - rc = CreateProcessW(NULL, filename, NULL, NULL, FALSE, 0, NULL, + rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL, c_collen, &si, &info); + HeapFree(GetProcessHeap(),0,cmd); + if ( !rc ) { ERR("Unable to execute command\n"); @@ -1324,74 +1610,82 @@ static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source, return ERROR_SUCCESS; } -static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source, +static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source, const LPWSTR target, const INT type) { - WCHAR filename[MAX_PATH*2]; + STARTUPINFOW si; + PROCESS_INFORMATION info; + WCHAR *prop; + BOOL rc; + WCHAR *deformated; + WCHAR *cmd; + INT len; + UINT prc; + static const WCHAR spc[] = {' ',0}; + + memset(&si,0,sizeof(STARTUPINFOW)); + memset(&info,0,sizeof(PROCESS_INFORMATION)); + + prop = load_dynamic_property(package,source,&prc); + if (!prop) + return prc; + + deformat_string(package,target,&deformated); + len = strlenW(prop) + strlenW(deformated) + 2; + cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*len); + + strcpyW(cmd,prop); + strcatW(cmd,spc); + strcatW(cmd,deformated); + + HeapFree(GetProcessHeap(),0,deformated); + + TRACE("executing exe %s \n",debugstr_w(cmd)); + + rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL, + c_collen, &si, &info); + + HeapFree(GetProcessHeap(),0,cmd); + + if ( !rc ) + { + ERR("Unable to execute command\n"); + return ERROR_SUCCESS; + } + + if (!(type & 0xc0)) + WaitForSingleObject(info.hProcess,INFINITE); + + CloseHandle( info.hProcess ); + CloseHandle( info.hThread ); + return ERROR_SUCCESS; +} + +static UINT HANDLE_CustomType34(MSIPACKAGE *package, const LPWSTR source, + const LPWSTR target, const INT type) +{ + LPWSTR filename, deformated; STARTUPINFOW si; PROCESS_INFORMATION info; BOOL rc; - WCHAR *deformated; - static const WCHAR spc[] = {' ',0}; - DWORD sz; memset(&si,0,sizeof(STARTUPINFOW)); - sz = MAX_PATH*2; - if (MSI_GetPropertyW(package,source,filename,&sz) != ERROR_SUCCESS) + filename = resolve_folder(package, source, FALSE, FALSE, NULL); + + if (!filename) return ERROR_FUNCTION_FAILED; - strcatW(filename,spc); - deformat_string(package,target,&deformated); - strcatW(filename,deformated); - - HeapFree(GetProcessHeap(),0,deformated); - - TRACE("executing exe %s \n",debugstr_w(filename)); - - rc = CreateProcessW(NULL, filename, NULL, NULL, FALSE, 0, NULL, - c_collen, &si, &info); - - if ( !rc ) - { - ERR("Unable to execute command\n"); - return ERROR_SUCCESS; - } - - if (!(type & 0xc0)) - WaitForSingleObject(info.hProcess,INFINITE); - - CloseHandle( info.hProcess ); - CloseHandle( info.hThread ); - return ERROR_SUCCESS; -} - -static UINT HANDLE_CustomType34(MSIPACKAGE *package, const LPWSTR source, - const LPWSTR target, const INT type) -{ - WCHAR filename[MAX_PATH*2]; - STARTUPINFOW si; - PROCESS_INFORMATION info; - BOOL rc; - WCHAR *deformated; - - memset(&si,0,sizeof(STARTUPINFOW)); - - rc = resolve_folder(package, source, filename, FALSE, FALSE, NULL); - if (rc != ERROR_SUCCESS) - return rc; - SetCurrentDirectoryW(filename); + HeapFree(GetProcessHeap(),0,filename); deformat_string(package,target,&deformated); - strcpyW(filename,deformated); - HeapFree(GetProcessHeap(),0,deformated); + TRACE("executing exe %s \n",debugstr_w(deformated)); - TRACE("executing exe %s \n",debugstr_w(filename)); - - rc = CreateProcessW(NULL, filename, NULL, NULL, FALSE, 0, NULL, + rc = CreateProcessW(NULL, deformated, NULL, NULL, FALSE, 0, NULL, c_collen, &si, &info); + HeapFree(GetProcessHeap(),0,deformated); if ( !rc ) { @@ -1421,7 +1715,8 @@ static BOOL create_full_pathW(const WCHAR *path) WCHAR *new_path; new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * -sizeof(WCHAR)); + sizeof(WCHAR)); + strcpyW(new_path, path); while((len = strlenW(new_path)) && new_path[len - 1] == '\\') @@ -1429,31 +1724,31 @@ sizeof(WCHAR)); while(!CreateDirectoryW(new_path, NULL)) { - WCHAR *slash; - DWORD last_error = GetLastError(); - if(last_error == ERROR_ALREADY_EXISTS) - break; + WCHAR *slash; + DWORD last_error = GetLastError(); + if(last_error == ERROR_ALREADY_EXISTS) + break; - if(last_error != ERROR_PATH_NOT_FOUND) - { - ret = FALSE; - break; - } + if(last_error != ERROR_PATH_NOT_FOUND) + { + ret = FALSE; + break; + } - if(!(slash = strrchrW(new_path, '\\'))) - { - ret = FALSE; - break; - } + if(!(slash = strrchrW(new_path, '\\'))) + { + ret = FALSE; + break; + } - len = slash - new_path; - new_path[len] = 0; - if(!create_full_pathW(new_path)) - { - ret = FALSE; - break; - } - new_path[len] = '\\'; + len = slash - new_path; + new_path[len] = 0; + if(!create_full_pathW(new_path)) + { + ret = FALSE; + break; + } + new_path[len] = '\\'; } HeapFree(GetProcessHeap(), 0, new_path); @@ -1488,7 +1783,7 @@ static UINT ACTION_CreateFolders(MSIPACKAGE *package) while (1) { WCHAR dir[0x100]; - WCHAR full_path[MAX_PATH]; + LPWSTR full_path; DWORD sz; MSIRECORD *row = NULL, *uirow; @@ -1510,9 +1805,8 @@ static UINT ACTION_CreateFolders(MSIPACKAGE *package) } sz = MAX_PATH; - rc = resolve_folder(package,dir,full_path,FALSE,FALSE,&folder); - - if (rc != ERROR_SUCCESS) + full_path = resolve_folder(package,dir,FALSE,FALSE,&folder); + if (!full_path) { ERR("Unable to resolve folder id %s\n",debugstr_w(dir)); msiobj_release(&row->hdr); @@ -1533,6 +1827,7 @@ static UINT ACTION_CreateFolders(MSIPACKAGE *package) folder->State = 3; msiobj_release(&row->hdr); + HeapFree(GetProcessHeap(),0,full_path); } MSI_ViewClose(view); msiobj_release(&view->hdr); @@ -1579,9 +1874,11 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row) sz = 96; MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz); - package->components[index].State = INSTALLSTATE_UNKNOWN; + package->components[index].Installed = INSTALLSTATE_ABSENT; + package->components[index].Action = INSTALLSTATE_UNKNOWN; + package->components[index].ActionRequest = INSTALLSTATE_UNKNOWN; + package->components[index].Enabled = TRUE; - package->components[index].FeatureState= FALSE; return index; } @@ -1591,13 +1888,12 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) int index = package->loaded_features; DWORD sz; static const WCHAR Query1[] = {'S','E','L','E','C','T',' ','C','o','m','p', -'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e', -'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e', -'a','t','u','r','e','_','=','\'','%','s','\'',0}; + 'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e', + 'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e', + 'a','t','u','r','e','_','=','\'','%','s','\'',0}; static const WCHAR Query2[] = {'S','E','L','E','C','T',' ','*',' ','F','R', -'O','M',' ','C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ','C', -'o','m','p','o','n','e','n','t','=','\'','%','s','\'',0}; - WCHAR Query[1024]; + 'O','M',' ','C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ','C', + 'o','m','p','o','n','e','n','t','=','\'','%','s','\'',0}; MSIQUERY * view; MSIQUERY * view2; MSIRECORD * row2; @@ -1642,12 +1938,14 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz); package->features[index].Attributes= MSI_RecordGetInteger(row,8); - package->features[index].State = INSTALLSTATE_UNKNOWN; + + package->features[index].Installed = INSTALLSTATE_ABSENT; + package->features[index].Action = INSTALLSTATE_UNKNOWN; + package->features[index].ActionRequest = INSTALLSTATE_UNKNOWN; /* load feature components */ - sprintfW(Query,Query1,package->features[index].Feature); - rc = MSI_DatabaseOpenViewW(package->db,Query,&view); + rc = ACTION_OpenQuery(package->db, &view, Query1, package->features[index].Feature); if (rc != ERROR_SUCCESS) return; rc = MSI_ViewExecute(view,0); @@ -1680,11 +1978,10 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) c_indx); package->features[index].Components[cnt] = c_indx; package->features[index].ComponentCount ++; + continue; } - sprintfW(Query,Query2,buffer); - - rc = MSI_DatabaseOpenViewW(package->db,Query,&view2); + rc = ACTION_OpenQuery(package->db, &view2, Query2, buffer); if (rc != ERROR_SUCCESS) { msiobj_release( &row2->hdr ); @@ -1710,6 +2007,7 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) package->features[index].Components[cnt] = c_indx; package->features[index].ComponentCount ++; + TRACE("Loaded new component to index %i\n",c_indx); } MSI_ViewClose(view2); msiobj_release( &view2->hdr ); @@ -1736,7 +2034,6 @@ static UINT ACTION_CostInitialize(MSIPACKAGE *package) { MSIQUERY * view; MSIRECORD * row; - DWORD sz; UINT rc; static const WCHAR Query_all[] = { 'S','E','L','E','C','T',' ','*',' ', @@ -1748,7 +2045,6 @@ static UINT ACTION_CostInitialize(MSIPACKAGE *package) MSI_SetPropertyW(package, szCosting, szZero); MSI_SetPropertyW(package, cszRootDrive , c_collen); - sz = 0x100; rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view); if (rc != ERROR_SUCCESS) return rc; @@ -1780,8 +2076,7 @@ static UINT load_file(MSIPACKAGE* package, MSIRECORD * row) { DWORD index = package->loaded_files; DWORD i; - WCHAR buffer[0x100]; - DWORD sz; + LPWSTR buffer; /* fill in the data */ @@ -1793,12 +2088,9 @@ static UINT load_file(MSIPACKAGE* package, MSIRECORD * row) package->files , package->loaded_files * sizeof(MSIFILE)); memset(&package->files[index],0,sizeof(MSIFILE)); - - sz = 72; - MSI_RecordGetStringW(row,1,package->files[index].File,&sz); - - sz = 0x100; - MSI_RecordGetStringW(row,2,buffer,&sz); + + package->files[index].File = load_dynamic_stringW(row, 1); + buffer = load_dynamic_stringW(row, 2); package->files[index].ComponentIndex = -1; for (i = 0; i < package->loaded_components; i++) @@ -1809,25 +2101,16 @@ static UINT load_file(MSIPACKAGE* package, MSIRECORD * row) } if (package->files[index].ComponentIndex == -1) ERR("Unfound Component %s\n",debugstr_w(buffer)); + HeapFree(GetProcessHeap(), 0, buffer); - sz = MAX_PATH; - MSI_RecordGetStringW(row,3,package->files[index].FileName,&sz); + package->files[index].FileName = load_dynamic_stringW(row,3); reduce_to_longfilename(package->files[index].FileName); package->files[index].FileSize = MSI_RecordGetInteger(row,4); - - sz = 72; - if (!MSI_RecordIsNull(row,5)) - MSI_RecordGetStringW(row,5,package->files[index].Version,&sz); - - sz = 20; - if (!MSI_RecordIsNull(row,6)) - MSI_RecordGetStringW(row,6,package->files[index].Language,&sz); - - if (!MSI_RecordIsNull(row,7)) - package->files[index].Attributes= MSI_RecordGetInteger(row,7); - + package->files[index].Version = load_dynamic_stringW(row, 5); + package->files[index].Language = load_dynamic_stringW(row, 6); + package->files[index].Attributes= MSI_RecordGetInteger(row,7); package->files[index].Sequence= MSI_RecordGetInteger(row,8); package->files[index].Temporary = FALSE; @@ -1883,18 +2166,13 @@ static UINT ACTION_FileCost(MSIPACKAGE *package) static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) { - WCHAR Query[1024] = -{'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c', -'t','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t', -'o','r','y','`',' ','=',' ','`',0}; - static const WCHAR end[]={'`',0}; + static const WCHAR Query[] = + {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c', + 't','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t', + 'o','r','y','`',' ','=',' ','`','%','s','`',0}; UINT rc; MSIQUERY * view; - WCHAR targetbuffer[0x100]; - WCHAR *srcdir = NULL; - WCHAR *targetdir = NULL; - WCHAR parent[0x100]; - DWORD sz=0x100; + LPWSTR targetdir, parent, srcdir; MSIRECORD * row = 0; INT index = -1; DWORD i; @@ -1912,10 +2190,8 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) TRACE("Working to load %s\n",debugstr_w(dir)); - index = package->loaded_folders; - - package->loaded_folders++; - if (package->loaded_folders== 1) + index = package->loaded_folders++; + if (package->loaded_folders==1) package->folders = HeapAlloc(GetProcessHeap(),0, sizeof(MSIFOLDER)); else @@ -1925,13 +2201,9 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) memset(&package->folders[index],0,sizeof(MSIFOLDER)); - strcpyW(package->folders[index].Directory,dir); - - strcatW(Query,dir); - strcatW(Query,end); - - rc = MSI_DatabaseOpenViewW(package->db, Query, &view); + package->folders[index].Directory = dupstrW(dir); + rc = ACTION_OpenQuery(package->db, &view, Query, dir); if (rc != ERROR_SUCCESS) return -1; @@ -1951,9 +2223,7 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) return -1; } - sz=0x100; - MSI_RecordGetStringW(row,3,targetbuffer,&sz); - targetdir=targetbuffer; + targetdir = load_dynamic_stringW(row,3); /* split src and target dir */ if (strchrW(targetdir,':')) @@ -1986,38 +2256,35 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) if (srcdir && srcdir[0] == '.' && srcdir[1] == 0) srcdir = NULL; - if (targetdir) - strcpyW(package->folders[index].TargetDefault,targetdir); - - if (srcdir) - strcpyW(package->folders[index].SourceDefault,srcdir); - else if (targetdir) - strcpyW(package->folders[index].SourceDefault,targetdir); - - if (MSI_RecordIsNull(row,2)) - parent[0]=0; - else + if (targetdir) { - sz=0x100; - MSI_RecordGetStringW(row,2,parent,&sz); + TRACE(" TargetDefault = %s\n",debugstr_w(targetdir)); + if (package->folders[index].TargetDefault) + HeapFree(GetProcessHeap(),0, package->folders[index].TargetDefault); + package->folders[index].TargetDefault = dupstrW(targetdir); } - if (parent[0]) + if (srcdir) + package->folders[index].SourceDefault = dupstrW(srcdir); + else if (targetdir) + package->folders[index].SourceDefault = dupstrW(targetdir); + HeapFree(GetProcessHeap(), 0, targetdir); + + parent = load_dynamic_stringW(row,2); + if (parent) { i = load_folder(package,parent); package->folders[index].ParentIndex = i; TRACE("Parent is index %i... %s %s\n", package->folders[index].ParentIndex, - debugstr_w(package->folders[package->folders[index].ParentIndex].Directory), + debugstr_w(package->folders[package->folders[index].ParentIndex].Directory), debugstr_w(parent)); } else package->folders[index].ParentIndex = -2; + HeapFree(GetProcessHeap(), 0, parent); - sz = MAX_PATH; - rc = MSI_GetPropertyW(package, dir, package->folders[index].Property, &sz); - if (rc != ERROR_SUCCESS) - package->folders[index].Property[0]=0; + package->folders[index].Property = load_dynamic_property(package, dir,NULL); msiobj_release(&row->hdr); MSI_ViewClose(view); @@ -2026,57 +2293,61 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) return index; } -static UINT resolve_folder(MSIPACKAGE *package, LPCWSTR name, LPWSTR path, + +static LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, BOOL set_prop, MSIFOLDER **folder) { DWORD i; - UINT rc = ERROR_SUCCESS; - DWORD sz; + LPWSTR p, path = NULL; TRACE("Working to resolve %s\n",debugstr_w(name)); - if (!path) - return rc; - /* special resolving for Target and Source root dir */ if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0) { if (!source) { - sz = MAX_PATH; - rc = MSI_GetPropertyW(package,cszTargetDir,path,&sz); - if (rc != ERROR_SUCCESS) + path = load_dynamic_property(package,cszTargetDir,NULL); + if (!path) { - sz = MAX_PATH; - rc = MSI_GetPropertyW(package,cszRootDrive,path,&sz); + path = load_dynamic_property(package,cszRootDrive,NULL); if (set_prop) MSI_SetPropertyW(package,cszTargetDir,path); } if (folder) - *folder = &(package->folders[0]); - return rc; + { + for (i = 0; i < package->loaded_folders; i++) + { + if (strcmpW(package->folders[i].Directory,name)==0) + break; + } + *folder = &(package->folders[i]); + } + return path; } else { - sz = MAX_PATH; - rc = MSI_GetPropertyW(package,cszSourceDir,path,&sz); - if (rc != ERROR_SUCCESS) + path = load_dynamic_property(package,cszSourceDir,NULL); + if (!path) { - sz = MAX_PATH; - rc = MSI_GetPropertyW(package,cszDatabase,path,&sz); - if (rc == ERROR_SUCCESS) + path = load_dynamic_property(package,cszDatabase,NULL); + if (path) { - LPWSTR ptr = strrchrW(path,'\\'); - if (ptr) - { - ptr++; - *ptr = 0; - } + p = strrchrW(path,'\\'); + if (p) + *(p+1) = 0; } } if (folder) - *folder = &(package->folders[0]); - return rc; + { + for (i = 0; i < package->loaded_folders; i++) + { + if (strcmpW(package->folders[i].Directory,name)==0) + break; + } + *folder = &(package->folders[i]); + } + return path; } } @@ -2087,67 +2358,186 @@ static UINT resolve_folder(MSIPACKAGE *package, LPCWSTR name, LPWSTR path, } if (i >= package->loaded_folders) - return ERROR_FUNCTION_FAILED; + return NULL; if (folder) *folder = &(package->folders[i]); - if (!source && package->folders[i].ResolvedTarget[0]) + if (!source && package->folders[i].ResolvedTarget) { - strcpyW(path,package->folders[i].ResolvedTarget); + path = dupstrW(package->folders[i].ResolvedTarget); TRACE(" already resolved to %s\n",debugstr_w(path)); - return ERROR_SUCCESS; + return path; } - else if (source && package->folders[i].ResolvedSource[0]) + else if (source && package->folders[i].ResolvedSource) { - strcpyW(path,package->folders[i].ResolvedSource); - return ERROR_SUCCESS; + path = dupstrW(package->folders[i].ResolvedSource); + return path; } - else if (!source && package->folders[i].Property[0]) + else if (!source && package->folders[i].Property) { - strcpyW(path,package->folders[i].Property); + path = dupstrW(package->folders[i].Property); TRACE(" internally set to %s\n",debugstr_w(path)); if (set_prop) MSI_SetPropertyW(package,name,path); - return ERROR_SUCCESS; + return path; } if (package->folders[i].ParentIndex >= 0) { - int len; - TRACE(" ! Parent is %s\n", debugstr_w(package->folders[ - package->folders[i].ParentIndex].Directory)); - resolve_folder(package, package->folders[ - package->folders[i].ParentIndex].Directory, path,source, - set_prop, NULL); + LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory; - len = strlenW(path); - if (len && path[len-1] != '\\') - strcatW(path, cszbs); + TRACE(" ! Parent is %s\n", debugstr_w(parent)); + p = resolve_folder(package, parent, source, set_prop, NULL); if (!source) { - if (package->folders[i].TargetDefault[0]) - { - strcatW(path,package->folders[i].TargetDefault); - strcatW(path,cszbs); - } - strcpyW(package->folders[i].ResolvedTarget,path); + TRACE(" TargetDefault = %s\n",debugstr_w(package->folders[i].TargetDefault)); + path = build_directory_name(3, p, package->folders[i].TargetDefault, NULL); + package->folders[i].ResolvedTarget = dupstrW(path); TRACE(" resolved into %s\n",debugstr_w(path)); if (set_prop) MSI_SetPropertyW(package,name,path); } else { - if (package->folders[i].SourceDefault[0]) + path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL); + package->folders[i].ResolvedSource = dupstrW(path); + } + HeapFree(GetProcessHeap(),0,p); + } + return path; +} + +static UINT SetFeatureStates(MSIPACKAGE *package) +{ + LPWSTR level; + INT install_level; + DWORD i; + INT j; + LPWSTR override = NULL; + static const WCHAR all[]={'A','L','L',0}; + static const WCHAR szlevel[] = { + 'I','N','S','T','A','L','L','L','E','V','E','L',0}; + static const WCHAR szAddLocal[] = { + 'A','D','D','L','O','C','A','L',0}; + + /* I do not know if this is where it should happen.. but */ + + TRACE("Checking Install Level\n"); + + level = load_dynamic_property(package,szlevel,NULL); + if (level) + { + install_level = atoiW(level); + HeapFree(GetProcessHeap(), 0, level); + } + else + install_level = 1; + + /* ok hereis the rub + * ADDLOCAL and its friend OVERRIDE INSTALLLEVLE + * I have confirmed this if ADDLOCALis stated then the INSTALLLEVEL is + * itnored for all the features. seems strange, epsecially since it is not + * documented anywhere, but it is how it works. + */ + + override = load_dynamic_property(package,szAddLocal,NULL); + + if (override) + { + for(i = 0; i < package->loaded_features; i++) + { + if (strcmpiW(override,all)==0) { - strcatW(path,package->folders[i].SourceDefault); - strcatW(path,cszbs); + package->features[i].ActionRequest= INSTALLSTATE_LOCAL; + package->features[i].Action = INSTALLSTATE_LOCAL; + } + else + { + LPWSTR ptr = override; + LPWSTR ptr2 = strchrW(override,','); + + while (ptr) + { + if ((ptr2 && + strncmpW(ptr,package->features[i].Feature, ptr2-ptr)==0) + || (!ptr2 && + strcmpW(ptr,package->features[i].Feature)==0)) + { + package->features[i].ActionRequest= INSTALLSTATE_LOCAL; + package->features[i].Action = INSTALLSTATE_LOCAL; + break; + } + if (ptr2) + { + ptr=ptr2+1; + ptr2 = strchrW(ptr,','); + } + else + break; + } + } + } + HeapFree(GetProcessHeap(),0,override); + } + else + { + for(i = 0; i < package->loaded_features; i++) + { + BOOL feature_state= ((package->features[i].Level > 0) && + (package->features[i].Level <= install_level)); + + if (feature_state) + { + package->features[i].ActionRequest= INSTALLSTATE_LOCAL; + package->features[i].Action = INSTALLSTATE_LOCAL; } - strcpyW(package->folders[i].ResolvedSource,path); } } - return rc; + + /* + * now we want to enable or disable components base on feature + */ + + for(i = 0; i < package->loaded_features; i++) + { + MSIFEATURE* feature = &package->features[i]; + TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n", + debugstr_w(feature->Feature), feature->Installed, feature->Action, + feature->ActionRequest); + + for( j = 0; j < feature->ComponentCount; j++) + { + MSICOMPONENT* component = &package->components[ + feature->Components[j]]; + + if (!component->Enabled) + { + component->Action = INSTALLSTATE_ABSENT; + component->ActionRequest = INSTALLSTATE_ABSENT; + } + else + { + if (feature->Action == INSTALLSTATE_LOCAL) + component->Action = INSTALLSTATE_LOCAL; + if (feature->ActionRequest == INSTALLSTATE_LOCAL) + component->ActionRequest = INSTALLSTATE_LOCAL; + } + } + } + + for(i = 0; i < package->loaded_components; i++) + { + MSICOMPONENT* component= &package->components[i]; + + TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n", + debugstr_w(component->Component), component->Installed, + component->Action, component->ActionRequest); + } + + + return ERROR_SUCCESS; } /* @@ -2166,10 +2556,13 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) 'C','o','n','d','i','t','i','o','n',0}; static const WCHAR szCosting[] = { 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 }; + static const WCHAR szlevel[] = { + 'I','N','S','T','A','L','L','L','E','V','E','L',0}; static const WCHAR szOne[] = { '1', 0 }; UINT rc; MSIQUERY * view; DWORD i; + LPWSTR level; TRACE("Building Directory properties\n"); @@ -2187,7 +2580,7 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) while (1) { WCHAR name[0x100]; - WCHAR path[MAX_PATH]; + LPWSTR path; MSIRECORD * row = 0; DWORD sz; @@ -2204,8 +2597,9 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) /* This helper function now does ALL the work */ TRACE("Dir %s ...\n",debugstr_w(name)); load_folder(package,name); - resolve_folder(package,name,path,FALSE,TRUE,NULL); + path = resolve_folder(package,name,FALSE,TRUE,NULL); TRACE("resolves to %s\n",debugstr_w(path)); + HeapFree( GetProcessHeap(), 0, path); msiobj_release(&row->hdr); } @@ -2224,21 +2618,29 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) if (file->ComponentIndex >= 0) comp = &package->components[file->ComponentIndex]; + if (file->Temporary == TRUE) + continue; + if (comp) { - int len; + LPWSTR p; + /* calculate target */ - resolve_folder(package, comp->Directory, file->TargetPath, FALSE, - FALSE, NULL); - /* make sure that the path ends in a \ */ - len = strlenW(file->TargetPath); - if (len && file->TargetPath[len-1] != '\\') - strcatW(file->TargetPath, cszbs); - strcatW(file->TargetPath,file->FileName); + p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL); + + if (file->TargetPath) + HeapFree(GetProcessHeap(),0,file->TargetPath); + + TRACE("file %s is named %s\n", + debugstr_w(file->File),debugstr_w(file->FileName)); + + file->TargetPath = build_directory_name(2, p, file->FileName); + + HeapFree(GetProcessHeap(),0,p); TRACE("file %s resolves to %s\n", debugstr_w(file->File),debugstr_w(file->TargetPath)); - + if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES) { file->State = 1; @@ -2246,7 +2648,7 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) } else { - if (file->Version[0]) + if (file->Version) { DWORD handle; DWORD versize; @@ -2295,55 +2697,55 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view); if (rc == ERROR_SUCCESS) { - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - WCHAR Feature[0x100]; - MSIRECORD * row = 0; - DWORD sz; - int feature_index; - - rc = MSI_ViewFetch(view,&row); - + rc = MSI_ViewExecute(view, 0); if (rc != ERROR_SUCCESS) { - rc = ERROR_SUCCESS; - break; + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return rc; } - - sz = 0x100; - MSI_RecordGetStringW(row,1,Feature,&sz); - - feature_index = get_loaded_feature(package,Feature); - if (feature_index < 0) - ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature)); - else + + while (1) { - LPWSTR Condition; - Condition = load_dynamic_stringW(row,3); + WCHAR Feature[0x100]; + MSIRECORD * row = 0; + DWORD sz; + int feature_index; + + rc = MSI_ViewFetch(view,&row); + + if (rc != ERROR_SUCCESS) + { + rc = ERROR_SUCCESS; + break; + } + + sz = 0x100; + MSI_RecordGetStringW(row,1,Feature,&sz); + + feature_index = get_loaded_feature(package,Feature); + if (feature_index < 0) + ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature)); + else + { + LPWSTR Condition; + Condition = load_dynamic_stringW(row,3); if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE) - { - int level = MSI_RecordGetInteger(row,2); + { + int level = MSI_RecordGetInteger(row,2); TRACE("Reseting feature %s to level %i\n", debugstr_w(Feature), level); - package->features[feature_index].Level = level; + package->features[feature_index].Level = level; + } + HeapFree(GetProcessHeap(),0,Condition); } - HeapFree(GetProcessHeap(),0,Condition); - } - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); + msiobj_release(&row->hdr); + } + MSI_ViewClose(view); + msiobj_release(&view->hdr); } TRACE("Enabling or Disabling Components\n"); @@ -2362,7 +2764,15 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) } MSI_SetPropertyW(package,szCosting,szOne); - return ERROR_SUCCESS; + /* set default run level if not set */ + level = load_dynamic_property(package,szlevel,NULL); + if (!level) + MSI_SetPropertyW(package,szlevel, szOne); + else + HeapFree(GetProcessHeap(),0,level); + + return SetFeatureStates(package); + } /* @@ -2408,6 +2818,12 @@ end: /* Support functions for FDI functions */ +typedef struct +{ + MSIPACKAGE* package; + LPCSTR cab_path; + LPCSTR file_name; +} CabData; static void * cabinet_alloc(ULONG cb) { @@ -2480,14 +2896,39 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) { case fdintCOPY_FILE: { - ULONG len = strlen((char*)pfdin->pv) + strlen(pfdin->psz1); - char *file = cabinet_alloc((len+1)*sizeof(char)); + CabData *data = (CabData*) pfdin->pv; + ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1); + char *file; - strcpy(file, (char*)pfdin->pv); + LPWSTR trackname; + LPWSTR trackpath; + LPWSTR tracknametmp; + static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0}; + + if (data->file_name && strcmp(data->file_name,pfdin->psz1)) + return 0; + + file = cabinet_alloc((len+1)*sizeof(char)); + strcpy(file, data->cab_path); strcat(file, pfdin->psz1); TRACE("file: %s\n", debugstr_a(file)); + /* track this file so it can be deleted if not installed */ + trackpath=strdupAtoW(file); + tracknametmp=strdupAtoW(strrchr(file,'\\')+1); + trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) + + strlenW(tmpprefix)+1) * sizeof(WCHAR)); + + strcpyW(trackname,tmpprefix); + strcatW(trackname,tracknametmp); + + track_tempfile(data->package, trackname, trackpath); + + HeapFree(GetProcessHeap(),0,trackpath); + HeapFree(GetProcessHeap(),0,trackname); + HeapFree(GetProcessHeap(),0,tracknametmp); + return cabinet_open(file, _O_WRONLY | _O_CREAT, 0); } case fdintCLOSE_FILE_INFO: @@ -2514,15 +2955,19 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) * * Extract files from a cab file. */ -static BOOL extract_cabinet_file(const WCHAR* source, const WCHAR* path) +static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source, + const WCHAR* path, const WCHAR* file) { HFDI hfdi; ERF erf; BOOL ret; char *cabinet; char *cab_path; + char *file_name; + CabData data; - TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path)); + TRACE("Extracting %s (%s) to %s\n",debugstr_w(source), + debugstr_w(file), debugstr_w(path)); hfdi = FDICreate(cabinet_alloc, cabinet_free, @@ -2551,7 +2996,12 @@ static BOOL extract_cabinet_file(const WCHAR* source, const WCHAR* path) return FALSE; } - ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, cab_path); + data.package = package; + data.cab_path = cab_path; + file_name = strdupWtoA(file); + data.file_name = file_name; + + ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data); if (!ret) ERR("FDICopy failed\n"); @@ -2560,17 +3010,18 @@ static BOOL extract_cabinet_file(const WCHAR* source, const WCHAR* path) HeapFree(GetProcessHeap(), 0, cabinet); HeapFree(GetProcessHeap(), 0, cab_path); + HeapFree(GetProcessHeap(), 0, file_name); return ret; } static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence, - WCHAR* path) + WCHAR* path, WCHAR* file) { UINT rc; MSIQUERY * view; MSIRECORD * row = 0; - WCHAR source[MAX_PATH]; + static WCHAR source[MAX_PATH]; static const WCHAR ExecSeqQuery[] = { 's','e','l','e','c','t',' ','*',' ', 'f','r','o','m',' ','M','e','d','i','a',' ', @@ -2585,6 +3036,7 @@ static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence, if (sequence <= last_sequence) { TRACE("Media already ready (%u, %u)\n",sequence,last_sequence); + extract_a_cabinet_file(package, source,path,file); return ERROR_SUCCESS; } @@ -2643,7 +3095,7 @@ static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence, GetTempPathW(MAX_PATH,path); } } - rc = !extract_cabinet_file(source,path); + rc = !extract_a_cabinet_file(package, source,path,file); } msiobj_release(&row->hdr); MSI_ViewClose(view); @@ -2655,13 +3107,12 @@ inline static UINT create_component_directory ( MSIPACKAGE* package, INT compone { UINT rc; MSIFOLDER *folder; - WCHAR install_path[MAX_PATH]; + LPWSTR install_path; - rc = resolve_folder(package, package->components[component].Directory, - install_path, FALSE, FALSE, &folder); - - if (rc != ERROR_SUCCESS) - return rc; + install_path = resolve_folder(package, package->components[component].Directory, + FALSE, FALSE, &folder); + if (!install_path) + return ERROR_FUNCTION_FAILED; /* create the path */ if (folder->State == 0) @@ -2669,6 +3120,7 @@ inline static UINT create_component_directory ( MSIPACKAGE* package, INT compone create_full_pathW(install_path); folder->State = 2; } + HeapFree(GetProcessHeap(), 0, install_path); return rc; } @@ -2684,7 +3136,7 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package) return ERROR_INVALID_HANDLE; /* increment progress bar each time action data is sent */ - ui_progress(package,1,1,1,0); + ui_progress(package,1,1,0,0); for (index = 0; index < package->loaded_files; index++) { @@ -2696,18 +3148,25 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package) if (file->Temporary) continue; - if (!package->components[file->ComponentIndex].Enabled || - !package->components[file->ComponentIndex].FeatureState) + if (package->components[file->ComponentIndex].ActionRequest != + INSTALLSTATE_LOCAL) { + ui_progress(package,2,file->FileSize,0,0); TRACE("File %s is not scheduled for install\n", debugstr_w(file->File)); + continue; } if ((file->State == 1) || (file->State == 2)) { + LPWSTR p; + INT len; + MSICOMPONENT* comp = NULL; + TRACE("Installing %s\n",debugstr_w(file->File)); - rc = ready_media_for_file(package,file->Sequence,path_to_source); + rc = ready_media_for_file(package,file->Sequence,path_to_source, + file->File); /* * WARNING! * our file table could change here because a new temp file @@ -2723,6 +3182,19 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package) create_component_directory( package, file->ComponentIndex); + /* recalculate file paths because things may have changed */ + + if (file->ComponentIndex >= 0) + comp = &package->components[file->ComponentIndex]; + + p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL); + if (file->TargetPath) + HeapFree(GetProcessHeap(),0,file->TargetPath); + + file->TargetPath = build_directory_name(2, p, file->FileName); + + len = strlenW(path_to_source) + strlenW(file->File) + 2; + file->SourcePath = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); strcpyW(file->SourcePath, path_to_source); strcatW(file->SourcePath, file->File); @@ -2738,6 +3210,7 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package) MSI_RecordSetInteger(uirow,6,file->FileSize); ui_actiondata(package,szInstallFiles,uirow); msiobj_release( &uirow->hdr ); + ui_progress(package,2,file->FileSize,0,0); if (!MoveFileW(file->SourcePath,file->TargetPath)) { @@ -2751,13 +3224,19 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package) DeleteFileW(file->SourcePath); rc = 0; } + else if (rc == ERROR_FILE_NOT_FOUND) + { + ERR("Source File Not Found! Continueing\n"); + rc = 0; + } else - break; + { + ERR("Ignoring Error and continuing...\n"); + rc = 0; + } } else file->State = 4; - - ui_progress(package,2,0,0,0); } } @@ -2765,7 +3244,7 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package) } inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, - LPWSTR file_source) + LPWSTR* file_source) { DWORD index; @@ -2778,7 +3257,7 @@ inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, { if (package->files[index].State >= 3) { - strcpyW(file_source,package->files[index].TargetPath); + *file_source = dupstrW(package->files[index].TargetPath); return ERROR_SUCCESS; } else @@ -2816,9 +3295,9 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package) while (1) { WCHAR file_key[0x100]; - WCHAR file_source[MAX_PATH]; + WCHAR *file_source = NULL; WCHAR dest_name[0x100]; - WCHAR dest_path[MAX_PATH]; + LPWSTR dest_path, dest; WCHAR component[0x100]; INT component_index; @@ -2841,8 +3320,8 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package) } component_index = get_loaded_component(package,component); - if (!package->components[component_index].Enabled || - !package->components[component_index].FeatureState) + if (package->components[component_index].ActionRequest != + INSTALLSTATE_LOCAL) { TRACE("Skipping copy due to disabled component\n"); msiobj_release(&row->hdr); @@ -2858,12 +3337,14 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package) break; } - rc = get_file_target(package,file_key,file_source); + rc = get_file_target(package,file_key,&file_source); if (rc != ERROR_SUCCESS) { ERR("Original file unknown %s\n",debugstr_w(file_key)); msiobj_release(&row->hdr); + if (file_source) + HeapFree(GetProcessHeap(),0,file_source); break; } @@ -2880,8 +3361,11 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package) if (MSI_RecordIsNull(row,5)) { - strcpyW(dest_path,file_source); - *strrchrW(dest_path,'\\')=0; + LPWSTR p; + dest_path = dupstrW(file_source); + p = strrchrW(dest_path,'\\'); + if (p) + *p=0; } else { @@ -2889,22 +3373,25 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package) sz=0x100; MSI_RecordGetStringW(row,5,destkey,&sz); sz = 0x100; - rc = resolve_folder(package, destkey, dest_path,FALSE,FALSE,NULL); - if (rc != ERROR_SUCCESS) + dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL); + if (!dest_path) { ERR("Unable to get destination folder\n"); msiobj_release(&row->hdr); + if (file_source) + HeapFree(GetProcessHeap(),0,file_source); break; } } - strcatW(dest_path,dest_name); + dest = build_directory_name(2, dest_path, dest_name); + HeapFree(GetProcessHeap(), 0, dest_path); TRACE("Duplicating file %s to %s\n",debugstr_w(file_source), - debugstr_w(dest_path)); + debugstr_w(dest)); - if (strcmpW(file_source,dest_path)) - rc = !CopyFileW(file_source,dest_path,TRUE); + if (strcmpW(file_source,dest)) + rc = !CopyFileW(file_source,dest,TRUE); else rc = ERROR_SUCCESS; @@ -2914,11 +3401,12 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package) FIXME("We should track these duplicate files as well\n"); msiobj_release(&row->hdr); + HeapFree(GetProcessHeap(),0,dest); + HeapFree(GetProcessHeap(),0,file_source); } MSI_ViewClose(view); msiobj_release(&view->hdr); return rc; - } @@ -3024,7 +3512,7 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) } /* increment progress bar each time action data is sent */ - ui_progress(package,1,1,1,0); + ui_progress(package,1,REG_PROGRESS_VALUE,1,0); while (1) { @@ -3038,19 +3526,15 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) static const WCHAR szHU[] = {'H','K','E','Y','_','U','S','E','R','S','\\',0}; - WCHAR key[0x100]; - WCHAR name[0x100]; - LPWSTR value; LPSTR value_data = NULL; HKEY root_key, hkey; DWORD type,size; - WCHAR component[0x100]; + LPWSTR value, key, name, component, deformated; + LPCWSTR szRoot; INT component_index; MSIRECORD * uirow; - WCHAR uikey[0x110]; - + LPWSTR uikey; INT root; - DWORD sz=0x100; rc = MSI_ViewFetch(view,&row); if (rc != ERROR_SUCCESS) @@ -3058,17 +3542,22 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) rc = ERROR_SUCCESS; break; } + ui_progress(package,2,0,0,0); - sz= 0x100; - MSI_RecordGetStringW(row,6,component,&sz); + value = NULL; + key = NULL; + uikey = NULL; + name = NULL; + + component = load_dynamic_stringW(row, 6); component_index = get_loaded_component(package,component); - if (!package->components[component_index].Enabled || - !package->components[component_index].FeatureState) + if (package->components[component_index].ActionRequest != + INSTALLSTATE_LOCAL) { TRACE("Skipping write due to disabled component\n"); msiobj_release(&row->hdr); - continue; + goto next; } /* null values have special meanings during uninstalls and such */ @@ -3076,59 +3565,68 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) if(MSI_RecordIsNull(row,5)) { msiobj_release(&row->hdr); - continue; + goto next; } root = MSI_RecordGetInteger(row,2); - sz = 0x100; - MSI_RecordGetStringW(row,3,key,&sz); + key = load_dynamic_stringW(row, 3); - sz = 0x100; - if (MSI_RecordIsNull(row,4)) - name[0]=0; - else - MSI_RecordGetStringW(row,4,name,&sz); + name = load_dynamic_stringW(row, 4); /* get the root key */ switch (root) { case 0: root_key = HKEY_CLASSES_ROOT; - strcpyW(uikey,szHCR); break; + szRoot = szHCR; + break; case 1: root_key = HKEY_CURRENT_USER; - strcpyW(uikey,szHCU); break; + szRoot = szHCU; + break; case 2: root_key = HKEY_LOCAL_MACHINE; - strcpyW(uikey,szHLM); break; + szRoot = szHLM; + break; case 3: root_key = HKEY_USERS; - strcpyW(uikey,szHU); break; + szRoot = szHU; + break; default: ERR("Unknown root %i\n",root); root_key=NULL; + szRoot = NULL; break; } if (!root_key) { msiobj_release(&row->hdr); - continue; + goto next; } - strcatW(uikey,key); - if (RegCreateKeyW( root_key, key, &hkey)) + deformat_string(package, key , &deformated); + size = strlenW(deformated) + strlenW(szRoot) + 1; + uikey = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR)); + strcpyW(uikey,szRoot); + strcatW(uikey,deformated); + + if (RegCreateKeyW( root_key, deformated, &hkey)) { - ERR("Could not create key %s\n",debugstr_w(key)); + ERR("Could not create key %s\n",debugstr_w(deformated)); msiobj_release(&row->hdr); - continue; + HeapFree(GetProcessHeap(),0,deformated); + goto next; } + HeapFree(GetProcessHeap(),0,deformated); value = load_dynamic_stringW(row,5); value_data = parse_value(package, value, &type, &size); + deformat_string(package, name, &deformated); + if (value_data) { - TRACE("Setting value %s\n",debugstr_w(name)); - RegSetValueExW(hkey, name, 0, type, value_data, size); + TRACE("Setting value %s\n",debugstr_w(deformated)); + RegSetValueExW(hkey, deformated, 0, type, value_data, size); uirow = MSI_CreateRecord(3); - MSI_RecordSetStringW(uirow,2,name); + MSI_RecordSetStringW(uirow,2,deformated); MSI_RecordSetStringW(uirow,1,uikey); if (type == REG_SZ) @@ -3137,15 +3635,24 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) MSI_RecordSetStringW(uirow,3,value); ui_actiondata(package,szWriteRegistryValues,uirow); - ui_progress(package,2,0,0,0); msiobj_release( &uirow->hdr ); HeapFree(GetProcessHeap(),0,value_data); } HeapFree(GetProcessHeap(),0,value); + HeapFree(GetProcessHeap(),0,deformated); msiobj_release(&row->hdr); RegCloseKey(hkey); +next: + if (uikey) + HeapFree(GetProcessHeap(),0,uikey); + if (key) + HeapFree(GetProcessHeap(),0,key); + if (name) + HeapFree(GetProcessHeap(),0,name); + if (component) + HeapFree(GetProcessHeap(),0,component); } MSI_ViewClose(view); msiobj_release(&view->hdr); @@ -3167,6 +3674,12 @@ static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data) DWORD sz; UINT rc; + if (ptr==NULL) + { + TRACE("Deformatting NULL string\n"); + *data = NULL; + return 0; + } /* scan for special characters */ if (!strchrW(ptr,'[') || (strchrW(ptr,'[') && !strchrW(ptr,']'))) { @@ -3241,82 +3754,21 @@ static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data) static UINT ACTION_InstallInitialize(MSIPACKAGE *package) { - WCHAR level[10000]; - INT install_level; - DWORD sz; - DWORD i; - INT j; - DWORD rc; - LPWSTR override = NULL; - static const WCHAR addlocal[]={'A','D','D','L','O','C','A','L',0}; - static const WCHAR all[]={'A','L','L',0}; - static const WCHAR szlevel[] = { - 'I','N','S','T','A','L','L','L','E','V','E','L',0}; - static const WCHAR szAddLocal[] = { - 'A','D','D','L','O','C','A','L',0}; - - /* I do not know if this is where it should happen.. but */ - - TRACE("Checking Install Level\n"); - - sz = 10000; - if (MSI_GetPropertyW(package,szlevel,level,&sz)==ERROR_SUCCESS) - install_level = atoiW(level); - else - install_level = 1; - - sz = 0; - rc = MSI_GetPropertyW(package,szAddLocal,NULL,&sz); - if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA) - { - sz++; - override = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR)); - MSI_GetPropertyW(package, addlocal,override,&sz); - } - - /* - * Components FeatureState defaults to FALSE. The idea is we want to - * enable the component is ANY feature that uses it is enabled to install - */ - for(i = 0; i < package->loaded_features; i++) - { - BOOL feature_state= ((package->features[i].Level > 0) && - (package->features[i].Level <= install_level)); - - if (override && (strcmpiW(override,all)==0 || - strstrW(override,package->features[i].Feature))) - { - TRACE("Override of install level found\n"); - feature_state = TRUE; - package->features[i].Enabled = feature_state; - } - - TRACE("Feature %s has a state of %i\n", - debugstr_w(package->features[i].Feature), feature_state); - for( j = 0; j < package->features[i].ComponentCount; j++) - { - package->components[package->features[i].Components[j]].FeatureState - |= feature_state; - } - } - if (override != NULL) - HeapFree(GetProcessHeap(),0,override); - /* - * So basically we ONLY want to install a component if its Enabled AND - * FeatureState are both TRUE - */ return ERROR_SUCCESS; } + static UINT ACTION_InstallValidate(MSIPACKAGE *package) { DWORD progress = 0; + DWORD total = 0; static const WCHAR q1[]={ 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ','R','e','g','i','s','t','r','y',0}; UINT rc; MSIQUERY * view; MSIRECORD * row = 0; + int i; TRACE(" InstallValidate \n"); @@ -3346,7 +3798,11 @@ static UINT ACTION_InstallValidate(MSIPACKAGE *package) MSI_ViewClose(view); msiobj_release(&view->hdr); - ui_progress(package,0,progress+package->loaded_files,0,0); + total = total + progress * REG_PROGRESS_VALUE; + total = total + package->loaded_components * COMPONENT_PROGRESS_VALUE; + for (i=0; i < package->loaded_files; i++) + total += package->files[i].FileSize; + ui_progress(package,0,total,0,0); return ERROR_SUCCESS; } @@ -3406,20 +3862,20 @@ static UINT ACTION_LaunchConditions(MSIPACKAGE *package) return rc; } -static void resolve_keypath( MSIPACKAGE* package, INT - component_index, WCHAR *keypath) +static LPWSTR resolve_keypath( MSIPACKAGE* package, INT + component_index) { MSICOMPONENT* cmp = &package->components[component_index]; if (cmp->KeyPath[0]==0) { - resolve_folder(package,cmp->Directory,keypath,FALSE,FALSE,NULL); - return; + LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL); + return p; } if ((cmp->Attributes & 0x4) || (cmp->Attributes & 0x20)) { FIXME("UNIMPLEMENTED keypath as Registry or ODBC Source\n"); - keypath[0]=0; + return NULL; } else { @@ -3427,8 +3883,12 @@ static void resolve_keypath( MSIPACKAGE* package, INT j = get_loaded_file(package,cmp->KeyPath); if (j>=0) - strcpyW(keypath,package->files[j].TargetPath); + { + LPWSTR p = dupstrW(package->files[j].TargetPath); + return p; + } } + return NULL; } /* @@ -3440,34 +3900,32 @@ static void resolve_keypath( MSIPACKAGE* package, INT */ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) { - WCHAR productcode[0x100]; + LPWSTR productcode; WCHAR squished_pc[0x100]; WCHAR squished_cc[0x100]; - DWORD sz; UINT rc; DWORD i; HKEY hkey=0,hkey2=0,hkey3=0; static const WCHAR szProductCode[]= -{'P','r','o','d','u','c','t','C','o','d','e',0}; + {'P','r','o','d','u','c','t','C','o','d','e',0}; static const WCHAR szInstaller[] = { -'S','o','f','t','w','a','r','e','\\', -'M','i','c','r','o','s','o','f','t','\\', -'W','i','n','d','o','w','s','\\', -'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', -'I','n','s','t','a','l','l','e','r',0 }; + 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'I','n','s','t','a','l','l','e','r',0 }; static const WCHAR szFeatures[] = { -'F','e','a','t','u','r','e','s',0 }; + 'F','e','a','t','u','r','e','s',0 }; static const WCHAR szComponents[] = { -'C','o','m','p','o','n','e','n','t','s',0 }; + 'C','o','m','p','o','n','e','n','t','s',0 }; if (!package) return ERROR_INVALID_HANDLE; /* writes the Component and Features values to the registry */ - sz = 0x100; - rc = MSI_GetPropertyW(package,szProductCode,productcode,&sz); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; + productcode = load_dynamic_property(package,szProductCode,&rc); + if (!productcode) + return rc; squash_guid(productcode,squished_pc); rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller,&hkey); @@ -3519,12 +3977,14 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) rc = RegCreateKeyW(hkey,szComponents,&hkey2); if (rc != ERROR_SUCCESS) goto end; - + + ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0); for (i = 0; i < package->loaded_components; i++) { + ui_progress(package,2,0,0,0); if (package->components[i].ComponentId[0]!=0) { - WCHAR keypath[0x1000]; + WCHAR *keypath = NULL; MSIRECORD * uirow; squash_guid(package->components[i].ComponentId,squished_cc); @@ -3532,22 +3992,27 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) if (rc != ERROR_SUCCESS) continue; - resolve_keypath(package,i,keypath); - - RegSetValueExW(hkey3,squished_pc,0,REG_SZ,(LPVOID)keypath, + keypath = resolve_keypath(package,i); + if (keypath) + { + RegSetValueExW(hkey3,squished_pc,0,REG_SZ,(LPVOID)keypath, (strlenW(keypath)+1)*sizeof(WCHAR)); - RegCloseKey(hkey3); + RegCloseKey(hkey3); - /* UI stuff */ - uirow = MSI_CreateRecord(3); - MSI_RecordSetStringW(uirow,1,productcode); - MSI_RecordSetStringW(uirow,2,package->components[i].ComponentId); - MSI_RecordSetStringW(uirow,3,keypath); - ui_actiondata(package,szProcessComponents,uirow); - msiobj_release( &uirow->hdr ); + /* UI stuff */ + uirow = MSI_CreateRecord(3); + MSI_RecordSetStringW(uirow,1,productcode); + MSI_RecordSetStringW(uirow,2,package->components[i]. + ComponentId); + MSI_RecordSetStringW(uirow,3,keypath); + ui_actiondata(package,szProcessComponents,uirow); + msiobj_release( &uirow->hdr ); + HeapFree(GetProcessHeap(),0,keypath); + } } } end: + HeapFree(GetProcessHeap(), 0, productcode); RegCloseKey(hkey2); RegCloseKey(hkey); return rc; @@ -3608,8 +4073,7 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) continue; } - if (!package->components[index].Enabled || - !package->components[index].FeatureState) + if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL) { TRACE("Skipping typelib reg due to disabled component\n"); msiobj_release(&row->hdr); @@ -3627,15 +4091,16 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) res = LoadTypeLib(package->files[index].TargetPath,&ptLib); if (SUCCEEDED(res)) { - WCHAR help[MAX_PATH]; + LPWSTR help; WCHAR helpid[0x100]; sz = 0x100; MSI_RecordGetStringW(row,6,helpid,&sz); - resolve_folder(package,helpid,help,FALSE,FALSE,NULL); - + help = resolve_folder(package,helpid,FALSE,FALSE,NULL); res = RegisterTypeLib(ptLib,package->files[index].TargetPath,help); + HeapFree(GetProcessHeap(),0,help); + if (!SUCCEEDED(res)) ERR("Failed to register type library %s\n", debugstr_w(package->files[index].TargetPath)); @@ -3672,18 +4137,15 @@ static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app ) MSIQUERY * view; MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = -{'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I' -,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0}; - WCHAR Query[0x1000]; + {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I' + ,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0}; HKEY hkey2,hkey3; LPWSTR buffer=0; if (!package) return ERROR_INVALID_HANDLE; - sprintfW(Query,ExecSeqQuery,clsid); - - rc = MSI_DatabaseOpenViewW(package->db, Query, &view); + rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, clsid); if (rc != ERROR_SUCCESS) return rc; @@ -3713,7 +4175,7 @@ static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app ) LPWSTR deformated=0; UINT size; static const WCHAR szRemoteServerName[] = -{'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0}; + {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0}; buffer = load_dynamic_stringW(row,2); size = deformat_string(package,buffer,&deformated); RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,(LPVOID)deformated, @@ -3725,7 +4187,7 @@ static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app ) if (!MSI_RecordIsNull(row,3)) { static const WCHAR szLocalService[] = -{'L','o','c','a','l','S','e','r','v','i','c','e',0}; + {'L','o','c','a','l','S','e','r','v','i','c','e',0}; UINT size; buffer = load_dynamic_stringW(row,3); size = (strlenW(buffer)+1) * sizeof(WCHAR); @@ -3736,7 +4198,7 @@ static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app ) if (!MSI_RecordIsNull(row,4)) { static const WCHAR szService[] = -{'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0}; + {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0}; UINT size; buffer = load_dynamic_stringW(row,4); size = (strlenW(buffer)+1) * sizeof(WCHAR); @@ -3747,7 +4209,7 @@ static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app ) if (!MSI_RecordIsNull(row,5)) { static const WCHAR szDLL[] = -{'D','l','l','S','u','r','r','o','g','a','t','e',0}; + {'D','l','l','S','u','r','r','o','g','a','t','e',0}; UINT size; buffer = load_dynamic_stringW(row,5); size = (strlenW(buffer)+1) * sizeof(WCHAR); @@ -3758,7 +4220,7 @@ static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app ) if (!MSI_RecordIsNull(row,6)) { static const WCHAR szActivate[] = -{'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0}; + {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0}; static const WCHAR szY[] = {'Y',0}; if (MSI_RecordGetInteger(row,6)) @@ -3769,7 +4231,7 @@ static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app ) { static const WCHAR szRunAs[] = {'R','u','n','A','s',0}; static const WCHAR szUser[] = -{'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0}; + {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0}; if (MSI_RecordGetInteger(row,7)) RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,34); @@ -3855,8 +4317,7 @@ static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) continue; } - if (!package->components[index].Enabled || - !package->components[index].FeatureState) + if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL) { TRACE("Skipping class reg due to disabled component\n"); msiobj_release(&row->hdr); @@ -3984,17 +4445,14 @@ static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent, MSIQUERY * view; MSIRECORD * row = 0; static const WCHAR Query_t[] = -{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g' -,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`' -,'%','s','`',0}; - WCHAR Query[0x1000]; + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g' + ,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`' + ,'%','s','`',0}; if (!package) return ERROR_INVALID_HANDLE; - sprintfW(Query,Query_t,parent); - - rc = MSI_DatabaseOpenViewW(package->db, Query, &view); + rc = ACTION_OpenQuery(package->db, &view, Query_t, parent); if (rc != ERROR_SUCCESS) return rc; @@ -4127,33 +4585,35 @@ static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package) } static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, - LPWSTR FilePath) + LPWSTR *FilePath) { - WCHAR ProductCode[0x100]; - WCHAR SystemFolder[MAX_PATH]; - DWORD sz; + LPWSTR ProductCode; + LPWSTR SystemFolder; + LPWSTR dest; + UINT rc; static const WCHAR szInstaller[] = -{'I','n','s','t','a','l','l','e','r','\\',0}; + {'I','n','s','t','a','l','l','e','r','\\',0}; static const WCHAR szProductCode[] = -{'P','r','o','d','u','c','t','C','o','d','e',0}; + {'P','r','o','d','u','c','t','C','o','d','e',0}; static const WCHAR szFolder[] = -{'W','i','n','d','o','w','s','F','o','l','d','e','r',0}; + {'W','i','n','d','o','w','s','F','o','l','d','e','r',0}; - sz = 0x100; - MSI_GetPropertyW(package,szProductCode,ProductCode,&sz); - if (strlenW(ProductCode)==0) - return ERROR_FUNCTION_FAILED; + ProductCode = load_dynamic_property(package,szProductCode,&rc); + if (!ProductCode) + return rc; - sz = MAX_PATH; - MSI_GetPropertyW(package,szFolder,SystemFolder,&sz); - strcatW(SystemFolder,szInstaller); - strcatW(SystemFolder,ProductCode); - create_full_pathW(SystemFolder); + SystemFolder = load_dynamic_property(package,szFolder,NULL); - strcpyW(FilePath,SystemFolder); - strcatW(FilePath,cszbs); - strcatW(FilePath,icon_name); + dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode); + + create_full_pathW(dest); + + *FilePath = build_directory_name(2, dest, icon_name); + + HeapFree(GetProcessHeap(),0,SystemFolder); + HeapFree(GetProcessHeap(),0,ProductCode); + HeapFree(GetProcessHeap(),0,dest); return ERROR_SUCCESS; } @@ -4193,7 +4653,7 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) while (1) { - WCHAR target_file[MAX_PATH]; + LPWSTR target_file, target_folder; WCHAR buffer[0x100]; DWORD sz; DWORD index; @@ -4217,8 +4677,7 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) continue; } - if (!package->components[index].Enabled || - !package->components[index].FeatureState) + if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL) { TRACE("Skipping shortcut creation due to disabled component\n"); msiobj_release(&row->hdr); @@ -4247,14 +4706,18 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) sz = 0x100; MSI_RecordGetStringW(row,2,buffer,&sz); - resolve_folder(package, buffer,target_file,FALSE,FALSE,NULL); + target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL); + + /* may be needed because of a bug somehwere else */ + create_full_pathW(target_folder); sz = 0x100; MSI_RecordGetStringW(row,3,buffer,&sz); reduce_to_longfilename(buffer); - strcatW(target_file,buffer); - if (!strchrW(target_file,'.')) - strcatW(target_file,szlnk); + if (!strchrW(buffer,'.') || strcmpiW(strchrW(buffer,'.'),szlnk)) + strcatW(buffer,szlnk); + target_file = build_directory_name(2, target_folder, buffer); + HeapFree(GetProcessHeap(),0,target_folder); sz = 0x100; MSI_RecordGetStringW(row,5,buffer,&sz); @@ -4297,16 +4760,17 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) if (!MSI_RecordIsNull(row,9)) { - WCHAR Path[MAX_PATH]; + WCHAR *Path = NULL; INT index; sz = 0x100; MSI_RecordGetStringW(row,9,buffer,&sz); - build_icon_path(package,buffer,Path); + build_icon_path(package,buffer,&Path); index = MSI_RecordGetInteger(row,10); IShellLinkW_SetIconLocation(sl,Path,index); + HeapFree(GetProcessHeap(),0,Path); } if (!MSI_RecordIsNull(row,11)) @@ -4314,17 +4778,19 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) if (!MSI_RecordIsNull(row,12)) { - WCHAR Path[MAX_PATH]; - + LPWSTR Path; sz = 0x100; MSI_RecordGetStringW(row,12,buffer,&sz); - resolve_folder(package, buffer, Path, FALSE, FALSE, NULL); + Path = resolve_folder(package, buffer, FALSE, FALSE, NULL); IShellLinkW_SetWorkingDirectory(sl,Path); + HeapFree(GetProcessHeap(), 0, Path); } TRACE("Writing shortcut to %s\n",debugstr_w(target_file)); IPersistFile_Save(pf,target_file,FALSE); - + + HeapFree(GetProcessHeap(),0,target_file); + IPersistFile_Release( pf ); IShellLinkW_Release( sl ); @@ -4374,8 +4840,8 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) while (1) { HANDLE the_file; - WCHAR FilePath[MAX_PATH]; - WCHAR FileName[MAX_PATH]; + WCHAR *FilePath=NULL; + WCHAR *FileName=NULL; CHAR buffer[1024]; rc = MSI_ViewFetch(view,&row); @@ -4385,16 +4851,17 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) break; } - sz = MAX_PATH; - MSI_RecordGetStringW(row,1,FileName,&sz); - if (sz == 0) + FileName = load_dynamic_stringW(row,1); + if (!FileName) { ERR("Unable to get FileName\n"); msiobj_release(&row->hdr); continue; } - build_icon_path(package,FileName,FilePath); + build_icon_path(package,FileName,&FilePath); + + HeapFree(GetProcessHeap(),0,FileName); TRACE("Creating icon file at %s\n",debugstr_w(FilePath)); @@ -4405,6 +4872,7 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) { ERR("Unable to create file %s\n",debugstr_w(FilePath)); msiobj_release(&row->hdr); + HeapFree(GetProcessHeap(),0,FilePath); continue; } @@ -4423,6 +4891,8 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) WriteFile(the_file,buffer,sz,&write,NULL); } while (sz == 1024); + HeapFree(GetProcessHeap(),0,FilePath); + CloseHandle(the_file); msiobj_release(&row->hdr); } @@ -4507,29 +4977,31 @@ UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder, UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR szPathBuf, DWORD* pcchPathBuf) { - WCHAR path[MAX_PATH]; - UINT rc; + LPWSTR path; + UINT rc = ERROR_FUNCTION_FAILED; MSIPACKAGE *package; TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf); package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if( !package ) + if (!package) return ERROR_INVALID_HANDLE; - rc = resolve_folder(package, szFolder, path, FALSE, FALSE, NULL); + path = resolve_folder(package, szFolder, FALSE, FALSE, NULL); msiobj_release( &package->hdr ); - if (rc == ERROR_SUCCESS && strlenW(path) > *pcchPathBuf) + if (path && (strlenW(path) > *pcchPathBuf)) { *pcchPathBuf = strlenW(path)+1; - return ERROR_MORE_DATA; + rc = ERROR_MORE_DATA; } - else if (rc == ERROR_SUCCESS) + else if (path) { *pcchPathBuf = strlenW(path)+1; strcpyW(szPathBuf,path); TRACE("Returning Path %s\n",debugstr_w(path)); + rc = ERROR_SUCCESS; } + HeapFree(GetProcessHeap(),0,path); return rc; } @@ -4569,8 +5041,8 @@ UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder, UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR szPathBuf, DWORD* pcchPathBuf) { - WCHAR path[MAX_PATH]; - UINT rc; + LPWSTR path; + UINT rc = ERROR_FUNCTION_FAILED; MSIPACKAGE *package; TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf); @@ -4578,20 +5050,22 @@ UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); if( !package ) return ERROR_INVALID_HANDLE; - rc = resolve_folder(package, szFolder, path, TRUE, FALSE, NULL); + path = resolve_folder(package, szFolder, TRUE, FALSE, NULL); msiobj_release( &package->hdr ); - if (rc == ERROR_SUCCESS && strlenW(path) > *pcchPathBuf) + if (path && strlenW(path) > *pcchPathBuf) { *pcchPathBuf = strlenW(path)+1; - return ERROR_MORE_DATA; + rc = ERROR_MORE_DATA; } - else if (rc == ERROR_SUCCESS) + else if (path) { *pcchPathBuf = strlenW(path)+1; strcpyW(szPathBuf,path); TRACE("Returning Path %s\n",debugstr_w(path)); + rc = ERROR_SUCCESS; } + HeapFree(GetProcessHeap(),0,path); return rc; } @@ -4632,7 +5106,9 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, LPCWSTR szFolderPath) { DWORD i; - WCHAR path[MAX_PATH]; + LPWSTR path = NULL; + LPWSTR path2 = NULL; + INT len; MSIFOLDER *folder; TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath)); @@ -4646,19 +5122,54 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES) return ERROR_FUNCTION_FAILED; - resolve_folder(package,szFolder,path,FALSE,FALSE,&folder); + path = resolve_folder(package,szFolder,FALSE,FALSE,&folder); - if (!folder) + if (!path) return ERROR_INVALID_PARAMETER; - strcpyW(folder->Property,szFolderPath); + if (folder->Property) + HeapFree(GetProcessHeap(),0,folder->Property); - for (i = 0; i < package->loaded_folders; i++) - package->folders[i].ResolvedTarget[0]=0; + len = strlenW(szFolderPath); - for (i = 0; i < package->loaded_folders; i++) - resolve_folder(package, package->folders[i].Directory, path, FALSE, + if (szFolderPath[len-1]!='\\') + { + len +=2; + folder->Property = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); + strcpyW(folder->Property,szFolderPath); + strcatW(folder->Property,cszbs); + } + else + folder->Property = dupstrW(szFolderPath); + + if (strcmpiW(path, szFolderPath) == 0) + { + /* + * Resolved Target has not really changed, so just + * set this folder and do not recalculate everything. + */ + HeapFree(GetProcessHeap(),0,folder->ResolvedTarget); + folder->ResolvedTarget = NULL; + path2 = resolve_folder(package,szFolder,FALSE,TRUE,NULL); + HeapFree(GetProcessHeap(),0,path2); + } + else + { + for (i = 0; i < package->loaded_folders; i++) + { + if (package->folders[i].ResolvedTarget) + HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget); + package->folders[i].ResolvedTarget=NULL; + } + + for (i = 0; i < package->loaded_folders; i++) + { + path2=resolve_folder(package, package->folders[i].Directory, FALSE, TRUE, NULL); + HeapFree(GetProcessHeap(),0,path2); + } + } + HeapFree(GetProcessHeap(),0,path); return ERROR_SUCCESS; } @@ -4677,10 +5188,44 @@ UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, return ret; } -BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, DWORD iRunMode) +/*********************************************************************** + * MsiGetMode (MSI.@) + * + * Returns an internal installer state (if it is running in a mode iRunMode) + * + * PARAMS + * hInstall [I] Handle to the installation + * hRunMode [I] Checking run mode + * MSIRUNMODE_ADMIN Administrative mode + * MSIRUNMODE_ADVERTISE Advertisement mode + * MSIRUNMODE_MAINTENANCE Maintenance mode + * MSIRUNMODE_ROLLBACKENABLED Rollback is enabled + * MSIRUNMODE_LOGENABLED Log file is writing + * MSIRUNMODE_OPERATIONS Operations in progress?? + * MSIRUNMODE_REBOOTATEND We need to reboot after installation completed + * MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation + * MSIRUNMODE_CABINET Files from cabinet are installed + * MSIRUNMODE_SOURCESHORTNAMES Long names in source files is supressed + * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is supressed + * MSIRUNMODE_RESERVED11 Reserved + * MSIRUNMODE_WINDOWS9X Running under Windows95/98 + * MSIRUNMODE_ZAWENABLED Demand installation is supported + * MSIRUNMODE_RESERVED14 Reserved + * MSIRUNMODE_RESERVED15 Reserved + * MSIRUNMODE_SCHEDULED called from install script + * MSIRUNMODE_ROLLBACK called from rollback script + * MSIRUNMODE_COMMIT called from commit script + * + * RETURNS + * In the state: TRUE + * Not in the state: FALSE + * + */ + +BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode) { - FIXME("STUB (%li)\n",iRunMode); - return FALSE; + FIXME("STUB (iRunMode=%i)\n",iRunMode); + return TRUE; } /* @@ -4721,7 +5266,7 @@ UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature, if (index < 0) return ERROR_UNKNOWN_FEATURE; - package->features[index].State = iState; + package->features[index].ActionRequest= iState; return ERROR_SUCCESS; } @@ -4751,15 +5296,12 @@ UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature, return ERROR_UNKNOWN_FEATURE; if (piInstalled) - *piInstalled = package->features[index].State; + *piInstalled = package->features[index].Installed; if (piAction) - { - if (package->features[index].Enabled) - *piAction = INSTALLSTATE_LOCAL; - else - *piAction = INSTALLSTATE_UNKNOWN; - } + *piAction = package->features[index].Action; + + TRACE("returning %i %i\n",*piInstalled,*piAction); return ERROR_SUCCESS; } @@ -4809,16 +5351,10 @@ piAction); return ERROR_UNKNOWN_COMPONENT; if (piInstalled) - *piInstalled = package->components[index].State; + *piInstalled = package->components[index].Installed; if (piAction) - { - if (package->components[index].Enabled && - package->components[index].FeatureState) - *piAction = INSTALLSTATE_LOCAL; - else - *piAction = INSTALLSTATE_UNKNOWN; - } + *piInstalled = package->components[index].Action; return ERROR_SUCCESS; } diff --git a/reactos/lib/msi/handle.c b/reactos/lib/msi/handle.c index ade5e1bf2ba..bd33099c1f0 100644 --- a/reactos/lib/msi/handle.c +++ b/reactos/lib/msi/handle.c @@ -41,7 +41,23 @@ static CRITICAL_SECTION_DEBUG MSI_handle_cs_debug = }; static CRITICAL_SECTION MSI_handle_cs = { &MSI_handle_cs_debug, -1, 0, 0, 0, 0 }; -MSIOBJECTHDR *msihandletable[MSIMAXHANDLES]; +static CRITICAL_SECTION MSI_object_cs; +static CRITICAL_SECTION_DEBUG MSI_object_cs_debug = +{ + 0, 0, &MSI_object_cs, + { &MSI_object_cs_debug.ProcessLocksList, + &MSI_object_cs_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": MSI_object_cs") } +}; +static CRITICAL_SECTION MSI_object_cs = { &MSI_object_cs_debug, -1, 0, 0, 0, 0 }; + +typedef struct msi_handle_info_t +{ + MSIOBJECTHDR *obj; + DWORD dwThreadId; +} msi_handle_info; + +static msi_handle_info msihandletable[MSIMAXHANDLES]; MSIHANDLE alloc_msihandle( MSIOBJECTHDR *obj ) { @@ -52,13 +68,14 @@ MSIHANDLE alloc_msihandle( MSIOBJECTHDR *obj ) /* find a slot */ for(i=0; i=MSIMAXHANDLES) || msihandletable[i] ) + if( (i>=MSIMAXHANDLES) || msihandletable[i].obj ) goto out; msiobj_addref( obj ); - msihandletable[i] = obj; + msihandletable[i].obj = obj; + msihandletable[i].dwThreadId = GetCurrentThreadId(); ret = (MSIHANDLE) (i+1); out: TRACE("%p -> %ld\n", obj, ret ); @@ -77,13 +94,13 @@ void *msihandle2msiinfo(MSIHANDLE handle, UINT type) goto out; if( handle>=MSIMAXHANDLES ) goto out; - if( !msihandletable[handle] ) + if( !msihandletable[handle].obj ) goto out; - if( msihandletable[handle]->magic != MSIHANDLE_MAGIC ) + if( msihandletable[handle].obj->magic != MSIHANDLE_MAGIC ) goto out; - if( type && (msihandletable[handle]->type != type) ) + if( type && (msihandletable[handle].obj->type != type) ) goto out; - ret = msihandletable[handle]; + ret = msihandletable[handle].obj; msiobj_addref( ret ); out: @@ -101,7 +118,7 @@ MSIHANDLE msiobj_findhandle( MSIOBJECTHDR *hdr ) EnterCriticalSection( &MSI_handle_cs ); for(i=0; (irefcount++; } +void msiobj_lock( MSIOBJECTHDR *info ) +{ + EnterCriticalSection( &MSI_object_cs ); +} + +void msiobj_unlock( MSIOBJECTHDR *info ) +{ + LeaveCriticalSection( &MSI_object_cs ); +} + int msiobj_release( MSIOBJECTHDR *info ) { int ret; @@ -170,6 +197,9 @@ int msiobj_release( MSIOBJECTHDR *info ) return ret; } +/*********************************************************** + * MsiCloseHandle [MSI.@] + */ UINT WINAPI MsiCloseHandle(MSIHANDLE handle) { MSIOBJECTHDR *info; @@ -190,7 +220,7 @@ UINT WINAPI MsiCloseHandle(MSIHANDLE handle) } msiobj_release( info ); - msihandletable[handle-1] = NULL; + msihandletable[handle-1].obj = NULL; ret = ERROR_SUCCESS; TRACE("handle %lx Destroyed\n", handle); @@ -202,14 +232,28 @@ out: return ret; } +/*********************************************************** + * MsiCloseAllHandles [MSI.@] + * + * Closes all handles owned by the current thread + * + * RETURNS: + * The number of handles closed + */ UINT WINAPI MsiCloseAllHandles(void) { - UINT i; + UINT i, n=0; TRACE("\n"); for(i=0; iref); + return InterlockedIncrement(&This->ref); } static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface) { IClassFactoryImpl *This = (IClassFactoryImpl *)iface; /* static class, won't be freed */ - return --(This->ref); + return InterlockedDecrement(&This->ref); } static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj) { @@ -1592,10 +1606,34 @@ BOOL WINAPI MSI_DllCanUnloadNow(void) return S_FALSE; } -UINT WINAPI MsiEnumRelatedProductsA (LPCSTR lpUpgradeCode, DWORD dwReserved, - DWORD iProductIndex, LPSTR lpProductBuf) +UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved, + DWORD iProductIndex, LPWSTR lpProductBuf) { - FIXME("STUB: (%s, %li %li %s)\n",lpUpgradeCode, dwReserved, iProductIndex, - lpProductBuf); + FIXME("%s %lu %lu %p\n", debugstr_w(szUpgradeCode), dwReserved, + iProductIndex, lpProductBuf); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved, + DWORD iProductIndex, LPSTR lpProductBuf) +{ + FIXME("%s %lu %lu %p\n", debugstr_a(szUpgradeCode), dwReserved, + iProductIndex, lpProductBuf); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiGetFeatureUsageW(LPCWSTR szProduct, LPCWSTR szFeature, + DWORD* pdwUseCount, WORD* pwDateUsed) +{ + FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature), + pdwUseCount, pwDateUsed); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiGetFeatureUsageA(LPCSTR szProduct, LPCSTR szFeature, + DWORD* pdwUseCount, WORD* pwDateUsed) +{ + FIXME("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature), + pdwUseCount, pwDateUsed); return ERROR_CALL_NOT_IMPLEMENTED; } diff --git a/reactos/lib/msi/msi.spec b/reactos/lib/msi/msi.spec index e8a98a30582..7b6029ae8f1 100644 --- a/reactos/lib/msi/msi.spec +++ b/reactos/lib/msi/msi.spec @@ -56,8 +56,8 @@ 56 stub MsiGetFeatureInfoW 57 stdcall MsiGetFeatureStateA(long str ptr ptr) 58 stdcall MsiGetFeatureStateW(long wstr ptr ptr) -59 stub MsiGetFeatureUsageA -60 stub MsiGetFeatureUsageW +59 stdcall MsiGetFeatureUsageA(str str ptr ptr) +60 stdcall MsiGetFeatureUsageW(wstr wstr ptr ptr) 61 stub MsiGetFeatureValidStatesA 62 stub MsiGetFeatureValidStatesW 63 stub MsiGetLanguage @@ -134,7 +134,7 @@ 134 stub MsiSetComponentStateA 135 stub MsiSetComponentStateW 136 stdcall MsiSetExternalUIA(ptr long ptr) -137 stub MsiSetExternalUIW +137 stdcall MsiSetExternalUIW(ptr long ptr) 138 stdcall MsiSetFeatureStateA(long str long) 139 stdcall MsiSetFeatureStateW(long wstr long) 140 stub MsiSetInstallLevel @@ -201,8 +201,8 @@ 201 stub MsiDecomposeDescriptorW 202 stub MsiProvideQualifiedComponentExA 203 stub MsiProvideQualifiedComponentExW -204 stdcall MsiEnumRelatedProductsA(str long long str) -205 stub MsiEnumRelatedProductsW +204 stdcall MsiEnumRelatedProductsA(str long long ptr) +205 stdcall MsiEnumRelatedProductsW(wstr long long ptr) 206 stub MsiSetFeatureAttributesA 207 stub MsiSetFeatureAttributesW 208 stub MsiSourceListClearAllA diff --git a/reactos/lib/msi/msipriv.h b/reactos/lib/msi/msipriv.h index ba36dcb2eda..306feca76f8 100644 --- a/reactos/lib/msi/msipriv.h +++ b/reactos/lib/msi/msipriv.h @@ -194,6 +194,8 @@ typedef struct tagMSIPACKAGE UINT loaded_components; struct tagMSIFILE *files; UINT loaded_files; + LPWSTR ActionFormat; + LPWSTR LastAction; } MSIPACKAGE; #define MSIHANDLETYPE_ANY 0 @@ -228,6 +230,8 @@ extern MSIHANDLE alloc_msihandle( MSIOBJECTHDR * ); extern void *alloc_msiobject(UINT type, UINT size, msihandledestructor destroy ); extern void msiobj_addref(MSIOBJECTHDR *); extern int msiobj_release(MSIOBJECTHDR *); +extern void msiobj_lock(MSIOBJECTHDR *); +extern void msiobj_unlock(MSIOBJECTHDR *); extern MSIHANDLE msiobj_findhandle( MSIOBJECTHDR *hdr ); /* add this table to the list of cached tables in the database */ @@ -269,6 +273,7 @@ extern UINT read_raw_stream_data( MSIDATABASE*, LPCWSTR stname, USHORT **pdata, UINT *psz ); extern UINT ACTION_DoTopLevelINSTALL( MSIPACKAGE *, LPCWSTR, LPCWSTR ); extern void ACTION_remove_tracked_tempfiles( MSIPACKAGE* ); +extern void ACTION_free_package_structures( MSIPACKAGE* ); /* record internals */ extern UINT MSI_RecordSetIStream( MSIRECORD *, unsigned int, IStream *); diff --git a/reactos/lib/msi/package.c b/reactos/lib/msi/package.c index cad20ed665b..639af427eaa 100644 --- a/reactos/lib/msi/package.c +++ b/reactos/lib/msi/package.c @@ -27,6 +27,7 @@ #include "winreg.h" #include "winnls.h" #include "shlwapi.h" +#include "wingdi.h" #include "wine/debug.h" #include "msi.h" #include "msiquery.h" @@ -53,18 +54,8 @@ void MSI_FreePackage( MSIOBJECTHDR *arg) MSIPACKAGE *package= (MSIPACKAGE*) arg; ACTION_remove_tracked_tempfiles(package); + ACTION_free_package_structures(package); - if (package->features && package->loaded_features > 0) - HeapFree(GetProcessHeap(),0,package->features); - - if (package->folders && package->loaded_folders > 0) - HeapFree(GetProcessHeap(),0,package->folders); - - if (package->components && package->loaded_components > 0) - HeapFree(GetProcessHeap(),0,package->components); - - if (package->files && package->loaded_files > 0) - HeapFree(GetProcessHeap(),0,package->files); msiobj_release( &package->db->hdr ); } @@ -169,9 +160,11 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/prope static VOID set_installer_properties(MSIPACKAGE *package) { WCHAR pth[MAX_PATH]; + WCHAR *ptr; OSVERSIONINFOA OSVersion; DWORD verval; - WCHAR verstr[10], msiver[10]; + WCHAR verstr[10], bufstr[20]; + HDC dc; static const WCHAR cszbs[]={'\\',0}; static const WCHAR CFF[] = @@ -202,6 +195,8 @@ static VOID set_installer_properties(MSIPACKAGE *package) {'A','p','p','D','a','t','a','F','o','l','d','e','r',0}; static const WCHAR SF[] = {'S','y','s','t','e','m','F','o','l','d','e','r',0}; + static const WCHAR SF16[] = +{'S','y','s','t','e','m','1','6','F','o','l','d','e','r',0}; static const WCHAR LADF[] = {'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0}; static const WCHAR MPF[] = @@ -210,6 +205,8 @@ static VOID set_installer_properties(MSIPACKAGE *package) {'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0}; static const WCHAR WF[] = {'W','i','n','d','o','w','s','F','o','l','d','e','r',0}; + static const WCHAR WV[] = +{'W','i','n','d','o','w','s','V','o','l','u','m','e',0}; static const WCHAR TF[]= {'T','e','m','p','F','o','l','d','e','r',0}; static const WCHAR szAdminUser[] = @@ -229,12 +226,15 @@ static VOID set_installer_properties(MSIPACKAGE *package) static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 }; static const WCHAR szFormat2[] = {'%','l','i','.','%','l','i',0}; +/* Screen properties */ + static const WCHAR szScreenX[] = {'S','c','r','e','e','n','X',0}; + static const WCHAR szScreenY[] = {'S','c','r','e','e','n','Y',0}; + static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0}; + static const WCHAR szScreenFormat[] = {'%','d',0}; /* * Other things I notice set * -ScreenY -ScreenX SystemLanguageID ComputerName UserLanguageID @@ -251,7 +251,6 @@ CaptionHeight BorderTop BorderSide TextHeight -ColorBits RedirectedDllSupport Time Date @@ -313,6 +312,7 @@ Privileged SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth); strcatW(pth,cszbs); MSI_SetPropertyW(package, SF, pth); + MSI_SetPropertyW(package, SF16, pth); SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth); strcatW(pth,cszbs); @@ -330,6 +330,12 @@ Privileged strcatW(pth,cszbs); MSI_SetPropertyW(package, WF, pth); + SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth); + ptr = strchrW(pth,'\\'); + if (ptr) + *(ptr+1) = 0; + MSI_SetPropertyW(package, WV, pth); + GetTempPathW(MAX_PATH,pth); MSI_SetPropertyW(package, TF, pth); @@ -357,8 +363,18 @@ Privileged /* just fudge this */ MSI_SetPropertyW(package,szSPL,szSix); - sprintfW( msiver, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION); - MSI_SetPropertyW( package, szVersionMsi, msiver ); + sprintfW( bufstr, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION); + MSI_SetPropertyW( package, szVersionMsi, bufstr ); + + /* Screen properties. */ + dc = GetDC(0); + sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, HORZRES ) ); + MSI_SetPropertyW( package, szScreenX, bufstr ); + sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, VERTRES )); + MSI_SetPropertyW( package, szScreenY, bufstr ); + sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, BITSPIXEL )); + MSI_SetPropertyW( package, szColorBits, bufstr ); + ReleaseDC(0, dc); } UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) @@ -406,6 +422,8 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) package->loaded_folders = 0; package->loaded_components= 0; package->loaded_files = 0; + package->ActionFormat = NULL; + package->LastAction = NULL; /* OK, here is where we do a slew of things to the database to * prep for all that is to come as a package */ @@ -747,6 +765,10 @@ UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName, UINT rc; rc = MSI_GetPropertyRow(package, szName, &row); + + if (*pchValueBuf > 0) + szValueBuf[0] = 0; + if (rc == ERROR_SUCCESS) { rc = MSI_RecordGetStringW(row,1,szValueBuf,pchValueBuf); @@ -756,6 +778,9 @@ UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName, if (rc == ERROR_SUCCESS) TRACE("returning %s for property %s\n", debugstr_w(szValueBuf), debugstr_w(szName)); + else if (rc == ERROR_MORE_DATA) + TRACE("need %li sized buffer for %s\n", *pchValueBuf, + debugstr_w(szName)); else { *pchValueBuf = 0; @@ -772,6 +797,9 @@ UINT MSI_GetPropertyA(MSIPACKAGE *package, LPCSTR szName, UINT rc, len; LPWSTR szwName; + if (*pchValueBuf > 0) + szValueBuf[0] = 0; + len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 ); szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); if (!szwName) @@ -788,6 +816,9 @@ UINT MSI_GetPropertyA(MSIPACKAGE *package, LPCSTR szName, if (rc == ERROR_SUCCESS) TRACE("returning %s for property %s\n", debugstr_a(szValueBuf), debugstr_a(szName)); + else if (rc == ERROR_MORE_DATA) + TRACE("need %ld sized buffer for %s\n", *pchValueBuf, + debugstr_a(szName)); else { *pchValueBuf = 0; diff --git a/reactos/lib/msi/query.h b/reactos/lib/msi/query.h index fc8ce425e56..dfe5816936d 100644 --- a/reactos/lib/msi/query.h +++ b/reactos/lib/msi/query.h @@ -52,6 +52,7 @@ #define EXPR_STRCMP 7 #define EXPR_UTF8 8 #define EXPR_WILDCARD 9 +#define EXPR_COL_NUMBER_STRING 10 struct sql_str { LPCWSTR data; diff --git a/reactos/lib/msi/record.c b/reactos/lib/msi/record.c index 3def0974a2b..30cde0f80ef 100644 --- a/reactos/lib/msi/record.c +++ b/reactos/lib/msi/record.c @@ -32,6 +32,7 @@ #include "msipriv.h" #include "objidl.h" #include "winnls.h" +#include "ole2.h" #include "query.h" @@ -77,10 +78,13 @@ MSIRECORD *MSI_CreateRecord( unsigned int cParams ) TRACE("%d\n", cParams); + if( cParams>65535 ) + return NULL; + len = sizeof (MSIRECORD) + sizeof (MSIFIELD)*cParams; rec = alloc_msiobject( MSIHANDLETYPE_RECORD, len, MSI_CloseRecord ); if( rec ) - rec->count = cParams; + rec->count = cParams; return rec; } @@ -111,12 +115,11 @@ unsigned int WINAPI MsiRecordGetFieldCount( MSIHANDLE handle ) rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); if( !rec ) - { - ERR("Record not found!\n"); - return 0; - } + return -1; + msiobj_lock( &rec->hdr ); ret = MSI_RecordGetFieldCount( rec ); + msiobj_unlock( &rec->hdr ); msiobj_release( &rec->hdr ); return ret; @@ -180,7 +183,9 @@ int WINAPI MsiRecordGetInteger( MSIHANDLE handle, unsigned int iField) if( !rec ) return MSI_NULL_INTEGER; + msiobj_lock( &rec->hdr ); ret = MSI_RecordGetInteger( rec, iField ); + msiobj_unlock( &rec->hdr ); msiobj_release( &rec->hdr ); return ret; @@ -197,12 +202,14 @@ UINT WINAPI MsiRecordClearData( MSIHANDLE handle ) if( !rec ) return ERROR_INVALID_HANDLE; + msiobj_lock( &rec->hdr ); for( i=0; i<=rec->count; i++) { MSI_FreeField( &rec->fields[i] ); rec->fields[i].type = MSIFIELD_NULL; rec->fields[i].u.iVal = 0; } + msiobj_unlock( &rec->hdr ); return ERROR_SUCCESS; } @@ -211,12 +218,12 @@ UINT MSI_RecordSetInteger( MSIRECORD *rec, unsigned int iField, int iVal ) { TRACE("%p %u %d\n", rec, iField, iVal); - if( iField <= rec->count ) - { - MSI_FreeField( &rec->fields[iField] ); - rec->fields[iField].type = MSIFIELD_INT; - rec->fields[iField].u.iVal = iVal; - } + if( iField > rec->count ) + return ERROR_INVALID_PARAMETER; + + MSI_FreeField( &rec->fields[iField] ); + rec->fields[iField].type = MSIFIELD_INT; + rec->fields[iField].u.iVal = iVal; return ERROR_SUCCESS; } @@ -232,7 +239,9 @@ UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, unsigned int iField, int iVal if( !rec ) return ERROR_INVALID_HANDLE; + msiobj_lock( &rec->hdr ); ret = MSI_RecordSetInteger( rec, iField, iVal ); + msiobj_unlock( &rec->hdr ); msiobj_release( &rec->hdr ); return ret; } @@ -258,8 +267,10 @@ BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, unsigned int iField ) rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); if( !rec ) - return ERROR_INVALID_HANDLE; + return 0; + msiobj_lock( &rec->hdr ); ret = MSI_RecordIsNull( rec, iField ); + msiobj_unlock( &rec->hdr ); msiobj_release( &rec->hdr ); return ret; @@ -289,9 +300,12 @@ UINT MSI_RecordGetStringA(MSIRECORD *rec, unsigned int iField, NULL, 0 , NULL, NULL); WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1, szValue, *pcchValue, NULL, NULL); + if( *pcchValue && len>*pcchValue ) + szValue[*pcchValue-1] = 0; + if( len ) + len--; break; case MSIFIELD_NULL: - len = 1; if( *pcchValue > 0 ) szValue[0] = 0; break; @@ -318,7 +332,9 @@ UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, unsigned int iField, rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); if( !rec ) return ERROR_INVALID_HANDLE; + msiobj_lock( &rec->hdr ); ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue); + msiobj_unlock( &rec->hdr ); msiobj_release( &rec->hdr ); return ret; } @@ -385,17 +401,49 @@ UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, unsigned int iField, if( !rec ) return ERROR_INVALID_HANDLE; + msiobj_lock( &rec->hdr ); ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue ); + msiobj_unlock( &rec->hdr ); msiobj_release( &rec->hdr ); return ret; } -UINT WINAPI MsiRecordDataSize(MSIHANDLE hRecord, unsigned int iField) +UINT MSI_RecordDataSize(MSIRECORD *rec, unsigned int iField) { - FIXME("%ld %d\n", hRecord, iField); + TRACE("%p %d\n", rec, iField); + + if( iField > rec->count ) + return 0; + + switch( rec->fields[iField].type ) + { + case MSIFIELD_INT: + return sizeof (INT); + case MSIFIELD_WSTR: + return lstrlenW( rec->fields[iField].u.szwVal ); + case MSIFIELD_NULL: + break; + } return 0; } +UINT WINAPI MsiRecordDataSize(MSIHANDLE handle, unsigned int iField) +{ + MSIRECORD *rec; + UINT ret; + + TRACE("%ld %d\n", handle, iField); + + rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); + if( !rec ) + return 0; + msiobj_lock( &rec->hdr ); + ret = MSI_RecordDataSize( rec, iField); + msiobj_unlock( &rec->hdr ); + msiobj_release( &rec->hdr ); + return ret; +} + UINT MSI_RecordSetStringA( MSIRECORD *rec, unsigned int iField, LPCSTR szValue ) { LPWSTR str; @@ -426,7 +474,9 @@ UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, unsigned int iField, LPCSTR s rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); if( !rec ) return ERROR_INVALID_HANDLE; + msiobj_lock( &rec->hdr ); ret = MSI_RecordSetStringA( rec, iField, szValue ); + msiobj_unlock( &rec->hdr ); msiobj_release( &rec->hdr ); return ret; } @@ -463,7 +513,9 @@ UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, unsigned int iField, LPCWSTR if( !rec ) return ERROR_INVALID_HANDLE; + msiobj_lock( &rec->hdr ); ret = MSI_RecordSetStringW( rec, iField, szValue ); + msiobj_unlock( &rec->hdr ); msiobj_release( &rec->hdr ); return ret; } @@ -480,16 +532,133 @@ UINT WINAPI MsiFormatRecordW(MSIHANDLE hInstall, MSIHANDLE hRecord, LPWSTR szRes return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, unsigned int iField, LPCSTR szFilename) +/* read the data in a file into an IStream */ +UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm) { - FIXME("%ld %d %s\n", hRecord, iField, debugstr_a(szFilename)); - return ERROR_CALL_NOT_IMPLEMENTED; + DWORD sz, szHighWord = 0, read; + HANDLE handle; + HGLOBAL hGlob = 0; + HRESULT hr; + ULARGE_INTEGER ulSize; + + TRACE("reading %s\n", debugstr_w(szFile)); + + /* read the file into memory */ + handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if( handle == INVALID_HANDLE_VALUE ) + return GetLastError(); + sz = GetFileSize(handle, &szHighWord); + if( sz != INVALID_FILE_SIZE && szHighWord == 0 ) + { + hGlob = GlobalAlloc(GMEM_FIXED, sz); + if( hGlob ) + { + BOOL r = ReadFile(handle, hGlob, sz, &read, NULL); + if( !r ) + { + GlobalFree(hGlob); + hGlob = 0; + } + } + } + CloseHandle(handle); + if( !hGlob ) + return ERROR_FUNCTION_FAILED; + + /* make a stream out of it, and set the correct file size */ + hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm); + if( FAILED( hr ) ) + { + GlobalFree(hGlob); + return ERROR_FUNCTION_FAILED; + } + + /* set the correct size - CreateStreamOnHGlobal screws it up */ + ulSize.QuadPart = sz; + IStream_SetSize(*pstm, ulSize); + + TRACE("read %s, %ld bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm); + + return ERROR_SUCCESS; } -UINT WINAPI MsiRecordSetStreamW(MSIHANDLE hRecord, unsigned int iField, LPCWSTR szFilename) +UINT MSI_RecordSetStreamW(MSIRECORD *rec, unsigned int iField, LPCWSTR szFilename) { - FIXME("%ld %d %s\n", hRecord, iField, debugstr_w(szFilename)); - return ERROR_CALL_NOT_IMPLEMENTED; + IStream *stm = NULL; + HRESULT r; + + if( (iField == 0) || (iField > rec->count) ) + return ERROR_INVALID_PARAMETER; + + /* no filename means we should seek back to the start of the stream */ + if( !szFilename ) + { + LARGE_INTEGER ofs; + ULARGE_INTEGER cur; + + if( rec->fields[iField].type != MSIFIELD_STREAM ) + return ERROR_INVALID_FIELD; + + stm = rec->fields[iField].u.stream; + if( !stm ) + return ERROR_INVALID_FIELD; + + ofs.QuadPart = 0; + r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur ); + if( FAILED( r ) ) + return ERROR_FUNCTION_FAILED; + } + else + { + /* read the file into a stream and save the stream in the record */ + r = RECORD_StreamFromFile(szFilename, &stm); + if( r != ERROR_SUCCESS ) + return r; + + /* if all's good, store it in the record */ + MSI_FreeField( &rec->fields[iField] ); + rec->fields[iField].type = MSIFIELD_STREAM; + rec->fields[iField].u.stream = stm; + } + + return ERROR_SUCCESS; +} + +UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, unsigned int iField, LPCSTR szFilename) +{ + LPWSTR wstr = NULL; + UINT ret, len; + + TRACE("%ld %d %s\n", hRecord, iField, debugstr_a(szFilename)); + + if( szFilename ) + { + len = MultiByteToWideChar(CP_ACP,0,szFilename,-1,NULL,0); + wstr = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP,0,szFilename,-1,wstr,len); + } + ret = MsiRecordSetStreamW(hRecord, iField, wstr); + HeapFree(GetProcessHeap(),0,wstr); + + return ret; +} + +UINT WINAPI MsiRecordSetStreamW(MSIHANDLE handle, unsigned int iField, LPCWSTR szFilename) +{ + MSIRECORD *rec; + UINT ret; + + TRACE("%ld %d %s\n", handle, iField, debugstr_w(szFilename)); + + rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); + if( !rec ) + return ERROR_INVALID_HANDLE; + + msiobj_lock( &rec->hdr ); + ret = MSI_RecordSetStreamW( rec, iField, szFilename ); + msiobj_unlock( &rec->hdr ); + msiobj_release( &rec->hdr ); + return ret; } UINT MSI_RecordReadStream(MSIRECORD *rec, unsigned int iField, char *buf, DWORD *sz) @@ -500,18 +669,18 @@ UINT MSI_RecordReadStream(MSIRECORD *rec, unsigned int iField, char *buf, DWORD TRACE("%p %d %p %p\n", rec, iField, buf, sz); - if( iField > rec->count ) - return ERROR_INVALID_FIELD; + if( !sz ) + return ERROR_INVALID_PARAMETER; + + if( iField > rec->count) + return ERROR_INVALID_PARAMETER; if( rec->fields[iField].type != MSIFIELD_STREAM ) - { - *sz = 0; - return ERROR_INVALID_FIELD; - } + return ERROR_INVALID_DATATYPE; stm = rec->fields[iField].u.stream; if( !stm ) - return ERROR_INVALID_FIELD; + return ERROR_INVALID_PARAMETER; /* if there's no buffer pointer, calculate the length to the end */ if( !buf ) @@ -554,7 +723,9 @@ UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, unsigned int iField, char *buf rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); if( !rec ) return ERROR_INVALID_HANDLE; + msiobj_lock( &rec->hdr ); ret = MSI_RecordReadStream( rec, iField, buf, sz ); + msiobj_unlock( &rec->hdr ); msiobj_release( &rec->hdr ); return ret; } diff --git a/reactos/lib/msi/sql.tab.c b/reactos/lib/msi/sql.tab.c index dafec32332e..7cfd6c0a553 100644 --- a/reactos/lib/msi/sql.tab.c +++ b/reactos/lib/msi/sql.tab.c @@ -1,2180 +1,2496 @@ -/* A Bison parser, made from ./sql.y - by GNU bison 1.35. */ - -#define YYBISON 1 /* Identify Bison output. */ - -#define yyparse SQL_parse -#define yylex SQL_lex -#define yyerror SQL_error -#define yylval SQL_lval -#define yychar SQL_char -#define yydebug SQL_debug -#define yynerrs SQL_nerrs -# define TK_ABORT 257 -# define TK_AFTER 258 -# define TK_AGG_FUNCTION 259 -# define TK_ALL 260 -# define TK_AND 261 -# define TK_AS 262 -# define TK_ASC 263 -# define TK_BEFORE 264 -# define TK_BEGIN 265 -# define TK_BETWEEN 266 -# define TK_BITAND 267 -# define TK_BITNOT 268 -# define TK_BITOR 269 -# define TK_BY 270 -# define TK_CASCADE 271 -# define TK_CASE 272 -# define TK_CHAR 273 -# define TK_CHECK 274 -# define TK_CLUSTER 275 -# define TK_COLLATE 276 -# define TK_COLUMN 277 -# define TK_COMMA 278 -# define TK_COMMENT 279 -# define TK_COMMIT 280 -# define TK_CONCAT 281 -# define TK_CONFLICT 282 -# define TK_CONSTRAINT 283 -# define TK_COPY 284 -# define TK_CREATE 285 -# define TK_DEFAULT 286 -# define TK_DEFERRABLE 287 -# define TK_DEFERRED 288 -# define TK_DELETE 289 -# define TK_DELIMITERS 290 -# define TK_DESC 291 -# define TK_DISTINCT 292 -# define TK_DOT 293 -# define TK_DROP 294 -# define TK_EACH 295 -# define TK_ELSE 296 -# define TK_END 297 -# define TK_END_OF_FILE 298 -# define TK_EQ 299 -# define TK_EXCEPT 300 -# define TK_EXPLAIN 301 -# define TK_FAIL 302 -# define TK_FLOAT 303 -# define TK_FOR 304 -# define TK_FOREIGN 305 -# define TK_FROM 306 -# define TK_FUNCTION 307 -# define TK_GE 308 -# define TK_GLOB 309 -# define TK_GROUP 310 -# define TK_GT 311 -# define TK_HAVING 312 -# define TK_HOLD 313 -# define TK_IGNORE 314 -# define TK_ILLEGAL 315 -# define TK_IMMEDIATE 316 -# define TK_IN 317 -# define TK_INDEX 318 -# define TK_INITIALLY 319 -# define TK_ID 320 -# define TK_INSERT 321 -# define TK_INSTEAD 322 -# define TK_INT 323 -# define TK_INTEGER 324 -# define TK_INTERSECT 325 -# define TK_INTO 326 -# define TK_IS 327 -# define TK_ISNULL 328 -# define TK_JOIN 329 -# define TK_JOIN_KW 330 -# define TK_KEY 331 -# define TK_LE 332 -# define TK_LIKE 333 -# define TK_LIMIT 334 -# define TK_LONG 335 -# define TK_LONGCHAR 336 -# define TK_LP 337 -# define TK_LSHIFT 338 -# define TK_LT 339 -# define TK_LOCALIZABLE 340 -# define TK_MATCH 341 -# define TK_MINUS 342 -# define TK_NE 343 -# define TK_NOT 344 -# define TK_NOTNULL 345 -# define TK_NULL 346 -# define TK_OBJECT 347 -# define TK_OF 348 -# define TK_OFFSET 349 -# define TK_ON 350 -# define TK_OR 351 -# define TK_ORACLE_OUTER_JOIN 352 -# define TK_ORDER 353 -# define TK_PLUS 354 -# define TK_PRAGMA 355 -# define TK_PRIMARY 356 -# define TK_RAISE 357 -# define TK_REFERENCES 358 -# define TK_REM 359 -# define TK_REPLACE 360 -# define TK_RESTRICT 361 -# define TK_ROLLBACK 362 -# define TK_ROW 363 -# define TK_RP 364 -# define TK_RSHIFT 365 -# define TK_SELECT 366 -# define TK_SEMI 367 -# define TK_SET 368 -# define TK_SHORT 369 -# define TK_SLASH 370 -# define TK_SPACE 371 -# define TK_STAR 372 -# define TK_STATEMENT 373 -# define TK_STRING 374 -# define TK_TABLE 375 -# define TK_TEMP 376 -# define TK_THEN 377 -# define TK_TRANSACTION 378 -# define TK_TRIGGER 379 -# define TK_UMINUS 380 -# define TK_UNCLOSED_STRING 381 -# define TK_UNION 382 -# define TK_UNIQUE 383 -# define TK_UPDATE 384 -# define TK_UPLUS 385 -# define TK_USING 386 -# define TK_VACUUM 387 -# define TK_VALUES 388 -# define TK_VIEW 389 -# define TK_WHEN 390 -# define TK_WHERE 391 -# define TK_WILDCARD 392 -# define END_OF_FILE 393 -# define ILLEGAL 394 -# define SPACE 395 -# define UNCLOSED_STRING 396 -# define COMMENT 397 -# define FUNCTION 398 -# define COLUMN 399 - -#line 1 "./sql.y" - - -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2002-2004 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include "config.h" - -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "query.h" -#include "wine/debug.h" -#include "wine/unicode.h" - -#define YYLEX_PARAM info -#define YYPARSE_PARAM info - -extern int SQL_error(const char *str); - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -typedef struct tag_SQL_input -{ - MSIDATABASE *db; - LPCWSTR command; - DWORD n, len; - MSIVIEW **view; /* view structure for the resulting query */ -} SQL_input; - -static LPWSTR SQL_getstring( struct sql_str *str ); -static INT SQL_getint( SQL_input *sql ); -static int SQL_lex( void *SQL_lval, SQL_input *info); - -static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, - string_list *columns ); -static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in, - string_list *columns ); - -static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, - string_list *keys); - -static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r ); -static struct expr * EXPR_column( LPWSTR ); -static struct expr * EXPR_ival( struct sql_str *); -static struct expr * EXPR_sval( struct sql_str *); -static struct expr * EXPR_wildcard(void); - - -#line 73 "./sql.y" -#ifndef YYSTYPE -typedef union -{ - struct sql_str str; - LPWSTR string; - string_list *column_list; - value_list *val_list; - MSIVIEW *query; - struct expr *expr; - USHORT column_type; - create_col_info *column_info; - column_assignment update_col_info; -} yystype; -# define YYSTYPE yystype -# define YYSTYPE_IS_TRIVIAL 1 -#endif -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - - - -#define YYFINAL 121 -#define YYFLAG -32768 -#define YYNTBASE 147 - -/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ -#define YYTRANSLATE(x) ((unsigned)(x) <= 400 ? yytranslate[x] : 171) - -/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ -static const short yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, - 146 -}; - -#if YYDEBUG -static const short yyprhs[] = -{ - 0, 0, 2, 4, 6, 8, 19, 31, 38, 46, - 53, 58, 63, 66, 68, 71, 73, 77, 79, 84, - 86, 88, 90, 92, 94, 96, 101, 103, 107, 112, - 114, 118, 120, 123, 128, 132, 136, 140, 144, 148, - 152, 156, 160, 164, 168, 172, 177, 179, 181, 183, - 187, 189, 193, 197, 199, 201, 203, 205, 209, 211, - 213, 215 -}; -static const short yyrhs[] = -{ - 157, 0, 149, 0, 148, 0, 150, 0, 67, 72, - 169, 83, 159, 110, 134, 83, 163, 110, 0, 67, - 72, 169, 83, 159, 110, 134, 83, 163, 110, 122, - 0, 31, 121, 169, 83, 151, 110, 0, 31, 121, - 169, 83, 151, 110, 59, 0, 130, 169, 114, 164, - 137, 161, 0, 152, 102, 77, 159, 0, 152, 24, - 168, 153, 0, 168, 153, 0, 154, 0, 154, 86, - 0, 155, 0, 155, 90, 92, 0, 19, 0, 19, - 83, 156, 110, 0, 82, 0, 115, 0, 69, 0, - 81, 0, 93, 0, 70, 0, 158, 99, 16, 159, - 0, 158, 0, 112, 159, 160, 0, 112, 38, 159, - 160, 0, 168, 0, 168, 24, 159, 0, 118, 0, - 52, 169, 0, 52, 169, 137, 161, 0, 83, 161, - 110, 0, 167, 45, 167, 0, 161, 7, 161, 0, - 161, 97, 161, 0, 167, 45, 162, 0, 167, 57, - 162, 0, 167, 85, 162, 0, 167, 78, 162, 0, - 167, 54, 162, 0, 167, 89, 162, 0, 167, 73, - 92, 0, 167, 73, 90, 92, 0, 167, 0, 166, - 0, 166, 0, 163, 24, 166, 0, 165, 0, 165, - 24, 164, 0, 168, 45, 166, 0, 70, 0, 120, - 0, 138, 0, 168, 0, 169, 39, 170, 0, 170, - 0, 170, 0, 66, 0, 120, 0 -}; - -#endif - -#if YYDEBUG -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ -static const short yyrline[] = -{ - 0, 141, 147, 152, 157, 164, 173, 183, 194, 206, - 217, 227, 247, 258, 263, 270, 275, 281, 286, 290, - 294, 298, 302, 306, 312, 323, 335, 338, 353, 370, - 384, 397, 403, 415, 433, 438, 442, 446, 450, 454, - 458, 462, 466, 470, 474, 478, 484, 486, 489, 502, - 517, 519, 527, 543, 548, 552, 558, 565, 570, 576, - 583, 588 -}; -#endif - - -#if (YYDEBUG) || defined YYERROR_VERBOSE - -/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */ -static const char *const yytname[] = -{ - "$", "error", "$undefined.", "TK_ABORT", "TK_AFTER", "TK_AGG_FUNCTION", - "TK_ALL", "TK_AND", "TK_AS", "TK_ASC", "TK_BEFORE", "TK_BEGIN", - "TK_BETWEEN", "TK_BITAND", "TK_BITNOT", "TK_BITOR", "TK_BY", - "TK_CASCADE", "TK_CASE", "TK_CHAR", "TK_CHECK", "TK_CLUSTER", - "TK_COLLATE", "TK_COLUMN", "TK_COMMA", "TK_COMMENT", "TK_COMMIT", - "TK_CONCAT", "TK_CONFLICT", "TK_CONSTRAINT", "TK_COPY", "TK_CREATE", - "TK_DEFAULT", "TK_DEFERRABLE", "TK_DEFERRED", "TK_DELETE", - "TK_DELIMITERS", "TK_DESC", "TK_DISTINCT", "TK_DOT", "TK_DROP", - "TK_EACH", "TK_ELSE", "TK_END", "TK_END_OF_FILE", "TK_EQ", "TK_EXCEPT", - "TK_EXPLAIN", "TK_FAIL", "TK_FLOAT", "TK_FOR", "TK_FOREIGN", "TK_FROM", - "TK_FUNCTION", "TK_GE", "TK_GLOB", "TK_GROUP", "TK_GT", "TK_HAVING", - "TK_HOLD", "TK_IGNORE", "TK_ILLEGAL", "TK_IMMEDIATE", "TK_IN", - "TK_INDEX", "TK_INITIALLY", "TK_ID", "TK_INSERT", "TK_INSTEAD", - "TK_INT", "TK_INTEGER", "TK_INTERSECT", "TK_INTO", "TK_IS", "TK_ISNULL", - "TK_JOIN", "TK_JOIN_KW", "TK_KEY", "TK_LE", "TK_LIKE", "TK_LIMIT", - "TK_LONG", "TK_LONGCHAR", "TK_LP", "TK_LSHIFT", "TK_LT", - "TK_LOCALIZABLE", "TK_MATCH", "TK_MINUS", "TK_NE", "TK_NOT", - "TK_NOTNULL", "TK_NULL", "TK_OBJECT", "TK_OF", "TK_OFFSET", "TK_ON", - "TK_OR", "TK_ORACLE_OUTER_JOIN", "TK_ORDER", "TK_PLUS", "TK_PRAGMA", - "TK_PRIMARY", "TK_RAISE", "TK_REFERENCES", "TK_REM", "TK_REPLACE", - "TK_RESTRICT", "TK_ROLLBACK", "TK_ROW", "TK_RP", "TK_RSHIFT", - "TK_SELECT", "TK_SEMI", "TK_SET", "TK_SHORT", "TK_SLASH", "TK_SPACE", - "TK_STAR", "TK_STATEMENT", "TK_STRING", "TK_TABLE", "TK_TEMP", - "TK_THEN", "TK_TRANSACTION", "TK_TRIGGER", "TK_UMINUS", - "TK_UNCLOSED_STRING", "TK_UNION", "TK_UNIQUE", "TK_UPDATE", "TK_UPLUS", - "TK_USING", "TK_VACUUM", "TK_VALUES", "TK_VIEW", "TK_WHEN", "TK_WHERE", - "TK_WILDCARD", "END_OF_FILE", "ILLEGAL", "SPACE", "UNCLOSED_STRING", - "COMMENT", "FUNCTION", "COLUMN", "AGG_FUNCTION.", "onequery", - "oneinsert", "onecreate", "oneupdate", "table_def", "column_def", - "column_type", "data_type_l", "data_type", "data_count", "oneselect", - "unorderedsel", "selcollist", "from", "expr", "val", "constlist", - "update_assign_list", "column_assignment", "const_val", "column_val", - "column", "table", "string_or_id", 0 -}; -#endif - -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const short yyr1[] = -{ - 0, 147, 147, 147, 147, 148, 148, 149, 149, 150, - 151, 152, 152, 153, 153, 154, 154, 155, 155, 155, - 155, 155, 155, 155, 156, 157, 157, 158, 158, 159, - 159, 159, 160, 160, 161, 161, 161, 161, 161, 161, - 161, 161, 161, 161, 161, 161, 162, 162, 163, 163, - 164, 164, 165, 166, 166, 166, 167, 168, 168, 169, - 170, 170 -}; - -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const short yyr2[] = -{ - 0, 1, 1, 1, 1, 10, 11, 6, 7, 6, - 4, 4, 2, 1, 2, 1, 3, 1, 4, 1, - 1, 1, 1, 1, 1, 4, 1, 3, 4, 1, - 3, 1, 2, 4, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 4, 1, 1, 1, 3, - 1, 3, 3, 1, 1, 1, 1, 3, 1, 1, - 1, 1 -}; - -/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE - doesn't specify something else to do. Zero means the default is an - error. */ -static const short yydefact[] = -{ - 0, 0, 0, 0, 0, 3, 2, 4, 1, 26, - 0, 0, 0, 60, 31, 61, 0, 29, 0, 58, - 0, 59, 0, 0, 0, 0, 0, 27, 0, 0, - 0, 0, 0, 0, 28, 32, 30, 57, 0, 50, - 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, - 7, 0, 0, 17, 21, 22, 19, 23, 20, 12, - 13, 15, 0, 0, 33, 0, 56, 9, 51, 53, - 54, 55, 52, 8, 0, 0, 0, 14, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 11, 10, 24, 0, 16, 0, 34, 36, 37, 54, - 38, 47, 35, 42, 46, 39, 0, 44, 41, 40, - 43, 18, 0, 48, 45, 0, 5, 49, 6, 0, - 0, 0 -}; - -static const short yydefgoto[] = -{ - 119, 5, 6, 7, 42, 43, 59, 60, 61, 93, - 8, 9, 16, 27, 64, 100, 112, 38, 39, 101, - 65, 66, 18, 19 -}; - -static const short yypact[] = -{ - -30, -113, -49, -34, -50,-32768,-32768,-32768,-32768, -79, - -50, -50, -52,-32768,-32768,-32768, -25, 4, -10, 0, - -72,-32768, 30, -36, -35, -25, -50,-32768, -52, -50, - -50, -52, -50, -52,-32768, -87,-32768,-32768, -84, 33, - 13,-32768, -51, -15, -17, -41, -53, -53, -50, -58, - 1, -50, -5, -8,-32768,-32768,-32768,-32768,-32768,-32768, - -13, -9, -57, -53, -4, 47,-32768, -4,-32768,-32768, - -32768,-32768,-32768,-32768, -17, -52, 18,-32768, -3, 11, - -7, -53, -53, -59, -59, -59, -71, -59, -59, -59, - -32768,-32768,-32768, -14,-32768, -58,-32768, -4, -4, 56, - -32768,-32768,-32768,-32768,-32768,-32768, 5,-32768,-32768,-32768, - -32768,-32768, -19,-32768,-32768, -58, -23,-32768,-32768, 102, - 108,-32768 -}; - -static const short yypgoto[] = -{ - -32768,-32768,-32768,-32768,-32768,-32768, 40,-32768,-32768,-32768, - -32768,-32768, 10, 93, -37, 28,-32768, 71,-32768, -32, - 22, 3, 14, 45 -}; - - -#define YYLAST 136 - - -static const short yytable[] = -{ - 81, 1, 53, 81, 12, 115, 17, 13, 10, 51, - 67, 69, 69, 13, 13, 17, 13, 72, 20, 106, - 22, 107, 25, 11, 23, 24, 80, 26, 28, 29, - 63, 17, 13, 40, 17, 44, 17, 2, 36, -59, - 35, 41, 30, 45, 97, 98, 31, 32, 33, 21, - 46, 40, 54, 47, 74, 21, 21, 48, 49, 50, - 73, 99, 70, 113, 55, 56, 14, 15, 15, 62, - 15, 21, 75, 77, 37, 76, 57, 79, 17, 71, - 71, 78, 3, 117, 14, 91, 15, 52, 92, 94, - 82, 116, 83, 82, 95, -61, 111, 114, 58, 118, - 4, 84, 120, 96, 85, 102, 104, 104, 121, 104, - 104, 104, 103, 105, 90, 108, 109, 110, 34, 68, - 86, 0, 0, 0, 0, 87, 0, 0, 0, 0, - 0, 0, 88, 0, 0, 0, 89 -}; - -static const short yycheck[] = -{ - 7, 31, 19, 7, 38, 24, 3, 66, 121, 24, - 47, 70, 70, 66, 66, 12, 66, 49, 4, 90, - 99, 92, 12, 72, 10, 11, 63, 52, 24, 39, - 83, 28, 66, 30, 31, 32, 33, 67, 28, 39, - 26, 31, 114, 33, 81, 82, 16, 83, 83, 4, - 137, 48, 69, 137, 51, 10, 11, 24, 45, 110, - 59, 120, 120, 95, 81, 82, 118, 120, 120, 110, - 120, 26, 77, 86, 29, 83, 93, 134, 75, 138, - 138, 90, 112, 115, 118, 75, 120, 102, 70, 92, - 97, 110, 45, 97, 83, 39, 110, 92, 115, 122, - 130, 54, 0, 110, 57, 83, 84, 85, 0, 87, - 88, 89, 84, 85, 74, 87, 88, 89, 25, 48, - 73, -1, -1, -1, -1, 78, -1, -1, -1, -1, - -1, -1, 85, -1, -1, -1, 89 -}; -#define YYPURE 1 - -/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ -#line 3 "/usr/share/bison/bison.simple" - -/* Skeleton output parser for bison, - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software - Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* As a special exception, when this file is copied by Bison into a - Bison output file, you may use that output file without restriction. - This special exception was added by the Free Software Foundation - in version 1.24 of Bison. */ - -/* This is the parser code that is written into each bison parser when - the %semantic_parser declaration is not specified in the grammar. - It was written by Richard Stallman by simplifying the hairy parser - used when %semantic_parser is specified. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE) - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# if YYSTACK_USE_ALLOCA -# define YYSTACK_ALLOC alloca -# else -# ifndef YYSTACK_USE_ALLOCA -# if defined (alloca) || defined (_ALLOCA_H) -# define YYSTACK_ALLOC alloca -# else -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) -# else -# if defined (__STDC__) || defined (__cplusplus) -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -# define YYSTACK_ALLOC malloc -# define YYSTACK_FREE free -# endif -#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */ - - -#if (! defined (yyoverflow) \ - && (! defined (__cplusplus) \ - || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - short yyss; - YYSTYPE yyvs; -# if YYLSP_NEEDED - YYLTYPE yyls; -# endif -}; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# if YYLSP_NEEDED -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ - + 2 * YYSTACK_GAP_MAX) -# else -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAX) -# endif - -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - register YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (0) -# endif -# endif - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack, Stack, yysize); \ - Stack = &yyptr->Stack; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (0) - -#endif - - -#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) -# define YYSIZE_T __SIZE_TYPE__ -#endif -#if ! defined (YYSIZE_T) && defined (size_t) -# define YYSIZE_T size_t -#endif -#if ! defined (YYSIZE_T) -# if defined (__STDC__) || defined (__cplusplus) -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -#endif -#if ! defined (YYSIZE_T) -# define YYSIZE_T unsigned int -#endif - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY -2 -#define YYEOF 0 -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrlab1 -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. */ -#define YYFAIL goto yyerrlab -#define YYRECOVERING() (!!yyerrstatus) -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - yychar1 = YYTRANSLATE (yychar); \ - YYPOPSTACK; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror ("syntax error: cannot back up"); \ - YYERROR; \ - } \ -while (0) - -#define YYTERROR 1 -#define YYERRCODE 256 - - -/* YYLLOC_DEFAULT -- Compute the default location (before the actions - are run). - - When YYLLOC_DEFAULT is run, CURRENT is set the location of the - first token. By default, to implement support for ranges, extend - its range to the last symbol. */ - -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - Current.last_line = Rhs[N].last_line; \ - Current.last_column = Rhs[N].last_column; -#endif - - -/* YYLEX -- calling `yylex' with the right arguments. */ - -#if YYPURE -# if YYLSP_NEEDED -# ifdef YYLEX_PARAM -# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) -# else -# define YYLEX yylex (&yylval, &yylloc) -# endif -# else /* !YYLSP_NEEDED */ -# ifdef YYLEX_PARAM -# define YYLEX yylex (&yylval, YYLEX_PARAM) -# else -# define YYLEX yylex (&yylval) -# endif -# endif /* !YYLSP_NEEDED */ -#else /* !YYPURE */ -# define YYLEX yylex () -#endif /* !YYPURE */ - - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (0) -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -#endif /* !YYDEBUG */ - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#if YYMAXDEPTH == 0 -# undef YYMAXDEPTH -#endif - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - -#ifdef YYERROR_VERBOSE - -# ifndef yystrlen -# if defined (__GLIBC__) && defined (_STRING_H) -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -static YYSIZE_T -# if defined (__STDC__) || defined (__cplusplus) -yystrlen (const char *yystr) -# else -yystrlen (yystr) - const char *yystr; -# endif -{ - register const char *yys = yystr; - - while (*yys++ != '\0') - continue; - - return yys - yystr - 1; -} -# endif -# endif - -# ifndef yystpcpy -# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -static char * -# if defined (__STDC__) || defined (__cplusplus) -yystpcpy (char *yydest, const char *yysrc) -# else -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -# endif -{ - register char *yyd = yydest; - register const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif -#endif - -#line 315 "/usr/share/bison/bison.simple" - - -/* The user can define YYPARSE_PARAM as the name of an argument to be passed - into yyparse. The argument should have type void *. - It should actually point to an object. - Grammar actions can access the variable by casting it - to the proper pointer type. */ - -#ifdef YYPARSE_PARAM -# if defined (__STDC__) || defined (__cplusplus) -# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM -# define YYPARSE_PARAM_DECL -# else -# define YYPARSE_PARAM_ARG YYPARSE_PARAM -# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; -# endif -#else /* !YYPARSE_PARAM */ -# define YYPARSE_PARAM_ARG -# define YYPARSE_PARAM_DECL -#endif /* !YYPARSE_PARAM */ - -/* Prevent warning if -Wstrict-prototypes. */ -#ifdef __GNUC__ -# ifdef YYPARSE_PARAM -int yyparse (void *); -# else -int yyparse (void); -# endif -#endif - -/* YY_DECL_VARIABLES -- depending whether we use a pure parser, - variables are global, or local to YYPARSE. */ - -#define YY_DECL_NON_LSP_VARIABLES \ -/* The lookahead symbol. */ \ -int yychar; \ - \ -/* The semantic value of the lookahead symbol. */ \ -YYSTYPE yylval; \ - \ -/* Number of parse errors so far. */ \ -int yynerrs; - -#if YYLSP_NEEDED -# define YY_DECL_VARIABLES \ -YY_DECL_NON_LSP_VARIABLES \ - \ -/* Location data for the lookahead symbol. */ \ -YYLTYPE yylloc; -#else -# define YY_DECL_VARIABLES \ -YY_DECL_NON_LSP_VARIABLES -#endif - - -/* If nonreentrant, generate the variables here. */ - -#if !YYPURE -YY_DECL_VARIABLES -#endif /* !YYPURE */ - -int -yyparse (YYPARSE_PARAM_ARG) - YYPARSE_PARAM_DECL -{ - /* If reentrant, generate the variables here. */ -#if YYPURE - YY_DECL_VARIABLES -#endif /* !YYPURE */ - - register int yystate; - register int yyn; - int yyresult; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - /* Lookahead token as an internal (translated) token number. */ - int yychar1 = 0; - - /* Three stacks and their tools: - `yyss': related to states, - `yyvs': related to semantic values, - `yyls': related to locations. - - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - short yyssa[YYINITDEPTH]; - short *yyss = yyssa; - register short *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - register YYSTYPE *yyvsp; - -#if YYLSP_NEEDED - /* The location stack. */ - YYLTYPE yylsa[YYINITDEPTH]; - YYLTYPE *yyls = yylsa; - YYLTYPE *yylsp; -#endif - -#if YYLSP_NEEDED -# define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) -#else -# define YYPOPSTACK (yyvsp--, yyssp--) -#endif - - YYSIZE_T yystacksize = YYINITDEPTH; - - - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; -#if YYLSP_NEEDED - YYLTYPE yyloc; -#endif - - /* When reducing, the number of symbols on the RHS of the reduced - rule. */ - int yylen; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - - yyssp = yyss; - yyvsp = yyvs; -#if YYLSP_NEEDED - yylsp = yyls; -#endif - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. so pushing a state here evens the stacks. - */ - yyssp++; - - yysetstate: - *yyssp = yystate; - - if (yyssp >= yyss + yystacksize - 1) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - short *yyss1 = yyss; - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. */ -# if YYLSP_NEEDED - YYLTYPE *yyls1 = yyls; - /* This used to be a conditional around just the two extra args, - but that might be undefined if yyoverflow is a macro. */ - yyoverflow ("parser stack overflow", - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yyls1, yysize * sizeof (*yylsp), - &yystacksize); - yyls = yyls1; -# else - yyoverflow ("parser stack overflow", - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yystacksize); -# endif - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyoverflowlab; -# else - /* Extend the stack our own way. */ - if (yystacksize >= YYMAXDEPTH) - goto yyoverflowlab; - yystacksize *= 2; - if (yystacksize > YYMAXDEPTH) - yystacksize = YYMAXDEPTH; - - { - short *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyoverflowlab; - YYSTACK_RELOCATE (yyss); - YYSTACK_RELOCATE (yyvs); -# if YYLSP_NEEDED - YYSTACK_RELOCATE (yyls); -# endif -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; -#if YYLSP_NEEDED - yylsp = yyls + yysize - 1; -#endif - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyssp >= yyss + yystacksize - 1) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - goto yybackup; - - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - -/* Do appropriate processing given the current state. */ -/* Read a lookahead token if we need one and don't already have one. */ -/* yyresume: */ - - /* First try to decide what to do without reference to lookahead token. */ - - yyn = yypact[yystate]; - if (yyn == YYFLAG) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* yychar is either YYEMPTY or YYEOF - or a valid token in external form. */ - - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; - } - - /* Convert token to internal form (in yychar1) for indexing tables with */ - - if (yychar <= 0) /* This means end of input. */ - { - yychar1 = 0; - yychar = YYEOF; /* Don't call YYLEX any more */ - - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yychar1 = YYTRANSLATE (yychar); - -#if YYDEBUG - /* We have to keep this `#if YYDEBUG', since we use variables - which are defined only if `YYDEBUG' is set. */ - if (yydebug) - { - YYFPRINTF (stderr, "Next token is %d (%s", - yychar, yytname[yychar1]); - /* Give the individual parser a way to print the precise - meaning of a token, for further debugging info. */ -# ifdef YYPRINT - YYPRINT (stderr, yychar, yylval); -# endif - YYFPRINTF (stderr, ")\n"); - } -#endif - } - - yyn += yychar1; - if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) - goto yydefault; - - yyn = yytable[yyn]; - - /* yyn is what to do for this token type in this state. - Negative => reduce, -yyn is rule number. - Positive => shift, yyn is new state. - New state is final state => don't bother to shift, - just return success. - 0, or most negative number => error. */ - - if (yyn < 0) - { - if (yyn == YYFLAG) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - else if (yyn == 0) - goto yyerrlab; - - if (yyn == YYFINAL) - YYACCEPT; - - /* Shift the lookahead token. */ - YYDPRINTF ((stderr, "Shifting token %d (%s), ", - yychar, yytname[yychar1])); - - /* Discard the token being shifted unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; - - *++yyvsp = yylval; -#if YYLSP_NEEDED - *++yylsp = yylloc; -#endif - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - yystate = yyn; - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. - - Otherwise, the following line sets YYVAL to the semantic value of - the lookahead token. This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - -#if YYLSP_NEEDED - /* Similarly for the default location. Let the user run additional - commands if for instance locations are ranges. */ - yyloc = yylsp[1-yylen]; - YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); -#endif - -#if YYDEBUG - /* We have to keep this `#if YYDEBUG', since we use variables which - are defined only if `YYDEBUG' is set. */ - if (yydebug) - { - int yyi; - - YYFPRINTF (stderr, "Reducing via rule %d (line %d), ", - yyn, yyrline[yyn]); - - /* Print the symbols being reduced, and their result. */ - for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++) - YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]); - YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]); - } -#endif - - switch (yyn) { - -case 1: -#line 143 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - *sql->view = yyvsp[0].query; - ; - break;} -case 2: -#line 148 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - *sql->view = yyvsp[0].query; - ; - break;} -case 3: -#line 153 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - *sql->view = yyvsp[0].query; - ; - break;} -case 4: -#line 158 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - *sql->view = yyvsp[0].query; - ; - break;} -case 5: -#line 166 "./sql.y" -{ - SQL_input *sql = (SQL_input*) info; - MSIVIEW *insert = NULL; - - INSERT_CreateView( sql->db, &insert, yyvsp[-7].string, yyvsp[-5].column_list, yyvsp[-1].val_list, FALSE ); - yyval.query = insert; - ; - break;} -case 6: -#line 174 "./sql.y" -{ - SQL_input *sql = (SQL_input*) info; - MSIVIEW *insert = NULL; - - INSERT_CreateView( sql->db, &insert, yyvsp[-8].string, yyvsp[-6].column_list, yyvsp[-2].val_list, TRUE ); - yyval.query = insert; - ; - break;} -case 7: -#line 185 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - MSIVIEW *create = NULL; - - if( !yyvsp[-1].column_info ) - YYABORT; - CREATE_CreateView( sql->db, &create, yyvsp[-3].string, yyvsp[-1].column_info, FALSE ); - yyval.query = create; - ; - break;} -case 8: -#line 195 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - MSIVIEW *create = NULL; - - if( !yyvsp[-2].column_info ) - YYABORT; - CREATE_CreateView( sql->db, &create, yyvsp[-4].string, yyvsp[-2].column_info, TRUE ); - yyval.query = create; - ; - break;} -case 9: -#line 208 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - MSIVIEW *update = NULL; - - UPDATE_CreateView( sql->db, &update, yyvsp[-4].string, &yyvsp[-2].update_col_info, yyvsp[0].expr ); - yyval.query = update; - ; - break;} -case 10: -#line 219 "./sql.y" -{ - if( SQL_MarkPrimaryKeys( yyvsp[-3].column_info, yyvsp[0].column_list ) ) - yyval.column_info = yyvsp[-3].column_info; - else - yyval.column_info = NULL; - ; - break;} -case 11: -#line 229 "./sql.y" -{ - create_col_info *ci; - - for( ci = yyvsp[-3].column_info; ci->next; ci = ci->next ) - ; - - ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info ); - if( !ci->next ) - { - /* FIXME: free $1 */ - YYABORT; - } - ci->next->colname = yyvsp[-1].string; - ci->next->type = yyvsp[0].column_type; - ci->next->next = NULL; - - yyval.column_info = yyvsp[-3].column_info; - ; - break;} -case 12: -#line 248 "./sql.y" -{ - yyval.column_info = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info ); - if( ! yyval.column_info ) - YYABORT; - yyval.column_info->colname = yyvsp[-1].string; - yyval.column_info->type = yyvsp[0].column_type; - yyval.column_info->next = NULL; - ; - break;} -case 13: -#line 260 "./sql.y" -{ - yyval.column_type = yyvsp[0].column_type | MSITYPE_VALID; - ; - break;} -case 14: -#line 264 "./sql.y" -{ - FIXME("LOCALIZABLE ignored\n"); - yyval.column_type = yyvsp[-1].column_type | MSITYPE_VALID; - ; - break;} -case 15: -#line 272 "./sql.y" -{ - yyval.column_type |= MSITYPE_NULLABLE; - ; - break;} -case 16: -#line 276 "./sql.y" -{ - yyval.column_type = yyvsp[-2].column_type; - ; - break;} -case 17: -#line 283 "./sql.y" -{ - yyval.column_type = MSITYPE_STRING | 1; - ; - break;} -case 18: -#line 287 "./sql.y" -{ - yyval.column_type = MSITYPE_STRING | 0x400 | yyvsp[-1].column_type; - ; - break;} -case 19: -#line 291 "./sql.y" -{ - yyval.column_type = 2; - ; - break;} -case 20: -#line 295 "./sql.y" -{ - yyval.column_type = 2; - ; - break;} -case 21: -#line 299 "./sql.y" -{ - yyval.column_type = 2; - ; - break;} -case 22: -#line 303 "./sql.y" -{ - yyval.column_type = 4; - ; - break;} -case 23: -#line 307 "./sql.y" -{ - yyval.column_type = 0; - ; - break;} -case 24: -#line 314 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - int val = SQL_getint(sql); - if( ( val > 255 ) || ( val < 0 ) ) - YYABORT; - yyval.column_type = val; - ; - break;} -case 25: -#line 325 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - - if( !yyvsp[-3].query ) - YYABORT; - if( yyvsp[0].column_list ) - yyval.query = do_order_by( sql->db, yyvsp[-3].query, yyvsp[0].column_list ); - else - yyval.query = yyvsp[-3].query; - ; - break;} -case 27: -#line 340 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - if( !yyvsp[0].query ) - YYABORT; - if( yyvsp[-1].column_list ) - { - yyval.query = do_one_select( sql->db, yyvsp[0].query, yyvsp[-1].column_list ); - if( !yyval.query ) - YYABORT; - } - else - yyval.query = yyvsp[0].query; - ; - break;} -case 28: -#line 354 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - MSIVIEW *view = yyvsp[0].query; - - if( !view ) - YYABORT; - if( yyvsp[-1].column_list ) - { - view = do_one_select( sql->db, view, yyvsp[-1].column_list ); - if( !view ) - YYABORT; - } - DISTINCT_CreateView( sql->db, & yyval.query, view ); - ; - break;} -case 29: -#line 372 "./sql.y" -{ - string_list *list; - - list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); - if( !list ) - YYABORT; - list->string = yyvsp[0].string; - list->next = NULL; - - yyval.column_list = list; - TRACE("Collist %s\n",debugstr_w(yyval.column_list->string)); - ; - break;} -case 30: -#line 385 "./sql.y" -{ - string_list *list; - - list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); - if( !list ) - YYABORT; - list->string = yyvsp[-2].string; - list->next = yyvsp[0].column_list; - - yyval.column_list = list; - TRACE("From table: %s\n",debugstr_w(yyval.column_list->string)); - ; - break;} -case 31: -#line 398 "./sql.y" -{ - yyval.column_list = NULL; - ; - break;} -case 32: -#line 405 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - UINT r; - - yyval.query = NULL; - TRACE("From table: %s\n",debugstr_w(yyvsp[0].string)); - r = TABLE_CreateView( sql->db, yyvsp[0].string, & yyval.query ); - if( r != ERROR_SUCCESS ) - YYABORT; - ; - break;} -case 33: -#line 416 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - MSIVIEW *view = NULL; - UINT r; - - yyval.query = NULL; - TRACE("From table: %s\n",debugstr_w(yyvsp[-2].string)); - r = TABLE_CreateView( sql->db, yyvsp[-2].string, &view ); - if( r != ERROR_SUCCESS ) - YYABORT; - r = WHERE_CreateView( sql->db, &view, view, yyvsp[0].expr ); - if( r != ERROR_SUCCESS ) - YYABORT; - yyval.query = view; - ; - break;} -case 34: -#line 435 "./sql.y" -{ - yyval.expr = yyvsp[-1].expr; - ; - break;} -case 35: -#line 439 "./sql.y" -{ - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_EQ, yyvsp[0].expr ); - ; - break;} -case 36: -#line 443 "./sql.y" -{ - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_AND, yyvsp[0].expr ); - ; - break;} -case 37: -#line 447 "./sql.y" -{ - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_OR, yyvsp[0].expr ); - ; - break;} -case 38: -#line 451 "./sql.y" -{ - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_EQ, yyvsp[0].expr ); - ; - break;} -case 39: -#line 455 "./sql.y" -{ - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_GT, yyvsp[0].expr ); - ; - break;} -case 40: -#line 459 "./sql.y" -{ - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_LT, yyvsp[0].expr ); - ; - break;} -case 41: -#line 463 "./sql.y" -{ - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_LE, yyvsp[0].expr ); - ; - break;} -case 42: -#line 467 "./sql.y" -{ - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_GE, yyvsp[0].expr ); - ; - break;} -case 43: -#line 471 "./sql.y" -{ - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_NE, yyvsp[0].expr ); - ; - break;} -case 44: -#line 475 "./sql.y" -{ - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_ISNULL, NULL ); - ; - break;} -case 45: -#line 479 "./sql.y" -{ - yyval.expr = EXPR_complex( yyvsp[-3].expr, OP_NOTNULL, NULL ); - ; - break;} -case 48: -#line 491 "./sql.y" -{ - value_list *vals; - - vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals ); - if( vals ) - { - vals->val = yyvsp[0].expr; - vals->next = NULL; - } - yyval.val_list = vals; - ; - break;} -case 49: -#line 503 "./sql.y" -{ - value_list *vals; - - vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals ); - if( vals ) - { - vals->val = yyvsp[0].expr; - vals->next = NULL; - } - yyvsp[-2].val_list->next = vals; - yyval.val_list = yyvsp[-2].val_list; - ; - break;} -case 51: -#line 520 "./sql.y" -{ - yyvsp[-2].update_col_info.col_list->next = yyvsp[0].update_col_info.col_list; - yyvsp[-2].update_col_info.val_list->next = yyvsp[0].update_col_info.val_list; - yyval.update_col_info = yyvsp[-2].update_col_info; - ; - break;} -case 52: -#line 529 "./sql.y" -{ - yyval.update_col_info.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.col_list ); - if( !yyval.update_col_info.col_list ) - YYABORT; - yyval.update_col_info.col_list->string = yyvsp[-2].string; - yyval.update_col_info.col_list->next = NULL; - yyval.update_col_info.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.val_list ); - if( !yyval.update_col_info.val_list ) - YYABORT; - yyval.update_col_info.val_list->val = yyvsp[0].expr; - yyval.update_col_info.val_list->next = 0; - ; - break;} -case 53: -#line 545 "./sql.y" -{ - yyval.expr = EXPR_ival( &yyvsp[0].str ); - ; - break;} -case 54: -#line 549 "./sql.y" -{ - yyval.expr = EXPR_sval( &yyvsp[0].str ); - ; - break;} -case 55: -#line 553 "./sql.y" -{ - yyval.expr = EXPR_wildcard(); - ; - break;} -case 56: -#line 560 "./sql.y" -{ - yyval.expr = EXPR_column( yyvsp[0].string ); - ; - break;} -case 57: -#line 567 "./sql.y" -{ - yyval.string = yyvsp[0].string; /* FIXME */ - ; - break;} -case 58: -#line 571 "./sql.y" -{ - yyval.string = yyvsp[0].string; - ; - break;} -case 59: -#line 578 "./sql.y" -{ - yyval.string = yyvsp[0].string; - ; - break;} -case 60: -#line 585 "./sql.y" -{ - yyval.string = SQL_getstring( &yyvsp[0].str ); - ; - break;} -case 61: -#line 589 "./sql.y" -{ - yyval.string = SQL_getstring( &yyvsp[0].str ); - ; - break;} -} - -#line 705 "/usr/share/bison/bison.simple" - - - yyvsp -= yylen; - yyssp -= yylen; -#if YYLSP_NEEDED - yylsp -= yylen; -#endif - -#if YYDEBUG - if (yydebug) - { - short *yyssp1 = yyss - 1; - YYFPRINTF (stderr, "state stack now"); - while (yyssp1 != yyssp) - YYFPRINTF (stderr, " %d", *++yyssp1); - YYFPRINTF (stderr, "\n"); - } -#endif - - *++yyvsp = yyval; -#if YYLSP_NEEDED - *++yylsp = yyloc; -#endif - - /* Now `shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTBASE] + *yyssp; - if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTBASE]; - - goto yynewstate; - - -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ -yyerrlab: - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; - -#ifdef YYERROR_VERBOSE - yyn = yypact[yystate]; - - if (yyn > YYFLAG && yyn < YYLAST) - { - YYSIZE_T yysize = 0; - char *yymsg; - int yyx, yycount; - - yycount = 0; - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - for (yyx = yyn < 0 ? -yyn : 0; - yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) - if (yycheck[yyx + yyn] == yyx) - yysize += yystrlen (yytname[yyx]) + 15, yycount++; - yysize += yystrlen ("parse error, unexpected ") + 1; - yysize += yystrlen (yytname[YYTRANSLATE (yychar)]); - yymsg = (char *) YYSTACK_ALLOC (yysize); - if (yymsg != 0) - { - char *yyp = yystpcpy (yymsg, "parse error, unexpected "); - yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]); - - if (yycount < 5) - { - yycount = 0; - for (yyx = yyn < 0 ? -yyn : 0; - yyx < (int) (sizeof (yytname) / sizeof (char *)); - yyx++) - if (yycheck[yyx + yyn] == yyx) - { - const char *yyq = ! yycount ? ", expecting " : " or "; - yyp = yystpcpy (yyp, yyq); - yyp = yystpcpy (yyp, yytname[yyx]); - yycount++; - } - } - yyerror (yymsg); - YYSTACK_FREE (yymsg); - } - else - yyerror ("parse error; also virtual memory exhausted"); - } - else -#endif /* defined (YYERROR_VERBOSE) */ - yyerror ("parse error"); - } - goto yyerrlab1; - - -/*--------------------------------------------------. -| yyerrlab1 -- error raised explicitly by an action | -`--------------------------------------------------*/ -yyerrlab1: - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - /* return failure if at end of input */ - if (yychar == YYEOF) - YYABORT; - YYDPRINTF ((stderr, "Discarding token %d (%s).\n", - yychar, yytname[yychar1])); - yychar = YYEMPTY; - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - - yyerrstatus = 3; /* Each real token shifted decrements this */ - - goto yyerrhandle; - - -/*-------------------------------------------------------------------. -| yyerrdefault -- current state does not do anything special for the | -| error token. | -`-------------------------------------------------------------------*/ -yyerrdefault: -#if 0 - /* This is wrong; only states that explicitly want error tokens - should shift them. */ - - /* If its default is to accept any token, ok. Otherwise pop it. */ - yyn = yydefact[yystate]; - if (yyn) - goto yydefault; -#endif - - -/*---------------------------------------------------------------. -| yyerrpop -- pop the current state because it cannot handle the | -| error token | -`---------------------------------------------------------------*/ -yyerrpop: - if (yyssp == yyss) - YYABORT; - yyvsp--; - yystate = *--yyssp; -#if YYLSP_NEEDED - yylsp--; -#endif - -#if YYDEBUG - if (yydebug) - { - short *yyssp1 = yyss - 1; - YYFPRINTF (stderr, "Error: state stack now"); - while (yyssp1 != yyssp) - YYFPRINTF (stderr, " %d", *++yyssp1); - YYFPRINTF (stderr, "\n"); - } -#endif - -/*--------------. -| yyerrhandle. | -`--------------*/ -yyerrhandle: - yyn = yypact[yystate]; - if (yyn == YYFLAG) - goto yyerrdefault; - - yyn += YYTERROR; - if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) - goto yyerrdefault; - - yyn = yytable[yyn]; - if (yyn < 0) - { - if (yyn == YYFLAG) - goto yyerrpop; - yyn = -yyn; - goto yyreduce; - } - else if (yyn == 0) - goto yyerrpop; - - if (yyn == YYFINAL) - YYACCEPT; - - YYDPRINTF ((stderr, "Shifting error token, ")); - - *++yyvsp = yylval; -#if YYLSP_NEEDED - *++yylsp = yylloc; -#endif - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -/*---------------------------------------------. -| yyoverflowab -- parser overflow comes here. | -`---------------------------------------------*/ -yyoverflowlab: - yyerror ("parser stack overflow"); - yyresult = 2; - /* Fall through. */ - -yyreturn: -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif - return yyresult; -} -#line 594 "./sql.y" - - -int SQL_lex( void *SQL_lval, SQL_input *sql) -{ - int token; - struct sql_str * str = SQL_lval; - - do - { - sql->n += sql->len; - if( ! sql->command[sql->n] ) - return 0; /* end of input */ - - TRACE("string : %s\n", debugstr_w(&sql->command[sql->n])); - sql->len = sqliteGetToken( &sql->command[sql->n], &token ); - if( sql->len==0 ) - break; - str->data = &sql->command[sql->n]; - str->len = sql->len; - } - while( token == TK_SPACE ); - - TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len)); - - return token; -} - -LPWSTR SQL_getstring( struct sql_str *strdata) -{ - LPCWSTR p = strdata->data; - UINT len = strdata->len; - LPWSTR str; - - /* if there's quotes, remove them */ - if( ( (p[0]=='`') && (p[len-1]=='`') ) || - ( (p[0]=='\'') && (p[len-1]=='\'') ) ) - { - p++; - len -= 2; - } - str = HeapAlloc( GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR)); - if(!str ) - return str; - memcpy(str, p, len*sizeof(WCHAR) ); - str[len]=0; - - return str; -} - -INT SQL_getint( SQL_input *sql ) -{ - LPCWSTR p = &sql->command[sql->n]; - - return atoiW( p ); -} - -int SQL_error(const char *str) -{ - return 0; -} - -static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, - string_list *columns ) -{ - MSIVIEW *view = NULL; - - SELECT_CreateView( db, &view, in, columns ); - delete_string_list( columns ); - if( !view ) - ERR("Error creating select query\n"); - return view; -} - -static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in, - string_list *columns ) -{ - MSIVIEW *view = NULL; - - ORDER_CreateView( db, &view, in ); - if( view ) - { - string_list *x = columns; - - for( x = columns; x ; x = x->next ) - ORDER_AddColumn( view, x->string ); - } - else - ERR("Error creating select query\n"); - delete_string_list( columns ); - return view; -} - -static struct expr * EXPR_wildcard() -{ - struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); - if( e ) - { - e->type = EXPR_WILDCARD; - } - return e; -} - -static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r ) -{ - struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); - if( e ) - { - e->type = EXPR_COMPLEX; - e->u.expr.left = l; - e->u.expr.op = op; - e->u.expr.right = r; - } - return e; -} - -static struct expr * EXPR_column( LPWSTR str ) -{ - struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); - if( e ) - { - e->type = EXPR_COLUMN; - e->u.sval = str; - } - return e; -} - -static struct expr * EXPR_ival( struct sql_str *str ) -{ - struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); - if( e ) - { - e->type = EXPR_IVAL; - e->u.ival = atoiW( str->data ); - } - return e; -} - -static struct expr * EXPR_sval( struct sql_str *str ) -{ - struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); - if( e ) - { - e->type = EXPR_SVAL; - e->u.sval = SQL_getstring( str ); - } - return e; -} - -void delete_expr( struct expr *e ) -{ - if( !e ) - return; - if( e->type == EXPR_COMPLEX ) - { - delete_expr( e->u.expr.left ); - delete_expr( e->u.expr.right ); - } - else if( e->type == EXPR_UTF8 ) - HeapFree( GetProcessHeap(), 0, e->u.utf8 ); - else if( e->type == EXPR_SVAL ) - HeapFree( GetProcessHeap(), 0, e->u.sval ); - HeapFree( GetProcessHeap(), 0, e ); -} - -void delete_string_list( string_list *sl ) -{ - while( sl ) - { - string_list *t = sl->next; - HeapFree( GetProcessHeap(), 0, sl->string ); - HeapFree( GetProcessHeap(), 0, sl ); - sl = t; - } -} - -void delete_value_list( value_list *vl ) -{ - while( vl ) - { - value_list *t = vl->next; - delete_expr( vl->val ); - HeapFree( GetProcessHeap(), 0, vl ); - vl = t; - } -} - -static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, - string_list *keys ) -{ - string_list *k; - BOOL found = TRUE; - - for( k = keys; k && found; k = k->next ) - { - create_col_info *c; - - found = FALSE; - for( c = cols; c && !found; c = c->next ) - { - if( lstrcmpW( k->string, c->colname ) ) - continue; - c->type |= MSITYPE_KEY; - found = TRUE; - } - } - - return found; -} - -UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview ) -{ - SQL_input sql; - int r; - - *phview = NULL; - - sql.db = db; - sql.command = command; - sql.n = 0; - sql.len = 0; - sql.view = phview; - - r = SQL_parse(&sql); - - TRACE("Parse returned %d\n", r); - if( r ) - { - if( *sql.view ) - (*sql.view)->ops->delete( *sql.view ); - *sql.view = NULL; - return ERROR_BAD_QUERY_SYNTAX; - } - - return ERROR_SUCCESS; -} +/* A Bison parser, made by GNU Bison 1.875b. */ + +/* Skeleton parser for Yacc-like parsing with Bison, + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* Written by Richard Stallman by simplifying the original so called + ``semantic'' parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + +/* If NAME_PREFIX is specified substitute the variables and functions + names. */ +#define yyparse SQL_parse +#define yylex SQL_lex +#define yyerror SQL_error +#define yylval SQL_lval +#define yychar SQL_char +#define yydebug SQL_debug +#define yynerrs SQL_nerrs + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + TK_ABORT = 258, + TK_AFTER = 259, + TK_AGG_FUNCTION = 260, + TK_ALL = 261, + TK_AND = 262, + TK_AS = 263, + TK_ASC = 264, + TK_BEFORE = 265, + TK_BEGIN = 266, + TK_BETWEEN = 267, + TK_BITAND = 268, + TK_BITNOT = 269, + TK_BITOR = 270, + TK_BY = 271, + TK_CASCADE = 272, + TK_CASE = 273, + TK_CHAR = 274, + TK_CHECK = 275, + TK_CLUSTER = 276, + TK_COLLATE = 277, + TK_COLUMN = 278, + TK_COMMA = 279, + TK_COMMENT = 280, + TK_COMMIT = 281, + TK_CONCAT = 282, + TK_CONFLICT = 283, + TK_CONSTRAINT = 284, + TK_COPY = 285, + TK_CREATE = 286, + TK_DEFAULT = 287, + TK_DEFERRABLE = 288, + TK_DEFERRED = 289, + TK_DELETE = 290, + TK_DELIMITERS = 291, + TK_DESC = 292, + TK_DISTINCT = 293, + TK_DOT = 294, + TK_DROP = 295, + TK_EACH = 296, + TK_ELSE = 297, + TK_END = 298, + TK_END_OF_FILE = 299, + TK_EQ = 300, + TK_EXCEPT = 301, + TK_EXPLAIN = 302, + TK_FAIL = 303, + TK_FLOAT = 304, + TK_FOR = 305, + TK_FOREIGN = 306, + TK_FROM = 307, + TK_FUNCTION = 308, + TK_GE = 309, + TK_GLOB = 310, + TK_GROUP = 311, + TK_GT = 312, + TK_HAVING = 313, + TK_HOLD = 314, + TK_IGNORE = 315, + TK_ILLEGAL = 316, + TK_IMMEDIATE = 317, + TK_IN = 318, + TK_INDEX = 319, + TK_INITIALLY = 320, + TK_ID = 321, + TK_INSERT = 322, + TK_INSTEAD = 323, + TK_INT = 324, + TK_INTEGER = 325, + TK_INTERSECT = 326, + TK_INTO = 327, + TK_IS = 328, + TK_ISNULL = 329, + TK_JOIN = 330, + TK_JOIN_KW = 331, + TK_KEY = 332, + TK_LE = 333, + TK_LIKE = 334, + TK_LIMIT = 335, + TK_LONG = 336, + TK_LONGCHAR = 337, + TK_LP = 338, + TK_LSHIFT = 339, + TK_LT = 340, + TK_LOCALIZABLE = 341, + TK_MATCH = 342, + TK_MINUS = 343, + TK_NE = 344, + TK_NOT = 345, + TK_NOTNULL = 346, + TK_NULL = 347, + TK_OBJECT = 348, + TK_OF = 349, + TK_OFFSET = 350, + TK_ON = 351, + TK_OR = 352, + TK_ORACLE_OUTER_JOIN = 353, + TK_ORDER = 354, + TK_PLUS = 355, + TK_PRAGMA = 356, + TK_PRIMARY = 357, + TK_RAISE = 358, + TK_REFERENCES = 359, + TK_REM = 360, + TK_REPLACE = 361, + TK_RESTRICT = 362, + TK_ROLLBACK = 363, + TK_ROW = 364, + TK_RP = 365, + TK_RSHIFT = 366, + TK_SELECT = 367, + TK_SEMI = 368, + TK_SET = 369, + TK_SHORT = 370, + TK_SLASH = 371, + TK_SPACE = 372, + TK_STAR = 373, + TK_STATEMENT = 374, + TK_STRING = 375, + TK_TABLE = 376, + TK_TEMP = 377, + TK_THEN = 378, + TK_TRANSACTION = 379, + TK_TRIGGER = 380, + TK_UMINUS = 381, + TK_UNCLOSED_STRING = 382, + TK_UNION = 383, + TK_UNIQUE = 384, + TK_UPDATE = 385, + TK_UPLUS = 386, + TK_USING = 387, + TK_VACUUM = 388, + TK_VALUES = 389, + TK_VIEW = 390, + TK_WHEN = 391, + TK_WHERE = 392, + TK_WILDCARD = 393, + COLUMN = 395, + FUNCTION = 396, + COMMENT = 397, + UNCLOSED_STRING = 398, + SPACE = 399, + ILLEGAL = 400, + END_OF_FILE = 401 + }; +#endif +#define TK_ABORT 258 +#define TK_AFTER 259 +#define TK_AGG_FUNCTION 260 +#define TK_ALL 261 +#define TK_AND 262 +#define TK_AS 263 +#define TK_ASC 264 +#define TK_BEFORE 265 +#define TK_BEGIN 266 +#define TK_BETWEEN 267 +#define TK_BITAND 268 +#define TK_BITNOT 269 +#define TK_BITOR 270 +#define TK_BY 271 +#define TK_CASCADE 272 +#define TK_CASE 273 +#define TK_CHAR 274 +#define TK_CHECK 275 +#define TK_CLUSTER 276 +#define TK_COLLATE 277 +#define TK_COLUMN 278 +#define TK_COMMA 279 +#define TK_COMMENT 280 +#define TK_COMMIT 281 +#define TK_CONCAT 282 +#define TK_CONFLICT 283 +#define TK_CONSTRAINT 284 +#define TK_COPY 285 +#define TK_CREATE 286 +#define TK_DEFAULT 287 +#define TK_DEFERRABLE 288 +#define TK_DEFERRED 289 +#define TK_DELETE 290 +#define TK_DELIMITERS 291 +#define TK_DESC 292 +#define TK_DISTINCT 293 +#define TK_DOT 294 +#define TK_DROP 295 +#define TK_EACH 296 +#define TK_ELSE 297 +#define TK_END 298 +#define TK_END_OF_FILE 299 +#define TK_EQ 300 +#define TK_EXCEPT 301 +#define TK_EXPLAIN 302 +#define TK_FAIL 303 +#define TK_FLOAT 304 +#define TK_FOR 305 +#define TK_FOREIGN 306 +#define TK_FROM 307 +#define TK_FUNCTION 308 +#define TK_GE 309 +#define TK_GLOB 310 +#define TK_GROUP 311 +#define TK_GT 312 +#define TK_HAVING 313 +#define TK_HOLD 314 +#define TK_IGNORE 315 +#define TK_ILLEGAL 316 +#define TK_IMMEDIATE 317 +#define TK_IN 318 +#define TK_INDEX 319 +#define TK_INITIALLY 320 +#define TK_ID 321 +#define TK_INSERT 322 +#define TK_INSTEAD 323 +#define TK_INT 324 +#define TK_INTEGER 325 +#define TK_INTERSECT 326 +#define TK_INTO 327 +#define TK_IS 328 +#define TK_ISNULL 329 +#define TK_JOIN 330 +#define TK_JOIN_KW 331 +#define TK_KEY 332 +#define TK_LE 333 +#define TK_LIKE 334 +#define TK_LIMIT 335 +#define TK_LONG 336 +#define TK_LONGCHAR 337 +#define TK_LP 338 +#define TK_LSHIFT 339 +#define TK_LT 340 +#define TK_LOCALIZABLE 341 +#define TK_MATCH 342 +#define TK_MINUS 343 +#define TK_NE 344 +#define TK_NOT 345 +#define TK_NOTNULL 346 +#define TK_NULL 347 +#define TK_OBJECT 348 +#define TK_OF 349 +#define TK_OFFSET 350 +#define TK_ON 351 +#define TK_OR 352 +#define TK_ORACLE_OUTER_JOIN 353 +#define TK_ORDER 354 +#define TK_PLUS 355 +#define TK_PRAGMA 356 +#define TK_PRIMARY 357 +#define TK_RAISE 358 +#define TK_REFERENCES 359 +#define TK_REM 360 +#define TK_REPLACE 361 +#define TK_RESTRICT 362 +#define TK_ROLLBACK 363 +#define TK_ROW 364 +#define TK_RP 365 +#define TK_RSHIFT 366 +#define TK_SELECT 367 +#define TK_SEMI 368 +#define TK_SET 369 +#define TK_SHORT 370 +#define TK_SLASH 371 +#define TK_SPACE 372 +#define TK_STAR 373 +#define TK_STATEMENT 374 +#define TK_STRING 375 +#define TK_TABLE 376 +#define TK_TEMP 377 +#define TK_THEN 378 +#define TK_TRANSACTION 379 +#define TK_TRIGGER 380 +#define TK_UMINUS 381 +#define TK_UNCLOSED_STRING 382 +#define TK_UNION 383 +#define TK_UNIQUE 384 +#define TK_UPDATE 385 +#define TK_UPLUS 386 +#define TK_USING 387 +#define TK_VACUUM 388 +#define TK_VALUES 389 +#define TK_VIEW 390 +#define TK_WHEN 391 +#define TK_WHERE 392 +#define TK_WILDCARD 393 +#define COLUMN 395 +#define FUNCTION 396 +#define COMMENT 397 +#define UNCLOSED_STRING 398 +#define SPACE 399 +#define ILLEGAL 400 +#define END_OF_FILE 401 + + + + +/* Copy the first part of user declarations. */ +#line 1 "./sql.y" + + +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002-2004 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "config.h" + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "query.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +#define YYLEX_PARAM info +#define YYPARSE_PARAM info + +extern int SQL_error(const char *str); + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +typedef struct tag_SQL_input +{ + MSIDATABASE *db; + LPCWSTR command; + DWORD n, len; + MSIVIEW **view; /* view structure for the resulting query */ +} SQL_input; + +static LPWSTR SQL_getstring( struct sql_str *str ); +static INT SQL_getint( SQL_input *sql ); +static int SQL_lex( void *SQL_lval, SQL_input *info); + +static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, + string_list *columns ); +static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in, + string_list *columns ); + +static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, + string_list *keys); + +static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r ); +static struct expr * EXPR_column( LPWSTR ); +static struct expr * EXPR_ival( struct sql_str *, int sign); +static struct expr * EXPR_sval( struct sql_str *); +static struct expr * EXPR_wildcard(void); + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) +#line 74 "./sql.y" +typedef union YYSTYPE { + struct sql_str str; + LPWSTR string; + string_list *column_list; + value_list *val_list; + MSIVIEW *query; + struct expr *expr; + USHORT column_type; + create_col_info *column_info; + column_assignment update_col_info; +} YYSTYPE; +/* Line 191 of yacc.c. */ +#line 457 "sql.tab.c" +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +/* Copy the second part of user declarations. */ + + +/* Line 214 of yacc.c. */ +#line 469 "sql.tab.c" + +#if ! defined (yyoverflow) || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# if YYSTACK_USE_ALLOCA +# define YYSTACK_ALLOC alloca +# else +# ifndef YYSTACK_USE_ALLOCA +# if defined (alloca) || defined (_ALLOCA_H) +# define YYSTACK_ALLOC alloca +# else +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# else +# if defined (__STDC__) || defined (__cplusplus) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +# define YYSTACK_ALLOC malloc +# define YYSTACK_FREE free +# endif +#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */ + + +#if (! defined (yyoverflow) \ + && (! defined (__cplusplus) \ + || (YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + short yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + register YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (0) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined (__STDC__) || defined (__cplusplus) + typedef signed char yysigned_char; +#else + typedef short yysigned_char; +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 23 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 125 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 147 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 25 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 63 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 123 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 401 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const unsigned char yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const unsigned char yyprhs[] = +{ + 0, 0, 3, 5, 7, 9, 11, 22, 34, 41, + 49, 56, 61, 66, 69, 71, 74, 76, 80, 82, + 87, 89, 91, 93, 95, 97, 99, 104, 106, 110, + 115, 117, 121, 123, 126, 131, 135, 139, 143, 147, + 151, 155, 159, 163, 167, 171, 175, 180, 182, 184, + 186, 190, 192, 196, 200, 202, 205, 207, 209, 211, + 215, 217, 219, 221 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const short yyrhs[] = +{ + 148, 0, -1, 158, -1, 150, -1, 149, -1, 151, + -1, 67, 72, 170, 83, 160, 110, 134, 83, 164, + 110, -1, 67, 72, 170, 83, 160, 110, 134, 83, + 164, 110, 122, -1, 31, 121, 170, 83, 152, 110, + -1, 31, 121, 170, 83, 152, 110, 59, -1, 130, + 170, 114, 165, 137, 162, -1, 153, 102, 77, 160, + -1, 153, 24, 169, 154, -1, 169, 154, -1, 155, + -1, 155, 86, -1, 156, -1, 156, 90, 92, -1, + 19, -1, 19, 83, 157, 110, -1, 82, -1, 115, + -1, 69, -1, 81, -1, 93, -1, 70, -1, 159, + 99, 16, 160, -1, 159, -1, 112, 160, 161, -1, + 112, 38, 160, 161, -1, 169, -1, 169, 24, 160, + -1, 118, -1, 52, 170, -1, 52, 170, 137, 162, + -1, 83, 162, 110, -1, 168, 45, 168, -1, 162, + 7, 162, -1, 162, 97, 162, -1, 168, 45, 163, + -1, 168, 57, 163, -1, 168, 85, 163, -1, 168, + 78, 163, -1, 168, 54, 163, -1, 168, 89, 163, + -1, 168, 73, 92, -1, 168, 73, 90, 92, -1, + 168, -1, 167, -1, 167, -1, 164, 24, 167, -1, + 166, -1, 166, 24, 165, -1, 169, 45, 167, -1, + 70, -1, 88, 70, -1, 120, -1, 138, -1, 169, + -1, 170, 39, 171, -1, 171, -1, 171, -1, 66, + -1, 120, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const unsigned short yyrline[] = +{ + 0, 142, 142, 147, 152, 157, 165, 173, 184, 194, + 207, 218, 228, 247, 259, 263, 271, 275, 282, 286, + 290, 294, 298, 302, 306, 313, 324, 335, 339, 353, + 371, 384, 397, 404, 415, 434, 438, 442, 446, 450, + 454, 458, 462, 466, 470, 474, 478, 485, 486, 490, + 502, 518, 519, 528, 544, 548, 552, 556, 563, 570, + 574, 581, 588, 592 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE +/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "TK_ABORT", "TK_AFTER", "TK_AGG_FUNCTION", + "TK_ALL", "TK_AND", "TK_AS", "TK_ASC", "TK_BEFORE", "TK_BEGIN", + "TK_BETWEEN", "TK_BITAND", "TK_BITNOT", "TK_BITOR", "TK_BY", + "TK_CASCADE", "TK_CASE", "TK_CHAR", "TK_CHECK", "TK_CLUSTER", + "TK_COLLATE", "TK_COLUMN", "TK_COMMA", "TK_COMMENT", "TK_COMMIT", + "TK_CONCAT", "TK_CONFLICT", "TK_CONSTRAINT", "TK_COPY", "TK_CREATE", + "TK_DEFAULT", "TK_DEFERRABLE", "TK_DEFERRED", "TK_DELETE", + "TK_DELIMITERS", "TK_DESC", "TK_DISTINCT", "TK_DOT", "TK_DROP", + "TK_EACH", "TK_ELSE", "TK_END", "TK_END_OF_FILE", "TK_EQ", "TK_EXCEPT", + "TK_EXPLAIN", "TK_FAIL", "TK_FLOAT", "TK_FOR", "TK_FOREIGN", "TK_FROM", + "TK_FUNCTION", "TK_GE", "TK_GLOB", "TK_GROUP", "TK_GT", "TK_HAVING", + "TK_HOLD", "TK_IGNORE", "TK_ILLEGAL", "TK_IMMEDIATE", "TK_IN", + "TK_INDEX", "TK_INITIALLY", "TK_ID", "TK_INSERT", "TK_INSTEAD", + "TK_INT", "TK_INTEGER", "TK_INTERSECT", "TK_INTO", "TK_IS", "TK_ISNULL", + "TK_JOIN", "TK_JOIN_KW", "TK_KEY", "TK_LE", "TK_LIKE", "TK_LIMIT", + "TK_LONG", "TK_LONGCHAR", "TK_LP", "TK_LSHIFT", "TK_LT", + "TK_LOCALIZABLE", "TK_MATCH", "TK_MINUS", "TK_NE", "TK_NOT", + "TK_NOTNULL", "TK_NULL", "TK_OBJECT", "TK_OF", "TK_OFFSET", "TK_ON", + "TK_OR", "TK_ORACLE_OUTER_JOIN", "TK_ORDER", "TK_PLUS", "TK_PRAGMA", + "TK_PRIMARY", "TK_RAISE", "TK_REFERENCES", "TK_REM", "TK_REPLACE", + "TK_RESTRICT", "TK_ROLLBACK", "TK_ROW", "TK_RP", "TK_RSHIFT", + "TK_SELECT", "TK_SEMI", "TK_SET", "TK_SHORT", "TK_SLASH", "TK_SPACE", + "TK_STAR", "TK_STATEMENT", "TK_STRING", "TK_TABLE", "TK_TEMP", + "TK_THEN", "TK_TRANSACTION", "TK_TRIGGER", "TK_UMINUS", + "TK_UNCLOSED_STRING", "TK_UNION", "TK_UNIQUE", "TK_UPDATE", "TK_UPLUS", + "TK_USING", "TK_VACUUM", "TK_VALUES", "TK_VIEW", "TK_WHEN", "TK_WHERE", + "TK_WILDCARD", "AGG_FUNCTION.", "COLUMN", "FUNCTION", "COMMENT", + "UNCLOSED_STRING", "SPACE", "ILLEGAL", "END_OF_FILE", "$accept", + "onequery", "oneinsert", "onecreate", "oneupdate", "table_def", + "column_def", "column_type", "data_type_l", "data_type", "data_count", + "oneselect", "unorderedsel", "selcollist", "from", "expr", "val", + "constlist", "update_assign_list", "column_assignment", "const_val", + "column_val", "column", "table", "string_or_id", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const unsigned short yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, 399, 400, 401 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const unsigned char yyr1[] = +{ + 0, 147, 148, 148, 148, 148, 149, 149, 150, 150, + 151, 152, 153, 153, 154, 154, 155, 155, 156, 156, + 156, 156, 156, 156, 156, 157, 158, 158, 159, 159, + 160, 160, 160, 161, 161, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 163, 163, 164, + 164, 165, 165, 166, 167, 167, 167, 167, 168, 169, + 169, 170, 171, 171 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const unsigned char yyr2[] = +{ + 0, 2, 1, 1, 1, 1, 10, 11, 6, 7, + 6, 4, 4, 2, 1, 2, 1, 3, 1, 4, + 1, 1, 1, 1, 1, 1, 4, 1, 3, 4, + 1, 3, 1, 2, 4, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 4, 1, 1, 1, + 3, 1, 3, 3, 1, 2, 1, 1, 1, 3, + 1, 1, 1, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const unsigned char yydefact[] = +{ + 0, 0, 0, 0, 0, 0, 4, 3, 5, 2, + 27, 0, 0, 0, 62, 32, 63, 0, 30, 0, + 60, 0, 61, 1, 0, 0, 0, 0, 0, 28, + 0, 0, 0, 0, 0, 0, 29, 33, 31, 59, + 0, 51, 0, 26, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 0, 0, 18, 22, 23, 20, 24, + 21, 13, 14, 16, 0, 0, 34, 0, 58, 10, + 52, 54, 0, 56, 57, 53, 9, 0, 0, 0, + 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 55, 12, 11, 25, 0, 17, 0, + 35, 37, 38, 56, 39, 48, 36, 43, 47, 40, + 0, 45, 42, 41, 44, 19, 0, 49, 46, 0, + 6, 50, 7 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yysigned_char yydefgoto[] = +{ + -1, 5, 6, 7, 8, 44, 45, 61, 62, 63, + 97, 9, 10, 17, 29, 66, 104, 116, 40, 41, + 105, 67, 68, 19, 20 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -105 +static const yysigned_char yypact[] = +{ + -30, -104, -46, -34, -51, 21, -105, -105, -105, -105, + -77, -51, -51, -52, -105, -105, -105, -25, 7, -1, + 2, -79, -105, -105, 31, -33, -32, -25, -51, -105, + -52, -51, -51, -52, -51, -52, -105, -88, -105, -105, + -82, 33, 14, -105, -48, -15, -17, -43, -50, -50, + -51, -64, 13, -51, -2, -6, -105, -105, -105, -105, + -105, -105, 6, -9, -49, -50, -4, 26, -105, -4, + -105, -105, 24, -105, -105, -105, -105, -17, -52, 25, + -105, 9, 19, -7, -50, -50, -59, -59, -59, -44, + -59, -59, -59, -105, -105, -105, -105, -3, -105, -64, + -105, -4, -4, 73, -105, -105, -105, -105, -105, -105, + 22, -105, -105, -105, -105, -105, -19, -105, -105, -64, + 1, -105, -105 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yysigned_char yypgoto[] = +{ + -105, -105, -105, -105, -105, -105, -105, 42, -105, -105, + -105, -105, -105, -5, 97, -31, 18, -105, 75, -105, + -41, 30, 10, 85, 8 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -64 +static const yysigned_char yytable[] = +{ + 84, 1, 55, 84, 13, 119, 71, 14, 27, 53, + 75, 71, 22, 18, 14, 14, 14, 11, 69, 22, + 22, 23, 24, 18, 72, 38, 12, 28, 43, 72, + 47, 30, 14, 65, 83, 32, 22, 2, 31, 39, + 18, -61, 42, 18, 46, 18, 110, 33, 111, 48, + 34, 35, 56, 101, 102, 49, 73, 50, 117, 51, + 42, 103, 52, 77, 57, 58, 15, 64, 16, 16, + 16, 86, 76, 95, 74, 78, 59, 79, 121, 74, + 87, 81, 3, 88, 15, 82, 16, 54, 18, 21, + 85, 120, 80, 85, 93, 96, 25, 26, 60, 89, + 4, 98, 99, 100, 90, 107, 109, 115, 112, 113, + 114, 91, -63, 37, 118, 92, 106, 108, 108, 94, + 108, 108, 108, 122, 36, 70 +}; + +static const unsigned char yycheck[] = +{ + 7, 31, 19, 7, 38, 24, 70, 66, 13, 24, + 51, 70, 4, 3, 66, 66, 66, 121, 49, 11, + 12, 0, 99, 13, 88, 30, 72, 52, 33, 88, + 35, 24, 66, 83, 65, 114, 28, 67, 39, 31, + 30, 39, 32, 33, 34, 35, 90, 16, 92, 137, + 83, 83, 69, 84, 85, 137, 120, 24, 99, 45, + 50, 120, 110, 53, 81, 82, 118, 110, 120, 120, + 120, 45, 59, 78, 138, 77, 93, 83, 119, 138, + 54, 90, 112, 57, 118, 134, 120, 102, 78, 4, + 97, 110, 86, 97, 70, 70, 11, 12, 115, 73, + 130, 92, 83, 110, 78, 87, 88, 110, 90, 91, + 92, 85, 39, 28, 92, 89, 86, 87, 88, 77, + 90, 91, 92, 122, 27, 50 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const unsigned char yystos[] = +{ + 0, 31, 67, 112, 130, 148, 149, 150, 151, 158, + 159, 121, 72, 38, 66, 118, 120, 160, 169, 170, + 171, 170, 171, 0, 99, 170, 170, 160, 52, 161, + 24, 39, 114, 16, 83, 83, 161, 170, 160, 171, + 165, 166, 169, 160, 152, 153, 169, 160, 137, 137, + 24, 45, 110, 24, 102, 19, 69, 81, 82, 93, + 115, 154, 155, 156, 110, 83, 162, 168, 169, 162, + 165, 70, 88, 120, 138, 167, 59, 169, 77, 83, + 86, 90, 134, 162, 7, 97, 45, 54, 57, 73, + 78, 85, 89, 70, 154, 160, 70, 157, 92, 83, + 110, 162, 162, 120, 163, 167, 168, 163, 168, 163, + 90, 92, 163, 163, 163, 110, 164, 167, 92, 24, + 110, 167, 122 +}; + +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# if defined (__STDC__) || defined (__cplusplus) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int +#endif + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrlab1 + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror ("syntax error: cannot back up");\ + YYERROR; \ + } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +/* YYLLOC_DEFAULT -- Compute the default location (before the actions + are run). */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + Current.first_line = Rhs[1].first_line; \ + Current.first_column = Rhs[1].first_column; \ + Current.last_line = Rhs[N].last_line; \ + Current.last_column = Rhs[N].last_column; +#endif + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, YYLEX_PARAM) +#else +# define YYLEX yylex (&yylval) +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +# define YYDSYMPRINT(Args) \ +do { \ + if (yydebug) \ + yysymprint Args; \ +} while (0) + +# define YYDSYMPRINTF(Title, Token, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yysymprint (stderr, \ + Token, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (cinluded). | +`------------------------------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yy_stack_print (short *bottom, short *top) +#else +static void +yy_stack_print (bottom, top) + short *bottom; + short *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (/* Nothing. */; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yy_reduce_print (int yyrule) +#else +static void +yy_reduce_print (yyrule) + int yyrule; +#endif +{ + int yyi; + unsigned int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ", + yyrule - 1, yylno); + /* Print the symbols being reduced, and their result. */ + for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++) + YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]); + YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]); +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (Rule); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YYDSYMPRINT(Args) +# define YYDSYMPRINTF(Title, Token, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#if YYMAXDEPTH == 0 +# undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +yystrlen (const char *yystr) +# else +yystrlen (yystr) + const char *yystr; +# endif +{ + register const char *yys = yystr; + + while (*yys++ != '\0') + continue; + + return yys - yystr - 1; +} +# endif +# endif + +# ifndef yystpcpy +# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +yystpcpy (char *yydest, const char *yysrc) +# else +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +# endif +{ + register char *yyd = yydest; + register const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +#endif /* !YYERROR_VERBOSE */ + + + +#if YYDEBUG +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep) +#else +static void +yysymprint (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + /* Pacify ``unused variable'' warnings. */ + (void) yyvaluep; + + if (yytype < YYNTOKENS) + { + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); +# ifdef YYPRINT + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + } + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + switch (yytype) + { + default: + break; + } + YYFPRINTF (yyoutput, ")"); +} + +#endif /* ! YYDEBUG */ +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yydestruct (int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yytype, yyvaluep) + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + /* Pacify ``unused variable'' warnings. */ + (void) yyvaluep; + + switch (yytype) + { + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +int yyparse (void *YYPARSE_PARAM); +# else +int yyparse (); +# endif +#else /* ! YYPARSE_PARAM */ +#if defined (__STDC__) || defined (__cplusplus) +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +int yyparse (void *YYPARSE_PARAM) +# else +int yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +# endif +#else /* ! YYPARSE_PARAM */ +#if defined (__STDC__) || defined (__cplusplus) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + /* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + register int yystate; + register int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + short yyssa[YYINITDEPTH]; + short *yyss = yyssa; + register short *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + register YYSTYPE *yyvsp; + + + +#define YYPOPSTACK (yyvsp--, yyssp--) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ + int yylen; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. + */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyoverflowlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyoverflowlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + short *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyoverflowlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken])); + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; + + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + yystate = yyn; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: +#line 143 "./sql.y" + { + SQL_input* sql = (SQL_input*) info; + *sql->view = yyvsp[0].query; + ;} + break; + + case 3: +#line 148 "./sql.y" + { + SQL_input* sql = (SQL_input*) info; + *sql->view = yyvsp[0].query; + ;} + break; + + case 4: +#line 153 "./sql.y" + { + SQL_input* sql = (SQL_input*) info; + *sql->view = yyvsp[0].query; + ;} + break; + + case 5: +#line 158 "./sql.y" + { + SQL_input* sql = (SQL_input*) info; + *sql->view = yyvsp[0].query; + ;} + break; + + case 6: +#line 166 "./sql.y" + { + SQL_input *sql = (SQL_input*) info; + MSIVIEW *insert = NULL; + + INSERT_CreateView( sql->db, &insert, yyvsp[-7].string, yyvsp[-5].column_list, yyvsp[-1].val_list, FALSE ); + yyval.query = insert; + ;} + break; + + case 7: +#line 174 "./sql.y" + { + SQL_input *sql = (SQL_input*) info; + MSIVIEW *insert = NULL; + + INSERT_CreateView( sql->db, &insert, yyvsp[-8].string, yyvsp[-6].column_list, yyvsp[-2].val_list, TRUE ); + yyval.query = insert; + ;} + break; + + case 8: +#line 185 "./sql.y" + { + SQL_input* sql = (SQL_input*) info; + MSIVIEW *create = NULL; + + if( !yyvsp[-1].column_info ) + YYABORT; + CREATE_CreateView( sql->db, &create, yyvsp[-3].string, yyvsp[-1].column_info, FALSE ); + yyval.query = create; + ;} + break; + + case 9: +#line 195 "./sql.y" + { + SQL_input* sql = (SQL_input*) info; + MSIVIEW *create = NULL; + + if( !yyvsp[-2].column_info ) + YYABORT; + CREATE_CreateView( sql->db, &create, yyvsp[-4].string, yyvsp[-2].column_info, TRUE ); + yyval.query = create; + ;} + break; + + case 10: +#line 208 "./sql.y" + { + SQL_input* sql = (SQL_input*) info; + MSIVIEW *update = NULL; + + UPDATE_CreateView( sql->db, &update, yyvsp[-4].string, &yyvsp[-2].update_col_info, yyvsp[0].expr ); + yyval.query = update; + ;} + break; + + case 11: +#line 219 "./sql.y" + { + if( SQL_MarkPrimaryKeys( yyvsp[-3].column_info, yyvsp[0].column_list ) ) + yyval.column_info = yyvsp[-3].column_info; + else + yyval.column_info = NULL; + ;} + break; + + case 12: +#line 229 "./sql.y" + { + create_col_info *ci; + + for( ci = yyvsp[-3].column_info; ci->next; ci = ci->next ) + ; + + ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info ); + if( !ci->next ) + { + /* FIXME: free $1 */ + YYABORT; + } + ci->next->colname = yyvsp[-1].string; + ci->next->type = yyvsp[0].column_type; + ci->next->next = NULL; + + yyval.column_info = yyvsp[-3].column_info; + ;} + break; + + case 13: +#line 248 "./sql.y" + { + yyval.column_info = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info ); + if( ! yyval.column_info ) + YYABORT; + yyval.column_info->colname = yyvsp[-1].string; + yyval.column_info->type = yyvsp[0].column_type; + yyval.column_info->next = NULL; + ;} + break; + + case 14: +#line 260 "./sql.y" + { + yyval.column_type = yyvsp[0].column_type | MSITYPE_VALID; + ;} + break; + + case 15: +#line 264 "./sql.y" + { + FIXME("LOCALIZABLE ignored\n"); + yyval.column_type = yyvsp[-1].column_type | MSITYPE_VALID; + ;} + break; + + case 16: +#line 272 "./sql.y" + { + yyval.column_type |= MSITYPE_NULLABLE; + ;} + break; + + case 17: +#line 276 "./sql.y" + { + yyval.column_type = yyvsp[-2].column_type; + ;} + break; + + case 18: +#line 283 "./sql.y" + { + yyval.column_type = MSITYPE_STRING | 1; + ;} + break; + + case 19: +#line 287 "./sql.y" + { + yyval.column_type = MSITYPE_STRING | 0x400 | yyvsp[-1].column_type; + ;} + break; + + case 20: +#line 291 "./sql.y" + { + yyval.column_type = 2; + ;} + break; + + case 21: +#line 295 "./sql.y" + { + yyval.column_type = 2; + ;} + break; + + case 22: +#line 299 "./sql.y" + { + yyval.column_type = 2; + ;} + break; + + case 23: +#line 303 "./sql.y" + { + yyval.column_type = 4; + ;} + break; + + case 24: +#line 307 "./sql.y" + { + yyval.column_type = 0; + ;} + break; + + case 25: +#line 314 "./sql.y" + { + SQL_input* sql = (SQL_input*) info; + int val = SQL_getint(sql); + if( ( val > 255 ) || ( val < 0 ) ) + YYABORT; + yyval.column_type = val; + ;} + break; + + case 26: +#line 325 "./sql.y" + { + SQL_input* sql = (SQL_input*) info; + + if( !yyvsp[-3].query ) + YYABORT; + if( yyvsp[0].column_list ) + yyval.query = do_order_by( sql->db, yyvsp[-3].query, yyvsp[0].column_list ); + else + yyval.query = yyvsp[-3].query; + ;} + break; + + case 28: +#line 340 "./sql.y" + { + SQL_input* sql = (SQL_input*) info; + if( !yyvsp[0].query ) + YYABORT; + if( yyvsp[-1].column_list ) + { + yyval.query = do_one_select( sql->db, yyvsp[0].query, yyvsp[-1].column_list ); + if( !yyval.query ) + YYABORT; + } + else + yyval.query = yyvsp[0].query; + ;} + break; + + case 29: +#line 354 "./sql.y" + { + SQL_input* sql = (SQL_input*) info; + MSIVIEW *view = yyvsp[0].query; + + if( !view ) + YYABORT; + if( yyvsp[-1].column_list ) + { + view = do_one_select( sql->db, view, yyvsp[-1].column_list ); + if( !view ) + YYABORT; + } + DISTINCT_CreateView( sql->db, & yyval.query, view ); + ;} + break; + + case 30: +#line 372 "./sql.y" + { + string_list *list; + + list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); + if( !list ) + YYABORT; + list->string = yyvsp[0].string; + list->next = NULL; + + yyval.column_list = list; + TRACE("Collist %s\n",debugstr_w(yyval.column_list->string)); + ;} + break; + + case 31: +#line 385 "./sql.y" + { + string_list *list; + + list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); + if( !list ) + YYABORT; + list->string = yyvsp[-2].string; + list->next = yyvsp[0].column_list; + + yyval.column_list = list; + TRACE("From table: %s\n",debugstr_w(yyval.column_list->string)); + ;} + break; + + case 32: +#line 398 "./sql.y" + { + yyval.column_list = NULL; + ;} + break; + + case 33: +#line 405 "./sql.y" + { + SQL_input* sql = (SQL_input*) info; + UINT r; + + yyval.query = NULL; + TRACE("From table: %s\n",debugstr_w(yyvsp[0].string)); + r = TABLE_CreateView( sql->db, yyvsp[0].string, & yyval.query ); + if( r != ERROR_SUCCESS ) + YYABORT; + ;} + break; + + case 34: +#line 416 "./sql.y" + { + SQL_input* sql = (SQL_input*) info; + MSIVIEW *view = NULL; + UINT r; + + yyval.query = NULL; + TRACE("From table: %s\n",debugstr_w(yyvsp[-2].string)); + r = TABLE_CreateView( sql->db, yyvsp[-2].string, &view ); + if( r != ERROR_SUCCESS ) + YYABORT; + r = WHERE_CreateView( sql->db, &view, view, yyvsp[0].expr ); + if( r != ERROR_SUCCESS ) + YYABORT; + yyval.query = view; + ;} + break; + + case 35: +#line 435 "./sql.y" + { + yyval.expr = yyvsp[-1].expr; + ;} + break; + + case 36: +#line 439 "./sql.y" + { + yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_EQ, yyvsp[0].expr ); + ;} + break; + + case 37: +#line 443 "./sql.y" + { + yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_AND, yyvsp[0].expr ); + ;} + break; + + case 38: +#line 447 "./sql.y" + { + yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_OR, yyvsp[0].expr ); + ;} + break; + + case 39: +#line 451 "./sql.y" + { + yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_EQ, yyvsp[0].expr ); + ;} + break; + + case 40: +#line 455 "./sql.y" + { + yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_GT, yyvsp[0].expr ); + ;} + break; + + case 41: +#line 459 "./sql.y" + { + yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_LT, yyvsp[0].expr ); + ;} + break; + + case 42: +#line 463 "./sql.y" + { + yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_LE, yyvsp[0].expr ); + ;} + break; + + case 43: +#line 467 "./sql.y" + { + yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_GE, yyvsp[0].expr ); + ;} + break; + + case 44: +#line 471 "./sql.y" + { + yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_NE, yyvsp[0].expr ); + ;} + break; + + case 45: +#line 475 "./sql.y" + { + yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_ISNULL, NULL ); + ;} + break; + + case 46: +#line 479 "./sql.y" + { + yyval.expr = EXPR_complex( yyvsp[-3].expr, OP_NOTNULL, NULL ); + ;} + break; + + case 49: +#line 491 "./sql.y" + { + value_list *vals; + + vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals ); + if( vals ) + { + vals->val = yyvsp[0].expr; + vals->next = NULL; + } + yyval.val_list = vals; + ;} + break; + + case 50: +#line 503 "./sql.y" + { + value_list *vals; + + vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals ); + if( vals ) + { + vals->val = yyvsp[0].expr; + vals->next = NULL; + } + yyvsp[-2].val_list->next = vals; + yyval.val_list = yyvsp[-2].val_list; + ;} + break; + + case 52: +#line 520 "./sql.y" + { + yyvsp[-2].update_col_info.col_list->next = yyvsp[0].update_col_info.col_list; + yyvsp[-2].update_col_info.val_list->next = yyvsp[0].update_col_info.val_list; + yyval.update_col_info = yyvsp[-2].update_col_info; + ;} + break; + + case 53: +#line 529 "./sql.y" + { + yyval.update_col_info.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.col_list ); + if( !yyval.update_col_info.col_list ) + YYABORT; + yyval.update_col_info.col_list->string = yyvsp[-2].string; + yyval.update_col_info.col_list->next = NULL; + yyval.update_col_info.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.val_list ); + if( !yyval.update_col_info.val_list ) + YYABORT; + yyval.update_col_info.val_list->val = yyvsp[0].expr; + yyval.update_col_info.val_list->next = 0; + ;} + break; + + case 54: +#line 545 "./sql.y" + { + yyval.expr = EXPR_ival( &yyvsp[0].str, 1 ); + ;} + break; + + case 55: +#line 549 "./sql.y" + { + yyval.expr = EXPR_ival( &yyvsp[0].str, -1 ); + ;} + break; + + case 56: +#line 553 "./sql.y" + { + yyval.expr = EXPR_sval( &yyvsp[0].str ); + ;} + break; + + case 57: +#line 557 "./sql.y" + { + yyval.expr = EXPR_wildcard(); + ;} + break; + + case 58: +#line 564 "./sql.y" + { + yyval.expr = EXPR_column( yyvsp[0].string ); + ;} + break; + + case 59: +#line 571 "./sql.y" + { + yyval.string = yyvsp[0].string; /* FIXME */ + ;} + break; + + case 60: +#line 575 "./sql.y" + { + yyval.string = yyvsp[0].string; + ;} + break; + + case 61: +#line 582 "./sql.y" + { + yyval.string = yyvsp[0].string; + ;} + break; + + case 62: +#line 589 "./sql.y" + { + yyval.string = SQL_getstring( &yyvsp[0].str ); + ;} + break; + + case 63: +#line 593 "./sql.y" + { + yyval.string = SQL_getstring( &yyvsp[0].str ); + ;} + break; + + + } + +/* Line 999 of yacc.c. */ +#line 2055 "sql.tab.c" + + yyvsp -= yylen; + yyssp -= yylen; + + + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (YYPACT_NINF < yyn && yyn < YYLAST) + { + YYSIZE_T yysize = 0; + int yytype = YYTRANSLATE (yychar); + const char* yyprefix; + char *yymsg; + int yyx; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 0; + + yyprefix = ", expecting "; + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]); + yycount += 1; + if (yycount == 5) + { + yysize = 0; + break; + } + } + yysize += (sizeof ("syntax error, unexpected ") + + yystrlen (yytname[yytype])); + yymsg = (char *) YYSTACK_ALLOC (yysize); + if (yymsg != 0) + { + char *yyp = yystpcpy (yymsg, "syntax error, unexpected "); + yyp = yystpcpy (yyp, yytname[yytype]); + + if (yycount < 5) + { + yyprefix = ", expecting "; + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + yyp = yystpcpy (yyp, yyprefix); + yyp = yystpcpy (yyp, yytname[yyx]); + yyprefix = " or "; + } + } + yyerror (yymsg); + YYSTACK_FREE (yymsg); + } + else + yyerror ("syntax error; also virtual memory exhausted"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror ("syntax error"); + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + /* Return failure if at end of input. */ + if (yychar == YYEOF) + { + /* Pop the error token. */ + YYPOPSTACK; + /* Pop the rest of the stack. */ + while (yyss < yyssp) + { + YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); + yydestruct (yystos[*yyssp], yyvsp); + YYPOPSTACK; + } + YYABORT; + } + + YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc); + yydestruct (yytoken, &yylval); + yychar = YYEMPTY; + + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*----------------------------------------------------. +| yyerrlab1 -- error raised explicitly by an action. | +`----------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); + yydestruct (yystos[yystate], yyvsp); + yyvsp--; + yystate = *--yyssp; + + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + YYDPRINTF ((stderr, "Shifting error token, ")); + + *++yyvsp = yylval; + + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*----------------------------------------------. +| yyoverflowlab -- parser overflow comes here. | +`----------------------------------------------*/ +yyoverflowlab: + yyerror ("parser stack overflow"); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + return yyresult; +} + + +#line 598 "./sql.y" + + +int SQL_lex( void *SQL_lval, SQL_input *sql) +{ + int token; + struct sql_str * str = SQL_lval; + + do + { + sql->n += sql->len; + if( ! sql->command[sql->n] ) + return 0; /* end of input */ + + TRACE("string : %s\n", debugstr_w(&sql->command[sql->n])); + sql->len = sqliteGetToken( &sql->command[sql->n], &token ); + if( sql->len==0 ) + break; + str->data = &sql->command[sql->n]; + str->len = sql->len; + } + while( token == TK_SPACE ); + + TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len)); + + return token; +} + +LPWSTR SQL_getstring( struct sql_str *strdata) +{ + LPCWSTR p = strdata->data; + UINT len = strdata->len; + LPWSTR str; + + /* if there's quotes, remove them */ + if( ( (p[0]=='`') && (p[len-1]=='`') ) || + ( (p[0]=='\'') && (p[len-1]=='\'') ) ) + { + p++; + len -= 2; + } + str = HeapAlloc( GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR)); + if(!str ) + return str; + memcpy(str, p, len*sizeof(WCHAR) ); + str[len]=0; + + return str; +} + +INT SQL_getint( SQL_input *sql ) +{ + LPCWSTR p = &sql->command[sql->n]; + + return atoiW( p ); +} + +int SQL_error(const char *str) +{ + return 0; +} + +static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, + string_list *columns ) +{ + MSIVIEW *view = NULL; + + SELECT_CreateView( db, &view, in, columns ); + delete_string_list( columns ); + if( !view ) + ERR("Error creating select query\n"); + return view; +} + +static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in, + string_list *columns ) +{ + MSIVIEW *view = NULL; + + ORDER_CreateView( db, &view, in ); + if( view ) + { + string_list *x = columns; + + for( x = columns; x ; x = x->next ) + ORDER_AddColumn( view, x->string ); + } + else + ERR("Error creating select query\n"); + delete_string_list( columns ); + return view; +} + +static struct expr * EXPR_wildcard() +{ + struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); + if( e ) + { + e->type = EXPR_WILDCARD; + } + return e; +} + +static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r ) +{ + struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); + if( e ) + { + e->type = EXPR_COMPLEX; + e->u.expr.left = l; + e->u.expr.op = op; + e->u.expr.right = r; + } + return e; +} + +static struct expr * EXPR_column( LPWSTR str ) +{ + struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); + if( e ) + { + e->type = EXPR_COLUMN; + e->u.sval = str; + } + return e; +} + +static struct expr * EXPR_ival( struct sql_str *str , int sign) +{ + struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); + if( e ) + { + e->type = EXPR_IVAL; + e->u.ival = atoiW( str->data ) * sign; + } + return e; +} + +static struct expr * EXPR_sval( struct sql_str *str ) +{ + struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); + if( e ) + { + e->type = EXPR_SVAL; + e->u.sval = SQL_getstring( str ); + } + return e; +} + +void delete_expr( struct expr *e ) +{ + if( !e ) + return; + if( e->type == EXPR_COMPLEX ) + { + delete_expr( e->u.expr.left ); + delete_expr( e->u.expr.right ); + } + else if( e->type == EXPR_UTF8 ) + HeapFree( GetProcessHeap(), 0, e->u.utf8 ); + else if( e->type == EXPR_SVAL ) + HeapFree( GetProcessHeap(), 0, e->u.sval ); + HeapFree( GetProcessHeap(), 0, e ); +} + +void delete_string_list( string_list *sl ) +{ + while( sl ) + { + string_list *t = sl->next; + HeapFree( GetProcessHeap(), 0, sl->string ); + HeapFree( GetProcessHeap(), 0, sl ); + sl = t; + } +} + +void delete_value_list( value_list *vl ) +{ + while( vl ) + { + value_list *t = vl->next; + delete_expr( vl->val ); + HeapFree( GetProcessHeap(), 0, vl ); + vl = t; + } +} + +static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, + string_list *keys ) +{ + string_list *k; + BOOL found = TRUE; + + for( k = keys; k && found; k = k->next ) + { + create_col_info *c; + + found = FALSE; + for( c = cols; c && !found; c = c->next ) + { + if( lstrcmpW( k->string, c->colname ) ) + continue; + c->type |= MSITYPE_KEY; + found = TRUE; + } + } + + return found; +} + +UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview ) +{ + SQL_input sql; + int r; + + *phview = NULL; + + sql.db = db; + sql.command = command; + sql.n = 0; + sql.len = 0; + sql.view = phview; + + r = SQL_parse(&sql); + + TRACE("Parse returned %d\n", r); + if( r ) + { + if( *sql.view ) + (*sql.view)->ops->delete( *sql.view ); + *sql.view = NULL; + return ERROR_BAD_QUERY_SYNTAX; + } + + return ERROR_SUCCESS; +} + diff --git a/reactos/lib/msi/sql.tab.h b/reactos/lib/msi/sql.tab.h index 62fdccd2012..bfc66b3f050 100644 --- a/reactos/lib/msi/sql.tab.h +++ b/reactos/lib/msi/sql.tab.h @@ -1,165 +1,347 @@ -#ifndef BISON_SQL_TAB_H -# define BISON_SQL_TAB_H - -#ifndef YYSTYPE -typedef union -{ - struct sql_str str; - LPWSTR string; - string_list *column_list; - value_list *val_list; - MSIVIEW *query; - struct expr *expr; - USHORT column_type; - create_col_info *column_info; - column_assignment update_col_info; -} yystype; -# define YYSTYPE yystype -# define YYSTYPE_IS_TRIVIAL 1 -#endif -# define TK_ABORT 257 -# define TK_AFTER 258 -# define TK_AGG_FUNCTION 259 -# define TK_ALL 260 -# define TK_AND 261 -# define TK_AS 262 -# define TK_ASC 263 -# define TK_BEFORE 264 -# define TK_BEGIN 265 -# define TK_BETWEEN 266 -# define TK_BITAND 267 -# define TK_BITNOT 268 -# define TK_BITOR 269 -# define TK_BY 270 -# define TK_CASCADE 271 -# define TK_CASE 272 -# define TK_CHAR 273 -# define TK_CHECK 274 -# define TK_CLUSTER 275 -# define TK_COLLATE 276 -# define TK_COLUMN 277 -# define TK_COMMA 278 -# define TK_COMMENT 279 -# define TK_COMMIT 280 -# define TK_CONCAT 281 -# define TK_CONFLICT 282 -# define TK_CONSTRAINT 283 -# define TK_COPY 284 -# define TK_CREATE 285 -# define TK_DEFAULT 286 -# define TK_DEFERRABLE 287 -# define TK_DEFERRED 288 -# define TK_DELETE 289 -# define TK_DELIMITERS 290 -# define TK_DESC 291 -# define TK_DISTINCT 292 -# define TK_DOT 293 -# define TK_DROP 294 -# define TK_EACH 295 -# define TK_ELSE 296 -# define TK_END 297 -# define TK_END_OF_FILE 298 -# define TK_EQ 299 -# define TK_EXCEPT 300 -# define TK_EXPLAIN 301 -# define TK_FAIL 302 -# define TK_FLOAT 303 -# define TK_FOR 304 -# define TK_FOREIGN 305 -# define TK_FROM 306 -# define TK_FUNCTION 307 -# define TK_GE 308 -# define TK_GLOB 309 -# define TK_GROUP 310 -# define TK_GT 311 -# define TK_HAVING 312 -# define TK_HOLD 313 -# define TK_IGNORE 314 -# define TK_ILLEGAL 315 -# define TK_IMMEDIATE 316 -# define TK_IN 317 -# define TK_INDEX 318 -# define TK_INITIALLY 319 -# define TK_ID 320 -# define TK_INSERT 321 -# define TK_INSTEAD 322 -# define TK_INT 323 -# define TK_INTEGER 324 -# define TK_INTERSECT 325 -# define TK_INTO 326 -# define TK_IS 327 -# define TK_ISNULL 328 -# define TK_JOIN 329 -# define TK_JOIN_KW 330 -# define TK_KEY 331 -# define TK_LE 332 -# define TK_LIKE 333 -# define TK_LIMIT 334 -# define TK_LONG 335 -# define TK_LONGCHAR 336 -# define TK_LP 337 -# define TK_LSHIFT 338 -# define TK_LT 339 -# define TK_LOCALIZABLE 340 -# define TK_MATCH 341 -# define TK_MINUS 342 -# define TK_NE 343 -# define TK_NOT 344 -# define TK_NOTNULL 345 -# define TK_NULL 346 -# define TK_OBJECT 347 -# define TK_OF 348 -# define TK_OFFSET 349 -# define TK_ON 350 -# define TK_OR 351 -# define TK_ORACLE_OUTER_JOIN 352 -# define TK_ORDER 353 -# define TK_PLUS 354 -# define TK_PRAGMA 355 -# define TK_PRIMARY 356 -# define TK_RAISE 357 -# define TK_REFERENCES 358 -# define TK_REM 359 -# define TK_REPLACE 360 -# define TK_RESTRICT 361 -# define TK_ROLLBACK 362 -# define TK_ROW 363 -# define TK_RP 364 -# define TK_RSHIFT 365 -# define TK_SELECT 366 -# define TK_SEMI 367 -# define TK_SET 368 -# define TK_SHORT 369 -# define TK_SLASH 370 -# define TK_SPACE 371 -# define TK_STAR 372 -# define TK_STATEMENT 373 -# define TK_STRING 374 -# define TK_TABLE 375 -# define TK_TEMP 376 -# define TK_THEN 377 -# define TK_TRANSACTION 378 -# define TK_TRIGGER 379 -# define TK_UMINUS 380 -# define TK_UNCLOSED_STRING 381 -# define TK_UNION 382 -# define TK_UNIQUE 383 -# define TK_UPDATE 384 -# define TK_UPLUS 385 -# define TK_USING 386 -# define TK_VACUUM 387 -# define TK_VALUES 388 -# define TK_VIEW 389 -# define TK_WHEN 390 -# define TK_WHERE 391 -# define TK_WILDCARD 392 -# define END_OF_FILE 393 -# define ILLEGAL 394 -# define SPACE 395 -# define UNCLOSED_STRING 396 -# define COMMENT 397 -# define FUNCTION 398 -# define COLUMN 399 - - -#endif /* not BISON_SQL_TAB_H */ +/* A Bison parser, made by GNU Bison 1.875b. */ + +/* Skeleton parser for Yacc-like parsing with Bison, + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + TK_ABORT = 258, + TK_AFTER = 259, + TK_AGG_FUNCTION = 260, + TK_ALL = 261, + TK_AND = 262, + TK_AS = 263, + TK_ASC = 264, + TK_BEFORE = 265, + TK_BEGIN = 266, + TK_BETWEEN = 267, + TK_BITAND = 268, + TK_BITNOT = 269, + TK_BITOR = 270, + TK_BY = 271, + TK_CASCADE = 272, + TK_CASE = 273, + TK_CHAR = 274, + TK_CHECK = 275, + TK_CLUSTER = 276, + TK_COLLATE = 277, + TK_COLUMN = 278, + TK_COMMA = 279, + TK_COMMENT = 280, + TK_COMMIT = 281, + TK_CONCAT = 282, + TK_CONFLICT = 283, + TK_CONSTRAINT = 284, + TK_COPY = 285, + TK_CREATE = 286, + TK_DEFAULT = 287, + TK_DEFERRABLE = 288, + TK_DEFERRED = 289, + TK_DELETE = 290, + TK_DELIMITERS = 291, + TK_DESC = 292, + TK_DISTINCT = 293, + TK_DOT = 294, + TK_DROP = 295, + TK_EACH = 296, + TK_ELSE = 297, + TK_END = 298, + TK_END_OF_FILE = 299, + TK_EQ = 300, + TK_EXCEPT = 301, + TK_EXPLAIN = 302, + TK_FAIL = 303, + TK_FLOAT = 304, + TK_FOR = 305, + TK_FOREIGN = 306, + TK_FROM = 307, + TK_FUNCTION = 308, + TK_GE = 309, + TK_GLOB = 310, + TK_GROUP = 311, + TK_GT = 312, + TK_HAVING = 313, + TK_HOLD = 314, + TK_IGNORE = 315, + TK_ILLEGAL = 316, + TK_IMMEDIATE = 317, + TK_IN = 318, + TK_INDEX = 319, + TK_INITIALLY = 320, + TK_ID = 321, + TK_INSERT = 322, + TK_INSTEAD = 323, + TK_INT = 324, + TK_INTEGER = 325, + TK_INTERSECT = 326, + TK_INTO = 327, + TK_IS = 328, + TK_ISNULL = 329, + TK_JOIN = 330, + TK_JOIN_KW = 331, + TK_KEY = 332, + TK_LE = 333, + TK_LIKE = 334, + TK_LIMIT = 335, + TK_LONG = 336, + TK_LONGCHAR = 337, + TK_LP = 338, + TK_LSHIFT = 339, + TK_LT = 340, + TK_LOCALIZABLE = 341, + TK_MATCH = 342, + TK_MINUS = 343, + TK_NE = 344, + TK_NOT = 345, + TK_NOTNULL = 346, + TK_NULL = 347, + TK_OBJECT = 348, + TK_OF = 349, + TK_OFFSET = 350, + TK_ON = 351, + TK_OR = 352, + TK_ORACLE_OUTER_JOIN = 353, + TK_ORDER = 354, + TK_PLUS = 355, + TK_PRAGMA = 356, + TK_PRIMARY = 357, + TK_RAISE = 358, + TK_REFERENCES = 359, + TK_REM = 360, + TK_REPLACE = 361, + TK_RESTRICT = 362, + TK_ROLLBACK = 363, + TK_ROW = 364, + TK_RP = 365, + TK_RSHIFT = 366, + TK_SELECT = 367, + TK_SEMI = 368, + TK_SET = 369, + TK_SHORT = 370, + TK_SLASH = 371, + TK_SPACE = 372, + TK_STAR = 373, + TK_STATEMENT = 374, + TK_STRING = 375, + TK_TABLE = 376, + TK_TEMP = 377, + TK_THEN = 378, + TK_TRANSACTION = 379, + TK_TRIGGER = 380, + TK_UMINUS = 381, + TK_UNCLOSED_STRING = 382, + TK_UNION = 383, + TK_UNIQUE = 384, + TK_UPDATE = 385, + TK_UPLUS = 386, + TK_USING = 387, + TK_VACUUM = 388, + TK_VALUES = 389, + TK_VIEW = 390, + TK_WHEN = 391, + TK_WHERE = 392, + TK_WILDCARD = 393, + COLUMN = 395, + FUNCTION = 396, + COMMENT = 397, + UNCLOSED_STRING = 398, + SPACE = 399, + ILLEGAL = 400, + END_OF_FILE = 401 + }; +#endif +#define TK_ABORT 258 +#define TK_AFTER 259 +#define TK_AGG_FUNCTION 260 +#define TK_ALL 261 +#define TK_AND 262 +#define TK_AS 263 +#define TK_ASC 264 +#define TK_BEFORE 265 +#define TK_BEGIN 266 +#define TK_BETWEEN 267 +#define TK_BITAND 268 +#define TK_BITNOT 269 +#define TK_BITOR 270 +#define TK_BY 271 +#define TK_CASCADE 272 +#define TK_CASE 273 +#define TK_CHAR 274 +#define TK_CHECK 275 +#define TK_CLUSTER 276 +#define TK_COLLATE 277 +#define TK_COLUMN 278 +#define TK_COMMA 279 +#define TK_COMMENT 280 +#define TK_COMMIT 281 +#define TK_CONCAT 282 +#define TK_CONFLICT 283 +#define TK_CONSTRAINT 284 +#define TK_COPY 285 +#define TK_CREATE 286 +#define TK_DEFAULT 287 +#define TK_DEFERRABLE 288 +#define TK_DEFERRED 289 +#define TK_DELETE 290 +#define TK_DELIMITERS 291 +#define TK_DESC 292 +#define TK_DISTINCT 293 +#define TK_DOT 294 +#define TK_DROP 295 +#define TK_EACH 296 +#define TK_ELSE 297 +#define TK_END 298 +#define TK_END_OF_FILE 299 +#define TK_EQ 300 +#define TK_EXCEPT 301 +#define TK_EXPLAIN 302 +#define TK_FAIL 303 +#define TK_FLOAT 304 +#define TK_FOR 305 +#define TK_FOREIGN 306 +#define TK_FROM 307 +#define TK_FUNCTION 308 +#define TK_GE 309 +#define TK_GLOB 310 +#define TK_GROUP 311 +#define TK_GT 312 +#define TK_HAVING 313 +#define TK_HOLD 314 +#define TK_IGNORE 315 +#define TK_ILLEGAL 316 +#define TK_IMMEDIATE 317 +#define TK_IN 318 +#define TK_INDEX 319 +#define TK_INITIALLY 320 +#define TK_ID 321 +#define TK_INSERT 322 +#define TK_INSTEAD 323 +#define TK_INT 324 +#define TK_INTEGER 325 +#define TK_INTERSECT 326 +#define TK_INTO 327 +#define TK_IS 328 +#define TK_ISNULL 329 +#define TK_JOIN 330 +#define TK_JOIN_KW 331 +#define TK_KEY 332 +#define TK_LE 333 +#define TK_LIKE 334 +#define TK_LIMIT 335 +#define TK_LONG 336 +#define TK_LONGCHAR 337 +#define TK_LP 338 +#define TK_LSHIFT 339 +#define TK_LT 340 +#define TK_LOCALIZABLE 341 +#define TK_MATCH 342 +#define TK_MINUS 343 +#define TK_NE 344 +#define TK_NOT 345 +#define TK_NOTNULL 346 +#define TK_NULL 347 +#define TK_OBJECT 348 +#define TK_OF 349 +#define TK_OFFSET 350 +#define TK_ON 351 +#define TK_OR 352 +#define TK_ORACLE_OUTER_JOIN 353 +#define TK_ORDER 354 +#define TK_PLUS 355 +#define TK_PRAGMA 356 +#define TK_PRIMARY 357 +#define TK_RAISE 358 +#define TK_REFERENCES 359 +#define TK_REM 360 +#define TK_REPLACE 361 +#define TK_RESTRICT 362 +#define TK_ROLLBACK 363 +#define TK_ROW 364 +#define TK_RP 365 +#define TK_RSHIFT 366 +#define TK_SELECT 367 +#define TK_SEMI 368 +#define TK_SET 369 +#define TK_SHORT 370 +#define TK_SLASH 371 +#define TK_SPACE 372 +#define TK_STAR 373 +#define TK_STATEMENT 374 +#define TK_STRING 375 +#define TK_TABLE 376 +#define TK_TEMP 377 +#define TK_THEN 378 +#define TK_TRANSACTION 379 +#define TK_TRIGGER 380 +#define TK_UMINUS 381 +#define TK_UNCLOSED_STRING 382 +#define TK_UNION 383 +#define TK_UNIQUE 384 +#define TK_UPDATE 385 +#define TK_UPLUS 386 +#define TK_USING 387 +#define TK_VACUUM 388 +#define TK_VALUES 389 +#define TK_VIEW 390 +#define TK_WHEN 391 +#define TK_WHERE 392 +#define TK_WILDCARD 393 +#define COLUMN 395 +#define FUNCTION 396 +#define COMMENT 397 +#define UNCLOSED_STRING 398 +#define SPACE 399 +#define ILLEGAL 400 +#define END_OF_FILE 401 + + + + +#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) +#line 74 "./sql.y" +typedef union YYSTYPE { + struct sql_str str; + LPWSTR string; + string_list *column_list; + value_list *val_list; + MSIVIEW *query; + struct expr *expr; + USHORT column_type; + create_col_info *column_info; + column_assignment update_col_info; +} YYSTYPE; +/* Line 1252 of yacc.c. */ +#line 339 "sql.tab.h" +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + + + diff --git a/reactos/lib/msi/sql.y b/reactos/lib/msi/sql.y index 709e78e3601..4f05a6a2892 100644 --- a/reactos/lib/msi/sql.y +++ b/reactos/lib/msi/sql.y @@ -62,7 +62,7 @@ static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r ); static struct expr * EXPR_column( LPWSTR ); -static struct expr * EXPR_ival( struct sql_str *); +static struct expr * EXPR_ival( struct sql_str *, int sign); static struct expr * EXPR_sval( struct sql_str *); static struct expr * EXPR_wildcard(void); @@ -543,7 +543,11 @@ column_assignment: const_val: TK_INTEGER { - $$ = EXPR_ival( &$1 ); + $$ = EXPR_ival( &$1, 1 ); + } + | TK_MINUS TK_INTEGER + { + $$ = EXPR_ival( &$2, -1 ); } | TK_STRING { @@ -717,13 +721,13 @@ static struct expr * EXPR_column( LPWSTR str ) return e; } -static struct expr * EXPR_ival( struct sql_str *str ) +static struct expr * EXPR_ival( struct sql_str *str , int sign) { struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); if( e ) { e->type = EXPR_IVAL; - e->u.ival = atoiW( str->data ); + e->u.ival = atoiW( str->data ) * sign; } return e; } diff --git a/reactos/lib/msi/table.c b/reactos/lib/msi/table.c index 7f097e9d0ad..52a5f01652a 100644 --- a/reactos/lib/msi/table.c +++ b/reactos/lib/msi/table.c @@ -1088,7 +1088,7 @@ static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT * return ERROR_FUNCTION_FAILED; } - TRACE("Data [%d][%d] = %d \n", row, col, *val ); + /* TRACE("Data [%d][%d] = %d \n", row, col, *val ); */ return ERROR_SUCCESS; } diff --git a/reactos/lib/msi/where.c b/reactos/lib/msi/where.c index 8500deec1eb..9ae20480cb9 100644 --- a/reactos/lib/msi/where.c +++ b/reactos/lib/msi/where.c @@ -137,7 +137,7 @@ static const WCHAR *STRING_evaluate( string_table *st, switch( expr->type ) { - case EXPR_COL_NUMBER: + case EXPR_COL_NUMBER_STRING: r = table->ops->fetch_int( table, row, expr->u.col_number, &val ); if( r != ERROR_SUCCESS ) return NULL; @@ -190,6 +190,7 @@ static UINT WHERE_evaluate( MSIDATABASE *db, MSIVIEW *table, UINT row, switch( cond->type ) { + case EXPR_COL_NUMBER_STRING: case EXPR_COL_NUMBER: return table->ops->fetch_int( table, row, cond->u.col_number, val ); @@ -368,9 +369,19 @@ static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr r = VIEW_find_column( table, cond->u.column, &val ); if( r == ERROR_SUCCESS ) { - *valid = 1; - cond->type = EXPR_COL_NUMBER; - cond->u.col_number = val; + UINT type = 0; + r = table->ops->get_column_info( table, val, NULL, &type ); + if( r == ERROR_SUCCESS ) + { + if (type&MSITYPE_STRING) + cond->type = EXPR_COL_NUMBER_STRING; + else + cond->type = EXPR_COL_NUMBER; + cond->u.col_number = val; + *valid = 1; + } + else + *valid = 0; } else { @@ -390,7 +401,9 @@ static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr /* check the type of the comparison */ if( ( cond->u.expr.left->type == EXPR_SVAL ) || - ( cond->u.expr.right->type == EXPR_SVAL ) ) + ( cond->u.expr.left->type == EXPR_COL_NUMBER_STRING ) || + ( cond->u.expr.right->type == EXPR_SVAL ) || + ( cond->u.expr.right->type == EXPR_COL_NUMBER_STRING ) ) { switch( cond->u.expr.op ) {