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