aboutsummaryrefslogblamecommitdiffstats
path: root/common/stringop.c
blob: b42604c17aff82a39ab333b2c1866f13418b3028 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                               

                    
                  
                   
                   
                    
                 

                     
 
                                               
 




                                                   



                                                                   

 

























                                                                 













                                                                












                                          

                                                           
                                 
                    





                                             
         
                   


                   


                                                 
                                                     


                               
                                                                  

                                









                                                                            



                                                                                                       

                                                   

                                                                                           















                                                                                            
                         

                                         
                 
         

                           


                                       
                            




                                 





                                         


                                                     
                                             

                                                     
                                                 


                                                     
                                                 
                                      

                                                     
                                                 


                                                     
                                                 


                                                     
                                                 


                                                     
                                                 


                                                     
                                                 
                                      
                                  
                                                 
                                      

                                                     
                                                 


                                                     
                                                 


                                                    
                                                 
                                      


                                                            
                                                                                       

                                                                                               

                                                                               
                                                                           
                                                 
                                                                   
                                         
                                                         

                                                          


                         










                                            
 
 
                                        


                                                                













                                           
 


































                                                                                       
#define _POSIX_C_SOURCE 200809L
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "list.h"
#include "log.h"
#include "stringop.h"

static const char whitespace[] = " \f\n\r\t\v";

void strip_whitespace(char *str) {
	size_t len = strlen(str);
	size_t start = strspn(str, whitespace);
	memmove(str, &str[start], len + 1 - start);

	if (*str) {
		for (len -= start + 1; isspace(str[len]); --len) {}
		str[len + 1] = '\0';
	}
}

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';
}

char *lenient_strcat(char *dest, const char *src) {
	if (dest && src) {
		return strcat(dest, src);
	}
	return dest;
}

char *lenient_strncat(char *dest, const char *src, size_t len) {
	if (dest && src) {
		return strncat(dest, src, len);
	}
	return dest;
}

// strcmp that also handles null pointers.
int lenient_strcmp(char *a, char *b) {
	if (a == b) {
		return 0;
	} else if (!a) {
		return -1;
	} else if (!b) {
		return 1;
	} else {
		return strcmp(a, b);
	}
}

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

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 in_brackets = false; // brackets are used for critera
	bool escaped = false;
	const char *end = start;
	if (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 == '[' && !in_string && !in_char && !in_brackets && !escaped) {
				in_brackets = true;
			} else if (*end == ']' && !in_string && !in_char && in_brackets && !escaped) {
				in_brackets = false;
			} else if (*end == '\\') {
				escaped = !escaped;
			} else if (*end == '\0' || (!in_string && !in_char && !in_brackets
						&& !escaped && strchr(whitespace, *end))) {
				goto add_token;
			}
			if (*end != '\\') {
				escaped = false;
			}
			++end;
			continue;
			add_token:
			if (end - start > 0) {
				char *token = malloc(end - start + 1);
				strncpy(token, start, end - start + 1);
				token[end - start] = '\0';
				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);
}

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(char **argv, int argc) {
	if (!sway_assert(argc > 0, "argc should be positive")) {
		return NULL;
	}
	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;
}

char *argsep(char **stringp, const char *delim) {
	char *start = *stringp;
	char *end = start;
	bool in_string = false;
	bool in_char = false;
	bool escaped = false;
	while (1) {
		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') {
			*stringp = NULL;
			goto found;
		} else if (!in_string && !in_char && !escaped && strchr(delim, *end)) {
			if (end - start) {
				*(end++) = 0;
				*stringp = end + strspn(end, delim);;
				if (!**stringp) *stringp = NULL;
				goto found;
			} else {
				++start;
				end = start;
			}
		}
		if (*end != '\\') {
			escaped = false;
		}
		++end;
	}
	found:
	return start;
}