There is a sign flip in how [BFZIII], Remark 2.4 should be implemented
[clav.git] / file-selection.c
blob4d3794cd6741103b39f0bfd1810faef810b52e8e
1 /*
2 * Copyright (c) 2018, S. Gilles <sgilles@math.umd.edu>
4 * Permission to use, copy, modify, and/or distribute this software
5 * for any purpose with or without fee is hereby granted, provided
6 * that the above copyright notice and this permission notice appear
7 * in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
14 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <errno.h>
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
25 #include "macros.h"
28 * I am fully aware of how ugly this file is, which is why it's specially
29 * split out, so that it can be completely redone one day, when some
30 * kind of better solution exists.
32 static uint_fast8_t try_kdialog = 1;
33 static uint_fast8_t try_qarma = 1;
34 static uint_fast8_t try_yad = 1;
35 static uint_fast8_t try_zenity = 1;
36 static uint_fast8_t try_xdialog = 1;
37 enum action { ACT_SAVE, ACT_LOAD };
38 static char *cmd_kdialog[] = {
39 /* */
40 [ACT_SAVE] = "kdialog --getsavefilename :clav 2>/dev/null", /* */
41 [ACT_LOAD] = "kdialog --getopenfilename :clav 2>/dev/null", /* */
43 static char *cmd_qarma[] = {
44 /* */
45 [ACT_SAVE] =
46 "qarma --title 'Save As' --file-selection --save 2>/dev/null", /* */
47 [ACT_LOAD] = "qarma --title 'Load' --file-selection 2>/dev/null", /* */
49 static char *cmd_yad[] = {
50 /* */
51 [ACT_SAVE] =
52 "yad --title 'Save As' --width=640 --height=480 --file-selection --save 2>/dev/null", /* */
53 [ACT_LOAD] =
54 "yad --title 'Load' --width=640 --height=480 --file-selection 2>/dev/null", /* */
56 static char *cmd_zenity[] = {
57 /* */
58 [ACT_SAVE] =
59 "zenity --title 'Save As' --file-selection --save 2>/dev/null", /* */
60 [ACT_LOAD] = "zenity --title 'Load' --file-selection 2>/dev/null", /* */
62 static char *cmd_xdialog[] = {
63 /* */
64 [ACT_SAVE] =
65 "Xdialog --stdout --title 'Save As' --fselect '' 0 0 2>/dev/null", /* */
66 [ACT_LOAD] =
67 "Xdialog --stdout --title 'Load' --fselect '' 0 0 2>/dev/null", /* */
70 /* Naively slurp stream in completly, truncate last `\n'. */
71 static int
72 slurp(FILE *f, char **out)
74 static size_t read_size = 1 << 7;
75 int ret = 0;
76 int pret = 0;
77 size_t len = 0;
78 size_t sz = read_size - 1;
79 char *buf = 0;
81 /* No need to check for overflow; sz + 1 == 1 << 7 */
82 if (!(buf = malloc(sz + 1))) {
83 ret = errno;
84 perror(L("malloc"));
85 goto done;
88 char *p = buf;
90 *p = '\0';
92 do {
93 if (!fgets(buf + len, read_size, f)) {
94 break;
97 p = strchr(buf + len, '\0');
98 len = p - buf;
99 sz += read_size;
100 void *newmem = 0;
102 if (sz + 1 < sz) {
103 ret = errno = EOVERFLOW;
104 perror(L(""));
105 goto done;
108 if (!(newmem = realloc(buf, sz + 1))) {
109 ret = errno;
110 perror(L("realloc"));
111 goto done;
114 buf = newmem;
115 } while (1);
117 if (len) {
118 if ((p = strrchr(buf + len - 1, '\n'))) {
119 *p = '\0';
123 ret = 0;
124 done:
125 pret = pclose(f);
127 if (!ret &&
128 WIFEXITED(pret) &&
129 WEXITSTATUS(pret) != 127) {
130 *out = buf;
131 } else {
132 ret = 1;
133 free(buf);
134 buf = 0;
135 *out = 0;
138 return ret;
141 static int
142 choose_file(char **out_filename, enum action act)
144 int ret = ENOTSUP;
145 char *filename = 0;
146 FILE *f = 0;
148 fflush(0);
150 if (try_kdialog) {
151 if ((f = popen(cmd_kdialog[act], "r"))) {
152 if (!(ret = slurp(f, &filename))) {
153 goto done;
157 free(filename);
158 filename = 0;
159 try_kdialog = 0;
162 if (try_qarma) {
163 if ((f = popen(cmd_qarma[act], "r"))) {
164 if (!(ret = slurp(f, &filename))) {
165 goto done;
169 free(filename);
170 filename = 0;
171 try_qarma = 0;
174 if (try_yad) {
175 if ((f = popen(cmd_yad[act], "r"))) {
176 if (!(ret = slurp(f, &filename))) {
177 goto done;
181 free(filename);
182 filename = 0;
183 try_yad = 0;
186 if (try_zenity) {
187 if ((f = popen(cmd_zenity[act], "r"))) {
188 if (!(ret = slurp(f, &filename))) {
189 goto done;
193 free(filename);
194 filename = 0;
195 try_zenity = 0;
198 if (try_xdialog) {
199 if ((f = popen(cmd_xdialog[act], "r"))) {
200 if (!(ret = slurp(f, &filename))) {
201 goto done;
205 free(filename);
206 filename = 0;
207 try_xdialog = 0;
210 ret = ENOTSUP;
211 done:
213 if (!ret) {
214 *out_filename = filename;
215 } else {
216 free(filename);
219 return ret;
223 choose_save_file(char **out_filename)
225 return choose_file(out_filename, ACT_SAVE);
229 choose_load_file(char **out_filename)
231 return choose_file(out_filename, ACT_LOAD);