980ffbeba94c243839f84119811bb9747fce57f3
[ncurses.git] / test / cardfile.c
1 /****************************************************************************
2  * Copyright (c) 1999,2000 Free Software Foundation, Inc.                   *
3  *                                                                          *
4  * Permission is hereby granted, free of charge, to any person obtaining a  *
5  * copy of this software and associated documentation files (the            *
6  * "Software"), to deal in the Software without restriction, including      *
7  * without limitation the rights to use, copy, modify, merge, publish,      *
8  * distribute, distribute with modifications, sublicense, and/or sell       *
9  * copies of the Software, and to permit persons to whom the Software is    *
10  * furnished to do so, subject to the following conditions:                 *
11  *                                                                          *
12  * The above copyright notice and this permission notice shall be included  *
13  * in all copies or substantial portions of the Software.                   *
14  *                                                                          *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22  *                                                                          *
23  * Except as contained in this notice, the name(s) of the above copyright   *
24  * holders shall not be used in advertising or otherwise to promote the     *
25  * sale, use or other dealings in this Software without prior written       *
26  * authorization.                                                           *
27  ****************************************************************************/
28
29 /*
30  * Author: Thomas E. Dickey <dickey@clark.net> 1999
31  *
32  * $Id: cardfile.c,v 1.4 2000/03/19 01:34:00 tom Exp $
33  *
34  * File format: text beginning in column 1 is a title; other text forms the content.
35  */
36
37 #include <test.priv.h>
38
39 #include <form.h>
40 #include <panel.h>
41
42 #include <string.h>
43 #include <ctype.h>
44
45 #define VISIBLE_CARDS 10
46 #define OFFSET_CARD 2
47
48 #ifndef CTRL
49 #define CTRL(x)         ((x) & 0x1f)
50 #endif
51
52 typedef struct _card {
53     struct _card *link;
54     PANEL *panel;
55     FORM *form;
56     char *title;
57     char *content;
58 } CARD;
59
60 static CARD *all_cards;
61 static char default_name[] = "cardfile.dat";
62
63 #if !HAVE_STRDUP
64 #define strdup my_strdup
65 static char *
66 strdup(char *s)
67 {
68     char *p = (char *) malloc(strlen(s) + 1);
69     if (p)
70         strcpy(p, s);
71     return (p);
72 }
73 #endif /* not HAVE_STRDUP */
74
75 static char *
76 skip(char *buffer)
77 {
78     while (isspace(*buffer))
79         buffer++;
80     return buffer;
81 }
82
83 static void
84 trim(char *buffer)
85 {
86     unsigned n = strlen(buffer);
87     while (n-- && isspace(buffer[n]))
88         buffer[n] = 0;
89 }
90
91 /*******************************************************************************/
92
93 static CARD *
94 add_title(const char *title)
95 {
96     CARD *card, *p, *q;
97
98     for (p = all_cards, q = 0; p != 0; q = p, p = p->link) {
99         int cmp = strcmp(p->title, title);
100         if (cmp == 0)
101             return p;
102         if (cmp > 0)
103             break;
104     }
105
106     card = (CARD *) calloc(1, sizeof(CARD));
107     card->title = strdup(title);
108     card->content = strdup("");
109
110     if (q == 0) {
111         card->link = all_cards;
112         all_cards = card;
113     } else {
114         card->link = q->link;
115         q->link = card;
116     }
117
118     return card;
119 }
120
121 static void
122 add_content(CARD * card, char *content)
123 {
124     unsigned total, offset;
125
126     content = skip(content);
127     if ((total = strlen(content)) != 0) {
128         if ((offset = strlen(card->content)) != 0) {
129             total += 1 + offset;
130             card->content = (char *) realloc(card->content, total + 1);
131             strcpy(card->content + offset++, " ");
132         } else {
133             card->content = (char *) malloc(total + 1);
134         }
135         strcpy(card->content + offset, content);
136     }
137 }
138
139 static CARD *
140 new_card(void)
141 {
142     CARD *card = add_title("");
143     add_content(card, "");
144     return card;
145 }
146
147 static CARD *
148 find_card(char *title)
149 {
150     CARD *card;
151
152     for (card = all_cards; card != 0; card = card->link)
153         if (!strcmp(card->title, title))
154             break;
155
156     return card;
157 }
158
159 static void
160 read_data(char *fname)
161 {
162     FILE *fp;
163     CARD *card = 0;
164     char buffer[BUFSIZ];
165
166     if ((fp = fopen(fname, "r")) != 0) {
167         while (fgets(buffer, sizeof(buffer), fp)) {
168             trim(buffer);
169             if (isspace(*buffer)) {
170                 if (card == 0)
171                     card = add_title("");
172                 add_content(card, buffer);
173             } else if ((card = find_card(buffer)) == 0) {
174                 card = add_title(buffer);
175             }
176         }
177         fclose(fp);
178     }
179 }
180
181 /*******************************************************************************/
182
183 static void
184 write_data(const char *fname)
185 {
186     FILE *fp;
187     CARD *p = 0;
188     int n;
189
190     if (!strcmp(fname, default_name))
191         fname = "cardfile.out";
192
193     if ((fp = fopen(fname, "w")) != 0) {
194         for (p = all_cards; p != 0; p = p->link) {
195             FIELD **f = form_fields(p->form);
196             for (n = 0; f[n] != 0; n++) {
197                 char *s = field_buffer(f[n], 0);
198                 if (s != 0
199                     && (s = strdup(s)) != 0) {
200                     trim(s);
201                     fprintf(fp, "%s%s\n", n ? "\t" : "", s);
202                     free(s);
203                 }
204             }
205         }
206         fclose(fp);
207     }
208 }
209
210 /*******************************************************************************/
211
212 /*
213  * Count the cards
214  */
215 static int
216 count_cards(void)
217 {
218     CARD *p;
219     int count = 0;
220
221     for (p = all_cards; p != 0; p = p->link)
222         count++;
223
224     return count;
225 }
226
227 /*
228  * Shuffle the panels to keep them in a natural hierarchy.
229  */
230 static void
231 order_cards(CARD * first, int depth)
232 {
233     if (first) {
234         if (depth && first->link)
235             order_cards(first->link, depth - 1);
236         top_panel(first->panel);
237     }
238 }
239
240 /*
241  * Return the next card in the list
242  */
243 static CARD *
244 next_card(CARD * now)
245 {
246     if (now->link)
247         now = now->link;
248     return now;
249 }
250
251 /*
252  * Return the previous card in the list
253  */
254 static CARD *
255 prev_card(CARD * now)
256 {
257     CARD *p;
258     for (p = all_cards; p != 0; p = p->link)
259         if (p->link == now)
260             return p;
261     return now;
262 }
263
264 /*******************************************************************************/
265
266 static int
267 form_virtualize(WINDOW *w)
268 {
269     int c = wgetch(w);
270
271     switch (c) {
272     case CTRL('W'):
273         return (MAX_FORM_COMMAND + 4);
274     case CTRL('N'):
275         return (MAX_FORM_COMMAND + 3);
276     case CTRL('P'):
277         return (MAX_FORM_COMMAND + 2);
278     case CTRL('Q'):
279     case 033:
280         return (MAX_FORM_COMMAND + 1);
281
282     case KEY_BACKSPACE:
283         return (REQ_DEL_PREV);
284     case KEY_DC:
285         return (REQ_DEL_CHAR);
286     case KEY_LEFT:
287         return (REQ_LEFT_CHAR);
288     case KEY_RIGHT:
289         return (REQ_RIGHT_CHAR);
290
291     case KEY_DOWN:
292     case KEY_NEXT:
293         return (REQ_NEXT_FIELD);
294     case KEY_UP:
295     case KEY_PREVIOUS:
296         return (REQ_PREV_FIELD);
297
298     default:
299         return (c);
300     }
301 }
302
303 /*******************************************************************************/
304
305 static void
306 cardfile(char *fname)
307 {
308     WINDOW *win;
309     CARD *p;
310     CARD *top_card;
311     int visible_cards = count_cards();
312     int panel_wide = COLS - (visible_cards * OFFSET_CARD);
313     int panel_high = LINES - (visible_cards * OFFSET_CARD) - 5;
314     int form_wide = panel_wide - 2;
315     int form_high = panel_high - 2;
316     int x = (visible_cards - 1) * OFFSET_CARD;
317     int y = 0;
318     int ch;
319     int finished = FALSE;
320
321     move(LINES - 3, 0);
322     addstr("^Q/ESC -- exit form            ^W   -- writes data to file\n");
323     addstr("^N   -- go to next card        ^P   -- go to previous card\n");
324     addstr("Arrow keys move left/right within a field, up/down between fields");
325
326     /* make a panel for each CARD */
327     for (p = all_cards; p != 0; p = p->link) {
328         FIELD **f = (FIELD **) calloc(3, sizeof(FIELD *));
329
330         win = newwin(panel_high, panel_wide, x, y);
331         keypad(win, TRUE);
332         p->panel = new_panel(win);
333         box(win, 0, 0);
334
335         /* ...and a form in each panel */
336         f[0] = new_field(1, form_wide, 0, 0, 0, 0);
337         set_field_back(f[0], A_REVERSE);
338         set_field_buffer(f[0], 0, p->title);
339
340         f[1] = new_field(form_high - 1, form_wide, 1, 0, 0, 0);
341         set_field_buffer(f[1], 0, p->content);
342         set_field_just(f[1], JUSTIFY_LEFT);
343
344         f[2] = 0;
345
346         p->form = new_form(f);
347         set_form_win(p->form, win);
348         set_form_sub(p->form, derwin(win, form_high, form_wide, 1, 1));
349         post_form(p->form);
350
351         x -= OFFSET_CARD;
352         y += OFFSET_CARD;
353     }
354
355     order_cards(top_card = all_cards, visible_cards);
356
357     while (!finished) {
358         update_panels();
359         doupdate();
360
361         switch (form_driver(top_card->form, ch =
362                 form_virtualize(panel_window(top_card->panel)))) {
363         case E_OK:
364             break;
365         case E_UNKNOWN_COMMAND:
366             switch (ch) {
367             case MAX_FORM_COMMAND + 1:
368                 finished = TRUE;
369                 break;
370             case MAX_FORM_COMMAND + 2:
371                 top_card = prev_card(top_card);
372                 order_cards(top_card, visible_cards);
373                 break;
374             case MAX_FORM_COMMAND + 3:
375                 top_card = next_card(top_card);
376                 order_cards(top_card, visible_cards);
377                 break;
378             case MAX_FORM_COMMAND + 4:
379                 write_data(fname);
380                 break;
381             default:
382                 beep();
383                 break;
384             }
385             break;
386         default:
387             flash();
388             break;
389         }
390     }
391 }
392
393 /*******************************************************************************/
394
395 int
396 main(int argc, char *argv[])
397 {
398     int n;
399
400     initscr();
401     cbreak();
402     noecho();
403
404     if (argc > 1) {
405         for (n = 1; n < argc; n++)
406             read_data(argv[n]);
407         if (count_cards() == 0)
408             new_card();
409         cardfile(argv[1]);
410     } else {
411         read_data(default_name);
412         if (count_cards() == 0)
413             new_card();
414         cardfile(default_name);
415     }
416
417     endwin();
418
419     return EXIT_SUCCESS;
420 }