File: intcompare.cpp

package info (click to toggle)
watchman 4.9.0-9
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 9,992 kB
  • sloc: cpp: 27,459; python: 6,538; java: 3,404; php: 3,257; ansic: 2,803; javascript: 1,116; makefile: 671; ruby: 364; sh: 124; xml: 102; lisp: 4
file content (106 lines) | stat: -rw-r--r-- 2,806 bytes parent folder | download | duplicates (3)
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
/* Copyright 2015-present Facebook, Inc.
 * Licensed under the Apache License, Version 2.0 */

#include "watchman.h"

#include "make_unique.h"

// Helper functions for integer comparisons in query expressions

static const struct {
  const char *opname;
  enum w_query_icmp_op op;
} opname_to_op[] = {
  {"eq", W_QUERY_ICMP_EQ},
  {"ne", W_QUERY_ICMP_NE},
  {"gt", W_QUERY_ICMP_GT},
  {"ge", W_QUERY_ICMP_GE},
  {"lt", W_QUERY_ICMP_LT},
  {"le", W_QUERY_ICMP_LE},
};

// term is a json array that looks like:
// ["size", "eq", 1024]
void parse_int_compare(const json_ref& term, struct w_query_int_compare* comp) {
  const char *opname;
  size_t i;
  bool found = false;

  if (json_array_size(term) != 3) {
    throw QueryParseError("integer comparator must have 3 elements");
  }
  if (!json_is_string(json_array_get(term, 1))) {
    throw QueryParseError("integer comparator op must be a string");
  }
  if (!json_is_integer(json_array_get(term, 2))) {
    throw QueryParseError("integer comparator operand must be an integer");
  }

  opname = json_string_value(json_array_get(term, 1));
  for (i = 0; i < sizeof(opname_to_op)/sizeof(opname_to_op[0]); i++) {
    if (!strcmp(opname_to_op[i].opname, opname)) {
      comp->op = opname_to_op[i].op;
      found = true;
      break;
    }
  }

  if (!found) {
    throw QueryParseError(watchman::to<std::string>(
        "integer comparator opname `", opname, "' is invalid"));
  }


  comp->operand = json_integer_value(json_array_get(term, 2));
}

bool eval_int_compare(json_int_t ival, struct w_query_int_compare *comp) {
  switch (comp->op) {
    case W_QUERY_ICMP_EQ:
      return ival == comp->operand;
    case W_QUERY_ICMP_NE:
      return ival != comp->operand;
    case W_QUERY_ICMP_GT:
      return ival > comp->operand;
    case W_QUERY_ICMP_GE:
      return ival >= comp->operand;
    case W_QUERY_ICMP_LT:
      return ival < comp->operand;
    case W_QUERY_ICMP_LE:
      return ival <= comp->operand;
    default:
      // Not possible to get here, but some compilers don't realize
      return false;
  }
}

class SizeExpr : public QueryExpr {
  w_query_int_compare comp;

 public:
  explicit SizeExpr(w_query_int_compare comp) : comp(comp) {}

  bool evaluate(struct w_query_ctx*, const FileResult* file) override {
    // Removed files never evaluate true
    if (!file->exists()) {
      return false;
    }

    return eval_int_compare(file->stat().size, &comp);
  }

  static std::unique_ptr<QueryExpr> parse(w_query*, const json_ref& term) {
    if (!json_is_array(term)) {
      throw QueryParseError("Expected array for 'size' term");
    }

    w_query_int_compare comp;
    parse_int_compare(term, &comp);

    return watchman::make_unique<SizeExpr>(comp);
  }
};
W_TERM_PARSER("size", SizeExpr::parse)

/* vim:ts=2:sw=2:et:
 */