home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Visual Database / Visual dBase Pro v7.0 / DATA1.CAB / Utilities / Upgrade / Qparse.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1997-11-20  |  14.2 KB  |  412 lines

  1. /*
  2.  
  3. Qparse.prg  -    Class Qparse reads in Visual dBASE 5.5 .QBE files and
  4.                     extracts table names, aliases, work areas, and relation
  5.                information
  6.  
  7.                In addition, it flags relation conversion errors.
  8.                Ex: Error: Expression in Relation
  9.  
  10. Main Method    -    The main method of Qparse is Parse(), which returns
  11.                     an array reference in the following format:
  12.  
  13. Alias            Filepath/Name                Area Set Rela TO        Into        Error Msg
  14. ------------------------------------------------------------------------------------------------
  15. CUSTFILE     \TRANSELCO\CUSTFILE.DBF     1 UPPER(ADDRESS1) CONTAINR Error: Expression in Relation
  16. CONTAINR     \TRANSELCO\CONTAINR.DBF     2 
  17. DICT             \TRANSELCO\DICT.DBF             3 
  18.  
  19. Note:            -     Elements are initialized to "", check for Len(trim()) for
  20.                 -    -no- value
  21.  
  22.  
  23. Syntax        -     Set Proc to QParse.cc Addi
  24.                     f = New QParse()
  25.                f.Parse('My.qbe')
  26.  
  27. Author:        -     A. A. Katz (Ksoft, Inc) under contract to Borland, International
  28.                     
  29.              (c) 1997 Borland International, All Rights Reserved
  30.  
  31. Version:        -    V. 2.0 11-12-1997
  32.  
  33. */
  34.  
  35. #DEFINE ALIAS        1     // Alias of table
  36. #DEFINE TABLENAME    2     // Table name
  37. #DEFINE SELECTAREA   3     // Work area
  38. #DEFINE RELATEFIELD  4     // Field in parent that relates to child
  39. #DEFINE RELATETABLE  5     // ALIAS of parent table in relation
  40. #DEFINE ORDER        6     // Index expression
  41. #DEFINE ERROR        7     // Error code
  42. #DEFINE TAG          8     // Index tag name
  43.  
  44.  
  45. Class QParse of Array 
  46.  
  47.    this.cCurrentSelectArea        = ''
  48.    this.cCurrentAlias             = ''
  49.    this.cCurrentTableName        = ''
  50.    this.cCurrentIndexTag         = ''
  51.    this.nCurrentElement            = 0
  52.    this.cCurrentOrder         = ''
  53.    this.cDefaultPath          = ''
  54.  
  55.    Function Parse(cQbeFile)
  56.  
  57.       this.cString     = ''
  58.       this.nHnd         = fOpen(cQbeFile,'R')
  59.  
  60.       if this.nHnd < 0
  61.          return
  62.       endif
  63.  
  64.       Do
  65.          this.cString = upper(class::GetNextLine()) 
  66.  
  67.              // Check if this line creates new work area
  68.          if at('SELE',this.cString) > 0   
  69.             Class::GetSelectArea( (this.cString) )
  70.          endif
  71.  
  72.             // Check if this line opens a table
  73.          if at('USE ',this.cString) > 0
  74.             Class::GetTableName( (this.cString) ) // also looks for alias
  75.          endif
  76.  
  77.             // Check if this line sets a relation
  78.          if at('SET RELA',this.cString) > 0
  79.             Class::GetRelation( (this.cString) )
  80.          endif
  81.  
  82.             // Check if this line sets an active index tag
  83.          If At('SET ORDE',this.cString) > 0
  84.             CLASS::GetOrder( (this.cString) )
  85.          EndIf
  86.       Until fEof(this.nHnd)   // file is fully parsed
  87.       fClose(this.nHnd)            // Close the table and
  88.       return this             // Return a reference to this array object
  89.  
  90.    //////////////////////////Method: GetNextLine///////////////////////////
  91.    /////////// handles "continued" strings (;) from fGets()////////////////
  92.  
  93.    Function GetNextLine()
  94.       Local cStr
  95.  
  96.       cStr = ';'
  97.       do while right(cStr,1) = ';'
  98.          cStr = substr(cStr,1,len(cStr)-1)+LTrim(RTrim(fGets(this.nHnd)))
  99.       enddo
  100.       return cStr
  101.   
  102.    /////////////////////////Method: GetSelectArea//////////////////////////
  103.    ////////////////// xtracts "select" area from string ///////////////////
  104.    ///////////////// determines if it's numberic or alias /////////////////
  105.    ///////////////// and sets current work area/alias /////////////////////
  106.  
  107.    Function GetSelectArea(cStr)
  108.       LOCAL cSelectArea, n
  109.  
  110.       cSelectArea = ''
  111.          // is this a Select statement?
  112.       if     at('SELECT SELECT()',cStr) > 0
  113.          cSelectArea = 'NextFree'
  114.       elseif at('SELECT(SELECT())',cStr) > 0
  115.          cSelectArea = 'NextFree'
  116.       elseif at(' IN SELECT()',cStr) > 0
  117.          cSelectArea = 'NextFree'
  118.       elseif at('SELECT ',cStr) > 0
  119.          cSelectArea= class::ExtractNextElement((cStr),'SELECT ')
  120.       elseif at('SELE ',cStr) > 0
  121.          cSelectArea= class::ExtractNextElement((cStr),'SELE ')
  122.       elseif at(' IN ',cStr) > 0
  123.          cSelectArea= class::ExtractNextElement((cStr),' IN ')
  124.       endif
  125.       // if something is found in a select statement
  126.       if len(trim(cSelectArea)) > 0
  127.          if cSelectArea = 'NextFree'
  128.             this.cCurrentSelectArea = cSelectArea
  129.          elseif val(cSelectArea) <= 0  // determine if it's numeric or alias
  130.             n = class::TraverseArrayFor(ALIAS,(cSelectArea))
  131.             If n > 0
  132.                this.cCurrentSelectArea = this[n,SELECTAREA]
  133.                this.cCurrentAlias = this[n, ALIAS]
  134.             Else
  135.                this.nCurrentElement = this.AddElement()
  136.                this[this.nCurrentElement, ALIAS] = cSelectArea
  137.                this[this.nCurrentElement, TABLENAME] = cSelectArea + ".DBF"
  138.                this[this.nCurrentElement, SELECTAREA] = "NextFree"
  139.                this[this.nCurrentElement, ERROR] =;
  140.                           "Error: Alias selected which was not opened in QBE"
  141.                this.cCurrentSelectArea = "NextFree"
  142.                this.cCurrentAlias = cSelectArea
  143.             EndIf
  144.             //
  145.             // look and see if alias exists
  146.             // if it does, retrieve index as numeric select area
  147.             // and make this the current selected area
  148.          else
  149.             this.cCurrentSelectArea = cSelectArea
  150.             n = CLASS::TraverseArrayFor(SELECTAREA, cSelectArea)
  151.             If n > 0
  152.                this.cCurrentAlias = this[n, ALIAS]
  153.             EndIf
  154.           endif
  155.       endif
  156.       return true
  157.  
  158.    //////////////////////Method: GetTableName ////////////////////////
  159.    ///////////////////Retrieve table and alias from a USE statement///
  160.  
  161.    Function GetTableName(cStr)
  162.       Local cTableName
  163.  
  164.       cTableName = ''
  165.       if at('USE ',cStr) =  0
  166.          return false
  167.       endif
  168.  
  169.       cTableName = class::ExtractNextElement((cStr),'USE ')
  170.  
  171.       this.cCurrentOrder = ''
  172.       if len(trim(cTableName)) > 0
  173.  
  174.          // clean up tablename to make sure no expressions involved
  175.          cTableName = class::RemoveExpression(cTableName)
  176.  
  177.          if at(' ',cTableName) > 0
  178.             cTableName = substr(cTableName,rat(' ',cTableName)+1)
  179.          endif
  180.  
  181.          this.cCurrentTableName = cTableName  // set table name property
  182.  
  183.             // determine alias for this table
  184.          cTemp = ''
  185.          If At(' ALIAS',cStr) > 0
  186.             cTemp = 'ALIAS'
  187.          ElseIf At(' ALIA',cStr) > 0
  188.             cTemp = 'ALIA'
  189.          EndIf
  190.          If Len(cTemp) > 0
  191.             this.cCurrentAlias = class::ExtractNextElement( (cStr),cTemp)
  192.          else
  193.             if at('\',cTableName) > 0
  194.                this.cCurrentAlias = substr(cTableName, rat('\',cTableName)+1)
  195.             else
  196.                this.cCurrentAlias = cTableName  // set current alias
  197.             endif
  198.  
  199.                // Strip off file extension
  200.             if at('.',this.cCurrentAlias) > 0
  201.                this.cCurrentAlias = substr(this.cCurrentAlias,;
  202.                     1, at('.',this.cCurrentAlias)-1)
  203.             endif
  204.          endif
  205.          cTemp = ''
  206.          If At(' ORDER',cStr) > 0
  207.             cTemp = 'ORDER'
  208.          ElseIf At(' ORDE',cStr) > 0
  209.             cTemp = 'ORDE'
  210.          EndIf
  211.          If At(' TAG ',cStr) > 0
  212.             cTemp = 'TAG'
  213.          EndIf
  214.          If Len(cTemp) > 0
  215.             this.cCurrentOrder = class::ExtractNextElement((cStr), cTemp)
  216.          EndIf
  217.  
  218.       endif
  219.  
  220.       // Add new table to the array....
  221.       If Not "." $ this.cCurrentTableName Or;
  222.                  Right(this.cCurrentTableName, 4) == ".DBF" Or;
  223.                  Right(this.cCurrentTableName, 3) == ".DB"
  224.          this.nCurrentElement = class::AddElement()
  225.          this[this.nCurrentElement,TABLENAME]    = this.cCurrentTableName
  226.          this[this.nCurrentElement,ALIAS]        = this.cCurrentAlias
  227.          this[this.nCurrentElement,SELECTAREA] = this.cCurrentSelectArea
  228.          If Len(this.cCurrentOrder) > 0
  229.             CLASS::ExtractOrder(this.cCurrentOrder)
  230.          EndIf
  231.          return trim(ltrim(cTableName))
  232.       Else
  233.          this.cCurrentTableName = ""
  234.          this.cCurrentAlias = ""
  235.          this.cCurrentSelectArea = ""
  236.       EndIf
  237.       RETURN ""
  238.  
  239.  
  240.    ///////////////////////Method: GetOrder/////////////////////////////
  241.    /////////////////////// Extracts SET ORDER TO... ///////////
  242.  
  243.    Function GetOrder(cStr)
  244.       LOCAL cOrder
  245.  
  246.       cOrder = cStr
  247.       If At("SET ORDE", cOrder) # 1
  248.          RETURN False
  249.       EndIf
  250.       If At(" TAG ", cOrder) > 0
  251.          cOrder = class::ExtractNextElement((cOrder), 'TAG')
  252.       Else
  253.          cOrder = class::ExtractNextElement((cOrder), 'TO')
  254.       EndIf
  255.       this.ExtractOrder(cOrder)
  256.  
  257.    ///////////////////////Method: ExtractOrder/////////////////////////////
  258.    //////////////// Extract index tag expression from tag name///////////
  259.  
  260.    Function ExtractOrder(cText)
  261.       LOCAL nInd, nArea, cExpr, cTable, xExcep
  262.  
  263.       nInd = this.TraverseArrayFor(ALIAS, this.cCurrentAlias)
  264.       cTable = IIf(At(".", this.cCurrentTableName) > 0,;
  265.                         this.cCurrentTableName, this.cCurrentTableName +;
  266.                                 IIf(Set("DBTYPE") == "DBASE", ".DBF", ".DB"))
  267.       cTable = this.cDefaultPath + cTable
  268.       If nInd # 0
  269.             this[nInd, TAG] = cText
  270.             If File(cTable)
  271.              nArea = Workarea()
  272.              Select Select()
  273.                 Try
  274.                  Use (cTable)
  275.                  cExpr = Key(TagNo(cText))
  276.                 Catch(Exception xExcep)
  277.                 Finally
  278.                  Use
  279.                  Select (nArea)
  280.                 EndTry
  281.              this[nInd, ORDER] = cExpr
  282.             EndIf
  283.       EndIf
  284.  
  285.  
  286.    ///////////////////////Method: GetRelation/////////////////////////////
  287.    /////////////////////// Extracts SET RELATION to... into... ///////////
  288.  
  289.    Function GetRelation(cStr)
  290.       LOCAL cText, cTemp, cToField, cIntoTable, nInd
  291.  
  292.       cText = cStr
  293.       If At("SET RELA", cText) # 1  // If no relation statement, go back
  294.          RETURN False
  295.       EndIf
  296.       * Strip 'SET RELATION TO '
  297.       cText = LTrim(Right(cText, (Len(cText) - At(" TO", cText)) - 3))
  298.       * Parse fields/tables/orders and save in array
  299.       Do While Not IsBlank(cText)
  300.          cToField = Left(cText, At(" ", cText) - 1)
  301.          cText = LTrim(Right(cText, (Len(cText) - At(" INTO ", cText)) - 5))
  302.          cIntoTable = IIf(At(" ", cText) > 0,;
  303.                                         RTrim(Left(cText, At(" ", cText) - 1)), cText)
  304.          If Right(cIntoTable, 1) == ","
  305.                 cIntoTable = Left(cIntoTable, Len(cIntoTable) - 1)
  306.             EndIf
  307.          If CLASS::IsThisAnExpression((cToField))
  308.             this[this.nCurrentElement,ERROR] = "Error: Expression in Relation"
  309.          EndIf
  310.          cText = Right(cText, Len(cText) - Len(cIntoTable))
  311.          If At(",", cText) > 0
  312.             cTemp = Left(cText, At(",", cText))
  313.          Else
  314.             cTemp = cText
  315.          EndIf
  316.          cText = LTrim(Right(cText, Len(cText) - Len(cTemp)))
  317.          nInd = this.TraverseArrayFor(ALIAS, cIntoTable)
  318.          If nInd = 0
  319.             nInd = this.AddElement()
  320.             this[nInd, TABLENAME] = cIntoTable
  321.             this[nInd, ALIAS] = cIntoTable
  322.             this[nInd, SELECTAREA] = "NextFree"
  323.             EndIf
  324.          this[nInd, RELATEFIELD] = cToField
  325.          this[nInd, RELATETABLE] = this.cCurrentAlias
  326.       EndDo
  327.  
  328.  
  329.    ///////////////////////Method: ExtractNextElement /////////////////////
  330.    ////// if only one param:          returns the next "stand alone section"
  331.    ////// if more than one param: returns the section in between both
  332.    //////                               strings sent as params
  333.  
  334.    Function ExtractNextElement(cStr,cE1,cE2)
  335.       Local cExpr
  336.  
  337.       cExpr = ltrim(substr(cStr,at(cE1,cStr)+len(cE1))) // remove key (E1,E2)
  338.       if not empty(cE2)
  339.          cExpr = substr(cExpr,1,at(cE2,cExpr)-1)  // extracts remainder to E2
  340.       elseif at(' ',cExpr) > 0                    // if there's a space after
  341.          cExpr = substr(cExpr,1,at(' ',cExpr)-1)  // extract up to the space
  342.       endif   // otherwise, remainder goes to end of line, leave remainder
  343.               // intact.
  344.       return ltrim(trim(cExpr))
  345.  
  346.    ///////////////////////Method: AddElement//////////////////////////////
  347.    ///////////////////////adds and resizes array
  348.    Function AddElement
  349.       local nLen
  350.  
  351.       nLen = 0
  352.       if empty(this)                         // if no elements, establish columns 
  353.          this.resize(1,8)
  354.       else
  355.          this.resize(alen(this,1)+1,8)   // add one row to existing array
  356.       endif
  357.       nLen = alen(this,1)
  358.                // init all elements to ""       
  359.       for n = 1 to 8
  360.         this[nLen,n] = ""
  361.       next
  362.       return nLen
  363.  
  364.    ///////////////////////Method: RemoveExpression/////////////////////////
  365.    ///////////////////////Param: String to clean up////////////////////////
  366.    ///////////////////////Removes expression elements to free up table name
  367.    Function RemoveExpression(cStr)
  368.       LOCAL n
  369.  
  370.       for n = 1 to len(cStr)
  371.             // if any expression elements found
  372.          if at(substr(cStr,n,1),"+=()->{}'") > 0 or ;
  373.                substr(cStr,n,1) = '"'
  374.                // replace them with an empty space
  375.             cStr = substr(cStr,1,n-1)+' '+substr(cStr,n+1)
  376.          endif
  377.       next
  378.       return trim(ltrim(cStr))
  379.  
  380.    //////////////// Method: TraverseArrayFor//////////////////////////
  381.    //////////////// Does a "seek" on sepcified column for //////////// 
  382.    //////////////// specified string. ////////////////////////////////
  383.    Function TraverseArrayFor(nCol,cStr)
  384.       local n
  385.  
  386.       For n = 1 to alen(this,1)
  387.           if this[n,nCol] == cStr
  388.              RETURN n
  389.           endif
  390.       Next
  391.       return 0
  392.  
  393.    /////////////////////// Method: IsThisAnExpression////////////////
  394.    /////////////////////// Param: String ////////////////////////////
  395.    ///////////////// Parses statement to see if there's an //////////
  396.    ///////////////// expression in it ///////////////////////////////
  397.    Function IsThisAnExpression(cStr)
  398.    local bIsExpression, n
  399.  
  400.    cStr = trim(ltrim(cStr))
  401.    bIsExpression = false
  402.            // check each character for an expression operator
  403.    for n = 1 to len(cStr)
  404.       if at(substr(cStr,n,1),'+ =)(') > 0
  405.          return true
  406.       endif
  407.    next
  408.    return false
  409.  
  410. endclass                  
  411.  
  412.