1 /*
2 * Copyright (C) 2014-2015 Christian Heckendorf <heckendorfc@gmail.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include "build.h"
21 #include "edit_shell.h"
22 #include "util.h"
23 #include "dbact.h"
24
25 /* substitute vars if needed
26 * escape words in quotes if needed
27 * glob
28 */
29
free_wordchain(wordchain_t * w)30 void free_wordchain(wordchain_t *w){
31 wordchain_t *p;
32 if(!w)return;
33 for(p=w->next;w;){
34 free(w);
35 w=p;
36 if(p)p=p->next;
37 }
38 }
39
free_arglist(arglist_t * a)40 void free_arglist(arglist_t *a){
41 arglist_t *p;
42 if(!a)return;
43 for(p=a->next;a;){
44 free(a->words);
45 free(a);
46 a=p;
47 if(p)p=p->next;
48 }
49 }
50
free_wordlist(wordlist_t * w)51 void free_wordlist(wordlist_t *w){
52 wordlist_t *p;
53 if(!w)return;
54 for(p=w->next;w;){
55 free(w->word);
56 free(w);
57 w=p;
58 if(p)p=p->next;
59 }
60 }
61
free_commands(command_t * c)62 void free_commands(command_t *c){
63 command_t *p;
64 if(!c)return;
65 for(p=c->next;c;){
66 free_arglist(c->args);
67 free(c);
68 c=p;
69 if(p)p=p->next;
70 }
71 }
72
make_word(wordchain_t * word,char * piece,int flags)73 wordchain_t* make_word(wordchain_t *word, char *piece, int flags){
74 wordchain_t *ptr=word;
75 if(piece && *piece){
76 if(!word){
77 INIT_MEM(word,1);
78 ptr=word;
79 word->word=NULL;
80 word->flags=0;
81 word->next=NULL;
82 }
83 else{
84 wordchain_t *temp=ptr;
85 INIT_MEM(ptr,1);
86 ptr->next=temp;
87 }
88 ptr->word=strdup(piece);
89 ptr->flags=flags;
90 }
91 return ptr;
92 }
93
94 /* default:
95 subs allowed
96 ":
97 no subs, vars allowed
98 ':
99 no subs, no vars
100 */
wordcat(char * word,int * wordsize,wordchain_t * wc)101 void wordcat(char *word, int *wordsize, wordchain_t *wc){
102 int i;
103 char *wp=word;
104
105 while(*wp)wp++;
106 if(wc->flags&(WORD_DEFAULT)){
107 for(i=0;wc->word[i];i++){
108 *(wp++)=wc->word[i];
109 }
110 *wp=0;
111 }
112 else if(wc->flags&(WORD_SQUOT|WORD_DQUOT)){
113 for(i=0;wc->word[i];i++){
114 switch(wc->word[i]){
115 case '\\':
116 case '*':
117 case '?':
118 case '[':
119 *(wp++)='\\';
120 break;
121 case '$':
122 if(wc->flags&WORD_SQUOT)
123 *(wp++)='\\';
124 break;
125 }
126 *(wp++)=wc->word[i];
127 }
128 *wp=0;
129 }
130 else
131 fprintf(stderr,"Warning: invalid word flags (%s)(%d)!\n",wc->word,wc->flags);
132 }
133
merge_wordchain(wordchain_t * word)134 char* merge_wordchain(wordchain_t *word){
135 wordchain_t *wc_ptr;
136 int wordsize=0;
137 char *ret;
138
139 for(wc_ptr=word;wc_ptr;wc_ptr=wc_ptr->next){
140 wordsize+=strlen(wc_ptr->word);
141 }
142
143 wordsize=2*wordsize+1;
144 INIT_MEM(ret,wordsize);
145 *ret=0;
146 for(wc_ptr=word;wc_ptr;wc_ptr=wc_ptr->next){
147 wordcat(ret,&wordsize,wc_ptr);
148 }
149
150 return ret;
151 }
152
append_wordlist(wordlist_t * a,wordlist_t * b)153 wordlist_t* append_wordlist(wordlist_t *a, wordlist_t *b){
154 if(!a){
155 if(b){
156 return b;
157 }
158 return NULL;
159 }
160 while(a->next){
161 a=a->next;
162 }
163 a->next=b;
164 return a;
165 }
166
167 /* concat all words in b onto the final word in a */
concat_wordlist(wordlist_t * a,wordlist_t * b)168 wordlist_t* concat_wordlist(wordlist_t *a, wordlist_t *b){
169 const char wordsep=' ';
170 int count,i;
171 char *c;
172 wordlist_t *temp;
173
174 if(!a || !b)return NULL; // Should do something else...
175
176 INIT_MEM(c,1);
177
178 while(a->next)a=a->next;
179
180 temp=b;
181 count=i=strlen(a->word);
182 while(temp){
183 i+=strlen(temp->word)+1;
184 temp=temp->next;
185 }
186
187 INIT_MEM(c,i);
188 memcpy(c,a->word,count);
189 temp=b;
190 for(i=0;temp;temp=temp->next){
191 i=strlen(temp->word);
192 memcpy(c+count,temp->word,i);
193 count+=i;
194 c[count++]=wordsep;
195 }
196 c[count-1]=0;
197 if(a->word)
198 free(a->word);
199 a->word=c;
200
201 return a;
202 }
203
make_word_list(wordlist_t * wl,wordchain_t * word)204 wordlist_t* make_word_list(wordlist_t *wl, wordchain_t *word){
205 wordlist_t *wl_ptr;
206 if(!wl){
207 INIT_MEM(wl,1);
208 wl_ptr=wl;
209 wl->next=NULL;
210 }
211 else{
212 for(wl_ptr=wl;wl_ptr->next;wl_ptr=wl_ptr->next);
213 INIT_MEM(wl_ptr->next,1);
214 wl_ptr=wl_ptr->next;
215 wl_ptr->next=NULL;
216 }
217
218 wl_ptr->word=merge_wordchain(word);
219 wl_ptr->flag=word->flags; // TODO: scan all words?
220
221 free_wordchain(word);
222
223 return wl;
224 }
225
226 static char *selectors[]={
227 "song",
228 "album",
229 "artist",
230 "playlist",
231 "tag",
232 NULL
233 };
234
235 static char *selectfield[]={
236 "SongID",
237 "AlbumID",
238 "ArtistID",
239 "PlaylistID",
240 "TagID",
241 };
242
243 static char *selecttable[]={
244 "Song",
245 "Album",
246 "Artist",
247 "Playlist",
248 "Tag"
249 };
250
251 static char *selectcomp[]={
252 "Title",
253 "Title",
254 "Name",
255 "Title",
256 "Name",
257 };
258
259 static char shouldmake[]={
260 0,
261 0,
262 0,
263 1,
264 1,
265 };
266
get_select_type(command_t * c)267 static int get_select_type(command_t *c){
268 int ret;
269
270 for(ret=0;selectors[ret];ret++){
271 if(strcmp(selectors[ret],c->cmd->word)==0)
272 return ret;
273 }
274 //return -1;
275 return 0; /* song default ? */
276 }
277
get_templist(arglist_t * a,int ctype)278 static int get_templist(arglist_t *a, int ctype){
279 if(a->words->flag==WORD_DEFAULT){ // ID
280 int id = strtol(a->words->word,NULL,10);
281 return insertTempSelect(&id,1);
282 }
283 else{ // Name
284 char query[300];
285 int ret,num;
286 if(a->words->flag==WORD_DQUOT)
287 sprintf(query,"SELECT %%d,%s FROM %s WHERE %s LIKE '%%%%%s%%%%'",selectfield[ctype],selecttable[ctype],selectcomp[ctype],a->words->word);
288 else
289 sprintf(query,"SELECT %%d,%s FROM %s WHERE %s='%s'",selectfield[ctype],selecttable[ctype],selectcomp[ctype],a->words->word);
290 ret=insertTempSelectQueryCount(query,&num);
291 if(num==0 && shouldmake[ctype]){
292 sprintf(query,"INSERT INTO %s(%s) VALUES(\"%s\")",selecttable[ctype],selectcomp[ctype],a->words->word);
293 harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
294 num=sqlite3_last_insert_rowid(conn);
295 return insertTempSelect(&num,1);
296 //sprintf(query,"SELECT %%d,%s FROM %s WHERE %s LIKE '%%%%%s%%%%'",selectfield[ctype],selecttable[ctype],selectcomp[ctype],a->words->word);
297 //return insertTempSelectQuery(query);
298 }
299 return ret;
300 }
301 }
302
303 static char *translatequery[]={
304 NULL,//ss
305 "SELECT %%d,AlbumID FROM Song WHERE SongID IN (%s)",//sa (song -> album)
306 "SELECT %%d,ArtistID FROM AlbumArtist NATURAL JOIN Song WHERE SongID IN (%s)",//sr
307 "SELECT %%d,PlaylistID FROM PlaylistSong WHERE SongID IN (%s)",//sp
308 "SELECT %%d,TagID FROM SongTag WHERE SongID IN (%s)",//st
309
310 "SELECT %%d,SongID FROM Song WHERE AlbumID IN (%s)",//as
311 NULL,//aa
312 "SELECT %%d,ArtistID FROM AlbumArtist WHERE AlbumID IN (%s)",//ar
313 "SELECT %%d,PlaylistID FROM PlaylistSong NATURAL JOIN Song WHERE AlbumID IN (%s)",//ap
314 "SELECT %%d,TagID FROM SongTag NATURAL JOIN Song WHERE AlbumID IN (%s)",//at
315
316 "SELECT %%d,SongID FROM Song NATURAL JOIN AlbumArtist WHERE ArtistID IN (%s)",//rs
317 "SELECT %%d,AlbumID FROM AlbumArtist WHERE ArtistID IN (%s)",//ra
318 NULL,//rr
319 "SELECT %%d,PlaylistID FROM PlaylistSong NATURAL JOIN Song NATURAL JOIN AlbumArtist WHERE IN ArtistID(%s)",//rp
320 "SELECT %%d,TagID FROM SongTag NATURAL JOIN Song NATURAL JOIN AlbumArtist WHERE ArtistID IN (%s)",//rt
321
322 "SELECT %%d,SongID FROM PlaylistSong WHERE PlaylistID IN (%s)",//ps
323 "SELECT %%d,AlbumID FROM PlaylistSong NATURAL JOIN Song WHERE PlaylistID IN (%s)",//pa
324 "SELECT %%d,ArtistID FROM PlaylistSong NATURAL JOIN Song NATURAL JOIN AlbumArtist WHERE PlaylistID IN (%s)",//pr
325 NULL,//pp
326 "SELECT %%d,TagID FROM SongTag NATURAL JOIN PlaylistSong WHERE PlaylistID IN (%s)",//pt
327
328 "SELECT %%d,SongID FROM SongTag WHERE TagID IN (%s)",//ts
329 "SELECT %%d,AlbumID FROM SongTag NATURAL JOIN Song WHERE TagID IN (%s)",//ta
330 "SELECT %%d,ArtistID FROM SongTag NATURAL JOIN Song NATURAL JOIN AlbumArtist WHERE TagID IN (%s)",//tr
331 "SELECT %%d,PlaylistID FROM SongTag NATURAL JOIN PlaylistSong WHERE TagID IN (%s)",//tp
332 NULL,//tt
333 };
334 static const int numtypes=5;
335
translate_templist(int toid,int totype,int fromid,int fromtype,int cleanup)336 static int translate_templist(int toid, int totype, int fromid, int fromtype, int cleanup){
337 char query[300];
338 char subquery[300];
339 int newid;
340 if(toid<0 && totype==fromtype)
341 return fromid;
342 else{
343 if(totype==fromtype){
344 mergeTempSelect(toid,fromid);
345 newid=toid;
346 }
347 else{
348 sprintf(subquery,"SELECT SelectID FROM TempSelect WHERE TempID=%d",fromid);
349 sprintf(query,translatequery[fromtype*numtypes+totype],subquery);
350 newid=insertTempSelectQuery(query);
351 //mergeTempSelect(toid,newid);
352 }
353 }
354
355 if(cleanup)
356 cleanTempSelect(fromid);
357
358 return newid;
359 }
360
make_com_arg(void * data,int flag)361 arglist_t* make_com_arg(void *data, int flag){
362 arglist_t *ret;
363
364 INIT_MEM(ret,1);
365 ret->flags=flag;
366 ret->next=NULL;
367
368 if(flag==COM_ARG_SELECTOR){
369 command_t *c = (command_t*)data;
370 arglist_t *a = c->args;
371 int atid;
372 int cid=-1;
373
374 ret->tltype=c->tltype;
375
376 if(c->tlid>=0)
377 cid=c->tlid;
378 else{
379 while(a){
380 atid=get_templist(a,c->tltype);
381
382 if(cid==-1)
383 cid=atid;
384 else
385 mergeTempSelect(cid,atid);
386
387 a=a->next;
388 }
389 }
390
391 ret->words=NULL;
392 ret->tlid=cid;
393 }
394 else{
395 wordlist_t *wl = (wordlist_t*)data;
396 ret->words=wl;
397 ret->tlid=-1;
398 ret->tltype=-1;
399 }
400
401 //ret->args=wl;
402 //fprintf(stderr,"arg: %s\n",wl->word);
403
404 return ret;
405 }
406
append_com_arg(arglist_t * a,arglist_t * b)407 arglist_t* append_com_arg(arglist_t *a, arglist_t *b){
408 if(b){
409 b->next=a;
410 return b;
411 }
412 return a;
413 }
414
com_sel_set_args(command_t * c,arglist_t * a)415 void com_sel_set_args(command_t *c, arglist_t *a){
416 arglist_t *ta;
417 int cid;
418 ta=c->args=a;
419
420 while(ta){
421 if(ta->tltype<0) // single native
422 cid=ta->tlid=get_templist(ta,c->tltype);
423 else
424 cid=translate_templist(c->tlid,c->tltype,ta->tlid,ta->tltype,1);
425
426 if(c->tlid<0)
427 c->tlid=cid;
428 else
429 mergeTempSelect(c->tlid,cid);
430
431 ta=ta->next;
432 }
433 }
434
com_act_set_args(command_t * c,arglist_t * a)435 void com_act_set_args(command_t *c, arglist_t *a){
436 c->args=a;
437 }
438
com_set_args(command_t * c,arglist_t * a,int flag)439 command_t* com_set_args(command_t *c, arglist_t *a, int flag){
440 c->flags=flag;
441
442 //if(flag==COM_SEL)
443 com_sel_set_args(c,a);
444 //else
445 //com_act_set_args(c,a);
446 return c;
447 }
448
make_command(wordlist_t * wl)449 command_t* make_command(wordlist_t *wl){
450 command_t *ret;
451
452 INIT_MEM(ret,1);
453 ret->cmd=wl;
454 ret->args=NULL;
455 ret->flags=0;
456 ret->next=NULL;
457 ret->tltype=get_select_type(ret);
458 ret->tlid=-1;
459
460 return ret;
461 }
462
append_command(command_t * a,command_t * b)463 command_t* append_command(command_t *a, command_t *b){
464 command_t *temp=a;
465
466 while(a->next)a=a->next;
467 a->next=b;
468
469 return temp;
470 }
471
append_command_flags(command_t * a,const int flags)472 void append_command_flags(command_t *a, const int flags){
473 while(a->next)a=a->next;
474 a->flags|=flags;
475 }
476
make_commandline(command_t * sel,command_t * act)477 commandline_t* make_commandline(command_t *sel, command_t *act){
478 commandline_t *ret;
479
480 INIT_MEM(ret,1);
481 ret->selector=sel;
482 ret->actions=act;
483
484 return ret;
485 }
486