/*-1* Redistribution and use in source and binary forms, with or without2* modification, are permitted provided that the following conditions3* are met:4* 1. Redistributions of source code must retain the above copyright5* notice, this list of conditions and the following disclaimer.6* 2. Redistributions in binary form must reproduce the above copyright7* notice, this list of conditions and the following disclaimer in the8* documentation and/or other materials provided with the distribution.9*10* Jordan K. Hubbard11* 29 August 199812*13* Routine for doing backslash elimination.14*/1516#include <stand.h>17#include <string.h>18#include "bootstrap.h"1920#define DIGIT(x) (isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')2122/*23* backslash: Return malloc'd copy of str with all standard "backslash24* processing" done on it. Original can be free'd if desired.25*/26char *27backslash(const char *str)28{29/*30* Remove backslashes from the strings. Turn \040 etc. into a single31* character (we allow eight bit values). Currently NUL is not32* allowed.33*34* Turn "\n" and "\t" into '\n' and '\t' characters. Etc.35*36*/37char *new_str;38int seenbs = 0;39int i = 0;4041if ((new_str = strdup(str)) == NULL)42return NULL;4344while (*str) {45if (seenbs) {46seenbs = 0;47switch (*str) {48case '\\':49new_str[i++] = '\\';50str++;51break;5253/* preserve backslashed quotes, dollar signs */54case '\'':55case '"':56case '$':57new_str[i++] = '\\';58new_str[i++] = *str++;59break;6061case 'b':62new_str[i++] = '\b';63str++;64break;6566case 'f':67new_str[i++] = '\f';68str++;69break;7071case 'r':72new_str[i++] = '\r';73str++;74break;7576case 'n':77new_str[i++] = '\n';78str++;79break;8081case 's':82new_str[i++] = ' ';83str++;84break;8586case 't':87new_str[i++] = '\t';88str++;89break;9091case 'v':92new_str[i++] = '\13';93str++;94break;9596case 'z':97str++;98break;99100case '0': case '1': case '2': case '3': case '4':101case '5': case '6': case '7': case '8': case '9': {102char val;103104/* Three digit octal constant? */105if (*str >= '0' && *str <= '3' &&106*(str + 1) >= '0' && *(str + 1) <= '7' &&107*(str + 2) >= '0' && *(str + 2) <= '7') {108109val = (DIGIT(*str) << 6) + (DIGIT(*(str + 1)) << 3) +110DIGIT(*(str + 2));111112/* Allow null value if user really wants to shoot113at feet, but beware! */114new_str[i++] = val;115str += 3;116break;117}118119/* One or two digit hex constant?120* If two are there they will both be taken.121* Use \z to split them up if this is not wanted.122*/123if (*str == '0' &&124(*(str + 1) == 'x' || *(str + 1) == 'X') &&125isxdigit(*(str + 2))) {126val = DIGIT(*(str + 2));127if (isxdigit(*(str + 3))) {128val = (val << 4) + DIGIT(*(str + 3));129str += 4;130}131else132str += 3;133/* Yep, allow null value here too */134new_str[i++] = val;135break;136}137}138break;139140default:141new_str[i++] = *str++;142break;143}144}145else {146if (*str == '\\') {147seenbs = 1;148str++;149}150else151new_str[i++] = *str++;152}153}154155if (seenbs) {156/*157* The final character was a '\'. Put it in as a single backslash.158*/159new_str[i++] = '\\';160}161new_str[i] = '\0';162return new_str;163}164165166