/* Split a string into words, but consider strings enclosed in '' and
* "" as words even if they include spaces. */
char *split_quoted(const char *c, size_t *l, char **state) {
- char *current;
+ char *current, *e;
+ bool escaped = false;
current = *state ? *state : (char*) c;
if (*current == '\'') {
current ++;
- *l = strcspn(current, "'");
- *state = current+*l;
- if (**state == '\'')
- (*state)++;
+ for (e = current; *e; e++) {
+ if (escaped)
+ escaped = false;
+ else if (*e == '\\')
+ escaped = true;
+ else if (*e == '\'')
+ break;
+ }
+
+ *l = e-current;
+ *state = *e == 0 ? e : e+1;
} else if (*current == '\"') {
current ++;
- *l = strcspn(current, "\"");
- *state = current+*l;
- if (**state == '\"')
- (*state)++;
+ for (e = current; *e; e++) {
+ if (escaped)
+ escaped = false;
+ else if (*e == '\\')
+ escaped = true;
+ else if (*e == '\"')
+ break;
+ }
+
+ *l = e-current;
+ *state = *e == 0 ? e : e+1;
} else {
- *l = strcspn(current, WHITESPACE);
- *state = current+*l;
+ for (e = current; *e; e++) {
+ if (escaped)
+ escaped = false;
+ else if (*e == '\\')
+ escaped = true;
+ else if (strchr(WHITESPACE, *e))
+ break;
+ }
+ *l = e-current;
+ *state = e;
}
- /* FIXME: Cannot deal with strings that have spaces AND ticks
- * in them */
-
return (char*) current;
}
fclose(f);
+ if (r[0] == 0)
+ return get_process_name(pid, line);
+
*line = r;
return 0;
}
-char *strappend(const char *s, const char *suffix) {
- size_t a, b;
+char *strnappend(const char *s, const char *suffix, size_t b) {
+ size_t a;
char *r;
+ if (!s && !suffix)
+ return strdup("");
+
+ if (!s)
+ return strndup(suffix, b);
+
+ if (!suffix)
+ return strdup(s);
+
assert(s);
assert(suffix);
a = strlen(s);
- b = strlen(suffix);
if (!(r = new(char, a+b+1)))
return NULL;
return r;
}
+char *strappend(const char *s, const char *suffix) {
+ return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
+}
+
int readlink_malloc(const char *p, char **r) {
size_t l = 100;
return r;
}
-char *cunescape(const char *s) {
+char *cunescape_length(const char *s, size_t length) {
char *r, *t;
const char *f;
/* Undoes C style string escaping */
- if (!(r = new(char, strlen(s)+1)))
+ if (!(r = new(char, length+1)))
return r;
- for (f = s, t = r; *f; f++) {
+ for (f = s, t = r; f < s + length; f++) {
if (*f != '\\') {
*(t++) = *f;
*(t++) = '\'';
break;
+ case 's':
+ /* This is an extension of the XDG syntax files */
+ *(t++) = ' ';
+ break;
+
case 'x': {
/* hexadecimal encoding */
int a, b;
return r;
}
+char *cunescape(const char *s) {
+ return cunescape_length(s, strlen(s));
+}
char *xescape(const char *s, const char *bad) {
char *r, *t;
#endif
}
+char *replace_env(const char *format, char **env) {
+ enum {
+ WORD,
+ DOLLAR,
+ VARIABLE
+ } state = WORD;
+
+ const char *e, *word = format;
+ char *r = NULL, *k;
+
+ assert(format);
+
+ for (e = format; *e; e ++) {
+
+ switch (state) {
+
+ case WORD:
+ if (*e == '$')
+ state = DOLLAR;
+ break;
+
+ case DOLLAR:
+ if (*e == '(') {
+ if (!(k = strnappend(r, word, e-word-1)))
+ goto fail;
+
+ free(r);
+ r = k;
+
+ word = e-1;
+ state = VARIABLE;
+
+ } else if (*e == '$') {
+ if (!(k = strnappend(r, word, e-word)))
+ goto fail;
+
+ free(r);
+ r = k;
+
+ word = e+1;
+ state = WORD;
+ } else
+ state = WORD;
+ break;
+
+ case VARIABLE:
+ if (*e == ')') {
+ char *t;
+
+ if ((t = strv_env_get_with_length(env, word+2, e-word-2))) {
+ if (!(k = strappend(r, t)))
+ goto fail;
+
+ free(r);
+ r = k;
+
+ word = e+1;
+ }
+
+ state = WORD;
+ }
+ break;
+ }
+ }
+
+ if (!(k = strnappend(r, word, e-word)))
+ goto fail;
+
+ free(r);
+ return k;
+
+fail:
+ free(r);
+ return NULL;
+}
+
+char **replace_env_argv(char **argv, char **env) {
+ char **r, **i;
+ unsigned k = 0;
+
+ if (!(r = new(char*, strv_length(argv)+1)))
+ return NULL;
+
+ STRV_FOREACH(i, argv) {
+ if (!(r[k++] = replace_env(*i, env))) {
+ strv_free(r);
+ return NULL;
+ }
+ }
+
+ r[k] = NULL;
+ return r;
+}
+
+int columns(void) {
+ static __thread int parsed_columns = 0;
+ const char *e;
+
+ if (parsed_columns > 0)
+ return parsed_columns;
+
+ if ((e = getenv("COLUMNS")))
+ parsed_columns = atoi(e);
+
+ if (parsed_columns <= 0) {
+ struct winsize ws;
+ zero(ws);
+
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0)
+ parsed_columns = ws.ws_col;
+ }
+
+ if (parsed_columns <= 0)
+ parsed_columns = 80;
+
+ return parsed_columns;
+}
+
+int running_in_chroot(void) {
+ struct stat a, b;
+
+ zero(a);
+ zero(b);
+
+ /* Only works as root */
+
+ if (stat("/proc/1/root", &a) < 0)
+ return -errno;
+
+ if (stat("/", &b) < 0)
+ return -errno;
+
+ return
+ a.st_dev != b.st_dev ||
+ a.st_ino != b.st_ino;
+}
+
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",