girara
utils.c
Go to the documentation of this file.
00001 /* See LICENSE file for license and copyright information */
00002 
00003 #define _BSD_SOURCE
00004 #define _XOPEN_SOURCE 700
00005 #define _FILE_OFFSET_BITS 64
00006 
00007 #include <ctype.h>
00008 #include <fcntl.h>
00009 #include <limits.h>
00010 #include <pwd.h>
00011 #include <stdbool.h>
00012 #include <stdlib.h>
00013 #include <string.h>
00014 #include <sys/types.h>
00015 #include <unistd.h>
00016 #include <glib.h>
00017 #include <stdio.h>
00018 #include <errno.h>
00019 #include <stdint.h>
00020 
00021 #include "utils.h"
00022 #include "datastructures.h"
00023 
00024 #define BLOCK_SIZE 64
00025 
00026 char*
00027 girara_fix_path(const char* path)
00028 {
00029   if (path == NULL) {
00030     return NULL;
00031   }
00032 
00033   char* rpath = NULL;
00034   if (path[0] == '~') {
00035     const size_t len = strlen(path);
00036     char* user = NULL;
00037     size_t idx = 1;
00038 
00039     if (len > 1 && path[1] != '/') {
00040       while (path[idx] && path[idx] != '/') {
00041         ++idx;
00042       }
00043 
00044       user = g_strndup(path + 1, idx - 1);
00045     }
00046 
00047     char* home_path = girara_get_home_directory(user);
00048     g_free(user);
00049 
00050     if (home_path == NULL) {
00051       return g_strdup(path);
00052     }
00053 
00054     rpath = g_build_filename(home_path, path + idx, NULL);
00055     g_free(home_path);
00056   } else {
00057     rpath = g_strdup(path);
00058   }
00059 
00060   return rpath;
00061 }
00062 
00063 bool
00064 girara_xdg_open(const char* uri)
00065 {
00066   if (uri == NULL || strlen(uri) == 0) {
00067     return false;
00068   }
00069 
00070   GString* command = g_string_new("xdg-open ");
00071   char* tmp        = g_shell_quote(uri);
00072 
00073   g_string_append(command, tmp);
00074   g_free(tmp);
00075 
00076   GError* error = NULL;
00077   bool res = g_spawn_command_line_async(command->str, &error);
00078   if (error != NULL) {
00079     girara_warning("Failed to execute command: %s", error->message);
00080     g_error_free(error);
00081   }
00082 
00083   g_string_free(command, TRUE);
00084   return res;
00085 }
00086 
00087 char*
00088 girara_get_home_directory(const char* user)
00089 {
00090   if (user == NULL || g_strcmp0(user, g_get_user_name()) == 0) {
00091     const char* homedir = g_getenv("HOME");
00092     return g_strdup(homedir ? homedir : g_get_home_dir());
00093   }
00094 
00095   // XXX: The following code is very unportable.
00096   struct passwd pwd;
00097   struct passwd* result;
00098 #ifdef _SC_GETPW_R_SIZE_MAX
00099   int bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
00100   if (bufsize < 0) {
00101     bufsize = 4096;
00102   }
00103 #else
00104   int bufsize = 4096;
00105 #endif
00106 
00107   char* buffer = g_malloc0(sizeof(char) * bufsize);
00108 
00109   getpwnam_r(user, &pwd, buffer, bufsize, &result);
00110   if (result == NULL) {
00111     g_free(buffer);
00112     return NULL;
00113   }
00114 
00115   char* dir = g_strdup(pwd.pw_dir);
00116   g_free(buffer);
00117   return dir;
00118 }
00119 
00120 char*
00121 girara_get_xdg_path(girara_xdg_path_t path)
00122 {
00123   static const char* VARS[] = {
00124     "XDG_CONFIG_HOME",
00125     "XDG_DATA_HOME",
00126     "XDG_CONFIG_DIRS",
00127     "XDG_DATA_DIRS"
00128   };
00129 
00130   static const char* DEFAULTS[] = {
00131     "NOTUSED",
00132     "NOTUSED",
00133     "/etc/xdg",
00134     "/usr/local/share/:/usr/share",
00135   };
00136 
00137   switch (path) {
00138     case XDG_DATA:
00139       return g_strdup(g_get_user_data_dir());
00140     case XDG_CONFIG:
00141       return g_strdup(g_get_user_config_dir());
00142     case XDG_CONFIG_DIRS:
00143     case XDG_DATA_DIRS:
00144     {
00145       const char* tmp = g_getenv(VARS[path]);
00146       if (tmp == NULL || !g_strcmp0(tmp, "")) {
00147         return g_strdup(DEFAULTS[path]);
00148       }
00149       return g_strdup(tmp);
00150     }
00151   }
00152 
00153   return NULL;
00154 }
00155 
00156 girara_list_t*
00157 girara_split_path_array(const char* patharray)
00158 {
00159   if (patharray == NULL || !g_strcmp0(patharray, "")) {
00160     return NULL;
00161   }
00162 
00163   girara_list_t* res = girara_list_new2(g_free);
00164   char** paths = g_strsplit(patharray, ":", 0);
00165   for (unsigned int i = 0; paths[i] != '\0'; ++i) {
00166     girara_list_append(res, g_strdup(paths[i]));
00167   }
00168   g_strfreev(paths);
00169 
00170   return res;
00171 }
00172 
00173 FILE*
00174 girara_file_open(const char* path, const char* mode)
00175 {
00176   char* fixed_path = girara_fix_path(path);
00177 
00178   if (fixed_path == NULL || mode == NULL) {
00179     return NULL;
00180   }
00181 
00182   FILE* fp = fopen(fixed_path, mode);
00183   g_free(fixed_path);
00184   if (fp  == NULL) {
00185         return NULL;
00186   }
00187 
00188   return fp;
00189 
00190   /* TODO */
00191   /*FILE* fp;*/
00192   /*struct stat lstat;*/
00193   /*struct stat fstat;*/
00194   /*int fd;*/
00195   /*char* mode = "rb+";*/
00196 
00197   /*if (lstat(path, &lstat) == -1) {*/
00198     /*if (errno != ENOENT) {*/
00199       /*return NULL;*/
00200     /*}*/
00201 
00202     /*if ((fd = open(path, O_CREAT | O_EXCL | O_RDWR, 0600)) == -1) {*/
00203       /*return NULL;*/
00204     /*}*/
00205 
00206     /*mode = "wb";*/
00207   /*} else {*/
00208     /*if ((fd = open(path, O_RDONLY)) == -1) {*/
00209       /*return NULL;*/
00210     /*}*/
00211 
00212     /*if (fstat(fd, &fstat) == -1) {*/
00213       /*if (lstat.st_mode != fstat.st_mode ||*/
00214           /*lstat.st_ino  != fstat.st_ino ||*/
00215           /*lstat.st_dev  != fstat.st_dev) {*/
00216         /*close(fd);*/
00217         /*return NULL;*/
00218       /*}*/
00219     /*}*/
00220 
00221     /*ftruncate(fd, 0);*/
00222   /*}*/
00223 
00224   /*if ((fp = fdopen(fd, mode)) == NULL) {*/
00225     /*close(fd);*/
00226     /*unlink(path);*/
00227     /*return NULL;*/
00228   /*}*/
00229 
00230   /*return fp;*/
00231 }
00232 
00233 #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
00234 char*
00235 girara_file_read_line(FILE* file)
00236 {
00237   if (file == NULL) {
00238     return NULL;
00239   }
00240 
00241   size_t size = 0;
00242   char* line = fgetln(file, &size);
00243   if (line  == NULL) {
00244     return NULL;
00245   }
00246 
00247   char* copy = strndup(line, size);
00248   if (copy == NULL) {
00249     return NULL;
00250   }
00251 
00252   /* remove the trailing line deliminator */
00253   g_strdelimit(copy, "\n\r", '\0');
00254 
00255   return copy;
00256 }
00257 #else
00258 char*
00259 girara_file_read_line(FILE* file)
00260 {
00261   if (file == NULL) {
00262     return NULL;
00263   }
00264 
00265   size_t size = 0;
00266   char* line = NULL;
00267   if (getline(&line, &size, file) == -1) {
00268     if (line != NULL) {
00269       free(line);
00270     }
00271     return NULL;
00272   }
00273 
00274   /* remove the trailing line deliminator */
00275   g_strdelimit(line, "\n\r", '\0');
00276   return line;
00277 }
00278 #endif
00279 
00280 char*
00281 girara_file_read(const char* path)
00282 {
00283   if (path == NULL) {
00284     return NULL;
00285   }
00286 
00287   FILE* file = girara_file_open(path, "r");
00288   if (file == NULL) {
00289     return NULL;
00290   }
00291 
00292   char* content = girara_file_read2(file);
00293   fclose(file);
00294   return content;
00295 }
00296 
00297 char*
00298 girara_file_read2(FILE* file)
00299 {
00300   if (file == NULL) {
00301     return NULL;
00302   }
00303 
00304   const off_t curpos = ftello(file);
00305   if (curpos == -1) {
00306     return NULL;
00307   }
00308 
00309   fseeko(file, 0, SEEK_END);
00310   const off_t size = ftello(file) - curpos;
00311   fseeko(file, curpos, SEEK_SET);
00312 
00313   if (size == 0) {
00314     char* content = malloc(1);
00315     content[0] = '\0';
00316     return content;
00317   }
00318   /* this can happen on 32 bit systems */
00319   if ((uintmax_t)size >= (uintmax_t)SIZE_MAX) {
00320     girara_error("file is too large");
00321     return NULL;
00322   }
00323 
00324   char* buffer    = malloc(size + 1);
00325   if (!buffer) {
00326     return NULL;
00327   }
00328 
00329   size_t read = fread(buffer, size, 1, file);
00330   if (read != 1) {
00331     free(buffer);
00332     return NULL;
00333   }
00334 
00335   buffer[size] = '\0';
00336   return buffer;
00337 }
00338 
00339 void
00340 girara_clean_line(char* line)
00341 {
00342   if (line == NULL) {
00343     return;
00344   }
00345 
00346   unsigned int i = 0;
00347   unsigned int j = 0;
00348   bool ws_mode   = true;
00349 
00350   for(i = 0; i < strlen(line); i++) {
00351     if (isspace(line[i]) != 0) {
00352       if (ws_mode) {
00353         continue;
00354       }
00355 
00356       line[j++] = ' ';
00357       ws_mode = true;
00358     } else {
00359       line[j++] = line[i];
00360       ws_mode = false;
00361     }
00362   }
00363 
00364   line[j] = '\0';
00365 }
00366 
00367 void*
00368 girara_safe_realloc(void** ptr, size_t size)
00369 {
00370   if(ptr == NULL) {
00371     return NULL;
00372   }
00373 
00374   if (size == 0) {
00375     goto error_free;
00376   }
00377 
00378   void* tmp = realloc(*ptr, size);
00379   if(tmp == NULL) {
00380     goto error_free;
00381   }
00382 
00383   *ptr = tmp;
00384   return *ptr;
00385 
00386 error_free:
00387 
00388   free(*ptr);
00389   *ptr = NULL;
00390 
00391   return NULL;
00392 }
00393 
00394 static girara_debug_level_t debug_level = GIRARA_DEBUG;
00395 
00396 void
00397 _girara_debug(const char* function, int line, girara_debug_level_t level, const char* format, ...)
00398 {
00399   /* This could be simplified if DEBUG, INFO, WARNING, ERROR were ordered. */
00400   if ((debug_level == GIRARA_ERROR && level != GIRARA_ERROR) ||
00401       (debug_level == GIRARA_WARNING && (level != GIRARA_ERROR && level != GIRARA_WARNING)) ||
00402       (debug_level == GIRARA_INFO && level == GIRARA_DEBUG)) {
00403     return;
00404   }
00405 
00406   switch (level)
00407   {
00408     case GIRARA_WARNING:
00409       fprintf(stderr, "warning: ");
00410       break;
00411     case GIRARA_ERROR:
00412       fprintf(stderr, "error: ");
00413       break;
00414     case GIRARA_INFO:
00415       fprintf(stderr, "info: ");
00416       break;
00417     case GIRARA_DEBUG:
00418       fprintf(stderr, "debug: (%s:%d) ", function, line);
00419       break;
00420     default:
00421       return;
00422   }
00423 
00424   va_list ap;
00425   va_start(ap, format);
00426   vfprintf(stderr, format, ap);
00427   va_end(ap);
00428 
00429   fprintf(stderr, "\n");
00430 }
00431 
00432 girara_debug_level_t
00433 girara_get_debug_level()
00434 {
00435   return debug_level;
00436 }
00437 
00438 void
00439 girara_set_debug_level(girara_debug_level_t level)
00440 {
00441   debug_level = level;
00442 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines