Scid  4.6.5
sc_filter.cpp
Go to the documentation of this file.
1 /*
2 # Copyright (C) 2016 Fulvio Benini
3 
4 * This file is part of Scid (Shane's Chess Information Database).
5 *
6 * Scid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation.
9 *
10 * Scid is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Scid. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include "common.h"
20 #include "dbasepool.h"
21 #include "scidbase.h"
22 #include "ui.h"
23 
24 namespace {
25 /*
26 * Filters are used to select games, usually when performing searches.
27 * To encapsulate database internal complexity this functions should only
28 * parse arguments and call other functions/objects.
29 *
30 * Command names are case sensitive
31 * Optional parameter are indicated using [value_opt]
32 * Alternative values are indicated using <value_a|value_b|value_c>
33 * BaseId is the handle used to select the database to work on
34 * filterId is the unique ID of the filter to work on
35 * Games are numbered starting from "1"
36 *
37 * Every database has a default filter with id "dbfilter".
38 */
39 
40 /**
41  * sc_filter_compose() - compose a new filter
42  * @baseId: valid database identifier
43  * @filterId: valid identifier of the "main" filter. If it is already a composed
44  * one, only the "main" part will be used.
45  * @maskfilterId: identifier of the "mask" Filter, can be an empty "" string.
46  *
47  * A composed filter include only the games contained in both @filterId and
48  * @maskfilterId. This function allows to compose a new filter, if @filterId and
49  * @maskfilterId are two valid filter identifiers, or to obtain the "main"
50  * filter of a composed one, if @maskfilterId is an empty "" string.
51  * A composed filter should not be released.
52  * Return:
53  * - the identifier of the composed filter, which can be used as a "normal"
54  * filter (modifying functions will affect only the "main" @filterId)
55  * - on error, an empty string.
56  */
57 UI_res_t sc_filter_compose(UI_handle_t ti, const scidBaseT& dbase, int argc,
58  const char** argv) {
59  const char* usage = "Usage: sc_filter compose baseId filterId maskfilterId";
60  if (argc != 5) return UI_Result(ti, ERROR_BadArg, usage);
61 
62  std::string res = dbase.composeFilter(argv[3], argv[4]);
63  if (res.empty())
64  return UI_Result(ti, ERROR_BadArg, "sc_filter: invalid filterId");
65 
66  return UI_Result(ti, OK, res);
67 }
68 
69 /**
70  * sc_filter_remove() - remove games from the filter
71  * @gnumber: the id of the game to be removed
72  * @+: also remove games after @gnumber
73  * @-: also remove games before @gnumber
74  * @sortCrit: criteria used to determine before/after
75  */
76 UI_res_t sc_filter_remove(UI_handle_t ti, scidBaseT& dbase, HFilter& filter,
77  int argc, const char** argv) {
78  const char* usage = "Usage: sc_filter remove baseId filterId gnumber [<+|-> sortCrit]";
79  if (argc != 5 && argc != 7) return UI_Result(ti, ERROR_BadArg, usage);
80 
81  uint gNum = strGetUnsigned(argv[4]);
82  if (gNum == 0 || gNum > dbase.numGames())
83  return UI_Result(ti, ERROR_BadArg);
84 
85  if (argc == 5) {
86  filter.erase(gNum - 1);
87  } else {
88  const char* crit = argv[6];
89  size_t start = dbase.sortedPosition(crit, filter, gNum - 1);
90  if (start == INVALID_GAMEID)
91  return UI_Result(ti, ERROR_BadArg, usage);
92 
93  size_t count;
94  switch (argv[5][0]) {
95  case '+':
96  count = filter->size() - start;
97  break;
98  case '-':
99  count = start + 1;
100  start = 0;
101  break;
102  default:
103  return UI_Result(ti, ERROR_BadArg, usage);
104  }
105 
106  gamenumT* idxList = new gamenumT[count];
107  count = dbase.listGames(crit, start, count, filter, idxList);
108  for (size_t i = 0; i < count; ++i) {
109  filter.erase(idxList[i]);
110  }
111  delete[] idxList;
112  }
113  return UI_Result(ti, OK);
114 }
115 
116 /**
117  * sc_filter_reset() - reset a filter to be empty or include all the games
118  * @full: reset the filter to include all the games
119  * @empty: reset the filter to exclude all the games
120  */
121 UI_res_t sc_filter_reset(UI_handle_t ti, HFilter& filter, int argc,
122  const char** argv) {
123  const char* usage = "Usage: sc_filter reset baseId filterId <full|empty>";
124  if (argc != 5) return UI_Result(ti, ERROR_BadArg, usage);
125 
126  if (strcmp("full", argv[4]) == 0) {
127  filter->includeAll();
128  } else if (strcmp("empty", argv[4]) == 0) {
129  filter->clear();
130  } else {
131  return UI_Result(ti, ERROR_BadArg, usage);
132  }
133  return UI_Result(ti, OK);
134 }
135 
136 /**
137  * sc_filter_sizes() - get the sizes of a filter
138  *
139  * Return a list containing:
140  * - the number of games included in the filter @filterId
141  * - the total number of games contained in the database @baseId
142  * - the number of games included in the "main" filter composing @filterId
143  * (if @filterId is not a combined filter, this value is equal to the first).
144  */
145 UI_res_t sc_filter_sizes(UI_handle_t ti, const scidBaseT& dbase, HFilter& filter,
146  int argc, const char** argv) {
147  const char* usage = "Usage: sc_filter sizes baseId filterId";
148  if (argc != 4) return UI_Result(ti, ERROR_BadArg, usage);
149 
150  HFilter unmasked = dbase.getMainFilter(argv[3]);
151  if (unmasked == 0)
152  return UI_Result(ti, ERROR_BadArg, "sc_filter: invalid filterId");
153 
154  UI_List res(3);
155  res.push_back(filter.size());
156  res.push_back(dbase.numGames());
157  res.push_back(unmasked.size());
158  return UI_Result(ti, OK, res);
159 }
160 
161 } // End of anonymous namespace
162 
163 int sc_filter_old(ClientData cd, Tcl_Interp* ti, int argc, const char** argv);
164 
165 UI_res_t sc_filter(UI_extra_t cd, UI_handle_t ti, int argc, const char** argv) {
166  const char* usage = "Usage: sc_filter <cmd> baseId filterId [args]";
167  if (argc < 2) return UI_Result(ti, ERROR_BadArg, usage);
168 
169  static const char* options[] = {"compose", "remove", "reset", "sizes", NULL};
170  if (strUniqueMatch(argv[1], options) == - 1)
171  return sc_filter_old(cd, ti, argc, argv);
172 
173  scidBaseT* dbase = 0;
174  HFilter filter(0);
175  if (argc > 3) {
176  dbase = DBasePool::getBase(strGetUnsigned(argv[2]));
177  filter = dbase->getFilter(argv[3]);
178  }
179  if (dbase == 0 || filter == 0) return UI_Result(ti, ERROR_BadArg, usage);
180 
181  const char* cmd = argv[1];
182  if (strcmp("compose", cmd) == 0)
183  return sc_filter_compose(ti, *dbase, argc, argv);
184  if (strcmp("remove", cmd) == 0)
185  return sc_filter_remove(ti, *dbase, filter, argc, argv);
186  if (strcmp("reset", cmd) == 0)
187  return sc_filter_reset(ti, filter, argc, argv);
188  if (strcmp("sizes", cmd) == 0)
189  return sc_filter_sizes(ti, *dbase, filter, argc, argv);
190 
191  std::string err = "sc_filter\nInvalid minor command: ";
192  return UI_Result(ti, ERROR_BadArg, err + cmd);
193 }
void clear()
Definition: hfilter.h:132
const errorT OK
Definition: error.h:23
const errorT ERROR_BadArg
Definition: error.h:28
gamenumT numGames() const
Definition: scidbase.h:97
void includeAll()
Definition: hfilter.h:143
void erase(gamenumT gnum)
Definition: hfilter.h:133
int strUniqueMatch(const char *keyStr, const char **strTable)
Definition: misc.h:336
const gamenumT INVALID_GAMEID
Definition: scidbase.h:35
scidBaseT * getBase(int baseHandle)
getBase() - get a database from the pool.
Definition: dbasepool.cpp:59
int UI_res_t
Definition: ui_tcltk.h:30
size_t sortedPosition(const char *criteria, const HFilter &filter, gamenumT gameId)
Get the sorted position of a game.
Definition: scidbase.cpp:872
uint32_t uint
Definition: common.h:99
uint32_t strGetUnsigned(const char *str)
Definition: misc.h:276
size_t size() const
Definition: hfilter.h:161
UI_res_t UI_Result(UI_handle_t ti, errorT res)
UI_Result() - pass the result of an operation from c++ to UI : OK for success or an error code (error...
Definition: ui.h:140
HFilter getMainFilter(const std::string &filterId) const
Definition: scidbase.h:180
class UI_List - create a list of values to be sent to UI : currently there is no automatic reallocati...
Definition: ui.h:163
Tcl_Interp * UI_handle_t
Definition: ui_tcltk.h:32
UI_res_t sc_filter(UI_extra_t cd, UI_handle_t ti, int argc, const char **argv)
Definition: sc_filter.cpp:165
cmd
Definition: fics.tcl:443
uint gamenumT
Definition: common.h:159
std::string composeFilter(const std::string &mainFilter, const std::string &maskFilter) const
Definition: scidbase.cpp:427
HFilter getFilter(const std::string &filterId) const
Definition: scidbase.h:177
int sc_filter_old(ClientData cd, Tcl_Interp *ti, int argc, const char **argv)
FILTER functions.
Definition: tkscid.cpp:1663
size_t listGames(const char *criteria, size_t start, size_t count, const HFilter &filter, gamenumT *destCont)
Retrieve a list of ordered game indexes sorted by criteria.
Definition: scidbase.cpp:863
ClientData UI_extra_t
Definition: ui_tcltk.h:31