#include #include #include #include #include "stringop.h" #include "log.h" #include "string.h" #include "list.h" const char *whitespace = " \f\n\r\t\v"; /* Note: This returns 8 characters for trimmed_start per tab character. */ char *strip_whitespace(char *_str) { if (*_str == '\0') return _str; char *strold = _str; while (*_str == ' ' || *_str == '\t') { _str++; } char *str = strdup(_str); free(strold); int i; for (i = 0; str[i] != '\0'; ++i); do { i--; } while (i >= 0 && (str[i] == ' ' || str[i] == '\t')); str[i + 1] = '\0'; return str; } char *strip_comments(char *str) { int in_string = 0, in_character = 0; int i = 0; while (str[i] != '\0') { if (str[i] == '"' && !in_character) { in_string = !in_string; } else if (str[i] == '\'' && !in_string) { in_character = !in_character; } else if (!in_character && !in_string) { if (str[i] == '#') { str[i] = '\0'; break; } } ++i; } return str; } void strip_quotes(char *str) { bool in_str = false; bool in_chr = false; bool escaped = false; char *end = strchr(str,0); while (*str) { if (*str == '\'' && !in_str && !escaped) { in_chr = !in_chr; goto shift_over; } else if (*str == '\"' && !in_chr && !escaped) { in_str = !in_str; goto shift_over; } else if (*str == '\\') { escaped = !escaped; ++str; continue; } escaped = false; ++str; continue; shift_over: memmove(str, str+1, end-- - str); } *end = '\0'; } list_t *split_string(const char *str, const char *delims) { list_t *res = create_list(); char *copy = strdup(str); char *token; token = strtok(copy, delims); while(token) { token = strdup(token); list_add(res, token); token = strtok(NULL, delims); } free(copy); return res; } void free_flat_list(list_t *list) { int i; for (i = 0; i < list->length; ++i) { free(list->items[i]); } list_free(list); } char **split_args(const char *start, int *argc) { *argc = 0; int alloc = 2; char **argv = malloc(sizeof(char *) * alloc); bool in_token = false; bool in_string = false; bool in_char = false; bool escaped = false; const char *end = start; while (*start) { if (!in_token) { start = (end += strspn(end, whitespace)); in_token = true; } if (*end == '"' && !in_char && !escaped) { in_string = !in_string; } else if (*end == '\'' && !in_string && !escaped) { in_char = !in_char; } else if (*end == '\\') { escaped = !escaped; } else if (*end == '\0' || (!in_string && !in_char && !escaped && strchr(whitespace, *end))) { goto add_part; } if (*end != '\\') { escaped = false; } ++end; continue; add_part: if (end - start > 0) { char *token = malloc(end - start + 1); strncpy(token, start, end - start + 1); token[end - start] = '\0'; strip_quotes(token); unescape_string(token); argv[*argc] = token; if (++*argc + 1 == alloc) { argv = realloc(argv, (alloc *= 2) * sizeof(char *)); } } in_token = false; escaped = false; } argv[*argc] = NULL; return argv; } void free_argv(int argc, char **argv) { while (--argc > 0) { free(argv[argc]); } free(argv); } char *code_strstr(const char *haystack, const char *needle) { /* TODO */ return strstr(haystack, needle); } char *code_strchr(const char *str, char delimiter) { int in_string = 0, in_character = 0; int i = 0; while (str[i] != '\0') { if (str[i] == '"' && !in_character) { in_string = !in_string; } else if (str[i] == '\'' && !in_string) { in_character = !in_character; } else if (!in_character && !in_string) { if (str[i] == delimiter) { return (char *)str + i; } } ++i; } return NULL; } int unescape_string(char *string) { /* TODO: More C string escapes */ int len = strlen(string); int i; for (i = 0; string[i]; ++i) { if (string[i] == '\\') { switch (string[++i]) { case '0': string[i - 1] = '\0'; return i - 1; case 'a': string[i - 1] = '\a'; string[i] = '\0'; break; case 'b': string[i - 1] = '\b'; string[i] = '\0'; break; case 'f': string[i - 1] = '\f'; string[i] = '\0'; break; case 'n': string[i - 1] = '\n'; string[i] = '\0'; break; case 'r': string[i - 1] = '\r'; string[i] = '\0'; break; case 't': string[i - 1] = '\t'; string[i] = '\0'; break; case 'v': string[i - 1] = '\v'; string[i] = '\0'; break; case '\\': string[i] = '\0'; break; case '\'': string[i - 1] = '\''; string[i] = '\0'; break; case '\"': string[i - 1] = '\"'; string[i] = '\0'; break; case '?': string[i - 1] = '?'; string[i] = '\0'; break; case 'x': { unsigned char c = 0; if (string[i+1] >= '0' && string[i+1] <= '9') { c = string[i+1] - '0'; if (string[i+2] >= '0' && string[i+2] <= '9') { c *= 0x10; c += string[i+2] - '0'; string[i+2] = '\0'; } string[i+1] = '\0'; } string[i] = '\0'; string[i - 1] = c; } } } } // Shift characters over nullspaces int shift = 0; for (i = 0; i < len; ++i) { if (string[i] == 0) { shift++; continue; } string[i-shift] = string[i]; } string[len - shift] = 0; return len - shift; } char *join_args(int argc, char **argv) { int len = 0, i; for (i = 0; i < argc; ++i) { len += strlen(argv[i]) + 1; } char *res = malloc(len); len = 0; for (i = 0; i < argc; ++i) { strcpy(res + len, argv[i]); len += strlen(argv[i]); res[len++] = ' '; } res[len - 1] = '\0'; return res; } /* * Join a list of strings, adding separator in between. Separator can be NULL. */ char *join_list(list_t *list, char *separator) { if (!sway_assert(list != NULL, "list != NULL") || list->length == 0) { return NULL; } size_t len = 1; // NULL terminator size_t sep_len = 0; if (separator != NULL) { sep_len = strlen(separator); len += (list->length - 1) * sep_len; } for (int i = 0; i < list->length; i++) { len += strlen(list->items[i]); } char *res = malloc(len); char *p = res + strlen(list->items[0]); strcpy(res, list->items[0]); for (int i = 1; i < list->length; i++) { if (sep_len) { memcpy(p, separator, sep_len); p += sep_len; } strcpy(p, list->items[i]); p += strlen(list->items[i]); } *p = '\0'; return res; }