text: /*++
  
  Copyright (c) 1990  Microsoft Corporation
  
  Module Name:
  
      mbrqry.c
  
  Abstract:
  
      This file contains the functions that perform the queries to the
      database. These functions are called by the top-level functions
      which implement the browser commands (see mbrdlg.c).
  
  Author:
  
      Ramon Juan San Andres (ramonsa) 07-Nov-1990
  
  
  Revision History:
  
  
  --*/
  
  
  #include "mbr.h"
  
  
  //  INST_MATCHES_CRITERIA
  //
  //  This macro is used to find out if an instance matches the
  //  current MBF criteria.
  //
  #define INST_MATCHES_CRITERIA(Iinst)  FInstFilter(Iinst, BscMbf)
  
  
  
  //
  //  Static variables reflect the current state of
  //  Definition/Reference queries.
  //
  static IREF    LastiRef;            //  Last reference index
  static IREF    iRefMin, iRefMax;    //  Current reference index range
  
  static IDEF    LastiDef;            //  Last definition index
  static IDEF    iDefMin, iDefMax;    //  Current definition index range
  
  static IINST   LastIinst;           //  Last instance index
  static IINST   IinstMin, IinstMax;  //  Current instance index range
  
  static DEFREF  LastQueryType;       //  last query type:
                                      //      Q_DEFINITION or
                                      //      Q_REFERENCE
  
  static buffer  LastSymbol;          //  Last symbol queried.
  
  
  
  
  /**************************************************************************/
  
  void
  pascal
  InitDefRef(
      IN DEFREF QueryType,
      IN char   *Symbol
      )
  /*++
  
  Routine Description:
  
      Initializes the query state, this must be done before querying for
      the first definition/reference of a symbol.
  
      After calling this function, the first definition/reference must be
      obtained by calling the NextDefRef function.
  
  Arguments:
  
      QueryType   -   Type of query (Q_DEFINITION or Q_REFERENCE).
      Symbol      -   Symbol name.
  
  Return Value:
  
      None.
  
  --*/
  
  {
  
      ISYM Isym;
  
      LastQueryType = QueryType;
      strcpy(LastSymbol, Symbol);
  
      Isym = IsymFrLsz(Symbol);
  
      InstRangeOfSym(Isym, &IinstMin, &IinstMax);
  
      LastIinst = IinstMin;
  
      if (QueryType == Q_DEFINITION) {
          DefRangeOfInst(LastIinst, &iDefMin, &iDefMax);
          LastiDef = iDefMin - 1;
      } else {
          RefRangeOfInst(LastIinst, &iRefMin, &iRefMax);
          LastiRef = iRefMin - 1;
      }
  }
  
  
  
  /**************************************************************************/
  
  void
  GotoDefRef (
      void
      )
  /*++
  
  Routine Description:
  
      Makes the file containing the current definition/reference the
      current file and positions the cursor in the line where the
      definition/reference takes place.
  
      The state of the query (current instance and definition/reference
      indexes) must be set before calling this function.
  
  Arguments:
  
      None.
  
  Return Value:
  
      None.
  
  --*/
  
  {
  
      char    *pName = NULL;
      WORD    Line   = 0;
      PFILE   pFile;
      char    szFullName[MAX_PATH];
  
  
      szFullName[0] = '\0';
      if (LastQueryType == Q_DEFINITION) {
          DefInfo(LastiDef, &pName, &Line);
      } else {
          RefInfo(LastiRef, &pName, &Line);
      }
  
      if (BscInUse && pName) {
  
          if (rootpath(pName, szFullName)) {
              strcpy(szFullName, pName);
          }
  
          pFile = FileNameToHandle(szFullName,NULL);
  
          if (!pFile) {
              pFile = AddFile(szFullName);
              if (!FileRead(szFullName, pFile)) {
                  RemoveFile(pFile);
                  pFile = NULL;
              }
          }
  
          if (!pFile) {
              errstat(MBRERR_NOSUCHFILE, szFullName);
              return;
          }
          pFileToTop(pFile);
          MoveCur(0,Line);
          GetLine(Line, buf, pFile);
          MoveToSymbol(Line, buf, LastSymbol);
      }
  }
  
  
  
  /**************************************************************************/
  
  void
  pascal
  MoveToSymbol(
      IN LINE Line,
      IN char *Buf,
      IN char *Symbol
      )
  /*++
  
  Routine Description:
  
      Moves the cursor to the first occurance of a symbol within
      a line.  It is case-sensitive.
  
  Arguments:
  
      Line    -   Line number
      Buf     -   Contents of the line
      Symbol  -   Symbol to look for.
  
  Return Value:
  
      None.
  
  --*/
  
  {
  
      //  First Symbol within Buf
      //
      char *p = Buf;
      char *q = Symbol;
      char *Mark;
  
      while (*p) {
          //
          // Look for first character
          //
          if (*p == *q) {
              Mark = p;
              //
              //  compare rest
              //
              while (*p && *q && *p == *q) {
                  p++;
                  q++;
              }
              if (*q) {
                  q = Symbol;
                  p = Mark+1;
              } else {
                  break;
              }
          } else {
              p++;
          }
      }
  
      if (!*q) {
          MoveCur((COL)(Mark-Buf), Line);
      }
  }
  
  
  
  /**************************************************************************/
  
  void
  NextDefRef (
      void
      )
  /*++
  
  Routine Description:
  
      Displays next definition or reference of a symbol.
  
  Arguments:
  
      None
  
  Return Value:
  
      None.
  
  --*/
  
  {
  
      IINST   Iinst;
  
  
      //  For locating the next def/ref we do the following:
      //
      //  1.- If the def/ref index is within the current range, we just
      //      increment it.
      //  2.- Otherwise we look for the next instance that matches the
      //      MBF criteria, and set the def/ref index to the min value of
      //      the def/ref range for that instance.
      //  3.- If no next instance is found, we display an error message
      //
  
      if (LastQueryType == Q_DEFINITION) {
          if (LastiDef == iDefMax-1) {
  
              Iinst = LastIinst;
  
              do {
                  LastIinst++;
              } while ((LastIinst < IinstMax) &&
                       (!INST_MATCHES_CRITERIA(LastIinst)));
  
              if (LastIinst == IinstMax ) {
                  LastIinst = Iinst;
                  errstat(MBRERR_LAST_DEF, "");
                  return;
              } else {
                  DefRangeOfInst(LastIinst, &iDefMin, &iDefMax);
                  LastiDef = iDefMin;
              }
  
          } else {
              LastiDef++;
          }
      } else {
          if (LastiRef == iRefMax-1) {
  
              Iinst = LastIinst;
  
              do {
                  LastIinst++;
              } while ((LastIinst < IinstMax) &&
                       (!INST_MATCHES_CRITERIA(LastIinst)));
  
              if (LastIinst == IinstMax) {
                  LastIinst = Iinst;
                  errstat(MBRERR_LAST_REF, "");
                  return;
              } else {
                  RefRangeOfInst(LastIinst, &iRefMin, &iRefMax);
                  LastiRef = iRefMin;
              }
          } else {
              LastiRef++;
          }
      }
      GotoDefRef();
  }
  
  
  
  /**************************************************************************/
  
  void
  PrevDefRef (
      void
      )
  /*++
  
  Routine Description:
  
      Displays the previous definition or reference of a symbol.
  
  Arguments:
  
      None
  
  Return Value:
  
      None.
  
  --*/
  
  {
  
      IINST   Iinst;
      BOOL    Match;
  
      //  For locating the previous def/ref we do the following:
      //
      //  1.- if the def/ref index is within the current range, we
      //      just decrement it.
      //  2.- Otherwise we look for the most previous instance that
      //      matches the MBF criteria, and set the def/ref index to
      //      the maximum value within the def/ref range for that
      //      instance.
      //  3.- If not such instance exist, we display an error message.
      //
  
      if (LastQueryType == Q_DEFINITION) {
          if (LastiDef == iDefMin) {
  
              if (LastIinst == IinstMin) {
                  errstat(MBRERR_FIRST_DEF, "");
                  return;
              }
  
              Iinst = LastIinst;
  
              do {
                  Iinst--;
              } while ((LastIinst > IinstMin) &&
                       (!(Match = INST_MATCHES_CRITERIA(LastIinst))));
  
              if (!Match) {
                  LastIinst = Iinst;
                  errstat(MBRERR_FIRST_DEF, "");
                  return;
              } else {
                  DefRangeOfInst(LastIinst, &iDefMin, &iDefMax);
                  LastiDef = iDefMax - 1;
              }
  
          } else {
              LastiDef--;
          }
      } else {
          if (LastiRef == iRefMin) {
  
              if (LastIinst == IinstMin) {
                  errstat(MBRERR_FIRST_REF, "");
                  return;
              }
  
              Iinst = LastIinst;
  
              do {
                  Iinst--;
              } while ((LastIinst > IinstMin) &&
                       (!(Match = INST_MATCHES_CRITERIA(LastIinst))));
  
              if (!Match) {
                  LastIinst = Iinst;
                  errstat(MBRERR_FIRST_REF, "");
                  return;
              } else {
                  RefRangeOfInst(LastIinst, &iRefMin, &iRefMax);
                  LastiRef = iRefMax - 1;
              }
  
          } else {
              LastiRef--;
          }
      }
      GotoDefRef();
  }
  