girara
|
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 }