home · contact · privacy
Fixed memory handling bug.
[plomrogue] / src / wincontrol.c
1 /* wincontrol.c */
2
3 #include "wincontrol.h"
4 #include <stdlib.h> /* for free() */
5 #include <string.h> /* for strlen(), strchr(), strstr() */
6 #include <stdint.h> /* for uint8_t, uint16_t */
7 #include <stdio.h> /* for fwrite() */
8 #include <unistd.h> /* for access(), unlink() */
9 #include "windows.h" /* for suspend_win(), append_win(), reset_pad_offset(),
10                       * resize_active_win(), init_win(), free_win(),
11                       * structs Win, WinMeta
12                       */
13 #include "yx_uint16.h" /* for yx_uint16 struct */
14 #include "main.h" /* for Wins struct */
15 #include "readwrite.h" /* for get_linemax(), try_fopen(), try_fclose(),
16                         * try_fgets(), try_fclose_unlink_rename()
17                         */
18 #include "rexit.h" /* for exit_err() */
19 #include "main.h" /* for World, Wins structs */
20 #include "draw_wins.h" /* for draw_keys_win(), draw_info_win(), draw_log_win(),
21                         * draw_map_win
22                         */
23 #include "misc.h" /* for try_malloc() */
24 #include "dirent.h" /* for opendir(), closedir(), readdir() */
25 #include "errno.h" /* for errno */
26
27
28
29 /* Return string "prefix" + "id"; malloc()'s string, remember to call free()! */
30 static char * string_prefixed_id(struct World * world, char * prefix, char id);
31
32
33
34 /* Create Winconf, init ->view/height_type/width_type to 0, ->id to "id". */
35 static void create_winconf(char id, struct WinConf * wcp);
36
37 /* Initialize Winconf of "id" from appropriate config file.*/
38 static void init_winconf_from_file(struct World * world, char id);
39
40 /* Wrapper around init_win() called with values from Winconf of "id". */
41 static void init_win_from_winconf(struct World * world, char id);
42
43 /* Save title, draw function, size of window identified by "id" to conffile. */
44 static void save_win_config(struct World * world, char id);
45
46
47
48 /* Write size of a window to its WinConf, as positive or negative values
49  * (dependent on state ofWinConf->height_type / WinConf->width_type).
50  */
51 static void set_winconf(struct World * world, char id);
52
53
54
55 /* Get WinConf by "id"; get id of WinConf mothering "win". */
56 static struct WinConf * get_winconf_by_id(struct World * world, char id);
57
58 /* Get (Win->draw) function identified by "c"; NULL if c not mapped to one. */
59 static void * get_drawfunc_by_char(char c);
60
61 /* Iterate over bytes of world->winconf_ids array. Re-start after null byte. */
62 static char get_next_winconf_id(struct World * world);
63
64
65
66 static char * string_prefixed_id(struct World * world, char * prefix, char id)
67 {
68     uint8_t size = strlen(prefix) + 2;
69     char * path = try_malloc(size, world, "string_prefixed_id()");
70     sprintf(path, "%s_", prefix);
71     path[size - 2] = id;
72     return path;
73 }
74
75
76
77 static void create_winconf(char id, struct WinConf * wcp)
78 {
79     wcp->id = id;
80     wcp->view = 0;
81     wcp->height_type = 0;
82     wcp->width_type = 0;
83 }
84
85
86
87 static void init_winconf_from_file(struct World * world, char id)
88 {
89     char * tmp = "init_winconf_from_file() on window id '_'";
90     char * context = try_malloc(strlen(tmp) + 1, world,
91                                "init_winconf_from_file()");
92     memcpy(context, tmp, strlen(tmp) + 1);
93     context[strlen(tmp) - 2] = id;
94
95     char * path = string_prefixed_id(world, "config/windows/Win_", id);
96     FILE * file = try_fopen(path, "r", world, context);
97     free(path);
98     uint16_t linemax = get_linemax(file, world, context);
99     char line[linemax + 1];
100
101     struct WinConf * winconf = get_winconf_by_id(world, id);
102     try_fgets(line, linemax + 1, file, world, context);
103     winconf->title = try_malloc(strlen(line), world, context);
104     memcpy(winconf->title, line, strlen(line) - 1); /* Eliminate newline char */
105     winconf->title[strlen(line) - 1] = '\0';        /* char at end of string. */
106
107     try_fgets(line, linemax + 1, file, world, context);
108     winconf->draw = line[0];
109
110     try_fgets(line, linemax + 1, file, world, context);
111     winconf->height = atoi(line);
112     if (0 >= winconf->height)
113     {
114         winconf->height_type = 1;
115     }
116     try_fgets(line, linemax + 1, file, world, context);
117     winconf->width = atoi(line);
118     if (0 >= winconf->width)
119     {
120         winconf->width_type = 1;
121     }
122
123     try_fclose(file, world, context);
124     free(context);
125 }
126
127
128
129 static void init_win_from_winconf(struct World * world, char id)
130 {
131     char * tmp = "Trouble in init_win_from_file() with init_win() (win id: _).";
132     char * err = try_malloc(strlen(tmp) + 1, world, "init_win_from_file()");
133     memcpy(err, tmp, strlen(tmp) + 1);
134     err[strlen(tmp) - 3] = id;
135     struct WinConf * winconf = get_winconf_by_id(world, id);
136     void * f = get_drawfunc_by_char(winconf->draw);
137     exit_err(NULL == f, world, err);
138     exit_err(init_win(world->wmeta, &winconf->win, winconf->title,
139                       winconf->height, winconf->width, world, f),
140              world, err);
141     free(err);
142 }
143
144
145
146 extern void save_win_config(struct World * world, char id)
147 {
148     char * f_name = "save_win_config()";
149
150     char * path_tmp = string_prefixed_id(world, "config/windows/Win_tmp_", id);
151     FILE * file = try_fopen(path_tmp, "w", world, f_name);
152
153     struct WinConf * wc = get_winconf_by_id(world, id);
154     uint8_t size = strlen(wc->title) + 2;
155     if (size < 7)
156     {
157         size = 7;
158     }
159     char line[size];
160     sprintf(line, "%s\n", wc->title);
161     fwrite(line, sizeof(char), strlen(line), file);
162     sprintf(line, "%c\n", wc->draw);
163     fwrite(line, sizeof(char), strlen(line), file);
164     sprintf(line, "%d\n", wc->height);
165     fwrite(line, sizeof(char), strlen(line), file);
166     sprintf(line, "%d\n", wc->width);
167     fwrite(line, sizeof(char), strlen(line), file);
168
169     char * path = string_prefixed_id(world, "config/windows/Win_", id);
170     try_fclose_unlink_rename(file, path_tmp, path, world, f_name);
171     free(path);
172     free(path_tmp);
173 }
174
175
176
177 static void set_winconf(struct World * world, char id)
178 {
179     struct WinConf * wcp = get_winconf_by_id(world, id);
180     if      (0 == wcp->height_type)
181     {
182         wcp->height = wcp->win->frame.size.y;
183     }
184     else if (1 == wcp->height_type)
185     {
186         wcp->height = wcp->win->frame.size.y - world->wmeta->padframe.size.y
187                       + 1;
188     }
189     if      (0 == wcp->width_type)
190     {
191         wcp->width = wcp->win->frame.size.x;
192     }
193     else if (1 == wcp->width_type)
194     {
195         wcp->width = wcp->win->frame.size.x - world->wmeta->padframe.size.x;
196     }
197 }
198
199
200
201 static struct WinConf * get_winconf_by_id(struct World * world, char id)
202 {
203     uint8_t i = 0;
204     while (1)
205     {
206         if (id == world->winconfs[i].id)
207         {
208             return &world->winconfs[i];
209         }
210         i++;
211     }
212 }
213
214
215
216 static void * get_drawfunc_by_char(char c)
217 {
218     if      ('i' == c)
219     {
220         return draw_info_win;
221     }
222     else if ('k' == c)
223     {
224         return draw_keys_win;
225     }
226     else if ('l' == c)
227     {
228         return draw_log_win;
229     }
230     else if ('m' == c)
231     {
232         return draw_map_win;
233     }
234     return NULL;
235 }
236
237
238
239 static char get_next_winconf_id(struct World * world)
240 {
241     static uint8_t i = 0;
242     char c = world->winconf_ids[i];
243     if (0 == c)
244     {
245         i = 0;
246     }
247     else
248     {
249         i++;
250     }
251     return c;
252 }
253
254
255
256 extern struct WinConf * get_winconf_by_win(struct World * world,
257                                            struct Win * win)
258 {
259     uint8_t i = 0;
260     while (1)
261     {
262         if (win == world->winconfs[i].win)
263         {
264             return &world->winconfs[i];
265         }
266         i++;
267     }
268 }
269
270
271
272 extern struct Win * get_win_by_id(struct World * world, char id)
273 {
274     struct WinConf * wc = get_winconf_by_id(world, id);
275     return wc->win;
276 }
277
278
279
280 extern void init_winconfs(struct World * world)
281 {
282     char * f_name = "init_winconfs()";
283     char * err_o = "Trouble in init_winconfs() with opendir().";
284     char * err_r = "Trouble in init_winconfs() with readdir().";
285     char * err_c = "Trouble in init_winconfs() with closedir().";
286
287     DIR * dp = opendir("config/windows");
288     exit_err(NULL == dp, world, err_o);
289     struct dirent * fn;
290     errno = 0;
291     char * winconf_ids = try_malloc(256, world, f_name);
292     uint8_t i = 0;
293     char id;
294     while (NULL != (fn = readdir(dp)))
295     {
296         if (   5 == strlen(fn->d_name)
297             && fn->d_name == strstr(fn->d_name, "Win_"))
298         {
299             id = fn->d_name[4];
300             winconf_ids[i] = id;
301             i++;
302         }
303     }
304     winconf_ids[i] = '\0';
305     exit_err(errno, world, err_r);
306     exit_err(closedir(dp), world, err_c);
307     world->winconf_ids = try_malloc(strlen(winconf_ids) + 1, world, f_name);
308     memcpy(world->winconf_ids, winconf_ids, strlen(winconf_ids) + 1);
309     free(winconf_ids);
310
311     struct WinConf * winconfs;
312     winconfs = try_malloc(strlen(world->winconf_ids) * sizeof(struct WinConf),
313                                  world, f_name);
314     i = 0;
315     while (0 != (id = get_next_winconf_id(world)))
316     {
317         create_winconf(id, &winconfs[i]);
318         i++;
319     }
320     world->winconfs = winconfs;
321     while (0 != (id = get_next_winconf_id(world)))
322     {
323         init_winconf_from_file(world, id);
324         i++;
325     }
326 }
327
328
329
330 extern void free_winconf(struct World * world, char id)
331 {
332     struct WinConf * wc = get_winconf_by_id(world, id);
333     free(wc->title);
334 }
335
336
337
338 extern void free_winconfs(struct World * world)
339 {
340     char id;
341     while (0 != (id = get_next_winconf_id(world)))
342     {
343         free_winconf(world, id);
344     }
345     free(world->winconf_ids);
346     free(world->winconfs);
347 }
348
349
350
351 extern void init_wins(struct World * world)
352 {
353     char id;
354     while (0 != (id = get_next_winconf_id(world)))
355     {
356         init_win_from_winconf(world, id);
357     }
358 }
359
360
361
362 extern void free_wins(struct World * world)
363 {
364     char id;
365     while (0 != (id = get_next_winconf_id(world)))
366     {
367         free_win(get_win_by_id(world, id));
368     }
369 }
370
371
372
373 extern void sorted_wintoggle(struct World * world)
374 {
375     char * f_name = "sorted_wintoggle()";
376     char * path = "config/windows/toggle_order";
377     FILE * file = try_fopen(path, "r", world, f_name);
378     uint16_t linemax = get_linemax(file, world, f_name);
379     char win_order[linemax + 1];
380     try_fgets(win_order, linemax + 1, file, world, f_name);
381     try_fclose(file, world, f_name);
382     uint8_t i = 0;
383     for (; i < linemax - 1; i++)
384     {
385         if (NULL == strchr(world->winconf_ids, win_order[i]))
386         {
387             continue;
388         }
389         toggle_window(world->wmeta, get_win_by_id(world, win_order[i]));
390     }
391 }
392
393
394
395 extern void reload_win_config(struct World * world)
396 {
397     while (0 != world->wmeta->active)
398     {
399         suspend_win(world->wmeta, world->wmeta->active);
400     }
401     free_wins(world);
402     free_winconfs(world);
403     init_winconfs(world);
404     init_wins(world);
405     sorted_wintoggle(world);
406 }
407
408
409
410 extern void save_win_configs(struct World * world)
411 {
412     char * f_name = "save_win_configs()";
413
414     char id;
415     while (0 != (id = get_next_winconf_id(world)))
416     {
417         save_win_config(world, id);
418     }
419
420     char * path     = "config/windows/toggle_order";
421     char * path_tmp = "config/windows/toggle_order_tmp";
422     FILE * file = try_fopen(path_tmp, "w", world, f_name);
423
424     char line[6];
425     struct Win * w_p = world->wmeta->chain_start;
426     uint8_t i = 0;
427     while (0 != w_p)
428     {
429         struct WinConf * wc = get_winconf_by_win(world, w_p);
430         line[i] = wc->id;
431         w_p = w_p->next;
432         i++;
433     }
434     line[i] = '\n';
435     fwrite(line, sizeof(char), strlen(line), file);
436
437     try_fclose_unlink_rename(file, path_tmp, path, world, f_name);
438 }
439
440
441
442 extern uint8_t toggle_window(struct WinMeta * win_meta, struct Win * win)
443 {
444     if (0 != win->frame.curses_win)
445     {
446         return suspend_win(win_meta, win);
447     }
448     else
449     {
450         return append_win(win_meta, win);
451     }
452 }
453
454
455
456 extern void toggle_winconfig(struct World * world, struct Win * win)
457 {
458     struct WinConf * wcp = get_winconf_by_win(world, win);
459     if (0 == wcp->view)
460     {
461         win->draw = draw_winconf;
462         wcp->view = 1;
463     }
464     else
465     {
466         win->draw = get_drawfunc_by_char(wcp->draw);
467         wcp->view = 0;
468     }
469 }
470
471
472
473 extern void toggle_win_height_type(struct World * world, struct Win * win)
474 {
475     struct WinConf * wcp = get_winconf_by_win(world, win);
476     if (0 == wcp->height_type)
477     {
478         wcp->height_type = 1;
479     }
480     else
481     {
482         wcp->height_type = 0;
483     }
484     set_winconf(world, wcp->id);
485 }
486
487
488
489 extern void toggle_win_width_type(struct World * world, struct Win * win)
490 {
491     struct WinConf * wcp = get_winconf_by_win(world, win);
492     if (   0 == wcp->width_type
493         && win->frame.size.x <= world->wmeta->padframe.size.x)
494     {
495         wcp->width_type = 1;
496     }
497     else
498     {
499         wcp->width_type = 0;
500     }
501     set_winconf(world, wcp->id);
502 }
503
504
505
506 extern void scroll_pad(struct WinMeta * win_meta, char dir)
507 {
508     if      ('+' == dir)
509     {
510         reset_pad_offset(win_meta, win_meta->pad_offset + 1);
511     }
512     else if ('-' == dir)
513     {
514         reset_pad_offset(win_meta, win_meta->pad_offset - 1);
515     }
516 }
517
518
519
520 extern uint8_t growshrink_active_window(struct World * world, char change)
521 {
522     if (0 != world->wmeta->active)
523     {
524         struct yx_uint16 size = world->wmeta->active->frame.size;
525         if      (change == '-')
526         {
527             size.y--;
528         }
529         else if (change == '+')
530         {
531             size.y++;
532         }
533         else if (change == '_')
534         {
535             size.x--;
536         }
537         else if (change == '*')
538         {
539             size.x++;
540         }
541         uint8_t x = resize_active_win(world->wmeta, size);
542         struct WinConf * wcp = get_winconf_by_win(world, world->wmeta->active);
543         if (   1 == wcp->width_type
544             && world->wmeta->active->frame.size.x
545                > world->wmeta->padframe.size.x)
546         {
547             wcp->width_type = 0;
548         }
549         set_winconf(world, wcp->id);
550         return x;
551     }
552     return 0;
553 }