Пример #1
0
  /**
   * Chooses tokens from the file cache that match the specified pattern.
   *
   * @param pattern file pattern
   * @param search search string
   * @param mode search mode (0-2)
   * @param results search result
   * @param exclude exclude file from content search
   * @param pathSearch path flag
   * @param pc file cache
   * @param id search id
   * @throws InterruptedException interruption
   */
  private void filter(
      final String pattern,
      final int[] search,
      final int mode,
      final TreeSet<String> results,
      final HashSet<String> exclude,
      final boolean pathSearch,
      final ProjectCache pc,
      final long id)
      throws InterruptedException {

    if (results.size() >= MAXHITS) return;

    for (final String path : pc) {
      // check if current file matches the pattern
      final String lc = path.toLowerCase(Locale.ENGLISH).replace('\\', '/');
      final int offset = offset(lc, pathSearch);
      if (mode == 0
          ? lc.startsWith(pattern, offset)
          : mode == 1 ? (lc.indexOf(pattern, offset) != -1) : matches(lc, pattern, offset)) {
        if (!exclude.contains(path)) {
          exclude.add(path);
          if (filterContent(path, search)) {
            results.add(path);
            if (results.size() >= MAXHITS) return;
          }
        }
      }
      if (id != filterId) throw new InterruptedException();
    }
  }
Пример #2
0
  /**
   * Returns the sorted names of all available databases and, optionally, backups. Filters for
   * {@code name} if not {@code null} with glob support.
   *
   * @param db return databases?
   * @param backup return backups?
   * @param name name filter (may be {@code null})
   * @return database and backups list
   */
  private StringList list(final boolean db, final boolean backup, final String name) {
    final Pattern pt;
    if (name != null) {
      final String nm =
          REGEX.matcher(name).matches()
              ? IOFile.regex(name)
              : name.replaceAll("([" + REGEXCHARS + "])", "\\\\$1");
      pt = Pattern.compile(nm, Prop.CASE ? 0 : Pattern.CASE_INSENSITIVE);
    } else {
      pt = null;
    }

    final IOFile[] children = soptions.dbpath().children();
    final StringList list = new StringList(children.length);
    final HashSet<String> map = new HashSet<>(children.length);
    for (final IOFile f : children) {
      final String fn = f.name();
      String add = null;
      if (backup && fn.endsWith(IO.ZIPSUFFIX)) {
        final String nn = ZIPPATTERN.split(fn)[0];
        if (!nn.equals(fn)) add = nn;
      } else if (db && f.isDir() && fn.indexOf('.') == -1) {
        add = fn;
      }
      // add entry if it matches the pattern, and has not already been added
      if (add != null && (pt == null || pt.matcher(add).matches()) && map.add(add)) {
        list.add(add);
      }
    }
    return list.sort(false);
  }
Пример #3
0
  /**
   * Refreshes the view after a file has been saved.
   *
   * @param root root directory
   * @param ctx database context
   * @throws InterruptedException interruption
   */
  void parse(final IOFile root, final Context ctx) throws InterruptedException {
    final long id = ++parseId;
    final HashSet<String> parsed = new HashSet<>();
    final TreeMap<String, InputInfo> errs = new TreeMap<>();

    // collect files to be parsed
    final ProjectCache pc = cache(root);
    final StringList mods = new StringList(), lmods = new StringList();
    for (final String path : pc) {
      final IOFile file = new IOFile(path);
      if (file.hasSuffix(IO.XQSUFFIXES)) (file.hasSuffix(IO.XQMSUFFIX) ? lmods : mods).add(path);
    }
    mods.add(lmods);

    // parse modules
    for (final String path : mods) {
      if (id != parseId) throw new InterruptedException();
      if (parsed.contains(path)) continue;

      final IOFile file = new IOFile(path);
      try (final TextInput ti = new TextInput(file)) {
        // parse query
        try (final QueryContext qc = new QueryContext(ctx)) {
          final String input = ti.cache().toString();
          final boolean lib = QueryProcessor.isLibrary(input);
          qc.parse(input, lib, path, null);
          // parsing was successful: remember path
          parsed.add(path);
          for (final byte[] mod : qc.modParsed) parsed.add(Token.string(mod));
        } catch (final QueryException ex) {
          // parsing failed: remember path
          final InputInfo ii = ex.info();
          errs.put(path, ii);
          parsed.add(ii.path());
        }
      } catch (final IOException ex) {
        // file may not be accessible
        Util.debug(ex);
      }
    }
    errors = errs;
  }
