This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
deb-goldedplus/golded3/gesrch.cpp
2005-12-15 11:40:31 +00:00

601 lines
17 KiB
C++

// ------------------------------------------------------------------
// GoldED+
// Copyright (C) 1990-1999 Odinn Sorensen
// Copyright (C) 1999-2000 Alexander S. Aganichev
// ------------------------------------------------------------------
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston,
// MA 02111-1307 USA
// ------------------------------------------------------------------
// $Id$
// ------------------------------------------------------------------
// Advanced search functions.
// ------------------------------------------------------------------
#include <golded.h>
#include <gmnubase.h>
#include <geval.h>
#include <gesrch.h>
// ------------------------------------------------------------------
golded_search_manager::golded_search_manager() {
}
// ------------------------------------------------------------------
golded_search_manager::~golded_search_manager() {
}
// ------------------------------------------------------------------
inline void search_item_option(bool& a, const char* s) {
if(s[1] == '^')
a = not a;
else
a = s[1] != '\'';
}
// ------------------------------------------------------------------
const char* search_item_set(search_item& item, const char* s, int what)
{
bool flag = false;
while(*s) {
switch(*s) {
case ')':
search_item_option(item.where.from, s);
search_item_option(item.where.to, s);
search_item_option(item.where.subject, s);
flag = true;
break;
case '(':
search_item_option(item.where.body, s);
search_item_option(item.where.tagline, s);
search_item_option(item.where.tearline, s);
search_item_option(item.where.origin, s);
search_item_option(item.where.signature, s);
search_item_option(item.where.kludges, s);
flag = true;
break;
case '!': search_item_option(item.reverse, s); break;
case '=': search_item_option(item.case_sensitive, s); break;
case '<': search_item_option(item.where.from, s); flag = true; break;
case '>': search_item_option(item.where.to, s); flag = true; break;
case ':': search_item_option(item.where.subject, s); flag = true; break;
case '#': search_item_option(item.where.body, s); flag = true; break;
case '.': search_item_option(item.where.tagline, s); flag = true; break;
case '_': search_item_option(item.where.tearline, s); flag = true; break;
case '*': search_item_option(item.where.origin, s); flag = true; break;
case '@': search_item_option(item.where.signature, s); flag = true; break;
case '%': search_item_option(item.where.kludges, s); flag = true; break;
case '?':
s++;
switch(g_tolower(*s)) {
case 'r': item.type = gsearch::regex; break;
case 'w': item.type = gsearch::wildcard; break;
case 'p': item.type = gsearch::plain; break;
case 'f':
item.type = gsearch::fuzzy;
if(isdigit(s[1])) {
item.fuzzydegree = atoi(s+1);
while(isdigit(s[1]))
s++;
}
break;
}
break;
case '^':
case '\'':
break;
default:
if (isspace(*s)) break;
else
goto lblLoopExit;
}
s++;
}
lblLoopExit:
if (what && !flag)
{
if (what & GFIND_FROM) item.where.from = true;
if (what & GFIND_TO) item.where.to = true;
if (what & GFIND_SUBJECT) item.where.subject = true;
if (what & GFIND_BODY) item.where.body = true;
if (what & GFIND_TAGLINE) item.where.tagline = true;
if (what & GFIND_TEARLINE) item.where.tearline = true;
if (what & GFIND_ORIGIN) item.where.origin = true;
if (what & GFIND_KLUDGES) item.where.kludges = true;
if (what & GFIND_SIGNATURE) item.where.signature = true;
}
return s;
}
// ------------------------------------------------------------------
void golded_search_manager::prepare_from_string(const char* prompt, int what)
{
// Get defaults
reverse = false;
direction = DIR_NEXT;
const char* p = prompt;
if (*p == '-' or *p == '+')
{
direction = (*p == '-') ? DIR_PREV : DIR_NEXT;
p++;
}
search_item default_item;
p = search_item_set(default_item, p, what);
search_item item = default_item;
default_item.reverse = false;
default_item.where.from = false;
default_item.where.to = false;
default_item.where.subject = false;
default_item.where.body = false;
default_item.where.tagline = false;
default_item.where.tearline = false;
default_item.where.origin = false;
default_item.where.kludges = false;
default_item.where.signature = false;
char buf[256];
char* b = buf;
bool item_complete = false;
do {
switch(*p) {
// Logic AND
case '&':
item.logic = search_item::logic_and;
item_complete = true;
p++;
break;
// Logic OR
case '|':
item.logic = search_item::logic_or;
item_complete = true;
p++;
break;
// Get quoted string
case '\"':
case '\'':
{
char q = *p++;
while(*p) {
if(*p == q) {
p++;
break;
}
switch(*p) {
case '\\':
if(*(++p))
*b++ = *p++;
break;
default:
*b++ = *p++;
}
}
}
break;
// Get literal escaped character
case '\\':
if(*(++p))
*b++ = *p++;
break;
// Skip whitespace
case ' ':
p++;
case NUL:
break;
default:
*b++ = *p++;
}
if(item_complete or (*p == NUL)) {
item_complete = false;
*b = NUL;
if(*buf != NUL) {
item.pattern = buf;
items.push_back(item);
}
if(*p == NUL)
break;
item = default_item;
p = search_item_set(item, strskip_wht(p), what);
b = buf;
}
} while(*p);
}
// ------------------------------------------------------------------
bool golded_search_manager::search(GMsg* msg, bool quick, bool shortcircuit) {
std::vector<search_item>::iterator item = items.begin();
bool exit = false;
bool and_cycle = false;
bool or_cycle = false;
for(int i=0; i<items.size(); i++, item++) {
if(shortcircuit) {
if(item->logic == search_item::logic_and) {
if(not and_cycle) {
if(exit)
return true;
}
else
if(not exit)
continue;
and_cycle = true;
}
else {
if(and_cycle) {
and_cycle = (item->logic == search_item::logic_and);
if(not exit)
continue;
} else {
and_cycle = (item->logic == search_item::logic_and);
if(exit)
return true;
}
or_cycle = (item->logic == search_item::logic_or);
}
}
int found = 0;
if(item->where.from) {
if(item->search(*msg->ifrom ? msg->ifrom : msg->By())) {
msg->foundwhere |= GFIND_FROM;
found++;
if(quick)
goto quick_found;
}
}
if(item->where.to) {
if(item->search(*msg->ito ? msg->ito : msg->to)) {
msg->foundwhere |= GFIND_TO;
found++;
if(quick)
goto quick_found;
}
else if(*msg->icc and item->search(msg->icc)) {
msg->foundwhere |= GFIND_TO;
found++;
if(quick)
goto quick_found;
}
else if(*msg->ibcc and item->search(msg->ibcc)) {
msg->foundwhere |= GFIND_TO;
found++;
if(quick)
goto quick_found;
}
}
if(item->where.subject) {
if(item->search(msg->re)) {
msg->foundwhere |= GFIND_SUBJECT;
found++;
if(quick)
goto quick_found;
}
}
if(item->where.body or item->where.tagline or item->where.tearline or item->where.origin or item->where.signature or item->where.kludges) {
Line* line = msg->lin;
while(line) {
uint type = line->type;
bool search_this_line = false;
if(item->where.body and not (type & (GLINE_TAGL|GLINE_TEAR|GLINE_ORIG|GLINE_SIGN|GLINE_KLUDGE)))
search_this_line = true;
if(item->where.tagline and (type & GLINE_TAGL))
search_this_line = true;
if(item->where.tearline and (type & GLINE_TEAR))
search_this_line = true;
if(item->where.origin and (type & GLINE_ORIG))
search_this_line = true;
if(item->where.signature and (type & GLINE_SIGN))
search_this_line = true;
if(item->where.kludges and (type & GLINE_KLUDGE))
search_this_line = true;
if(search_this_line) {
if(item->search(line->txt.c_str())) {
line->type |= GLINE_HIGH;
if(type & (GLINE_TAGL|GLINE_TEAR|GLINE_ORIG|GLINE_SIGN|GLINE_KLUDGE)) {
if(type & GLINE_TAGL)
msg->foundwhere |= GFIND_TAGLINE;
else if(type & GLINE_TEAR)
msg->foundwhere |= GFIND_TEARLINE;
else if(type & GLINE_ORIG)
msg->foundwhere |= GFIND_ORIGIN;
else if(type & GLINE_SIGN)
msg->foundwhere |= GFIND_SIGNATURE;
else if(type & GLINE_KLUDGE)
msg->foundwhere |= GFIND_KLUDGES;
}
else {
msg->foundwhere |= GFIND_BODY;
}
found++;
if(quick)
goto quick_found;
}
}
line = line->next;
}
}
quick_found:
if(item->reverse)
found = not found;
// Perform short-circuit logic analysis
if(shortcircuit) {
exit = make_bool(found);
if(item == items.end()-1)
return exit;
}
// else save success/failure as score
else {
item->score = found ? 1 : 0;
}
}
if(not shortcircuit) {
gevalhum logic;
if(items.size()) {
for(int i=0; i<items.size(); i++) {
logic.push_value(items[i].score);
if((i+1) < items.size()) {
if(items[i].logic == search_item::logic_and)
logic.push_operator(geval::logic_and);
else
logic.push_operator(geval::logic_or);
}
}
return make_bool(logic.evaluate());
}
}
// It should never end up here unless there are no items
return false;
}
// ------------------------------------------------------------------
void search_mgr_form::before() {
gwinput2::before();
}
// ------------------------------------------------------------------
void search_mgr_form::after() {
gwinput2::after();
}
// ------------------------------------------------------------------
void search_mgr_form::select(gstrarray& menu, const char* title) {
int srow = window.start_row + current->row;
int scol = window.start_column + current->column;
if((current->id < id_direction) and ((current->id % 3) == 2))
scol -= 20;
GMnu m;
m.Init();
m.SetColor(7, 7, 7, 112, 8);
m.SetTitle(title, 14);
m.SetBorder(0, 7);
m.SetPos(srow, scol);
m.SetMask(0);
m.Begin();
for(int i=0; i<menu.size(); i++)
m.Item(i, menu[i].c_str());
m.End();
vcurhide();
m.Start();
vcurshow();
if(m.FinalTag() != -1) {
if(not ((current->id < id_direction) and ((current->id % 3) == 2))) {
strbtrim(strcpy(current->buf, menu[m.FinalTag()].c_str()+1));
current->update();
}
}
}
// ------------------------------------------------------------------
bool search_mgr_form::validate() {
gstrarray menu;
if(current->id >= id_direction) {
switch(current->id) {
case id_direction:
menu.insert(menu.end(), "F Forward");
menu.insert(menu.end(), "B Backward ");
select(menu, "Direction");
break;
case id_messages:
menu.insert(menu.end(), "N New");
menu.insert(menu.end(), "U Unread ");
menu.insert(menu.end(), "A All");
select(menu, "Messages");
break;
case id_action:
menu.insert(menu.end(), "R Read");
menu.insert(menu.end(), "T Tag");
menu.insert(menu.end(), "D Delete ");
menu.insert(menu.end(), "W Write");
menu.insert(menu.end(), "C Copy");
menu.insert(menu.end(), "M Move");
select(menu, "Action");
break;
case id_areas:
menu.insert(menu.end(), "C Current ");
menu.insert(menu.end(), "A All");
menu.insert(menu.end(), "T Tagged");
select(menu, "Areas");
break;
}
}
else if((current->id % 3) == 1) {
menu.insert(menu.end(), "a and ");
menu.insert(menu.end(), "o or");
select(menu, "Logic");
}
else if((current->id % 3) == 2) {
menu.insert(menu.end(), " Plain ");
menu.insert(menu.end(), " Regex ");
menu.insert(menu.end(), " Wildcard ");
menu.insert(menu.end(), " Fuzzy ");
menu.insert(menu.end(), " Success if not found ");
menu.insert(menu.end(), " Case sensitive ");
menu.insert(menu.end(), " Search \"from\" ");
menu.insert(menu.end(), " Search \"to\" ");
menu.insert(menu.end(), " Search \"subject\" ");
menu.insert(menu.end(), " Search msg body ");
menu.insert(menu.end(), " Search tagline ");
menu.insert(menu.end(), " Search tearline ");
menu.insert(menu.end(), " Search origin ");
menu.insert(menu.end(), " Search signature ");
menu.insert(menu.end(), " Search kludges ");
select(menu, "Options");
}
return true;
}
// ------------------------------------------------------------------
void AdvancedSearch(GMsg*, int&, int&) {
int patterns = 9;
int width = 77;
int height = patterns+11;
int widths[3] = { 55, 5, 7 };
int field_widths[3] = { 100, 5, 7 };
int border_type = BT_SINGLE;
int title_color = YELLOW | _BLUE;
int heading_color = YELLOW | _BLUE;
int window_color = LGREY | _BLUE;
int border_color = LBLUE | _BLUE;
int edit_color = YELLOW | _BLUE;
int idle_color = LGREY | _BLUE;
int active_color = WHITE | _BLUE;
int shadow_color = DGREY | _BLACK;
widths[0] = width - 3*2 - 2 - 5 - 7 - 2;
gwindow window;
window.openxy(1, ((MAXCOL-width)/2), height, width,
border_type, border_color, window_color);
window.shadow(shadow_color);
window.horizontal_line( 1, 0, width-2, border_type, border_color);
window.horizontal_line(patterns+2, 0, width-2, border_type, border_color);
window.vertical_line(0, widths[0]+2, patterns+3, border_type, border_color);
window.vertical_line(0, widths[0]+widths[1]+5, patterns+3, border_type, border_color);
window.title(" Advanced Search Manager ", title_color);
window.prints(0, 1, heading_color, "Pattern");
window.prints(0, widths[0]+4, heading_color, "Logic");
window.prints(0, widths[0]+widths[1]+7, heading_color, "Options");
window.prints(patterns+3, 1, heading_color, "Direction : ");
window.prints(patterns+4, 1, heading_color, "Messages : ");
window.prints(patterns+5, 1, heading_color, "Action : ");
window.prints(patterns+6, 1, heading_color, "Areas : ");
window.prints(patterns+7, 1, heading_color, "Destination : ");
window.prints(patterns+8, 1, heading_color, "Identifier : ");
search_mgr_form iform(window);
iform.setup(idle_color, active_color, edit_color, _box_table(border_type, 13), true);
std::string buffers[9*3 + 6];
int i = 0;
for(int r=0; r<9; r++) {
int cs = 1;
for(int c=0; c<3; c++,i++) {
char z[80];
sprintf(z, "%i,%i", r+1, c+1);
buffers[i] = z;
iform.add_field(i, r+2, cs, widths[c], buffers[i], field_widths[c]);
cs += widths[c] + 3;
}
}
buffers[i+0] = "Forward";
buffers[i+1] = "New";
buffers[i+2] = "Read";
buffers[i+3] = "Current";
buffers[i+4] = "C:\\TEMP\\DUMPFILE.TXT";
buffers[i+5] = "Testing";
for(int y=0; y<6; y++,i++)
iform.add_field(100+y, patterns+3+y, 15, width-15-3, buffers[i], width-15-3, gwinput::cvt_none, y>=4 ? gwinput::entry_conditional : gwinput::entry_noedit);
iform.run(0);
window.close();
}
// ------------------------------------------------------------------