home *** CD-ROM | disk | FTP | other *** search
- /*
-
- Qparse.prg - Class Qparse reads in Visual dBASE 5.5 .QBE files and
- extracts table names, aliases, work areas, and relation
- information
-
- In addition, it flags relation conversion errors.
- Ex: Error: Expression in Relation
-
- Main Method - The main method of Qparse is Parse(), which returns
- an array reference in the following format:
-
- Alias Filepath/Name Area Set Rela TO Into Error Msg
- ------------------------------------------------------------------------------------------------
- CUSTFILE \TRANSELCO\CUSTFILE.DBF 1 UPPER(ADDRESS1) CONTAINR Error: Expression in Relation
- CONTAINR \TRANSELCO\CONTAINR.DBF 2
- DICT \TRANSELCO\DICT.DBF 3
-
- Note: - Elements are initialized to "", check for Len(trim()) for
- - -no- value
-
-
- Syntax - Set Proc to QParse.cc Addi
- f = New QParse()
- f.Parse('My.qbe')
-
- Author: - A. A. Katz (Ksoft, Inc) under contract to Borland, International
-
- (c) 1997 Borland International, All Rights Reserved
-
- Version: - V. 2.0 11-12-1997
-
- */
-
- #DEFINE ALIAS 1 // Alias of table
- #DEFINE TABLENAME 2 // Table name
- #DEFINE SELECTAREA 3 // Work area
- #DEFINE RELATEFIELD 4 // Field in parent that relates to child
- #DEFINE RELATETABLE 5 // ALIAS of parent table in relation
- #DEFINE ORDER 6 // Index expression
- #DEFINE ERROR 7 // Error code
- #DEFINE TAG 8 // Index tag name
-
-
- Class QParse of Array
-
- this.cCurrentSelectArea = ''
- this.cCurrentAlias = ''
- this.cCurrentTableName = ''
- this.cCurrentIndexTag = ''
- this.nCurrentElement = 0
- this.cCurrentOrder = ''
- this.cDefaultPath = ''
-
- Function Parse(cQbeFile)
-
- this.cString = ''
- this.nHnd = fOpen(cQbeFile,'R')
-
- if this.nHnd < 0
- return
- endif
-
- Do
- this.cString = upper(class::GetNextLine())
-
- // Check if this line creates new work area
- if at('SELE',this.cString) > 0
- Class::GetSelectArea( (this.cString) )
- endif
-
- // Check if this line opens a table
- if at('USE ',this.cString) > 0
- Class::GetTableName( (this.cString) ) // also looks for alias
- endif
-
- // Check if this line sets a relation
- if at('SET RELA',this.cString) > 0
- Class::GetRelation( (this.cString) )
- endif
-
- // Check if this line sets an active index tag
- If At('SET ORDE',this.cString) > 0
- CLASS::GetOrder( (this.cString) )
- EndIf
- Until fEof(this.nHnd) // file is fully parsed
- fClose(this.nHnd) // Close the table and
- return this // Return a reference to this array object
-
- //////////////////////////Method: GetNextLine///////////////////////////
- /////////// handles "continued" strings (;) from fGets()////////////////
-
- Function GetNextLine()
- Local cStr
-
- cStr = ';'
- do while right(cStr,1) = ';'
- cStr = substr(cStr,1,len(cStr)-1)+LTrim(RTrim(fGets(this.nHnd)))
- enddo
- return cStr
-
- /////////////////////////Method: GetSelectArea//////////////////////////
- ////////////////// xtracts "select" area from string ///////////////////
- ///////////////// determines if it's numberic or alias /////////////////
- ///////////////// and sets current work area/alias /////////////////////
-
- Function GetSelectArea(cStr)
- LOCAL cSelectArea, n
-
- cSelectArea = ''
- // is this a Select statement?
- if at('SELECT SELECT()',cStr) > 0
- cSelectArea = 'NextFree'
- elseif at('SELECT(SELECT())',cStr) > 0
- cSelectArea = 'NextFree'
- elseif at(' IN SELECT()',cStr) > 0
- cSelectArea = 'NextFree'
- elseif at('SELECT ',cStr) > 0
- cSelectArea= class::ExtractNextElement((cStr),'SELECT ')
- elseif at('SELE ',cStr) > 0
- cSelectArea= class::ExtractNextElement((cStr),'SELE ')
- elseif at(' IN ',cStr) > 0
- cSelectArea= class::ExtractNextElement((cStr),' IN ')
- endif
- // if something is found in a select statement
- if len(trim(cSelectArea)) > 0
- if cSelectArea = 'NextFree'
- this.cCurrentSelectArea = cSelectArea
- elseif val(cSelectArea) <= 0 // determine if it's numeric or alias
- n = class::TraverseArrayFor(ALIAS,(cSelectArea))
- If n > 0
- this.cCurrentSelectArea = this[n,SELECTAREA]
- this.cCurrentAlias = this[n, ALIAS]
- Else
- this.nCurrentElement = this.AddElement()
- this[this.nCurrentElement, ALIAS] = cSelectArea
- this[this.nCurrentElement, TABLENAME] = cSelectArea + ".DBF"
- this[this.nCurrentElement, SELECTAREA] = "NextFree"
- this[this.nCurrentElement, ERROR] =;
- "Error: Alias selected which was not opened in QBE"
- this.cCurrentSelectArea = "NextFree"
- this.cCurrentAlias = cSelectArea
- EndIf
- //
- // look and see if alias exists
- // if it does, retrieve index as numeric select area
- // and make this the current selected area
- else
- this.cCurrentSelectArea = cSelectArea
- n = CLASS::TraverseArrayFor(SELECTAREA, cSelectArea)
- If n > 0
- this.cCurrentAlias = this[n, ALIAS]
- EndIf
- endif
- endif
- return true
-
- //////////////////////Method: GetTableName ////////////////////////
- ///////////////////Retrieve table and alias from a USE statement///
-
- Function GetTableName(cStr)
- Local cTableName
-
- cTableName = ''
- if at('USE ',cStr) = 0
- return false
- endif
-
- cTableName = class::ExtractNextElement((cStr),'USE ')
-
- this.cCurrentOrder = ''
- if len(trim(cTableName)) > 0
-
- // clean up tablename to make sure no expressions involved
- cTableName = class::RemoveExpression(cTableName)
-
- if at(' ',cTableName) > 0
- cTableName = substr(cTableName,rat(' ',cTableName)+1)
- endif
-
- this.cCurrentTableName = cTableName // set table name property
-
- // determine alias for this table
- cTemp = ''
- If At(' ALIAS',cStr) > 0
- cTemp = 'ALIAS'
- ElseIf At(' ALIA',cStr) > 0
- cTemp = 'ALIA'
- EndIf
- If Len(cTemp) > 0
- this.cCurrentAlias = class::ExtractNextElement( (cStr),cTemp)
- else
- if at('\',cTableName) > 0
- this.cCurrentAlias = substr(cTableName, rat('\',cTableName)+1)
- else
- this.cCurrentAlias = cTableName // set current alias
- endif
-
- // Strip off file extension
- if at('.',this.cCurrentAlias) > 0
- this.cCurrentAlias = substr(this.cCurrentAlias,;
- 1, at('.',this.cCurrentAlias)-1)
- endif
- endif
- cTemp = ''
- If At(' ORDER',cStr) > 0
- cTemp = 'ORDER'
- ElseIf At(' ORDE',cStr) > 0
- cTemp = 'ORDE'
- EndIf
- If At(' TAG ',cStr) > 0
- cTemp = 'TAG'
- EndIf
- If Len(cTemp) > 0
- this.cCurrentOrder = class::ExtractNextElement((cStr), cTemp)
- EndIf
-
- endif
-
- // Add new table to the array....
- If Not "." $ this.cCurrentTableName Or;
- Right(this.cCurrentTableName, 4) == ".DBF" Or;
- Right(this.cCurrentTableName, 3) == ".DB"
- this.nCurrentElement = class::AddElement()
- this[this.nCurrentElement,TABLENAME] = this.cCurrentTableName
- this[this.nCurrentElement,ALIAS] = this.cCurrentAlias
- this[this.nCurrentElement,SELECTAREA] = this.cCurrentSelectArea
- If Len(this.cCurrentOrder) > 0
- CLASS::ExtractOrder(this.cCurrentOrder)
- EndIf
- return trim(ltrim(cTableName))
- Else
- this.cCurrentTableName = ""
- this.cCurrentAlias = ""
- this.cCurrentSelectArea = ""
- EndIf
- RETURN ""
-
-
- ///////////////////////Method: GetOrder/////////////////////////////
- /////////////////////// Extracts SET ORDER TO... ///////////
-
- Function GetOrder(cStr)
- LOCAL cOrder
-
- cOrder = cStr
- If At("SET ORDE", cOrder) # 1
- RETURN False
- EndIf
- If At(" TAG ", cOrder) > 0
- cOrder = class::ExtractNextElement((cOrder), 'TAG')
- Else
- cOrder = class::ExtractNextElement((cOrder), 'TO')
- EndIf
- this.ExtractOrder(cOrder)
-
- ///////////////////////Method: ExtractOrder/////////////////////////////
- //////////////// Extract index tag expression from tag name///////////
-
- Function ExtractOrder(cText)
- LOCAL nInd, nArea, cExpr, cTable, xExcep
-
- nInd = this.TraverseArrayFor(ALIAS, this.cCurrentAlias)
- cTable = IIf(At(".", this.cCurrentTableName) > 0,;
- this.cCurrentTableName, this.cCurrentTableName +;
- IIf(Set("DBTYPE") == "DBASE", ".DBF", ".DB"))
- cTable = this.cDefaultPath + cTable
- If nInd # 0
- this[nInd, TAG] = cText
- If File(cTable)
- nArea = Workarea()
- Select Select()
- Try
- Use (cTable)
- cExpr = Key(TagNo(cText))
- Catch(Exception xExcep)
- Finally
- Use
- Select (nArea)
- EndTry
- this[nInd, ORDER] = cExpr
- EndIf
- EndIf
-
-
- ///////////////////////Method: GetRelation/////////////////////////////
- /////////////////////// Extracts SET RELATION to... into... ///////////
-
- Function GetRelation(cStr)
- LOCAL cText, cTemp, cToField, cIntoTable, nInd
-
- cText = cStr
- If At("SET RELA", cText) # 1 // If no relation statement, go back
- RETURN False
- EndIf
- * Strip 'SET RELATION TO '
- cText = LTrim(Right(cText, (Len(cText) - At(" TO", cText)) - 3))
- * Parse fields/tables/orders and save in array
- Do While Not IsBlank(cText)
- cToField = Left(cText, At(" ", cText) - 1)
- cText = LTrim(Right(cText, (Len(cText) - At(" INTO ", cText)) - 5))
- cIntoTable = IIf(At(" ", cText) > 0,;
- RTrim(Left(cText, At(" ", cText) - 1)), cText)
- If Right(cIntoTable, 1) == ","
- cIntoTable = Left(cIntoTable, Len(cIntoTable) - 1)
- EndIf
- If CLASS::IsThisAnExpression((cToField))
- this[this.nCurrentElement,ERROR] = "Error: Expression in Relation"
- EndIf
- cText = Right(cText, Len(cText) - Len(cIntoTable))
- If At(",", cText) > 0
- cTemp = Left(cText, At(",", cText))
- Else
- cTemp = cText
- EndIf
- cText = LTrim(Right(cText, Len(cText) - Len(cTemp)))
- nInd = this.TraverseArrayFor(ALIAS, cIntoTable)
- If nInd = 0
- nInd = this.AddElement()
- this[nInd, TABLENAME] = cIntoTable
- this[nInd, ALIAS] = cIntoTable
- this[nInd, SELECTAREA] = "NextFree"
- EndIf
- this[nInd, RELATEFIELD] = cToField
- this[nInd, RELATETABLE] = this.cCurrentAlias
- EndDo
-
-
- ///////////////////////Method: ExtractNextElement /////////////////////
- ////// if only one param: returns the next "stand alone section"
- ////// if more than one param: returns the section in between both
- ////// strings sent as params
-
- Function ExtractNextElement(cStr,cE1,cE2)
- Local cExpr
-
- cExpr = ltrim(substr(cStr,at(cE1,cStr)+len(cE1))) // remove key (E1,E2)
- if not empty(cE2)
- cExpr = substr(cExpr,1,at(cE2,cExpr)-1) // extracts remainder to E2
- elseif at(' ',cExpr) > 0 // if there's a space after
- cExpr = substr(cExpr,1,at(' ',cExpr)-1) // extract up to the space
- endif // otherwise, remainder goes to end of line, leave remainder
- // intact.
- return ltrim(trim(cExpr))
-
- ///////////////////////Method: AddElement//////////////////////////////
- ///////////////////////adds and resizes array
- Function AddElement
- local nLen
-
- nLen = 0
- if empty(this) // if no elements, establish columns
- this.resize(1,8)
- else
- this.resize(alen(this,1)+1,8) // add one row to existing array
- endif
- nLen = alen(this,1)
- // init all elements to ""
- for n = 1 to 8
- this[nLen,n] = ""
- next
- return nLen
-
- ///////////////////////Method: RemoveExpression/////////////////////////
- ///////////////////////Param: String to clean up////////////////////////
- ///////////////////////Removes expression elements to free up table name
- Function RemoveExpression(cStr)
- LOCAL n
-
- for n = 1 to len(cStr)
- // if any expression elements found
- if at(substr(cStr,n,1),"+=()->{}'") > 0 or ;
- substr(cStr,n,1) = '"'
- // replace them with an empty space
- cStr = substr(cStr,1,n-1)+' '+substr(cStr,n+1)
- endif
- next
- return trim(ltrim(cStr))
-
- //////////////// Method: TraverseArrayFor//////////////////////////
- //////////////// Does a "seek" on sepcified column for ////////////
- //////////////// specified string. ////////////////////////////////
- Function TraverseArrayFor(nCol,cStr)
- local n
-
- For n = 1 to alen(this,1)
- if this[n,nCol] == cStr
- RETURN n
- endif
- Next
- return 0
-
- /////////////////////// Method: IsThisAnExpression////////////////
- /////////////////////// Param: String ////////////////////////////
- ///////////////// Parses statement to see if there's an //////////
- ///////////////// expression in it ///////////////////////////////
- Function IsThisAnExpression(cStr)
- local bIsExpression, n
-
- cStr = trim(ltrim(cStr))
- bIsExpression = false
- // check each character for an expression operator
- for n = 1 to len(cStr)
- if at(substr(cStr,n,1),'+ =)(') > 0
- return true
- endif
- next
- return false
-
- endclass
-
-