]> git.decadent.org.uk Git - ion3.git/blob - mod_query/history.c
[svn-upgrade] Integrating new upstream version, ion3 (20070203)
[ion3.git] / mod_query / history.c
1 /*
2  * ion/mod_query/history.h
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2007. 
5  *
6  * Ion is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  */
11
12 #include <string.h>
13
14 #include <ioncore/common.h>
15 #include <libextl/extl.h>
16
17 #include "history.h"
18
19
20 #define HISTORY_SIZE 1024
21
22
23 static int hist_head=HISTORY_SIZE;
24 static int hist_count=0;
25 static char *hist[HISTORY_SIZE];
26
27
28 int get_index(int i)
29 {
30     if(i<0 || i>=hist_count)
31         return -1;
32     return (hist_head+i)%HISTORY_SIZE;
33 }
34     
35
36 /*EXTL_DOC
37  * Push an entry into line editor history.
38  */
39 EXTL_EXPORT
40 bool mod_query_history_push(const char *str)
41 {
42     char *s=scopy(str);
43     
44     if(s==NULL)
45         return FALSE;
46     
47     mod_query_history_push_(s);
48     
49     return TRUE;
50 }
51
52
53 void mod_query_history_push_(char *str)
54 {
55     int ndx=mod_query_history_search(str, 0, FALSE, TRUE);
56     
57     if(ndx==0){
58         free(str);
59         return; /* First entry already */
60     }else if(ndx>0){
61         int i, j;
62         i=get_index(ndx);
63         free(hist[i]);
64         while(++ndx<hist_count){
65             j=get_index(ndx);
66             hist[i]=hist[j];
67             i=j;
68         }
69         hist_count--;
70     }
71     
72     hist_head--;
73     if(hist_head<0)
74         hist_head=HISTORY_SIZE-1;
75     
76     if(hist_count==HISTORY_SIZE)
77         free(hist[hist_head]);
78     else
79         hist_count++;
80     
81     hist[hist_head]=str;
82 }
83
84
85 /*EXTL_DOC
86  * Get entry at index \var{n} in line editor history, 0 being the latest.
87  */
88 EXTL_SAFE
89 EXTL_EXPORT
90 const char *mod_query_history_get(int n)
91 {
92     int i=get_index(n);
93     return (i<0 ? NULL : hist[i]);
94 }
95
96
97 /*EXTL_DOC
98  * Clear line editor history.
99  */
100 EXTL_EXPORT
101 void mod_query_history_clear()
102 {
103     while(hist_count!=0){
104         free(hist[hist_head]);
105         hist_count--;
106         if(++hist_head==HISTORY_SIZE)
107             hist_head=0;
108     }
109     hist_head=HISTORY_SIZE;
110 }
111
112
113
114 static bool match(const char *h, const char *b, bool exact)
115 {
116     const char *h_;
117     
118     if(b==NULL)
119         return TRUE;
120     
121     /* Special case: search in any context. */
122     if(*b=='*' && *(b+1)==':'){
123         b=b+2;
124         h_=strchr(h, ':');
125         if(h_!=NULL)
126             h=h_+1;
127     }
128     
129     return (exact
130             ? strcmp(h, b)==0
131             : strncmp(h, b, strlen(b))==0);
132 }
133
134
135 static const char *skip_colon(const char *s)
136 {
137     const char *p=strchr(s, ':');
138     return (p!=NULL ? p+1 : s);
139 }
140
141
142 /*EXTL_DOC
143  * Try to find matching history entry. Returns -1 if none was
144  * found. The parameter \var{from} specifies where to start 
145  * searching from, and \var{bwd} causes backward search from
146  * that point. If \var{exact} is not set, \var{s} only required
147  * to be a prefix of the match.
148  */
149 EXTL_SAFE
150 EXTL_EXPORT
151 int mod_query_history_search(const char *s, int from, bool bwd, bool exact)
152 {
153     while(1){
154         int i=get_index(from);
155         if(i<0)
156             return -1;
157         if(match(hist[i], s, exact))
158             return from;
159         if(bwd)
160             from--;
161         else
162             from++;
163     }
164 }
165
166
167 uint mod_query_history_complete(const char *s, char ***h_ret)
168 {
169     char **h=ALLOC_N(char *, hist_count);
170     int i, n=0;
171     
172     if(h==NULL)
173         return 0;
174     
175     for(i=0; i<hist_count; i++){
176         int j=get_index(i);
177         if(j<0)
178             break;
179         if(match(hist[j], s, FALSE)){
180             h[n]=scopy(skip_colon(hist[j]));
181             if(h[n]!=NULL)
182                 n++;
183         }
184     }
185     
186     if(n==0)
187         free(h);
188     else
189         *h_ret=h;
190     
191     return n;
192 }
193
194
195 /*EXTL_DOC
196  * Return table of history entries.
197  */
198 EXTL_SAFE
199 EXTL_EXPORT
200 ExtlTab mod_query_history_table()
201 {
202     ExtlTab tab=extl_create_table();
203     int i;
204
205     for(i=0; i<hist_count; i++){
206         int j=get_index(i);
207         extl_table_seti_s(tab, i+1, hist[j]);
208     }
209     
210     return tab;
211 }