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