Пример #4
0
  /**
   * Inserts a data instance at the specified pre value. Note that the specified data instance must
   * differ from this instance.
   *
   * @param ipre value at which to insert new data
   * @param ipar parent pre value of node
   * @param clip data clip
   */
  public final void insert(final int ipre, final int ipar, final DataClip clip) {
    meta.update();

    // update value and document indexes
    if (meta.updindex) indexBegin();
    resources.insert(ipre, clip);

    final int dsize = clip.size();
    final int buf = Math.min(dsize, IO.BLOCKSIZE >> IO.NODEPOWER);
    // resize buffer to cache more entries
    buffer(buf);

    // find all namespaces in scope to avoid duplicate declarations
    final TokenMap nsScope = nspaces.scope(ipar, this);

    // loop through all entries
    final IntList preStack = new IntList();
    final NSNode nsRoot = nspaces.current();
    final HashSet<NSNode> newNodes = new HashSet<NSNode>();
    final IntList flagPres = new IntList();

    // indicates if database only contains a dummy node
    final Data data = clip.data;
    int c = 0;
    for (int dpre = clip.start; dpre < clip.end; ++dpre, ++c) {
      if (c != 0 && c % buf == 0) insert(ipre + c - buf);

      final int pre = ipre + c;
      final int dkind = data.kind(dpre);
      final int dpar = data.parent(dpre, dkind);
      // ipar < 0 if document nodes on top level are added
      final int dis = dpar >= 0 ? dpre - dpar : ipar >= 0 ? pre - ipar : 0;
      final int par = dis == 0 ? -1 : pre - dis;

      if (c == 0) nspaces.root(par, this);

      while (!preStack.isEmpty() && preStack.peek() > par) nspaces.close(preStack.pop());

      switch (dkind) {
        case DOC:
          // add document
          nspaces.prepare();
          final int s = data.size(dpre, dkind);
          doc(pre, s, data.text(dpre, true));
          meta.ndocs++;
          preStack.push(pre);
          break;
        case ELEM:
          // add element
          nspaces.prepare();
          boolean ne = false;
          if (data.nsFlag(dpre)) {
            final Atts at = data.ns(dpre);
            for (int a = 0; a < at.size(); ++a) {
              // see if prefix has been declared/ is part of current ns scope
              final byte[] old = nsScope.get(at.name(a));
              if (old == null || !eq(old, at.value(a))) {
                // we have to keep track of all new NSNodes that are added
                // to the Namespace structure, as their pre values must not
                // be updated. I.e. if an NSNode N with pre value 3 existed
                // prior to inserting and two new nodes are inserted at
                // location pre == 3 we have to make sure N and only N gets
                // updated.
                newNodes.add(nspaces.add(at.name(a), at.value(a), pre));
                ne = true;
              }
            }
          }
          byte[] nm = data.name(dpre, dkind);
          elem(
              dis,
              tagindex.index(nm, null, false),
              data.attSize(dpre, dkind),
              data.size(dpre, dkind),
              nspaces.uri(nm, true),
              ne);
          preStack.push(pre);
          break;
        case TEXT:
        case COMM:
        case PI:
          // add text
          text(pre, dis, data.text(dpre, true), dkind);
          break;
        case ATTR:
          // add attribute
          nm = data.name(dpre, dkind);
          // check if prefix already in nsScope or not
          final byte[] attPref = prefix(nm);
          // check if prefix of attribute has already been declared, otherwise
          // add declaration to parent node
          if (data.nsFlag(dpre) && nsScope.get(attPref) == null) {
            nspaces.add(
                par,
                preStack.isEmpty() ? -1 : preStack.peek(),
                attPref,
                data.nspaces.uri(data.uri(dpre, dkind)),
                this);
            // save pre value to set ns flag later for this node. can't be done
            // here as direct table access would interfere with the buffer
            flagPres.add(par);
          }
          attr(
              pre,
              dis,
              atnindex.index(nm, null, false),
              data.text(dpre, false),
              nspaces.uri(nm, false),
              false);
          break;
      }
    }
    // finalize and update namespace structure
    while (!preStack.isEmpty()) nspaces.close(preStack.pop());
    nspaces.root(nsRoot);

    if (bp != 0) insert(ipre + c - 1 - (c - 1) % buf);
    // reset buffer to old size
    buffer(1);

    // set ns flags
    for (int f = 0; f < flagPres.size(); f++) {
      final int fl = flagPres.get(f);
      table.write2(fl, 1, name(fl) | 1 << 15);
    }

    // increase size of ancestors
    int p = ipar;
    while (p >= 0) {
      final int k = kind(p);
      size(p, k, size(p, k) + dsize);
      p = parent(p, k);
    }

    if (meta.updindex) {
      // add the entries to the ID -> PRE mapping:
      idmap.insert(ipre, id(ipre), dsize);
      indexEnd();
    }

    if (!cache) updateDist(ipre + dsize, dsize);

    // propagate PRE value shifts to namespaces
    if (ipar != -1) nspaces.insert(ipre, dsize, newNodes);
  }