girara
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
utils.c
Go to the documentation of this file.
1 /* See LICENSE file for license and copyright information */
2 
3 #define _BSD_SOURCE
4 #define _XOPEN_SOURCE 700
5 #define _FILE_OFFSET_BITS 64
6 
7 #include <ctype.h>
8 #include <fcntl.h>
9 #include <limits.h>
10 #include <pwd.h>
11 #include <stdbool.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16 #include <glib.h>
17 #include <stdio.h>
18 #include <errno.h>
19 #include <stdint.h>
20 
21 #include "utils.h"
22 #include "datastructures.h"
23 
24 #define BLOCK_SIZE 64
25 
26 char*
27 girara_fix_path(const char* path)
28 {
29  if (path == NULL) {
30  return NULL;
31  }
32 
33  char* rpath = NULL;
34  if (path[0] == '~') {
35  const size_t len = strlen(path);
36  char* user = NULL;
37  size_t idx = 1;
38 
39  if (len > 1 && path[1] != '/') {
40  while (path[idx] && path[idx] != '/') {
41  ++idx;
42  }
43 
44  user = g_strndup(path + 1, idx - 1);
45  }
46 
47  char* home_path = girara_get_home_directory(user);
48  g_free(user);
49 
50  if (home_path == NULL) {
51  return g_strdup(path);
52  }
53 
54  rpath = g_build_filename(home_path, path + idx, NULL);
55  g_free(home_path);
56  } else {
57  rpath = g_strdup(path);
58  }
59 
60  return rpath;
61 }
62 
63 bool
64 girara_xdg_open(const char* uri)
65 {
66  if (uri == NULL || strlen(uri) == 0) {
67  return false;
68  }
69 
70  GString* command = g_string_new("xdg-open ");
71  char* tmp = g_shell_quote(uri);
72 
73  g_string_append(command, tmp);
74  g_free(tmp);
75 
76  GError* error = NULL;
77  bool res = g_spawn_command_line_async(command->str, &error);
78  if (error != NULL) {
79  girara_warning("Failed to execute command: %s", error->message);
80  g_error_free(error);
81  }
82 
83  g_string_free(command, TRUE);
84  return res;
85 }
86 
87 char*
88 girara_get_home_directory(const char* user)
89 {
90  if (user == NULL || g_strcmp0(user, g_get_user_name()) == 0) {
91  const char* homedir = g_getenv("HOME");
92  return g_strdup(homedir ? homedir : g_get_home_dir());
93  }
94 
95  // XXX: The following code is very unportable.
96  struct passwd pwd;
97  struct passwd* result;
98 #ifdef _SC_GETPW_R_SIZE_MAX
99  int bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
100  if (bufsize < 0) {
101  bufsize = 4096;
102  }
103 #else
104  int bufsize = 4096;
105 #endif
106 
107  char* buffer = g_malloc0(sizeof(char) * bufsize);
108 
109  getpwnam_r(user, &pwd, buffer, bufsize, &result);
110  if (result == NULL) {
111  g_free(buffer);
112  return NULL;
113  }
114 
115  char* dir = g_strdup(pwd.pw_dir);
116  g_free(buffer);
117  return dir;
118 }
119 
120 char*
122 {
123  static const char* VARS[] = {
124  "XDG_CONFIG_HOME",
125  "XDG_DATA_HOME",
126  "XDG_CONFIG_DIRS",
127  "XDG_DATA_DIRS"
128  };
129 
130  static const char* DEFAULTS[] = {
131  "NOTUSED",
132  "NOTUSED",
133  "/etc/xdg",
134  "/usr/local/share/:/usr/share",
135  };
136 
137  switch (path) {
138  case XDG_DATA:
139  return g_strdup(g_get_user_data_dir());
140  case XDG_CONFIG:
141  return g_strdup(g_get_user_config_dir());
142  case XDG_CONFIG_DIRS:
143  case XDG_DATA_DIRS:
144  {
145  const char* tmp = g_getenv(VARS[path]);
146  if (tmp == NULL || !g_strcmp0(tmp, "")) {
147  return g_strdup(DEFAULTS[path]);
148  }
149  return g_strdup(tmp);
150  }
151  }
152 
153  return NULL;
154 }
155 
156 girara_list_t*
157 girara_split_path_array(const char* patharray)
158 {
159  if (patharray == NULL || !g_strcmp0(patharray, "")) {
160  return NULL;
161  }
162 
163  girara_list_t* res = girara_list_new2(g_free);
164  char** paths = g_strsplit(patharray, ":", 0);
165  for (unsigned int i = 0; paths[i] != '\0'; ++i) {
166  girara_list_append(res, g_strdup(paths[i]));
167  }
168  g_strfreev(paths);
169 
170  return res;
171 }
172 
173 FILE*
174 girara_file_open(const char* path, const char* mode)
175 {
176  char* fixed_path = girara_fix_path(path);
177 
178  if (fixed_path == NULL || mode == NULL) {
179  return NULL;
180  }
181 
182  FILE* fp = fopen(fixed_path, mode);
183  g_free(fixed_path);
184  if (fp == NULL) {
185  return NULL;
186  }
187 
188  return fp;
189 
190  /* TODO */
191  /*FILE* fp;*/
192  /*struct stat lstat;*/
193  /*struct stat fstat;*/
194  /*int fd;*/
195  /*char* mode = "rb+";*/
196 
197  /*if (lstat(path, &lstat) == -1) {*/
198  /*if (errno != ENOENT) {*/
199  /*return NULL;*/
200  /*}*/
201 
202  /*if ((fd = open(path, O_CREAT | O_EXCL | O_RDWR, 0600)) == -1) {*/
203  /*return NULL;*/
204  /*}*/
205 
206  /*mode = "wb";*/
207  /*} else {*/
208  /*if ((fd = open(path, O_RDONLY)) == -1) {*/
209  /*return NULL;*/
210  /*}*/
211 
212  /*if (fstat(fd, &fstat) == -1) {*/
213  /*if (lstat.st_mode != fstat.st_mode ||*/
214  /*lstat.st_ino != fstat.st_ino ||*/
215  /*lstat.st_dev != fstat.st_dev) {*/
216  /*close(fd);*/
217  /*return NULL;*/
218  /*}*/
219  /*}*/
220 
221  /*ftruncate(fd, 0);*/
222  /*}*/
223 
224  /*if ((fp = fdopen(fd, mode)) == NULL) {*/
225  /*close(fd);*/
226  /*unlink(path);*/
227  /*return NULL;*/
228  /*}*/
229 
230  /*return fp;*/
231 }
232 
233 #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
234 char*
235 girara_file_read_line(FILE* file)
236 {
237  if (file == NULL) {
238  return NULL;
239  }
240 
241  size_t size = 0;
242  char* line = fgetln(file, &size);
243  if (line == NULL) {
244  return NULL;
245  }
246 
247  char* copy = strndup(line, size);
248  if (copy == NULL) {
249  return NULL;
250  }
251 
252  /* remove the trailing line deliminator */
253  g_strdelimit(copy, "\n\r", '\0');
254 
255  return copy;
256 }
257 #else
258 char*
260 {
261  if (file == NULL) {
262  return NULL;
263  }
264 
265  size_t size = 0;
266  char* line = NULL;
267  if (getline(&line, &size, file) == -1) {
268  if (line != NULL) {
269  free(line);
270  }
271  return NULL;
272  }
273 
274  /* remove the trailing line deliminator */
275  g_strdelimit(line, "\n\r", '\0');
276  return line;
277 }
278 #endif
279 
280 char*
281 girara_file_read(const char* path)
282 {
283  if (path == NULL) {
284  return NULL;
285  }
286 
287  FILE* file = girara_file_open(path, "r");
288  if (file == NULL) {
289  return NULL;
290  }
291 
292  char* content = girara_file_read2(file);
293  fclose(file);
294  return content;
295 }
296 
297 char*
298 girara_file_read2(FILE* file)
299 {
300  if (file == NULL) {
301  return NULL;
302  }
303 
304  const off_t curpos = ftello(file);
305  if (curpos == -1) {
306  return NULL;
307  }
308 
309  fseeko(file, 0, SEEK_END);
310  const off_t size = ftello(file) - curpos;
311  fseeko(file, curpos, SEEK_SET);
312 
313  if (size == 0) {
314  char* content = malloc(1);
315  content[0] = '\0';
316  return content;
317  }
318  /* this can happen on 32 bit systems */
319  if ((uintmax_t)size >= (uintmax_t)SIZE_MAX) {
320  girara_error("file is too large");
321  return NULL;
322  }
323 
324  char* buffer = malloc(size + 1);
325  if (!buffer) {
326  return NULL;
327  }
328 
329  size_t read = fread(buffer, size, 1, file);
330  if (read != 1) {
331  free(buffer);
332  return NULL;
333  }
334 
335  buffer[size] = '\0';
336  return buffer;
337 }
338 
339 void
340 girara_clean_line(char* line)
341 {
342  if (line == NULL) {
343  return;
344  }
345 
346  unsigned int i = 0;
347  unsigned int j = 0;
348  bool ws_mode = true;
349 
350  for(i = 0; i < strlen(line); i++) {
351  if (isspace(line[i]) != 0) {
352  if (ws_mode) {
353  continue;
354  }
355 
356  line[j++] = ' ';
357  ws_mode = true;
358  } else {
359  line[j++] = line[i];
360  ws_mode = false;
361  }
362  }
363 
364  line[j] = '\0';
365 }
366 
367 void*
368 girara_safe_realloc(void** ptr, size_t size)
369 {
370  if(ptr == NULL) {
371  return NULL;
372  }
373 
374  if (size == 0) {
375  goto error_free;
376  }
377 
378  void* tmp = realloc(*ptr, size);
379  if(tmp == NULL) {
380  goto error_free;
381  }
382 
383  *ptr = tmp;
384  return *ptr;
385 
386 error_free:
387 
388  free(*ptr);
389  *ptr = NULL;
390 
391  return NULL;
392 }
393 
394 static girara_debug_level_t debug_level = GIRARA_DEBUG;
395 
396 void
397 _girara_debug(const char* function, int line, girara_debug_level_t level, const char* format, ...)
398 {
399  /* This could be simplified if DEBUG, INFO, WARNING, ERROR were ordered. */
400  if ((debug_level == GIRARA_ERROR && level != GIRARA_ERROR) ||
401  (debug_level == GIRARA_WARNING && (level != GIRARA_ERROR && level != GIRARA_WARNING)) ||
402  (debug_level == GIRARA_INFO && level == GIRARA_DEBUG)) {
403  return;
404  }
405 
406  switch (level)
407  {
408  case GIRARA_WARNING:
409  fprintf(stderr, "warning: ");
410  break;
411  case GIRARA_ERROR:
412  fprintf(stderr, "error: ");
413  break;
414  case GIRARA_INFO:
415  fprintf(stderr, "info: ");
416  break;
417  case GIRARA_DEBUG:
418  fprintf(stderr, "debug: (%s:%d) ", function, line);
419  break;
420  default:
421  return;
422  }
423 
424  va_list ap;
425  va_start(ap, format);
426  vfprintf(stderr, format, ap);
427  va_end(ap);
428 
429  fprintf(stderr, "\n");
430 }
431 
434 {
435  return debug_level;
436 }
437 
438 void
440 {
441  debug_level = level;
442 }