ncurses 5.0
[ncurses.git] / test / cardfile.c
1 /****************************************************************************
2  * Copyright (c) 1999 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.2 1999/06/16 00:41:57 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 *strdup (char *s)
66 {
67     char *p = (char *)malloc(strlen(s)+1);
68     if (p)
69         strcpy(p, s);
70     return(p);
71 }
72 #endif /* not HAVE_STRDUP */
73
74 static char *skip(char *buffer)
75 {
76     while (isspace(*buffer))
77         buffer++;
78     return buffer;
79 }
80
81 static void trim(char *buffer)
82 {
83     unsigned n = strlen(buffer);
84     while (n-- && isspace(buffer[n]))
85         buffer[n] = 0;
86 }
87
88 /*******************************************************************************/
89
90 static CARD *add_title(const char *title)
91 {
92     CARD *card, *p, *q;
93
94     for (p = all_cards, q = 0; p != 0; q = p, p = p->link)
95     {
96         int cmp = strcmp(p->title, title);
97         if (cmp == 0)
98             return p;
99         if (cmp > 0)
100             break;
101     }
102
103     card = (CARD *)calloc(1, sizeof(CARD));
104     card->title = strdup(title);
105     card->content = strdup("");
106
107     if (q == 0)
108     {
109         card->link = all_cards;
110         all_cards = card;
111     }
112     else
113     {
114         card->link = q->link;
115         q->link = card;
116     }
117
118     return card;
119 }
120
121 static void add_content(CARD *card, char *content)
122 {
123     unsigned total, offset;
124
125     content = skip(content);
126     if ((total = strlen(content)) != 0)
127     {
128         if ((offset = strlen(card->content)) != 0)
129         {
130             total += 1 + offset;
131             card->content = (char *)realloc(card->content, total + 1);
132             strcpy(card->content + offset++, " ");
133         }
134         else
135         {
136             card->content = (char *)malloc(total + 1);
137         }
138         strcpy(card->content + offset, content);
139     }
140 }
141
142 static CARD *find_card(char *title)
143 {
144     CARD *card;
145
146     for (card = all_cards; card != 0; card = card->link)
147         if (!strcmp(card->title, title))
148             break;
149
150     return card;
151 }
152
153 static void read_data(char *fname)
154 {
155     FILE *fp;
156     CARD *card = 0;
157     char buffer[BUFSIZ];
158
159     if ((fp = fopen(fname, "r")) != 0)
160     {
161         while (fgets(buffer, sizeof(buffer), fp))
162         {
163             trim(buffer);
164             if (isspace(*buffer))
165             {
166                 if (card == 0)
167                     card = add_title("");
168                 add_content(card, buffer);
169             }
170             else if ((card = find_card(buffer)) == 0)
171             {
172                 card = add_title(buffer);
173             }
174         }
175         fclose(fp);
176     }
177 }
178
179 /*******************************************************************************/
180
181 static void write_data(const char *fname)
182 {
183     FILE *fp;
184     CARD *p = 0;
185     int n;
186
187     if (!strcmp(fname, default_name))
188         fname = "cardfile.out";
189
190     if ((fp = fopen(fname, "w")) != 0)
191     {
192         for (p = all_cards; p != 0; p = p->link)
193         {
194             FIELD **f = form_fields(p->form);
195             for (n = 0; f[n] != 0; n++)
196             {
197                 char *s = field_buffer(f[n], 0);
198                 if (s != 0
199                  && (s = strdup(s)) != 0)
200                 {
201                     trim(s);
202                     fprintf(fp, "%s%s\n", n ? "\t" : "", s);
203                     free(s);
204                 }
205             }
206         }
207         fclose(fp);
208     }
209 }
210
211 /*******************************************************************************/
212
213 /*
214  * Count the cards
215  */
216 static int 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 order_cards(CARD *first, int depth)
231 {
232     if (first)
233     {
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 *next_card(CARD *now)
244 {
245     if (now->link)
246         now = now->link;
247     return now;
248 }
249
250 /*
251  * Return the previous card in the list
252  */
253 static CARD *prev_card(CARD *now)
254 {
255     CARD *p;
256     for (p = all_cards; p != 0; p = p->link)
257         if (p->link == now)
258             return p;
259     return now;
260 }
261
262
263 /*******************************************************************************/
264
265 static int form_virtualize(WINDOW *w)
266 {
267     int         c = wgetch(w);
268
269     switch(c)
270     {
271     case CTRL('W'):
272         return(MAX_FORM_COMMAND + 4);
273     case CTRL('N'):
274         return(MAX_FORM_COMMAND + 3);
275     case CTRL('P'):
276         return(MAX_FORM_COMMAND + 2);
277     case CTRL('Q'):
278     case 033:
279         return(MAX_FORM_COMMAND + 1);
280
281     case KEY_BACKSPACE:
282         return(REQ_DEL_PREV);
283     case KEY_DC:
284         return(REQ_DEL_CHAR);
285     case KEY_LEFT:
286         return(REQ_LEFT_CHAR);
287     case KEY_RIGHT:
288         return(REQ_RIGHT_CHAR);
289
290     case KEY_DOWN:
291     case KEY_NEXT:
292         return(REQ_NEXT_FIELD);
293     case KEY_UP:
294     case KEY_PREVIOUS:
295         return(REQ_PREV_FIELD);
296
297     default:
298         return(c);
299     }
300 }
301
302 /*******************************************************************************/
303
304 static void cardfile(char *fname)
305 {
306     WINDOW *win;
307     CARD *p;
308     CARD *top_card;
309     int visible_cards = count_cards();
310     int panel_wide = COLS - (visible_cards * OFFSET_CARD);
311     int panel_high = LINES - (visible_cards * OFFSET_CARD) - 5;
312     int form_wide = panel_wide - 2;
313     int form_high = panel_high - 2;
314     int x = (visible_cards - 1) * OFFSET_CARD;
315     int y = 0;
316     int ch;
317     int finished = FALSE;
318
319     move(LINES - 3, 0);
320     addstr("^Q/ESC -- exit form            ^W   -- writes data to file\n");
321     addstr("^N   -- go to next card        ^P   -- go to previous card\n");
322     addstr("Arrow keys move left/right within a field, up/down between fields");
323
324     /* make a panel for each CARD */
325     for (p = all_cards; p != 0; p = p->link)
326     {
327         FIELD **f = (FIELD **)calloc(3, sizeof(FIELD *));
328
329         win = newwin(panel_high, panel_wide, x, y);
330         keypad(win, TRUE);
331         p->panel = new_panel(win);
332         box(win, 0, 0);
333
334         /* ...and a form in each panel */
335         f[0] = new_field(1, form_wide, 0, 0, 0, 0);
336         set_field_back(f[0], A_REVERSE);
337         set_field_buffer(f[0], 0, p->title);
338
339         f[1] = new_field(form_high-1, form_wide, 1, 0, 0, 0);
340         set_field_buffer(f[1], 0, p->content);
341         set_field_just(f[1], JUSTIFY_LEFT);
342
343         f[2] = 0;
344
345         p->form = new_form(f);
346         set_form_win(p->form, win);
347         set_form_sub(p->form, derwin(win, form_high, form_wide, 1, 1));
348         post_form(p->form);
349
350         x -= OFFSET_CARD;
351         y += OFFSET_CARD;
352     }
353
354     order_cards(top_card = all_cards, visible_cards);
355
356     update_panels();
357
358     while (!finished)
359     {
360         update_panels();
361         doupdate();
362
363         switch(form_driver(top_card->form, ch = form_virtualize(panel_window(top_card->panel))))
364         {
365         case E_OK:
366             break;
367         case E_UNKNOWN_COMMAND:
368             switch (ch) {
369             case MAX_FORM_COMMAND+1:
370                 finished = TRUE;
371                 break;
372             case MAX_FORM_COMMAND+2:
373                 top_card = prev_card(top_card);
374                 order_cards(top_card, visible_cards);
375                 break;
376             case MAX_FORM_COMMAND+3:
377                 top_card = next_card(top_card);
378                 order_cards(top_card, visible_cards);
379                 break;
380             case MAX_FORM_COMMAND+4:
381                 write_data(fname);
382                 break;
383             default:
384                 beep();
385                 break;
386             }
387             break;
388         default:
389             flash();
390             break;
391         }
392     }
393 }
394
395 /*******************************************************************************/
396
397 int main(int argc, char *argv[])
398 {
399     int n;
400
401     initscr();
402     cbreak();
403     noecho();
404
405     if (argc > 1)
406     {
407         for (n = 1; n < argc; n++)
408             read_data(argv[n]);
409         cardfile(argv[1]);
410     }
411     else
412     {
413         read_data(default_name);
414         cardfile(default_name);
415     }
416
417     endwin();
418
419     return EXIT_SUCCESS;
420 }