Make file handling more general so it can be reused.
[fw/altos] / aoview / aoview_file.c
1 /*
2  * Copyright © 2009 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include "aoview.h"
19
20 static char *aoview_file_dir;
21
22 #define ALTOS_DIR_PATH  "/apps/aoview/log_dir"
23 #define DEFAULT_DIR     "AltOS"
24
25 struct aoview_file {
26         char    *ext;
27         FILE    *file;
28         char    *name;
29         int     failed;
30         int     serial;
31         int     sequence;
32 };
33
34 static void
35 aoview_file_save_conf(void)
36 {
37         GConfClient     *gconf_client;
38
39         gconf_client = gconf_client_get_default();
40         if (gconf_client)
41         {
42                 gconf_client_set_string(gconf_client,
43                                         ALTOS_DIR_PATH,
44                                         aoview_file_dir,
45                                         NULL);
46                 g_object_unref(G_OBJECT(gconf_client));
47         }
48 }
49
50 static void
51 aoview_file_configure(GtkWidget *widget, gpointer data)
52 {
53         GtkFileChooser *chooser = data;
54         aoview_file_dir = gtk_file_chooser_get_filename(chooser);
55         aoview_file_save_conf();
56         gtk_widget_hide(GTK_WIDGET(chooser));
57 }
58
59 void
60 aoview_file_finish(struct aoview_file *file)
61 {
62         if (file->file) {
63                 fclose(file->file);
64                 file->file = NULL;
65                 free(file->name);
66                 file->name = NULL;
67         }
68         file->failed = 0;
69 }
70
71 static GtkMessageDialog *file_fail_dialog;
72
73 static void
74 aoview_file_open_failed(char *name)
75 {
76         char    *utf8_file;
77         utf8_file = g_filename_to_utf8(name, -1, NULL, NULL, NULL);
78         if (!utf8_file)
79                 utf8_file = name;
80         gtk_message_dialog_format_secondary_text(file_fail_dialog,
81                                                  "\"%s\"", utf8_file);
82         if (utf8_file != name)
83                 g_free(utf8_file);
84         gtk_widget_show(GTK_WIDGET(file_fail_dialog));
85 }
86
87 gboolean
88 aoview_file_start(struct aoview_file *file)
89 {
90         char            base[50];
91         struct tm       tm;
92         time_t          now;
93         char            *full;
94         int             r;
95
96         if (file->file)
97                 return TRUE;
98
99         if (file->failed)
100                 return FALSE;
101
102         now = time(NULL);
103         (void) localtime_r(&now, &tm);
104         aoview_mkdir(aoview_file_dir);
105         for (;;) {
106                 snprintf(base, sizeof (base), "%04d-%02d-%02d-serial-%03d-flight-%03d.%s",
107                         tm.tm_year + 1900,
108                         tm.tm_mon + 1,
109                         tm.tm_mday,
110                         file->serial,
111                         file->sequence,
112                         file->ext);
113                 full = aoview_fullname(aoview_file_dir, base);
114                 r = access(full, F_OK);
115                 if (r < 0) {
116                         file->file = fopen(full, "w");
117                         if (!file->file) {
118                                 aoview_file_open_failed(full);
119                                 free(full);
120                                 file->failed = 1;
121                                 return FALSE;
122                         } else {
123                                 setlinebuf(file->file);
124                                 file->name = full;
125                                 return TRUE;
126                         }
127                 }
128                 free(full);
129                 file->sequence++;
130         }
131 }
132
133 void
134 aoview_file_vprintf(struct aoview_file *file, char *format, va_list ap)
135 {
136         if (!aoview_file_start(file))
137                 return;
138         vfprintf(file->file, format, ap);
139 }
140
141 void
142 aoview_file_printf(struct aoview_file *file, char *format, ...)
143 {
144         va_list ap;
145
146         va_start(ap, format);
147         aoview_file_vprintf(file, format, ap);
148         va_end(ap);
149 }
150
151 struct aoview_file *
152 aoview_file_new(char *ext)
153 {
154         struct aoview_file      *file;
155
156         file = calloc (1, sizeof (struct aoview_file));
157         if (!file)
158                 return NULL;
159         file->ext = strdup(ext);
160         if (!file->ext) {
161                 free(file);
162                 return NULL;
163         }
164         return file;
165 }
166
167 void
168 aoview_file_destroy(struct aoview_file *file)
169 {
170         if (file->file)
171                 fclose(file->file);
172         if (file->name)
173                 free(file->name);
174         free(file->ext);
175         free(file);
176 }
177
178 void
179 aoview_file_set_serial(struct aoview_file *file, int serial)
180 {
181         if (serial != file->serial)
182                 aoview_file_finish(file);
183         file->serial = serial;
184 }
185
186 int
187 aoview_file_get_serial(struct aoview_file *file)
188 {
189         return file->serial;
190 }
191
192 void
193 aoview_file_init(GladeXML *xml)
194 {
195         GConfClient     *gconf_client;
196         char            *file_dir = NULL;
197         GtkFileChooser  *file_chooser_dialog;
198         GtkWidget       *file_configure_ok;
199
200         g_type_init();
201         gconf_client = gconf_client_get_default();
202         if (gconf_client)
203         {
204                 file_dir = gconf_client_get_string(gconf_client,
205                                                    ALTOS_DIR_PATH,
206                                                    NULL);
207                 g_object_unref(G_OBJECT(gconf_client));
208         }
209         if (!file_dir) {
210                 aoview_file_dir = aoview_fullname(getenv("HOME"), DEFAULT_DIR);
211                 aoview_file_save_conf();
212         } else {
213                 aoview_file_dir = strdup(file_dir);
214         }
215
216         file_chooser_dialog = GTK_FILE_CHOOSER(glade_xml_get_widget(xml, "file_chooser_dialog"));
217         assert(file_chooser_dialog);
218         gtk_file_chooser_set_filename(file_chooser_dialog, aoview_file_dir);
219
220         file_configure_ok = glade_xml_get_widget(xml, "file_configure_ok");
221         assert(file_configure_ok);
222
223         g_signal_connect(G_OBJECT(file_configure_ok), "clicked",
224                          G_CALLBACK(aoview_file_configure),
225                          file_chooser_dialog);
226
227
228         file_fail_dialog = GTK_MESSAGE_DIALOG(glade_xml_get_widget(xml, "file_fail_dialog"));
229         assert(file_fail_dialog);
230 }