summaryrefslogtreecommitdiff
path: root/src/dynmenu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dynmenu.cpp')
-rw-r--r--src/dynmenu.cpp821
1 files changed, 821 insertions, 0 deletions
diff --git a/src/dynmenu.cpp b/src/dynmenu.cpp
new file mode 100644
index 0000000..d231639
--- /dev/null
+++ b/src/dynmenu.cpp
@@ -0,0 +1,821 @@
1#include <unistd.h>
2#include <curses.h>
3#include <string.h>
4#include <string>
5#include <vector>
6#include <assert.h>
7#include <algorithm>
8#include <signal.h>
9
10class DynmenuView;
11typedef DynmenuView *DynmenuViewRef; // boost::shared_ptr<DynmenuView>
12
13class Dynmenu
14{
15 std::string m_title;
16 std::string m_welcomeText;
17 std::vector<DynmenuViewRef> views;
18
19 class Item {
20 char *desc;
21 Item(const Item &i) { assert(false); }
22 public:
23 std::string id;
24 std::string key;
25 std::string cmd;
26 const char *getText() const { return desc; }
27 void setText(const char *desc) {
28 if(this->desc) delete [] this->desc;
29 this->desc=new char[strlen(desc)+1];
30 strcpy(this->desc,desc);
31 }
32 Item(const char *id, const char *key, const char *desc, const char *cmd) :
33 id(id), key(key), cmd(cmd) { this->desc=NULL; setText(desc); }
34 ~Item() { delete [] desc; }
35 };
36
37 std::vector<Item *> items;
38
39 typedef std::vector<Item *>::iterator ItemIterator;
40 struct has_id : public std::binary_function<Item*,const char *,bool> {
41 bool operator ()( Item *item , const char *id) const { return item->id==id; }
42 };
43
44 int m_selection;
45
46public:
47
48 enum notify_id { TITLE, WELCOMETEXT, SELECTION };
49 void redraw() { sendNotify(TITLE); sendNotify(WELCOMETEXT); sendNotify(SELECTION); }
50 void setTitle(const char *s) { m_title = s; sendNotify(TITLE); }
51 const char*title() const { return m_title.c_str(); }
52 void setWelcomeText(const char *s) { m_welcomeText = s; sendNotify(WELCOMETEXT); }
53 const char *welcomeText() const { return m_welcomeText.c_str(); }
54 void setItem(const char *id, const char *sortkey, const char *desc, const char *cmd);
55 void delItem(const char *id);
56 int selection() const { return m_selection; }
57 bool haveSelection() const { return m_selection >= 0; }
58 void selectItem(const char *id);
59 const char *selectedCommand() const { return haveSelection() ? items[m_selection]->cmd.c_str() : ""; }
60 void cursorUp() { if( m_selection>0) m_selection--; sendNotify(SELECTION); }
61 void cursorDown() { if( m_selection+1<items.size()) m_selection++; sendNotify(SELECTION); }
62 Dynmenu() { m_selection = -1; }
63 ~Dynmenu() { for(int i=0;i<items.size();i++) delete items[i]; }
64
65 void registerView(DynmenuViewRef view);
66private:
67 void sendNotify(notify_id id);
68 void sendItemInsertion(int idx, const char *text);
69 void sendItemChanged(int idx, const char *text);
70 ItemIterator findItem(const char *id);
71};
72
73class DynmenuView
74{
75public:
76 virtual void notify(Dynmenu *menu, Dynmenu::notify_id id) = 0;
77 virtual void itemInserted(Dynmenu *menu, int index, const char *text ) = 0;
78 virtual void itemChanged(Dynmenu *menu, int index, const char *text ) = 0;
79 virtual ~DynmenuView() {}
80};
81
82class DynmenuSimpleView : public DynmenuView
83{
84public:
85 virtual void notify(Dynmenu *menu, Dynmenu::notify_id id) {
86 printf("notify %p %i\n", menu, id );
87 }
88 virtual void itemInserted(Dynmenu *menu, int index, const char *text ) {
89 //printf("itemInserted %p %i \"%s\" \"%s\"\n", menu, index, text, menu->items[index]->cmd.c_str() );
90 printf("itemInserted %p %i \"%s\"\n", menu, index, text );
91 }
92 virtual void itemChanged(Dynmenu *menu, int index, const char *text ) {
93 printf("itemChanged %p %i \"%s\"\n", menu, index, text );
94 }
95 virtual ~DynmenuSimpleView() {}
96};
97
98
99Dynmenu::ItemIterator Dynmenu::findItem(const char *id)
100{
101 using namespace std;
102 ItemIterator ret = find_if( items.begin(), items.end(), bind2nd( has_id(), id ) );
103 return ret;
104}
105
106void Dynmenu::setItem(const char *id, const char *sortkey, const char *desc, const char *cmd)
107{
108 std::vector<Item*>::iterator i;
109 i = findItem(id);
110 if(i==items.end()) {
111 items.push_back( new Item(id,sortkey,desc,cmd) );
112 // TODO: sort
113 sendItemInsertion( items.size()-1, items.back()->getText() );
114 if(m_selection==-1) {
115 m_selection=items.size()-1;
116 sendNotify(SELECTION);
117 }
118 }
119 else {
120 (*i)->cmd = cmd;
121 (*i)->setText(desc);
122 (*i)->key = sortkey; // TODO: resort
123 sendItemChanged( i - items.begin(), (*i)->getText() );
124 }
125}
126
127void Dynmenu::selectItem(const char *id)
128{
129 std::vector<Item*>::iterator i;
130 i = findItem(id);
131 if(i!=items.end()) {
132 m_selection = i - items.begin();
133 sendNotify(SELECTION);
134 }
135}
136
137void Dynmenu::delItem(const char *id){}
138
139void Dynmenu::registerView(DynmenuViewRef view)
140{
141 view->notify(this,TITLE);
142 view->notify(this,WELCOMETEXT);
143 std::vector<Item*>::iterator i;
144 for(i=items.begin(); i!=items.end(); i++ ) {
145 view->itemInserted( this, i - items.begin(), (*i)->getText() );
146 }
147 view->notify(this,SELECTION);
148 views.push_back(view);
149}
150
151void Dynmenu::sendNotify(notify_id id)
152{
153 for( std::vector<DynmenuViewRef>::iterator i=views.begin(); i!=views.end(); i++ ) {
154 (*i)->notify(this, id);
155 }
156}
157void Dynmenu::sendItemInsertion(int idx, const char *text )
158{
159 for( std::vector<DynmenuViewRef>::iterator i=views.begin(); i!=views.end(); i++ ) {
160 (*i)->itemInserted(this, idx, text);
161 }
162}
163void Dynmenu::sendItemChanged(int idx, const char *text )
164{
165 for( std::vector<DynmenuViewRef>::iterator i=views.begin(); i!=views.end(); i++ ) {
166 (*i)->itemChanged(this, idx, text);
167 }
168}
169
170int _g_y = 0;
171
172#define kdprintf(fmt,...) \
173 { char buf[200]; _g_y++; sprintf( buf, fmt "\n", ## __VA_ARGS__); mvaddnstr(_g_y,1,buf,strlen(buf)); refresh(); }
174#define dprintf(fmt,...)
175
176
177struct TextBox
178{
179 int y,x,w,h;
180 TextBox() : y(0),x(0),w(0),h(0) {}
181 void update(int x_, int y_, int w_, int h_) { y=y_;x=x_;w=w_;h=h_; }
182};
183
184
185class LineDrawer
186{
187public:
188 virtual void drawLine(WINDOW *win, int width, int number) = 0;
189 virtual int size() const = 0;
190};
191
192class ScrollWindow
193{
194 WINDOW *win;
195 int top_index;
196 LineDrawer *drawer;
197 void getExtants(int &maxy, int &maxx, int &count);
198public:
199 void redraw();
200 ScrollWindow() : win(NULL), top_index(0), drawer(NULL) {}
201 void setWin(WINDOW *w) { win=w; redraw(); }
202 void setLineDrawer(LineDrawer *d) { drawer = d; redraw(); }
203 void doScroll(int delta);
204 void scrollTo(int start, int end);
205 void invalidate(int start, int end);
206 void changedSize();
207};
208
209void ScrollWindow::getExtants(int &maxy, int &maxx, int &count)
210{
211 getmaxyx(win,maxy,maxx);
212 count = drawer->size();
213}
214
215void ScrollWindow::redraw()
216{
217 if(!win || !drawer) return;
218 int maxy,maxx,count;
219 getExtants(maxy,maxx,count);
220 wborder(win, 0, 0, top_index>0 ? '.' : 0, count < top_index+maxy-1 ? 0 : '.' , 0, 0, 0, 0);
221 for(int y=1,i=top_index;y<maxy-1;y++) {
222 if( i<count ) {
223 wmove(win,y,1);
224 drawer->drawLine(win,maxx-2,i++);
225 }
226 }
227 wrefresh(win);
228}
229
230void ScrollWindow::invalidate(int start, int end)
231{
232 int maxy,maxx,count;
233 if( end <= top_index ) return;
234 getExtants(maxy,maxx,count);
235 if( start > top_index+maxy-2 ) return;
236
237 if(start < top_index ) start = top_index;
238 if(end > top_index+maxy-2 ) end = top_index+maxy-2;
239 //if(end > count ) end = count;
240
241
242 int starty = 1 + start - top_index;
243 int stopy = starty + end - start;
244
245 for(int y=starty,i=start;y<stopy;y++) {
246 //if( i<count ) {
247 wmove(win,y,1);
248 drawer->drawLine(win,maxx-2,i++);
249 //}
250 }
251 wrefresh(win);
252}
253
254void ScrollWindow::scrollTo(int start, int end)
255{
256 if( start < top_index ) doScroll(start-top_index);
257 int maxy,maxx,count;
258 getExtants(maxy,maxx,count);
259 if( end > top_index+maxy-2 && start>top_index) {
260 int delta=end-top_index-maxy+2;
261 if( top_index+delta > start ) delta = start - top_index;
262 doScroll(delta);
263 }
264}
265
266void ScrollWindow::changedSize()
267{
268 int maxy,maxx,count;
269 getExtants(maxy,maxx,count);
270 wmove(win,maxy-1,1);
271 if( top_index+maxy-2<count) {
272 whline(win,'.',maxx-2);
273 wrefresh(win);
274 }
275 else if( top_index+maxy-2==count) {
276 whline(win,0,maxx-2);
277 wrefresh(win);
278 }
279}
280
281void ScrollWindow::doScroll(int delta)
282{
283 if(!win || !drawer) return;
284 //assert(delta>=-1 && delta<=1);
285 int maxy,maxx,count;
286 getExtants(maxy,maxx,count);
287
288 if( top_index+delta<0 ) delta = -top_index;
289 if (delta>0 && top_index>0 && top_index+maxy-1+delta>count) delta=count-top_index-maxy+2;
290 if (top_index+delta>count) delta=0;
291
292 if(delta==0) return;
293 dprintf("scrolling win=%p, drawer=%p, top_index+delta=%i, v=%i, count=%i", win, drawer, top_index+delta, top_index+maxy-1+delta, count);
294
295 dprintf("scrolling %i", delta);
296
297 WINDOW *w = derwin(win, maxy-2,maxx-2,1,1);
298 scrollok(w,true);
299 wscrl(w,delta);
300 scrollok(w,false);
301 touchwin(win);
302
303 if( top_index==0 ) {
304 wmove(win,0,1);
305 whline(win,'.',maxx-2);
306 }
307 if( top_index+maxy-2==count) {
308 wmove(win,maxy-1,1);
309 whline(win,'.',maxx-2);
310 }
311 top_index += delta;
312 int y = delta<0 ? 0 : maxy-2-delta;
313 int i = y + top_index;
314 dprintf("scroll values i=%i, y=%i", i, y);
315 delta = delta<0 ? -delta : delta;
316 for(int j=0;j<delta;j++) {
317 wmove(w,y++,0);
318 if(i<count) drawer->drawLine(w,maxx-2,i++);
319
320 }
321 wrefresh(w);
322 delwin(w);
323 if( top_index==0 ) {
324 wmove(win,0,1);
325 whline(win,0,maxx-2);
326 }
327 if( top_index+maxy-2==count) {
328 wmove(win,maxy-1,1);
329 whline(win,0,maxx-2);
330 }
331 wrefresh(win);
332}
333
334/*
335class ItemDrawer : public LineDrawer
336{
337public:
338 void drawLine(WINDOW *win, int width, int number);
339 int size() const { return 50; }
340};
341
342void ItemDrawer::drawLine(WINDOW *win, int width, int number)
343{
344 char buf[200];
345 sprintf(buf, "This is line #%i.", number );
346 waddnstr(win,buf, width);
347}
348*/
349
350class DynmenuCursesView : public DynmenuView, public LineDrawer
351{
352 int maxx, maxy;
353 WINDOW *win;
354 TextBox titleBox;
355 TextBox welcomeBox;
356 WINDOW *itemwin;
357 ScrollWindow itemScroll;
358 struct Item {
359 int top;
360 std::vector<const char *> text;
361 int compare(int line) {
362 if(line<top) return -1;
363 else if(line>=top+text.size()) return 1;
364 else return 0;
365 }
366 };
367 std::vector<Item> items;
368 int cached_index;
369 int selected;
370public:
371 DynmenuCursesView() : win(NULL),itemwin(NULL), maxx(0), maxy(0), cached_index(0), selected(-1) {
372 itemScroll.setLineDrawer(this);
373 }
374 ~DynmenuCursesView() { delwin(itemwin); }
375 void show(WINDOW *win);
376 void notify(Dynmenu *menu, Dynmenu::notify_id id);
377 void itemInserted(Dynmenu *menu, int index, const char *text );
378 void itemChanged(Dynmenu *menu, int index, const char *text );
379
380 // LineDrawer interface
381 void drawLine(WINDOW *win, int width, int number);
382 int size() const { if(items.size()==0) return 0; else return items.back().top + items.back().text.size(); }
383};
384
385void DynmenuCursesView::drawLine(WINDOW *win, int width, int number )
386{
387 int i = cached_index;
388 while( items[i].compare(number)>0 && i<items.size()-1 ) i++;
389 while( items[i].compare(number)<0 && i>0 ) i--;
390 if( items[i].compare(number)!=0 ) {
391 // If out of range, clear row
392 wattroff(win, A_STANDOUT);
393 for(int i=0;i<width;i++) waddch(win,' ');
394 return;
395 }
396 cached_index = i;
397 Item &item = items[cached_index];
398 i = number - item.top;
399 const char *end = NULL;
400 if( i < item.text.size()-1 ) end = item.text[i+1]-1;
401 if(!end) for(end=item.text[i];*end;end++);
402 size_t len = end - item.text[i];
403 len = len>width ? width : len;
404 // TODO: draw selection
405 if( selected == cached_index )
406 wattron(win, A_STANDOUT);
407 else
408 wattroff(win, A_STANDOUT);
409 waddnstr( win, item.text[i], len );
410 int mright = width - len;
411 for(int j=0;j<mright;j++) waddstr(win," ");
412 wattroff(win, A_STANDOUT);
413}
414
415void DynmenuCursesView::itemInserted(Dynmenu *menu, int index, const char *text)
416{
417 std::vector<Item>::iterator item = items.insert( items.begin() + index, Item() );
418 const char *p = text;
419 item->text.push_back(p);
420 for(;;) {
421 while( *p && *p!='\n' ) p++;
422 if(*p) p++;
423 if(*p) item->text.push_back(p);
424 else break;
425 }
426 int firstrow = 0;
427 if(item!=items.begin()) {
428 item->top = (item-1)->top + (item-1)->text.size();
429 }
430 else
431 item->top = 0;
432
433 firstrow = item->top;
434 if((item+1)!=items.end()) {
435 size_t newrows = item->text.size();
436 for( item++; item!=items.end(); item++ ) item->top += newrows;
437 }
438 itemScroll.invalidate( firstrow, size() );
439 itemScroll.changedSize();
440 wrefresh(win);
441}
442
443void DynmenuCursesView::itemChanged(Dynmenu *menu, int index, const char *text)
444{
445 std::vector<Item>::iterator item = items.begin() + index;
446 size_t oldsize = item->text.size();
447 int lastrow = items.back().top + items.back().text.size();
448 item->text.clear();
449 const char *p = text;
450 item->text.push_back(p);
451 for(;;) {
452 while( *p && *p!='\n' ) p++;
453 if(*p) p++;
454 if(*p) item->text.push_back(p);
455 else break;
456 }
457 int firstrow = item->top;
458 int diff = item->text.size() - oldsize;
459 if( diff ) {
460 for( item ++; item!=items.end(); item++ ) item->top += diff;
461 item = items.end() - 1;
462 }
463 else lastrow = item->top + oldsize;
464 if( lastrow < item->top + item->text.size() ) lastrow = item->top + item->text.size();
465
466 itemScroll.invalidate( firstrow, lastrow );
467 itemScroll.changedSize();
468 wrefresh(win);
469}
470
471void getTextExtents(const char *text, int &width, int &height )
472{
473 width = 0;
474 height = 0;
475 const char *p;
476 const char *s;
477 p = text;
478 do {
479 s = p;
480 while( *p && *p!='\n' ) p++;
481 if(p-s>0) {
482 height++;
483 if(width<p-s) width=p-s;
484 } else if (*p) height++;
485 if(*p) p++;
486 } while( *p );
487}
488
489void drawText( WINDOW *win, const TextBox &b, const char *text, const bool center = false )
490{
491 int cx,cy;
492 const char *p;
493 const char *s;
494 cx = b.x;
495 cy = b.y;
496 p = text;
497 do {
498 s = p;
499 while( *p && *p!='\n' ) p++;
500 int len = p-s;
501 if(len && cy<b.y+b.h ) {
502 int offset = center ? (b.w - cx - len) / 2 : 0;
503 int res = mvwaddnstr( win, cy, cx + offset, s, len);
504 }
505 cy++;
506 if(*p) p++;
507 } while( *p );
508}
509
510void clearBox( WINDOW *win, const TextBox &b )
511{
512 if(b.w==0 || b.h==0 ) return;
513 dprintf("clearing: h=%i, w=%i, y=%i, x=%i", b.h, b.w, b.y,b.x);
514 WINDOW *w = derwin(win,b.h,b.w,b.y,b.x);
515 werase(w);
516 touchwin(win);
517 wrefresh(w);
518 delwin(w);
519}
520
521void DynmenuCursesView::notify(Dynmenu *menu, Dynmenu::notify_id id)
522{
523 int tx,ty, tw,th, oldbottom;
524 switch(id) {
525 case Dynmenu::TITLE:
526 getTextExtents( menu->title(), tw, th );
527 tx = 0;
528 ty = 0;
529 tw = maxx - tx;
530 dprintf("tx = %i, ty=%i, title=%s, tw=%i", tx, ty, menu->title(), tw );
531 clearBox(win,titleBox);
532 oldbottom = titleBox.y+titleBox.h;
533 titleBox.update(tx,ty,tw,th);
534 if(oldbottom!=titleBox.y+titleBox.h) {
535 notify(menu,Dynmenu::WELCOMETEXT);
536 }
537 drawText(win,titleBox, menu->title(), true );
538 break;
539 case Dynmenu::WELCOMETEXT:
540 getTextExtents( menu->welcomeText(), tw, th );
541 tx = ( maxx - tw )/ 2;
542 ty = titleBox.y+titleBox.h+2;
543 clearBox(win,welcomeBox);
544 if(ty+th!=welcomeBox.y+welcomeBox.h) {
545 // Need to resize itemsBox
546 if(itemwin) {
547 werase(itemwin);
548 delwin(itemwin);
549 }
550 itemwin = derwin(win,maxy-ty-th-1,maxx-3, ty+th, 2);
551 itemScroll.setWin(itemwin);
552 }
553 welcomeBox.update(tx,ty,tw,th);
554 drawText(win,welcomeBox, menu->welcomeText() );
555 //mvwaddstr(win,ty,tx, menu->welcomeText() );
556 break;
557 case Dynmenu::SELECTION:
558 //dprintf("items=%zu, selection=%i", menu->items.size(), menu->selection() );
559 int sel=selected;
560 selected = menu->selection();
561 if(sel!=-1)
562 itemScroll.invalidate(items[sel].top, items[sel].top+items[sel].text.size() );
563 sel = selected;
564 if(sel!=-1) {
565 itemScroll.invalidate(items[sel].top, items[sel].top+items[sel].text.size() );
566 itemScroll.scrollTo(items[sel].top, items[sel].top+items[sel].text.size() );
567 wrefresh(itemwin);
568 }
569 break;
570 }
571 wrefresh(win);
572}
573
574void DynmenuCursesView::show(WINDOW *win)
575{
576 if( win ) {
577 this->win = win;
578 getmaxyx(win,maxy,maxx);
579 //box(win, 0, 0);
580 if(itemwin) { wrefresh(itemwin); }
581 wrefresh(win);
582 }
583 else {
584 }
585}
586
587#include <string>
588#include <cctype>
589
590using std::string;
591using std::isspace;
592
593class Parser
594{
595 int peeked;
596 void *gdata;
597 int (*getter)(void *);
598 int peek() { return peeked==-2 ? (peeked=getter(gdata)) : peeked; }
599 int get() { int retv = peeked==-2? (peeked=getter(gdata)) : peeked; peeked=-2; return retv;}
600 bool peekedSpace() { return isspace(peek()); }
601 void skipSpace() { while(peekedSpace()) get(); }
602public:
603 enum tokentype { Identifier, String, EOL };
604 enum exception { NoGetter, SyntaxError };
605 void setCharGetter( int (*g)(void*), void *user ) { getter=g; gdata=user; }
606 void expect( tokentype t, std::string &s );
607 Parser() : peeked(-2), getter(NULL), gdata(NULL) {}
608};
609
610void Parser::expect( tokentype t, std::string &s )
611{
612 if(! getter ) throw NoGetter;
613
614 int c;
615
616 switch( t ) {
617 case Identifier:
618 skipSpace();
619 s = "";
620 while( peek()!=-1 && ! peekedSpace() ) s += (char)get() ;
621 break;
622 case String:
623 skipSpace();
624 s = "";
625 if( peek() !='"' ) throw SyntaxError;
626 get(); // peel off open-quote
627 while(peek()!='"' && peek()!=-1 ) {
628 c = get();
629 if( c=='\\') {
630 c=get(); // allow escaped quotes
631 if(c=='n') c='\n';
632 else if(c=='t') c='\t';
633 }
634 s += (char)c ;
635 }
636 get(); // peel off close-quote
637 break;
638 case EOL:
639 while( peek()!=-1 && isspace(peek()) && peek()!='\n' ) get();
640 if( !isspace(peek()) ) throw SyntaxError;
641 break;
642 }
643}
644
645
646
647
648#include <sys/select.h>
649#include <errno.h>
650#include <fcntl.h>
651#include <stdio.h>
652
653#define CTRLL 12
654
655
656int buf_getc( const char **p )
657{
658 if(**p) return *((*p)++);
659 else return -1;
660}
661
662void trap_signals()
663{
664 struct sigaction s;
665 s.sa_handler = SIG_IGN;
666 int sig[] = { SIGINT, SIGTSTP, SIGQUIT, };
667 for (int i=0; i<sizeof(sig)/sizeof(sig[0]); ++i)
668 sigaction(sig[i], &s, 0);
669}
670
671void bye(void) { if (!isendwin()) endwin(); }
672
673int main(int argc, char **argv)
674{
675 // char buf1[3]; strcpy(buf1, "joehere"); printf("buf=\"%s\"\n");
676 if (argc != 2) {
677 fputs("usage: dynmenu socket-file\n", stderr);
678 return 1;
679 }
680
681 trap_signals();
682
683 Dynmenu menu;
684
685//#define SIMPLE
686#ifdef SIMPLE
687 DynmenuSimpleView view;
688#else
689 DynmenuCursesView view;
690 WINDOW *win = initscr();
691 atexit(bye);
692 curs_set(0); cbreak(); noecho(); keypad(stdscr, 1);
693 wclear(win);
694 view.show(win);
695#endif
696 menu.registerView( &view );
697 int fd;
698
699 fd_set fds;
700 int res;
701 if ((fd = open((const char *) argv[1], O_RDWR|O_NONBLOCK)) < 0) {
702 perror("error opening socket-file");
703 return 1;
704 }
705 FILE *fifo;
706 if ((fifo = fdopen(fd, "r")) == NULL) {
707 perror("error opening socket-file: fdopen");
708 return 1;
709 }
710
711 FD_ZERO(&fds); FD_SET(fd, &fds); FD_SET(0, &fds);
712top:
713 /* Note: On terminal resize, select returns -1 and sets errno to EINTR */
714 dprintf("mainloop...");
715 while ((res = select(fd+1, &fds, NULL, NULL, NULL)) >= 0)
716 {
717 if (FD_ISSET(0, &fds)) {
718 //dprintf("char !");//space!");
719 int c = getch();
720 if (c == ERR) {
721 perror("error reading stdin");
722 return 1;
723 }
724 switch (c) {
725 case KEY_UP: case 'k': menu.cursorUp(); break;
726 case KEY_DOWN: case 'j': menu.cursorDown(); break;
727 case KEY_RIGHT: case '\n': case '\x0d': case 'l':
728 case KEY_ENTER:
729 if (!menu.haveSelection())
730 break;
731 bye();
732 endwin();
733 execl("/bin/sh", "/bin/sh", "-c", menu.selectedCommand(), (char *) NULL);
734 perror("exec failed");
735 exit(1);
736 break;
737
738 case 'Q': bye(); endwin(); exit(0); break;
739
740#ifndef SIMPLE
741 case 'r':
742 case CTRLL: menu.redraw(); break;
743#endif
744/*
745 case ' ':
746 {
747 dprintf("space!");
748 static char b = 'A';
749 char buf[80]; sprintf( buf, "Letter '%c'", b++ );
750 menu.setItem( "id3", "3", buf, "id3 cmd");
751 }
752*/
753 break;
754 }
755 }
756 if (FD_ISSET(fd, &fds)) {
757 Parser *p = new Parser;
758 char line[1024];//[PIPE_BUF];
759 assert(line);
760 char *pointer = line;
761 while (fgets(line, 1024, fifo) != NULL) {
762 dprintf("%s", line );
763 try {
764 pointer = line;
765 string menuMethod(1024,' ');
766 string id(1024, ' '); string sortkey(1024, ' ');
767 string desc(1024, ' '); string cmd(1024, ' '); string dummy;
768 p->setCharGetter( (int (*)(void*))buf_getc, (void*)&pointer );
769 p->expect( Parser::Identifier, menuMethod );
770 if( menuMethod=="setItem" ) {
771 p->expect( Parser::String, id );
772 p->expect( Parser::String, sortkey );
773 p->expect( Parser::String, desc );
774 p->expect( Parser::String, cmd );
775 menu.setItem( id.c_str(), sortkey.c_str(), desc.c_str(), cmd.c_str() );
776 }
777 else if( menuMethod=="setTitle" ) {
778 p->expect( Parser::String, desc );
779 menu.setTitle( desc.c_str() );
780 }
781 else if( menuMethod=="setWelcomeText" ) {
782 p->expect( Parser::String, desc );
783 menu.setWelcomeText( desc.c_str() );
784 }
785 else if( menuMethod=="delItem" ) {
786 p->expect( Parser::String, id );
787 menu.delItem( id.c_str() );
788 }
789 else if( menuMethod=="selectItem" ) {
790 p->expect( Parser::String, id );
791 menu.selectItem( id.c_str() );
792 }
793 }
794 catch(...) {
795 dprintf("exception");
796 }
797 }
798 }
799 FD_ZERO(&fds);
800 if (!feof(fifo)) // will never eof if it is a fifo
801 FD_SET(fd, &fds); // could use inotify here...
802 FD_SET(0, &fds);
803 }
804 char ebuf[80] ="";
805 switch(errno)
806 {
807 case EINTR:
808 menu.redraw();
809 goto top;
810 case EBADF: strcpy(ebuf, "EBADF"); break;
811 case EINVAL: strcpy(ebuf, "EINVAL"); break;
812 case ENOMEM: strcpy(ebuf, "ENOMEM"); break;
813 default: sprintf(ebuf, "0x%X", errno);
814 }
815 endwin();
816 printf(" errno = %s\n", ebuf );
817
818 return 0;
819}
820
821// vim:ts=2 sw=2 et: