1 #include <stdarg.h>
2 #include <sys/types.h>
3
4 #include "quirc.h"
5 #include "hash.h"
6 #include "config.h"
7 #include "format.h"
8 #include "echo.h"
9 #include "channel.h"
10
11 #include <string>
12 #ifdef USING_STD_STRING
13 using std::string;
14 #endif
15
16 #define NUMBER '0':\
17 case '1':\
18 case '2':\
19 case '3':\
20 case '4':\
21 case '5':\
22 case '6':\
23 case '7':\
24 case '8':\
25 case '9'
26
27 char *fparse_result;
28
29 static char buflow[20];
30 static char bufhigh[20];
31 static char *buflowp;
32 static char *bufhighp;
33
append(char * low,char * high,string & assemble,int argc,const char * const * argv)34 int append(char *low, char *high, string &assemble, int argc,
35 const char * const * argv) {
36 int start=atoi(low);
37 int end=atoi(high);
38 int n;
39 char *dst;
40 int flags;
41
42 for(n=start;n<=end;n++) {
43 if(n>=argc) return 1;
44 dst=(char *)malloc(Tcl_ScanElement(argv[n],&flags));
45 if(!dst) return 1;
46 flags|=TCL_DONT_USE_BRACES;
47 Tcl_ConvertElement(argv[n], dst, flags);
48 if(strcmp(dst,"{}")) {
49 assemble+=dst;
50 }
51 free(dst);
52 if(n!=end) assemble+="\\ ";
53 }
54 strcpy(buflow,"0");
55 sprintf(bufhigh,"%d",argc-1);
56 bufhighp=bufhigh;
57 buflowp=buflow;
58 return 0;
59 }
60
fparsev(const char * type,int server,int argc,const char * const * argv)61 char *fparsev(const char *type, int server, int argc,
62 const char * const * argv) {
63 // %X- %-X %X-Y %- %%
64 // Replaces arguments with an escaped version of a space seperated arg list.
65 // Argument is then evaluated within a set.
66 // Return 0 if there is an error (ie. no arg for format number)
67
68 // Set buflow to 0, bufhigh to argc-1
69
70 // N is number, D is default.
71
72 // State 0:
73 // Got nothing
74 // %, go to state 1.
75 // D, insert letter.
76 // State 1:
77 // Got %
78 // %, simply insert a %, go back to state 0.
79 // N, could be %X- %X %X-Y, set buflow to it, go to state 2.
80 // -, could be %-X %-, go to state 3.
81 // D, insert %, backup, go to state 0.
82 // State 2:
83 // Got %N
84 // N, append to buflow, loop.
85 // -, go to state 3
86 // D, insert argument buflow, backup, go to state 0.
87 // State 3:
88 // Got %- or %N-
89 // N, set bufhigh to it, go to state 4.
90 // D, insert buflow to bufhigh, backup, go to state 0.
91 // State 4:
92 // Got %-N or %N-N
93 // N, append to bufhigh, loop.
94 // D, insert buflow to bufhigh, backup, go to state 0.
95 // Post loop processing is identical to default without backup or state 0
96 // stuff.
97
98 string assemble;
99 char *format;
100 int n;
101 int state=0;
102
103 if(fparse_result) {
104 free(fparse_result);
105 fparse_result=0;
106 }
107 format=hash_get(&formats,type);
108 if(!format) return 0;
109
110 strcpy(buflow,"0");
111 sprintf(bufhigh,"%d",argc-1);
112 bufhighp=bufhigh;
113 buflowp=buflow;
114
115 for(n=0;n<(signed)strlen(format);n++) {
116 switch(state) {
117 case 0:
118 switch(format[n]) {
119 case '%':
120 state=1;
121 break;
122 default:
123 assemble+=format[n];
124 }
125 break;
126 case 1:
127 switch(format[n]) {
128 case '%':
129 assemble+='%';
130 state=0;
131 break;
132 case NUMBER:
133 *(buflowp++)=format[n];
134 *buflowp=0;
135 state=2;
136 break;
137 case '-':
138 state=3;
139 break;
140 default:
141 assemble+='%';
142 n--;
143 state=0;
144 }
145 break;
146 case 2:
147 switch(format[n]) {
148 case NUMBER:
149 *(buflowp++)=format[n];
150 *buflowp=0;
151 break;
152 case '-':
153 state=3;
154 break;
155 default:
156 if(append(buflow,buflow,assemble,argc,argv)) return 0;
157 n--;
158 state=0;
159 }
160 break;
161 case 3:
162 switch(format[n]) {
163 case NUMBER:
164 *(bufhighp++)=format[n];
165 *bufhighp=0;
166 break;
167 default:
168 if(append(buflow,bufhigh,assemble,argc,argv)) return 0;
169 n--;
170 state=0;
171 }
172 break;
173 }
174 }
175 switch(state) {
176 case 1:
177 assemble+='%';
178 break;
179 case 2:
180 if(append(buflow,buflow,assemble,argc,argv)) return 0;
181 break;
182 case 3:
183 if(append(buflow,bufhigh,assemble,argc,argv)) return 0;
184 break;
185 }
186 if(server==-1) {
187 return (fparse_result=strdup(TT_StrF(TT_ARGS,"set ::internal::junk \"%s\"",assemble.c_str())));
188 } else {
189 return (fparse_result=strdup(TT_StrF(TT_ARGS,"namespace eval ::%d \"set ::internal::junk \\\"%q\\\"\"",server,assemble.c_str())));
190 }
191 }
192
fparse(char * type,int server,int arguments,...)193 char *fparse(char *type, int server, int arguments, ...) {
194 char *args[100]; // Make this dynamic.
195 int argpos=0;
196 int n;
197 va_list ap;
198
199 // Error kludge
200 if(arguments>100) {
201 fprintf(stderr,"fparse argument limit hit. Contact author.\n");
202 exit(1);
203 }
204
205 va_start(ap,arguments);
206 for(n=0;n<arguments;n++) {
207 args[argpos++]=va_arg(ap,char*);
208 }
209 va_end(ap);
210
211 return(fparsev(type, server, arguments, args));
212 }
213
fgetformat(const char * type)214 char *fgetformat(const char *type) {
215 return hash_get(&formats,type);
216 }
217
fgetpathnames(const char * type,int server,int argc,const char * const * argv)218 char *fgetpathnames(const char *type, int server, int argc,
219 const char * const * argv) {
220 char *location;
221 char *newloc;
222 twindow window;
223 twindow *windowp;
224 twindow *windowp2;
225 tchan channel;
226 tchan *channelp;
227 int arg;
228
229 // errors should be handled here via bgerror
230 location=hash_get(&locations,type);
231 if(!location) {
232 // Replace this with an fparse'd or M_ error.
233 TT_Eval(TT_ARGS,"error {fdisplay: No location present for given display type.}");
234 return 0;
235 }
236 if(server==-1) {
237 if(!(newloc=strdup(TT_StrF(TT_ARGS,"set ::internal::junk \"%s\"",location)))) {
238 // Replace this with an fparse'd or M_ error.
239 TT_Eval(TT_ARGS,"error {fdisplay: Out of memory.}");
240 return 0;
241 }
242 windowp=0; /* Avoids a warning message. Make sure server!=-1 or
243 windowp!=0 before attempting to use the windowp pointer.
244 It will only be valid when called in a server manner. */
245 } else {
246 if(!(newloc=strdup(TT_StrF(TT_ARGS,"namespace eval ::%d \"set ::internal::junk \\\"%q\\\"\"",server,location)))) {
247 // Replace this with an fparse'd or M_ error.
248 TT_Eval(TT_ARGS,"error {fdisplay: Out of memory.}");
249 return 0;
250 }
251 if(!strcmp(newloc,"{}")) {
252 free(newloc);
253 if(!(newloc=strdup(""))) {
254 // Replace this with an fparse'd or M_ error.
255 TT_Eval(TT_ARGS,"error {fdisplay: Out of memory.}");
256 return 0;
257 }
258 }
259
260 sprintf(window.pathname,".status%d",server);
261 if(!(windowp=windows.find(window)) || !windowp->server) {
262 free(newloc);
263 TT_Eval(TT_ARGS,"error {fdisplay: Invalid server index.}");
264 return 0;
265 }
266 }
267
268 if(!strncmp(newloc,"onchannel ",10)) {
269 if((arg=atoi(newloc+10))>=argc) {
270 free(newloc);
271 TT_Eval(TT_ARGS,"error {fdisplay: No argument present for location format argument number.}");
272 return 0;
273 }
274 if(server==-1) {
275 free(newloc);
276 TT_Eval(TT_ARGS,"error {fdisplay: Cannot run server specific format globally.}");
277 return 0;
278 }
279 *newloc=0;
280 strcpy(channel.name,argv[arg]);
281 if((channelp=windowp->server->chanlist.find(channel))) {
282 if(channelp->ison) {
283 free(newloc);
284 if(!(newloc=strdup(channelp->pathname))) {
285 TT_Eval(TT_ARGS,"error {fdisplay: Out of memory.}");
286 return 0;
287 }
288 }
289 }
290 }
291 if(!strncmp(newloc,"channelorstatus ",16)) {
292 if((arg=atoi(newloc+16))>=argc) {
293 free(newloc);
294 TT_Eval(TT_ARGS,"error {fdisplay: No argument present for location format argument number.}");
295 return 0;
296 }
297 if(server==-1) {
298 free(newloc);
299 TT_Eval(TT_ARGS,"error {fdisplay: Cannot run server specific format globally.}");
300 return 0;
301 }
302 free(newloc);
303 strcpy(channel.name,argv[arg]);
304 if((channelp=windowp->server->chanlist.find(channel))) {
305 if(!(newloc=strdup(channelp->pathname))) {
306 TT_Eval(TT_ARGS,"error {fdisplay: Out of memory.}");
307 return 0;
308 }
309 } else {
310 if(!(newloc=strdup(windowp->server->pathname))) {
311 TT_Eval(TT_ARGS,"error {fdisplay: Out of memory.}");
312 return 0;
313 }
314 }
315 }
316 if(!strncmp(newloc,"chat ",5)) {
317 if((arg=atoi(newloc+5))>=argc) {
318 free(newloc);
319 TT_Eval(TT_ARGS,"error {fdisplay: No argument present for location format argument number.}");
320 return 0;
321 }
322 if(server==-1) {
323 free(newloc);
324 TT_Eval(TT_ARGS,"error {fdisplay: Cannot run server specific format globally.}");
325 return 0;
326 }
327 free(newloc);
328
329 windows.init_trav();
330 while((windowp2=windows.trav())) {
331 if(windowp2->server==windowp->server&&windowp2->dcc) {
332 if((!strcasecmp(windowp2->dcc->getnick(),argv[arg]))||(!strcasecmp(windowp2->name,argv[arg]))) {
333 if(!(newloc=strdup(windowp2->pathname))) {
334 TT_Eval(TT_ARGS,"error {fdisplay: Out of memory.}");
335 return 0;
336 }
337 }
338 }
339 }
340 }
341
342 if(!strncmp(newloc,"pathname ",9)) {
343 if((arg=atoi(newloc+9))>=argc) {
344 free(newloc);
345 TT_Eval(TT_ARGS,"error {fdisplay: No argument present for location format argument number.}");
346 return 0;
347 }
348 free(newloc);
349 if(!(newloc=strdup(argv[arg]))) {
350 TT_Eval(TT_ARGS,"error {fdisplay: Out of memory.}");
351 return 0;
352 }
353 }
354
355 return newloc;
356 }
357
fdisplayv(const char * type,int server,int argc,const char * const * argv)358 void fdisplayv(const char *type, int server, int argc,
359 const char * const * argv) {
360 char *result;
361 char *newloc;
362
363 int listc;
364 char **listv;
365 int n;
366
367 if(!(newloc = fgetpathnames(type,server,argc,argv))) return;
368
369 if(!(result=fparsev(type,server,argc,argv))) {
370 free(newloc);
371 TT_Eval(TT_ARGS,"error {fparse: Error parsing format (No argument present for format argument number?).}");
372 return;
373 }
374
375 if(Tcl_SplitList(TT_Interp,newloc,&listc,(const char ***)&listv)==TCL_ERROR) {
376 free(newloc);
377 TT_Eval(TT_ARGS,"error {fdisplay: Given pathname argument is not a proper TCL list.}");
378 return;
379 }
380 for(n=0;n<listc;n++) {
381 echo(result,listv[n],atoi(hash_get(&activate,type)));
382 }
383 Tcl_Free((char *)listv);
384 free(newloc);
385 }
386
fdisplay(char * type,int server,int arguments,...)387 void fdisplay(char *type, int server, int arguments, ...) {
388 char *args[100]; // Make this dynamic.
389 int argpos=0;
390 int n;
391 va_list ap;
392
393 // Error kludge
394 if(arguments>100) {
395 fprintf(stderr,"fparse argument limit hit. Contact author.\n");
396 exit(1);
397 }
398
399 va_start(ap,arguments);
400 for(n=0;n<arguments;n++) {
401 args[argpos++]=va_arg(ap,char*);
402 }
403 va_end(ap);
404
405 fdisplayv(type, server, arguments, args);
406 }
407
fexists(const char * type)408 int fexists(const char *type) {
409 return (int)*hash_get(&formats,type);
410 }
411