00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "ClientPattern.hh"
00026 #include "RegExp.hh"
00027 #include "StringUtil.hh"
00028 #include "WinClient.hh"
00029
00030
00031 #ifndef _GNU_SOURCE
00032 #define _GNU_SOURCE
00033 #endif // _GNU_SOURCE
00034
00035
00036 #include <iostream>
00037 #include <fstream>
00038 #include <string>
00039 #include <memory>
00040 #include <cstdio>
00041
00042
00043 #include <strings.h>
00044
00045 #ifdef HAVE_CONFIG_H
00046 #include "config.h"
00047 #endif // HAVE_CONFIG_H
00048
00049 #ifdef HAVE_SSTREAM
00050 #include <sstream>
00051 #define FB_istringstream istringstream
00052 #elif HAVE_STRSTREAM
00053 #include <strstream>
00054 #define FB_istringstream istrstream
00055 #else
00056 #error "You dont have sstream or strstream headers!"
00057 #endif // HAVE_STRSTREAM
00058
00059
00060 using namespace std;
00061
00062 ClientPattern::ClientPattern():
00063 m_matchlimit(0),
00064 m_nummatches(0) {}
00065
00066
00067 ClientPattern::ClientPattern(const char *str):
00068 m_matchlimit(0),
00069 m_nummatches(0)
00070 {
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085 int had_error = 0;
00086
00087 int pos = 0;
00088 string match;
00089 int err = 1;
00090 while (had_error == 0 && err > 0) {
00091 err = FbTk::StringUtil::getStringBetween(match,
00092 str + pos,
00093 '(', ')', " \t\n", true);
00094 if (err > 0) {
00095 size_t eq = match.find_first_of('=');
00096 if (eq == match.npos) {
00097 if (!addTerm(match, NAME)) {
00098 had_error = pos + match.find_first_of('(') + 1;
00099 break;
00100 }
00101 } else {
00102
00103 string memstr, expr;
00104 WinProperty prop;
00105 memstr.assign(match, 0, eq);
00106 expr.assign(match, eq+1, match.length());
00107 if (strcasecmp(memstr.c_str(), "name") == 0) {
00108 prop = NAME;
00109 } else if (strcasecmp(memstr.c_str(), "class") == 0) {
00110 prop = CLASS;
00111 } else if (strcasecmp(memstr.c_str(), "title") == 0) {
00112 prop = TITLE;
00113 } else {
00114 had_error = pos + match.find_first_of('(') + 1;
00115 break;
00116 }
00117 if (!addTerm(expr, prop)) {
00118 had_error = pos + ((str+pos) - index(str+pos, '=')) + 1;
00119 break;
00120 }
00121 }
00122 pos += err;
00123 }
00124 }
00125 if (pos == 0 && had_error == 0) {
00126
00127 had_error = 1;
00128 }
00129
00130 if (had_error == 0) {
00131
00132 string number;
00133 err = FbTk::StringUtil::getStringBetween(number,
00134 str+pos,
00135 '{', '}');
00136 if (err > 0) {
00137 FB_istringstream iss(number.c_str());
00138 iss >> m_matchlimit;
00139 pos+=err;
00140 }
00141
00142
00143
00144 match = str + pos;
00145 err = match.find_first_not_of(" \t\n", pos);
00146 if ((unsigned) err != match.npos) {
00147
00148 had_error = err;
00149 }
00150 }
00151
00152 if (had_error > 0) {
00153 m_matchlimit = had_error;
00154
00155 while (!m_terms.empty()) {
00156 Term * term = m_terms.back();
00157 delete term;
00158 m_terms.pop_back();
00159 }
00160 }
00161 }
00162
00163 ClientPattern::~ClientPattern() {
00164
00165 while (!m_terms.empty()) {
00166 delete m_terms.back();
00167 m_terms.pop_back();
00168 }
00169 }
00170
00171
00172 std::string ClientPattern::toString() const {
00173 string pat;
00174 Terms::const_iterator it = m_terms.begin();
00175 Terms::const_iterator it_end = m_terms.end();
00176 for (; it != it_end; ++it) {
00177 pat.append(" (");
00178
00179 switch ((*it)->prop) {
00180 case NAME:
00181
00182 break;
00183 case CLASS:
00184 pat.append("class=");
00185 break;
00186 case TITLE:
00187 pat.append("title=");
00188 break;
00189 }
00190
00191 pat.append((*it)->orig);
00192 pat.append(")");
00193 }
00194
00195 if (m_matchlimit > 0) {
00196 char num[20];
00197 sprintf(num, " {%d}", m_matchlimit);
00198 pat.append(num);
00199 }
00200 return pat;
00201 }
00202
00203
00204 bool ClientPattern::match(const WinClient &win) const {
00205 if (m_matchlimit != 0 && m_nummatches >= m_matchlimit ||
00206 m_terms.empty())
00207 return false;
00208
00209
00210
00211
00212 Terms::const_iterator it = m_terms.begin();
00213 Terms::const_iterator it_end = m_terms.end();
00214 for (; it != it_end; ++it) {
00215 if (!(*it)->regexp.match(getProperty((*it)->prop, win)))
00216 return false;
00217 }
00218 return true;
00219 }
00220
00221
00222
00223
00224 bool ClientPattern::addTerm(const std::string &str, WinProperty prop) {
00225
00226 Term *term = new Term(str, true);
00227 term->orig = str;
00228 term->prop = prop;
00229
00230 if (term->regexp.error()) {
00231 delete term;
00232 return false;
00233 }
00234 m_terms.push_back(term);
00235 return true;
00236 }
00237
00238 std::string ClientPattern::getProperty(WinProperty prop, const WinClient &client) const {
00239 switch (prop) {
00240 case TITLE:
00241 return client.title();
00242 break;
00243 case CLASS:
00244 return client.getWMClassClass();
00245 break;
00246 case NAME:
00247 return client.getWMClassName();
00248 break;
00249 }
00250 return client.getWMClassName();
00251 }