1 /*
2  * Copyright (C) 2002 2003 2004 2005 2006 2011, Magnus Hjorth
3  *
4  * This file is part of mhWaveEdit.
5  *
6  * mhWaveEdit is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * mhWaveEdit is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with mhWaveEdit; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <config.h>
22 
23 #include <stdio.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include "um.h"
31 #include "gtkfiles.h"
32 #include "main.h"
33 #include "mainloop.h"
34 #include "inifile.h"
35 #include "gettext.h"
36 
37 gboolean report_write_errors = TRUE;
38 
39 static int highest_fd = 2;
40 
xopen(char * filename,int flags,int mode)41 int xopen(char *filename, int flags, int mode)
42 {
43      int fd;
44      gchar *c;
45      fd = open(filename,flags,mode);
46      if (fd == -1) {
47 	  if (report_write_errors || mode==EFILE_READ) {
48 	       c = g_strdup_printf(_("Could not open %s: %s"),filename,
49 				   strerror(errno));
50 	       user_error(c);
51 	       g_free(c);
52 	  } else if (errno != ENOSPC) {
53 	       c = g_strdup_printf(_("Warning: Unexpected error: %s"),
54 				   filename);
55 	       user_perror(c);
56 	       g_free(c);
57 	  }
58      }
59      if (fd > highest_fd) highest_fd = fd;
60      return fd;
61 }
62 
63 
e_fopen(char * filename,int mode)64 EFILE *e_fopen(char *filename, int mode)
65 {
66      int fd,flag;
67      switch (mode) {
68      case EFILE_READ:   flag = O_RDONLY; break;
69      case EFILE_WRITE:  flag = O_WRONLY | O_CREAT | O_TRUNC; break;
70      case EFILE_APPEND: flag = O_WRONLY | O_CREAT | O_APPEND; break;
71      default: g_assert_not_reached(); return NULL;
72      }
73      fd = xopen(filename,flag,0666);
74      if (fd == -1) return NULL;
75      return e_fopen_fd(fd,filename);
76 }
77 
e_fopen_fd(int fd,gchar * virtual_filename)78 EFILE *e_fopen_fd(int fd, gchar *virtual_filename)
79 {
80      EFILE *e;
81      e = g_malloc(sizeof(*e));
82      e->fd = fd;
83      e->filename = g_strdup(virtual_filename);
84      return e;
85 }
86 
close_all_files(void)87 void close_all_files(void)
88 {
89      close_all_files_except(NULL,0);
90 }
91 
close_all_files_except(int * fds,int count)92 void close_all_files_except(int *fds, int count)
93 {
94      /* We close one file higher than highest_fd because of some sound
95 	drivers keep a file handle that wasn't opened through us. */
96      int i,j;
97      for (i=3; i<=highest_fd+1; i++) {
98 	  for (j=0; j<count; j++)
99 	       if (i == fds[j]) break;
100 	  if (j==count && close(i) == -1 && errno != EBADF)
101 	       console_perror("close_all_files");
102      }
103 }
104 
e_fclose(EFILE * f)105 gboolean e_fclose(EFILE *f)
106 {
107      gchar *c;
108      gboolean b=FALSE;
109      if (close(f->fd) != 0) {
110 	  c = g_strdup_printf(_("Error closing %s: %s"), f->filename, strerror(errno));
111 	  user_error(c);
112 	  g_free(c);
113 	  b = TRUE;
114      }
115      g_free(f->filename);
116      g_free(f);
117      return b;
118 }
119 
e_fclose_remove(EFILE * f)120 gboolean e_fclose_remove(EFILE *f)
121 {
122      gchar *c;
123      gboolean b=FALSE;
124      if (close(f->fd) != 0) {
125 	  c = g_strdup_printf(_("Error closing %s: %s"), f->filename, strerror(errno));
126 	  user_error(c);
127 	  g_free(c);
128 	  b=TRUE;
129      }
130      if (xunlink(f->filename)) b=TRUE;
131      g_free(f->filename);
132      g_free(f);
133      return b;
134 }
135 
e_fseek(EFILE * stream,off_t offset,int whence)136 gboolean e_fseek(EFILE *stream, off_t offset, int whence)
137 {
138      char *c;
139      if (lseek(stream->fd,offset,whence) == (off_t)-1) {
140 	  c = g_strdup_printf(_("Could not seek in %s: %s"),stream->filename,
141 			      strerror(errno));
142 	  user_error(c);
143 	  g_free(c);
144 	  return TRUE;
145      }
146      return FALSE;
147 }
148 
e_fread_upto(void * data,size_t size,EFILE * stream)149 gint e_fread_upto(void *data, size_t size, EFILE *stream)
150 {
151      char *c;
152      gint r = 0;
153      ssize_t i;
154      while (size > 0) {
155 	  i = read(stream->fd, (void *)(((char *)data)+r), size);
156 	  if (i == 0) return r;
157 	  if (i < 0) {
158 	       if (errno == EINTR) continue;
159 	       c = g_strdup_printf(_("Could not read from %s: %s"),
160 				   stream->filename,strerror(errno));
161 	       user_error(c);
162 	       g_free(c);
163 	       return -1;
164 	  }
165 	  r += i;
166 	  size -= i;
167      }
168      return r;
169 }
170 
e_fread(void * data,size_t size,EFILE * stream)171 gboolean e_fread(void *data, size_t size, EFILE *stream)
172 {
173      gint i;
174      gchar *c;
175      i = e_fread_upto(data,size,stream);
176      if (i < size) {
177 	  if (i >= 0) {
178 	       c = g_strdup_printf(_("Unexpected end of file reading from %s"),
179 				   stream->filename);
180 	       user_error(c);
181 	       g_free(c);
182 	  }
183 	  return TRUE;
184      }
185      return FALSE;
186 }
187 
e_fwrite(void * data,size_t size,EFILE * stream)188 gboolean e_fwrite(void *data, size_t size, EFILE *stream)
189 {
190      char *c;
191      gint w = 0;
192      ssize_t i;
193      while (size > 0) {
194 	  i = write(stream->fd, (void *)(((char *)data)+w), size);
195 	  if (i == 0) {
196 	       c = g_strdup_printf(_("Unable to write data to %s"),
197 				   stream->filename);
198 	       user_error(c);
199 	       g_free(c);
200 	       return TRUE;
201 	  }
202 	  if (i < 0) {
203 	       if (errno == EINTR) continue;
204 	       c = g_strdup_printf(_("Could not read from %s: %s"),
205 				   stream->filename,strerror(errno));
206 	       user_error(c);
207 	       g_free(c);
208 	       return TRUE;
209 	  }
210 	  w += i;
211 	  size -= i;
212      }
213      return FALSE;
214 }
215 
e_fwrite0(size_t size,EFILE * stream)216 gboolean e_fwrite0(size_t size, EFILE *stream)
217 {
218      char buf[4096];
219      size_t s;
220      memset(buf,0,sizeof(buf));
221      while (size>0) {
222 	  s = MIN(size,sizeof(buf));
223 	  if (e_fwrite(buf,s,stream)) return TRUE;
224 	  size -= s;
225      }
226      return FALSE;
227 }
228 
e_fread_bswap(void * data,size_t size,EFILE * stream)229 gboolean e_fread_bswap(void *data, size_t size, EFILE *stream)
230 {
231      size_t i;
232      gchar c;
233      if (e_fread(data,size,stream)) return TRUE;
234      i=0;
235      size--;
236      while (i<size) {
237 	  c = ((gchar *)data)[i];
238 	  ((gchar *)data)[i] = ((gchar *)data)[size];
239 	  ((gchar *)data)[size] = c;
240 	  i++;
241 	  size--;
242      }
243      return FALSE;
244 }
245 
e_fwrite_bswap(void * data,size_t size,EFILE * stream)246 gboolean e_fwrite_bswap(void *data, size_t size, EFILE *stream)
247 {
248      static gchar *buf = NULL;
249      static size_t bufsize = 0;
250      size_t i;
251      if (size>bufsize) { buf=g_realloc(buf,size); bufsize=size; }
252      for (i=0; i<size; i++) buf[i]=((gchar *)data)[size-(1+i)];
253      return e_fwrite(buf,size,stream);
254 }
255 
e_ftell(EFILE * stream)256 off_t e_ftell(EFILE *stream)
257 {
258      off_t l;
259      char *c;
260      l = lseek(stream->fd, 0, SEEK_CUR);
261      if (l == -1) {
262 	  c = g_strdup_printf(_("Could not get file position in %s: %s"),
263 			      stream->filename, strerror(errno));
264 	  user_error(c);
265 	  g_free(c);
266      }
267      return l;
268 }
269 
is_same_file(char * filename1,char * filename2)270 gboolean is_same_file(char *filename1, char *filename2)
271 {
272      struct stat s1, s2;
273 
274      if (!strcmp(filename1,filename2)) return TRUE;
275      if (stat(filename1,&s1)) {
276 	  if (errno == ENOENT) return FALSE;
277 	  else return TRUE;
278      }
279      if (stat(filename2,&s2)) {
280 	  if (errno == ENOENT) return FALSE;
281 	  else return TRUE;
282      }
283      return (s1.st_dev==s2.st_dev && s1.st_ino==s2.st_ino);
284 }
285 
286 /* Removes double slashes */
cleanup_filename(gchar * fn)287 static void cleanup_filename(gchar *fn)
288 {
289      gchar *c;
290      while (1) {
291 	  c = strstr(fn,"//");
292 	  if (c == NULL) return;
293 	  while (*c != 0) { c[0]=c[1]; c++; }
294      }
295 }
296 
297 #if (GTK_MAJOR_VERSION < 2) || (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 4) || defined(DISABLE_FILECHOOSER)
298 
299 /* Use the GtkFileSelection */
300 
301 static gchar *get_filename_result;
302 static gboolean get_filename_quitflag;
303 static gboolean get_filename_savemode;
304 static GtkFileSelection *get_filename_fs;
305 
get_filename_callback(GtkButton * button,gpointer user_data)306 static void get_filename_callback(GtkButton *button, gpointer user_data)
307 {
308      GtkFileSelection *fs = GTK_FILE_SELECTION(user_data);
309      gchar *c;
310      if (button==GTK_BUTTON(fs->ok_button)) {
311 	  if (get_filename_savemode &&
312 	      file_exists((gchar *)gtk_file_selection_get_filename(fs))) {
313 	       if (user_message(_("File already exists. Overwrite?"),
314 				UM_YESNOCANCEL) != MR_YES) {
315 		    gtk_signal_emit_stop_by_name(GTK_OBJECT(button),"clicked");
316 		    return;
317 	       }
318 	  } else if (!get_filename_savemode &&
319 		     !file_exists((gchar *)
320 				  gtk_file_selection_get_filename(fs))) {
321 	       user_error(_("No file with that name!"));
322 	       gtk_signal_emit_stop_by_name(GTK_OBJECT(button),"clicked");
323 	       return;
324 	  }
325 	  if (get_filename_result) free(get_filename_result);
326 	  get_filename_result = g_strdup(gtk_file_selection_get_filename(fs));
327 	  if (inifile_get_gboolean("useGeometry",FALSE)) {
328 	       c = get_geom(GTK_WINDOW(fs));
329 	       inifile_set("fileGeometry",c);
330 	       g_free(c);
331 	  }
332      }
333 }
334 
get_filename_destroy(void)335 static void get_filename_destroy(void)
336 {
337      get_filename_quitflag = TRUE;
338 }
339 
get_filename_internal_get_name(void)340 static gchar *get_filename_internal_get_name(void)
341 {
342      return g_strdup(gtk_file_selection_get_filename(get_filename_fs));
343 }
344 
get_filename_internal_set_name(gchar * new_name)345 static void get_filename_internal_set_name(gchar *new_name)
346 {
347      gtk_file_selection_set_filename(get_filename_fs,new_name);
348 }
349 
get_filename(gchar * current_name,gchar * filemask,gchar * title_text,gboolean savemode,GtkWidget * custom_widget)350 gchar *get_filename(gchar *current_name, gchar *filemask, gchar *title_text,
351 		    gboolean savemode, GtkWidget *custom_widget)
352 {
353      GtkFileSelection *f;
354      GtkAllocation all;
355      gchar *c;
356 
357      get_filename_result=NULL;
358      get_filename_savemode = savemode;
359      f=GTK_FILE_SELECTION(gtk_file_selection_new(title_text));
360      get_filename_fs = f;
361      if (custom_widget != NULL)
362 	  gtk_box_pack_end(GTK_BOX(GTK_FILE_SELECTION(f)->main_vbox),
363 			   custom_widget, FALSE, FALSE, 0);
364      c = inifile_get("fileGeometry",NULL);
365      if (c!=NULL && inifile_get_gboolean("useGeometry",FALSE) &&
366 	 !parse_geom(c,&all)) {
367 	  gtk_window_set_default_size(GTK_WINDOW(f),all.width,all.height);
368 	  gtk_widget_set_uposition(GTK_WIDGET(f),all.x,all.y);
369      } else
370 	  gtk_window_set_position(GTK_WINDOW(f),GTK_WIN_POS_CENTER);
371      if (current_name) gtk_file_selection_set_filename(f,current_name);
372      if (filemask) gtk_file_selection_complete(f,filemask);
373      gtk_signal_connect(GTK_OBJECT(f),"destroy",
374 			GTK_SIGNAL_FUNC(get_filename_destroy),NULL);
375      gtk_signal_connect(GTK_OBJECT(f->ok_button),"clicked",
376 			GTK_SIGNAL_FUNC(get_filename_callback),f);
377      gtk_signal_connect(GTK_OBJECT(f->cancel_button),"clicked",
378 			GTK_SIGNAL_FUNC(get_filename_callback),f);
379      gtk_signal_connect_object(GTK_OBJECT(f->ok_button),"clicked",
380 			       GTK_SIGNAL_FUNC(gtk_widget_destroy),
381 			       GTK_OBJECT(f));
382      gtk_signal_connect_object(GTK_OBJECT(f->cancel_button),"clicked",
383 			       GTK_SIGNAL_FUNC(gtk_widget_destroy),
384 			       GTK_OBJECT(f));
385      gtk_window_set_modal(GTK_WINDOW(f),TRUE);
386      gtk_widget_show(GTK_WIDGET(f));
387 
388      /* gtk_window_maximize(GTK_WINDOW(f)); */
389 
390 
391      get_filename_quitflag=FALSE;
392      while (!get_filename_quitflag) mainloop();
393      if (get_filename_result != NULL)
394 	  cleanup_filename(get_filename_result);
395      return get_filename_result;
396 }
397 
get_directory_callback(GtkButton * button,gpointer user_data)398 static void get_directory_callback(GtkButton *button, gpointer user_data)
399 {
400      GtkFileSelection *fs = GTK_FILE_SELECTION(user_data);
401      gchar *c;
402      get_filename_result = g_strdup(gtk_file_selection_get_filename(fs));
403      c = strchr(get_filename_result,0);
404      c--;
405      while (c>get_filename_result && *c=='/') {
406 	  *c = 0;
407 	  c--;
408      }
409      if (inifile_get_gboolean("useGeometry",FALSE)) {
410 	  c = get_geom(GTK_WINDOW(fs));
411 	  inifile_set("dirGeometry",c);
412 	  g_free(c);
413      }
414 }
415 
get_directory(gchar * current_name,gchar * title_text)416 gchar *get_directory(gchar *current_name, gchar *title_text)
417 {
418      GtkFileSelection *f;
419      gchar *c;
420      GtkAllocation all;
421 
422      f = GTK_FILE_SELECTION(gtk_file_selection_new(title_text));
423      c = inifile_get("dirGeometry",NULL);
424      if (c!=NULL && inifile_get_gboolean("useGeometry",FALSE) &&
425 	 !parse_geom(c,&all)) {
426 	  gtk_window_set_default_size(GTK_WINDOW(f),all.width,all.height);
427 	  gtk_widget_set_uposition(GTK_WIDGET(f),all.x,all.y);
428      } else
429 	  gtk_window_set_position(GTK_WINDOW(f),GTK_WIN_POS_CENTER);
430      if (current_name) gtk_file_selection_set_filename(f,current_name);
431      gtk_signal_connect(GTK_OBJECT(f),"destroy",
432 			GTK_SIGNAL_FUNC(get_filename_destroy),NULL);
433      gtk_signal_connect(GTK_OBJECT(f->ok_button),"clicked",
434 			GTK_SIGNAL_FUNC(get_directory_callback),f);
435      gtk_signal_connect(GTK_OBJECT(f->cancel_button),"clicked",
436 			GTK_SIGNAL_FUNC(get_directory_callback),f);
437      gtk_signal_connect_object(GTK_OBJECT(f->ok_button),"clicked",
438 			       GTK_SIGNAL_FUNC(gtk_widget_destroy),
439 			       GTK_OBJECT(f));
440      gtk_signal_connect_object(GTK_OBJECT(f->cancel_button),"clicked",
441 			       GTK_SIGNAL_FUNC(gtk_widget_destroy),
442 			       GTK_OBJECT(f));
443      gtk_window_set_modal(GTK_WINDOW(f),TRUE);
444      gtk_widget_set_sensitive(GTK_WIDGET(f->file_list),FALSE);
445      gtk_widget_show(GTK_WIDGET(f));
446 
447      get_filename_quitflag=FALSE;
448      while (!get_filename_quitflag) mainloop();
449      if (get_filename_result != NULL) cleanup_filename(get_filename_result);
450      return get_filename_result;
451 
452 }
453 
454 #else
455 
456 /* Use the GtkFileChooserDialog */
457 
458 static GtkFileChooser *get_filename_fc;
459 
460 struct response {
461      gboolean savemode;
462      gboolean responded;
463      gint r;
464 };
465 
response(GtkDialog * dialog,gint arg1,gpointer user_data)466 static void response(GtkDialog *dialog, gint arg1, gpointer user_data)
467 {
468      struct response *sr = (struct response *)user_data;
469      gchar *c;
470      if (sr->savemode && arg1 == GTK_RESPONSE_ACCEPT) {
471 	  c = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
472 	  if (c != NULL && file_exists(c)) {
473 	       if (user_message(_("File already exists. Overwrite?"),
474 				UM_YESNOCANCEL) != MR_YES)
475 		    return;
476 	  }
477      }
478      sr->responded = TRUE;
479      sr->r = arg1;
480 }
481 
get_filename_internal_get_name(void)482 static gchar *get_filename_internal_get_name(void)
483 {
484      gchar *c;
485      c = gtk_file_chooser_get_filename(get_filename_fc);
486      if (c == NULL) return g_strdup("");
487      return c;
488 }
489 
get_filename_internal_set_name(gchar * new_name)490 static void get_filename_internal_set_name(gchar *new_name)
491 {
492      gchar *c,*d;
493      c = g_filename_to_utf8(new_name,-1,NULL,NULL,NULL);
494      gtk_file_chooser_set_filename(get_filename_fc,c);
495      d = strrchr(c,'/');
496      if (d != NULL && d[1] != 0)
497 	  gtk_file_chooser_set_current_name(get_filename_fc,d+1);
498      g_free(c);
499 }
500 
get_filename_main(gchar * current_name,gchar * title_text,gboolean savemode,GtkFileChooserAction action,gchar * geom_setting,GtkWidget * custom_widget)501 static gchar *get_filename_main(gchar *current_name, gchar *title_text,
502 				gboolean savemode,
503 				GtkFileChooserAction action,
504 				gchar *geom_setting, GtkWidget *custom_widget)
505 {
506      GtkWidget *w;
507      GtkFileChooser *fc;
508      gchar *c,*d;
509      GtkAllocation all;
510      struct response sr = { savemode, FALSE, 0 };
511      if (current_name != NULL)
512          c = g_filename_to_utf8(current_name,-1,NULL,NULL,NULL);
513      else
514          c = NULL;
515      w = gtk_file_chooser_dialog_new(title_text,NULL,
516 				     action,
517 				     savemode?GTK_STOCK_SAVE_AS:GTK_STOCK_OPEN,
518 				     GTK_RESPONSE_ACCEPT,GTK_STOCK_CANCEL,
519 				     GTK_RESPONSE_CANCEL,NULL);
520      fc = GTK_FILE_CHOOSER(w);
521      get_filename_fc = fc;
522      if (custom_widget != NULL)
523 	  gtk_file_chooser_set_extra_widget(fc, custom_widget);
524 
525      d = inifile_get(geom_setting,NULL);
526      if (d!=NULL && !savemode && inifile_get_gboolean("useGeometry",FALSE) &&
527 	 !parse_geom(d,&all)) {
528 	  gtk_window_set_default_size(GTK_WINDOW(w),all.width,all.height);
529 	  gtk_widget_set_uposition(GTK_WIDGET(w),all.x,all.y);
530      } else
531 	  gtk_window_set_position(GTK_WINDOW(w),GTK_WIN_POS_CENTER);
532      gtk_window_set_modal(GTK_WINDOW(w),TRUE);
533 
534      if (c != NULL) {
535 	  if (c[0] == '/' &&
536 	      (action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
537 	       file_is_directory(c))) {
538 	       gtk_file_chooser_set_current_folder(fc,c);
539 	  } else {
540 	       gtk_file_chooser_set_filename(fc,c);
541 	       if (savemode) {
542 		    d = strrchr(c,'/');
543 		    if (d != NULL && d[1] != 0)
544 			 gtk_file_chooser_set_current_name(fc,d+1);
545 	       }
546 	       g_free(c);
547 	  }
548      }
549      gtk_signal_connect(GTK_OBJECT(fc),"response",GTK_SIGNAL_FUNC(response),
550 			&sr);
551      gtk_widget_show(w);
552      while (!sr.responded) mainloop();
553      c = NULL;
554      if (sr.r == GTK_RESPONSE_ACCEPT)
555 	  c = gtk_file_chooser_get_filename(fc);
556      if (sr.r != GTK_RESPONSE_DELETE_EVENT) {
557 	  if (!savemode && inifile_get_gboolean("useGeometry",FALSE)) {
558 	       d = get_geom(GTK_WINDOW(w));
559 	       inifile_set(geom_setting,d);
560 	       g_free(d);
561 	  }
562 	  gtk_widget_destroy(w);
563      }
564      if (c != NULL) cleanup_filename(c);
565      return c;
566 }
567 
get_filename(gchar * current_name,gchar * filemask,gchar * title_text,gboolean savemode,GtkWidget * custom_widget)568 gchar *get_filename(gchar *current_name, gchar *filemask, gchar *title_text,
569 		    gboolean savemode, GtkWidget *custom_widget)
570 {
571      return get_filename_main(current_name,title_text,savemode,
572 			      savemode?GTK_FILE_CHOOSER_ACTION_SAVE:
573 			      GTK_FILE_CHOOSER_ACTION_OPEN,"fileGeometry",
574 			      custom_widget);
575 }
576 
get_directory(gchar * current_name,gchar * title_text)577 gchar *get_directory(gchar *current_name, gchar *title_text)
578 {
579      return get_filename_main(current_name,title_text,FALSE,
580 			      GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
581 			      "dirGeometry",NULL);
582 }
583 
584 #endif
585 
get_filename_modify_extension(gchar * new_extension)586 void get_filename_modify_extension(gchar *new_extension)
587 {
588      gchar *c,*d,*e,*f;
589      c = get_filename_internal_get_name();
590      d = strrchr(c,'.');
591      e = strrchr(c,'/');
592      if (d != NULL && (e == NULL || e < d))
593 	  *d = 0;
594      if (c[0] != 0 && (e == NULL || e[1] != 0)) {
595 	  /* printf("%s\n",c); */
596 	  f = g_strdup_printf("%s%s",c,new_extension);
597 	  get_filename_internal_set_name(f);
598 	  g_free(f);
599      }
600      g_free(c);
601 }
602 
e_copydata(EFILE * from,EFILE * to,off_t bytes)603 gboolean e_copydata(EFILE *from, EFILE *to, off_t bytes)
604 {
605      off_t count;
606      size_t rest;
607      guint8 buf[4096];
608      count = bytes / sizeof(buf);
609      rest = bytes % sizeof(buf);
610      for (; count>0; count--)
611 	  if (e_fread(buf,sizeof(buf),from) ||
612 	      e_fwrite(buf,sizeof(buf),to)) return TRUE;
613      if (rest>0)
614 	  return (e_fread(buf,rest,from) ||
615 		  e_fwrite(buf,rest,to));
616      else
617 	  return FALSE;
618 }
619 
errdlg_filesize(gchar * filename)620 off_t errdlg_filesize(gchar *filename)
621 {
622      EFILE *f;
623      off_t r;
624 
625      f = e_fopen(filename,EFILE_READ);
626      if (f == NULL) return -1;
627      if (e_fseek(f,0,SEEK_END)) { e_fclose(f); return -1; }
628      r = e_ftell(f);
629      e_fclose(f);
630      return r;
631 }
632 
errdlg_copyfile(gchar * from,gchar * to)633 gboolean errdlg_copyfile(gchar *from, gchar *to)
634 {
635      off_t l;
636      EFILE *in, *out;
637      gboolean b;
638      l = errdlg_filesize ( from );
639      if ( l == -1 ) return TRUE;
640      in = e_fopen(from,EFILE_READ);
641      if (!in) return TRUE;
642      out = e_fopen(to,EFILE_WRITE);
643      if (!out) { e_fclose(in); return TRUE; }
644      b = e_copydata(in,out,l);
645      e_fclose(in);
646      if (b) e_fclose_remove(out);
647      else e_fclose(out);
648      return b;
649 }
650 
file_exists(char * filename)651 gboolean file_exists(char *filename)
652 {
653      int i;
654      struct stat ss;
655      i = stat(filename,&ss);
656      if (i && errno==ENOENT) return FALSE;
657      return TRUE;
658 }
659 
program_exists(char * progname)660 gboolean program_exists(char *progname)
661 {
662      gchar *c,*d,*e;
663      c = getenv("PATH");
664      if (c == NULL) c="/bin:/usr/bin";
665      c = g_strdup(c);
666      for (d=strtok(c,":"); d!=NULL; d=strtok(NULL,":")) {
667 	  e = g_strdup_printf("%s/%s",d,progname);
668 	  if (file_exists(e)) {
669 	       g_free(e);
670 	       g_free(c);
671 	       return TRUE;
672 	  }
673 	  g_free(e);
674      }
675      g_free(c);
676      return FALSE;
677 }
678 
file_is_normal(char * filename)679 gboolean file_is_normal(char *filename)
680 {
681      struct stat s;
682      int i;
683      i = stat(filename,&s);
684      return (i==0 && S_ISREG(s.st_mode));
685 }
686 
file_is_directory(char * filename)687 gboolean file_is_directory(char *filename)
688 {
689      struct stat s;
690      int i;
691      i = stat(filename,&s);
692      return (i==0 && S_ISDIR(s.st_mode));
693 }
694 
e_fgetc(EFILE * stream)695 static int e_fgetc(EFILE *stream)
696 {
697      unsigned char c;
698      ssize_t i;
699      gchar *m;
700      while (1) {
701 	  i = read(stream->fd,&c,1);
702 	  if (i == 0) return -1;
703 	  if (i == -1) {
704 	       if (errno == EINTR) continue;
705 	       m = g_strdup_printf(_("Error reading from %s: %s"),
706 				   stream->filename,strerror(errno));
707 	       user_error(m);
708 	       g_free(m);
709 	       return -1;
710 	  }
711 	  return (int)c;
712      }
713 }
714 
e_readline(gchar ** line,size_t * size,EFILE * stream)715 long int e_readline(gchar **line, size_t *size, EFILE *stream)
716 {
717      size_t s = 0;
718      int c;
719      while (1) {
720 	  if (s == *size) {
721 	       *size = *size ? *size * 2 : 32;
722 	       *line = g_realloc(*line, *size);
723 	  }
724 	  c = e_fgetc(stream);
725 	  if (c==EOF || (c=='\n' && s>0)) { (*line)[s]=0; return s; }
726 	  if (c=='\n') return e_readline(line,size,stream);
727 	  (*line)[s] = (gchar)c;
728 	  s++;
729      }
730 }
731 
xunlink(gchar * filename)732 gboolean xunlink(gchar *filename)
733 {
734      gchar *c;
735 
736      if (unlink(filename) == -1 && errno != ENOENT) {
737 	  c = g_strdup_printf(_("Could not remove '%s': %s"),filename,
738 			      strerror(errno));
739 	  user_error(c);
740 	  g_free(c);
741 	  return TRUE;
742      }
743      return FALSE;
744 }
745 
xrename(gchar * oldname,gchar * newname,gboolean allow_copy)746 gint xrename(gchar *oldname, gchar *newname, gboolean allow_copy)
747 {
748      gchar *c;
749 
750      g_assert(strcmp(oldname,newname) != 0);
751 
752      if (rename(oldname,newname) == 0) return 0;
753      if (errno == EXDEV) {
754 	  if (allow_copy) return errdlg_copyfile(oldname,newname)?1:0;
755 	  else return 2;
756      } else {
757 	  c = g_strdup_printf(_("Error creating link to '%s': %s"),oldname,
758 			      strerror(errno));
759 	  user_error(c);
760 	  g_free(c);
761 	  return 1;
762      }
763 }
764 
make_filename_rooted(gchar * name)765 gchar *make_filename_rooted(gchar *name)
766 {
767      gchar *c,*d;
768      if (name[0] == '/' || name[0] == 0) return g_strdup(name);
769      c = g_get_current_dir();
770      d = g_strdup_printf("%s/%s",c,name);
771      g_free(c);
772      cleanup_filename(d);
773      return d;
774 }
775 
fd_canwrite(int fd)776 gboolean fd_canwrite(int fd)
777 {
778      fd_set set;
779      struct timeval tv = {};
780      int i;
781      FD_ZERO(&set);
782      FD_SET(fd,&set);
783      i = select(fd+1,NULL,&set,NULL,&tv);
784      if (i == 0) return FALSE;
785      else return TRUE;
786 }
787 
fd_canread(int fd)788 gboolean fd_canread(int fd)
789 {
790      fd_set set;
791      struct timeval tv = {};
792      int i;
793      FD_ZERO(&set);
794      FD_SET(fd,&set);
795      i = select(fd+1,&set,NULL,NULL,&tv);
796      if (i == 0) return FALSE;
797      else return TRUE;
798 }
799 
e_fread_u16_xe(guint16 * data,EFILE * stream,gboolean be)800 gboolean e_fread_u16_xe(guint16 *data, EFILE *stream, gboolean be)
801 {
802      unsigned char buf[2];
803      guint16 i;
804      if (e_fread(buf,2,stream)) return TRUE;
805      if (be) {
806 	  i=buf[0];
807 	  i<<=8; i|=buf[1];
808      } else {
809 	  i=buf[1];
810 	  i<<=8; i|=buf[0];
811      }
812      *data = i;
813      return FALSE;
814 }
815 
e_fread_u32_xe(guint32 * data,EFILE * stream,gboolean be)816 gboolean e_fread_u32_xe(guint32 *data, EFILE *stream, gboolean be)
817 {
818      unsigned char buf[4];
819      guint32 i;
820      if (e_fread(buf,4,stream)) return TRUE;
821      if (be) {
822 	  i=buf[0];
823 	  i<<=8; i|=buf[1];
824 	  i<<=8; i|=buf[2];
825 	  i<<=8; i|=buf[3];
826      } else {
827 	  i=buf[3];
828 	  i<<=8; i|=buf[2];
829 	  i<<=8; i|=buf[1];
830 	  i<<=8; i|=buf[0];
831      }
832      *data = i;
833      return FALSE;
834 }
835