/* * uhub - A tiny ADC p2p connection hub * Copyright (C) 2007-2011, Jan Vidar Krey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "uhub.h" static const char* BASE32_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; int is_space(char c) { if (c == ' ') return 1; return 0; } int is_white_space(char c) { if (c == ' ' || c == '\t' || c == '\r') return 1; return 0; } static int is_printable(unsigned char c) { if (c >= 32) return 1; if (c == '\t' || c == '\r' || c == '\n') return 1; return 0; } char* strip_white_space(char* string) { char* pos; if (!string) return ""; while (string[0] && is_white_space(string[0])) string++; if (!*string) return string; /* Strip appending whitespace */ pos = &string[strlen(string)-1]; while (&string[0] < &pos[0] && is_white_space(pos[0])) { pos[0] = 0; pos--; } return string; } static int is_valid_utf8_str(const char* string, size_t length) { int expect = 0; char div = 0; size_t pos = 0; if (length == 0) return 1; for (pos = 0; pos < length; pos++) { if (expect) { if ((string[pos] & 0xC0) == 0x80) expect--; else return 0; } else { if (string[pos] & 0x80) { for (div = 0x40; div > 0x10; div /= 2) { if (string[pos] & div) expect++; else break; } if ((string[pos] & div) || (pos+expect >= length)) return 0; } } } return 1; } int is_valid_utf8(const char* string) { return is_valid_utf8_str(string, strlen(string)); } int is_printable_utf8(const char* string, size_t length) { size_t pos = 0; for (pos = 0; pos < length; pos++) { if (!is_printable(string[pos])) return 0; } return is_valid_utf8_str(string, length); } int is_valid_base32_char(char c) { if ((c >= 'A' && c <= 'Z') || (c >= '2' && c <= '7')) return 1; return 0; } int is_num(char c) { if (c >= '0' && c <= '9') return 1; return 0; } void base32_encode(const unsigned char* buffer, size_t len, char* result) { unsigned char word = 0; size_t n = 0; size_t i = 0; size_t index = 0; for (; i < len;) { if (index > 3) { word = (buffer[i] & (0xFF >> index)); index = (index + 5) % 8; word <<= index; if (i < len - 1) word |= buffer[i + 1] >> (8 - index); i++; } else { word = (buffer[i] >> (8 - (index + 5))) & 0x1F; index = (index + 5) % 8; if (index == 0) i++; } result[n++] = BASE32_ALPHABET[word]; } result[n] = '\0'; } void base32_decode(const char* src, unsigned char* dst, size_t len) { size_t index = 0; size_t offset = 0; size_t i = 0; memset(dst, 0, len); for (i = 0; src[i]; i++) { unsigned char n = 0; for (; n < 32; n++) if (src[i] == BASE32_ALPHABET[n]) break; if (n == 32) continue; if (index <= 3) { index = (index + 5) % 8; if (index == 0) { dst[offset++] |= n; if (offset == len) break; } else { dst[offset] |= n << (8 - index); } } else { index = (index + 5) % 8; dst[offset++] |= (n >> index); if (offset == len) break; dst[offset] |= n << (8 - index); } } } int string_split(const char* string, const char* split, void* data, string_split_handler_t handler) { char* buf = strdup(string); char* start; char* pos; int count = 0; start = buf; while ((pos = strstr(start, split))) { pos[0] = '\0'; start = strip_white_space(start); if (*start) { if (handler(start, count, data) < 0) { hub_free(buf); return -1; } } start = &pos[1]; count++; } start = strip_white_space(start); if (*start) { if (handler(start, count, data) < 0) { hub_free(buf); return -1; } } hub_free(buf); return count+1; } struct file_read_line_data { file_line_handler_t handler; void* data; }; static int file_read_line_handler(char* line, int count, void* ptr) { struct file_read_line_data* data = (struct file_read_line_data*) ptr; LOG_DUMP("Line: %s", line); if (data->handler(line, count+1, data->data) < 0) return -1; return 0; } int file_read_lines(const char* file, void* data, file_line_handler_t handler) { int fd; ssize_t ret; char buf[MAX_RECV_BUF]; struct file_read_line_data split_data; memset(buf, 0, MAX_RECV_BUF); LOG_TRACE("Opening file %s for line reading.", file); fd = open(file, 0); if (fd == -1) { LOG_ERROR("Unable to open file %s: %s", file, strerror(errno)); return -2; } ret = read(fd, buf, MAX_RECV_BUF-1); close(fd); if (ret < 0) { LOG_ERROR("Unable to read from file %s: %s", file, strerror(errno)); return -1; } else if (ret == 0) { LOG_WARN("File is empty."); return 0; } buf[ret] = 0; /* Parse configuration */ split_data.handler = handler; split_data.data = data; return string_split(buf, "\n", &split_data, file_read_line_handler); } int uhub_atoi(const char* value) { int len = strlen(value); int offset = 0; int val = 0; int i = 0; for (; i < len; i++) if (value[i] > '9' || value[i] < '0') offset++; for (i = offset; i< len; i++) val = val*10 + (value[i] - '0'); return value[0] == '-' ? -val : val; } int is_number(const char* value, int* num) { int len = strlen(value); int offset = (value[0] == '-') ? 1 : 0; int val = 0; int i = offset; if (!*(value + offset)) return 0; for (; i < len; i++) if (value[i] > '9' || value[i] < '0') return 0; for (i = offset; i< len; i++) val = val*10 + (value[i] - '0'); *num = value[0] == '-' ? -val : val; return 1; } const char* uhub_itoa(int val) { static char buf[22]; return snprintf(buf, sizeof(buf), "%d", val) < 0 ? NULL : buf; } const char* uhub_ulltoa(uint64_t val) { static char buf[22]; return snprintf(buf, sizeof(buf), PRINTF_UINT64_T, val) < 0 ? NULL : buf; } #ifndef HAVE_STRNDUP char* strndup(const char* string, size_t n) { size_t max = MIN(strlen(string), n); char* tmp = hub_malloc(max+1); memcpy(tmp, string, max); tmp[max] = 0; return tmp; } #endif #ifndef HAVE_MEMMEM void* memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { char* c_buf = (char*) haystack; char* c_pat = (char*) needle; char* ptr = memchr(c_buf, c_pat[0], haystacklen); while (ptr && ((size_t) (&ptr[0] - &c_buf[0]) < haystacklen)) { if (!memcmp(ptr, c_pat, needlelen)) return ptr; ptr = memchr(&ptr[1], c_pat[0], &c_buf[haystacklen] - &ptr[0]); } return 0; } #endif int split_string(const char* string, const char* split, struct linked_list* list, int allow_empty) { char* tmp1, *tmp2; int n = 0; if (!string || !*string || !split || !*split || !list) return -1; for (;;) { tmp1 = strstr(string, split); if (tmp1) tmp2 = hub_strndup(string, tmp1 - string); else tmp2 = hub_strdup(string); if (!tmp2) { list_clear(list, &hub_free); return -1; } if (*tmp2 || allow_empty) { /* store in list */ list_append(list, tmp2); n++; } else { /* ignore element */ hub_free(tmp2); } if (!tmp1) break; /* last element found */ string = tmp1; string += strlen(split); } return n; } const char* get_timestamp(time_t now) { static char ts[32] = {0, }; struct tm* t = localtime(&now); snprintf(ts, sizeof(ts), "[%02d:%02d]", t->tm_hour, t->tm_min); return ts; } void strip_off_ini_line_comments(char* line, int line_count) { char* p = line; char* out = line; int backslash = 0; if (!*line) return; for (; *p; p++) { if (!backslash) { if (*p == '\\') { backslash = 1; } else if (*p == '#') { *out = '\0'; out++; break; } else { *out = *p; out++; } } else { if (*p == '\\' || *p == '#' || *p == '\"') { *out = *p; out++; } else { LOG_WARN("Invalid backslash escape on line %d", line_count); *out = *p; out++; } backslash = 0; } } *out = '\0'; } int string_to_boolean(const char* str, int* boolean) { if (!str || !*str || !boolean) return 0; switch (strlen(str)) { case 1: if (str[0] == '1') { *boolean = 1; return 1; } else if (str[0] == '0') { *boolean = 0; return 1; } return 0; case 2: if (!strcasecmp(str, "on")) { *boolean = 1; return 1; } if (!strcasecmp(str, "no")) { *boolean = 0; return 1; } return 0; case 3: if (!strcasecmp(str, "yes")) { *boolean = 1; return 1; } if (!strcasecmp(str, "off")) { *boolean = 0; return 1; } return 0; case 4: if (!strcasecmp(str, "true")) { *boolean = 1; return 1; } return 0; case 5: if (!strcasecmp(str, "false")) { *boolean = 0; return 1; } return 0; default: return 0; } } char* strip_off_quotes(char* line) { size_t len; if (!*line) return line; len = strlen(line); if (len < 2) return line; if ((line[0] == '"' && line[len - 1] == '"') || (line[0] == '\'' && line[len - 1] == '\'')) { line[len-1] = '\0'; return line + 1; } return line; }