1119483Sobrien/*-
238716Smsmith * Redistribution and use in source and binary forms, with or without
338716Smsmith * modification, are permitted provided that the following conditions
438716Smsmith * are met:
538716Smsmith * 1. Redistributions of source code must retain the above copyright
638716Smsmith *    notice, this list of conditions and the following disclaimer.
738716Smsmith * 2. Redistributions in binary form must reproduce the above copyright
838716Smsmith *    notice, this list of conditions and the following disclaimer in the
938716Smsmith *    documentation and/or other materials provided with the distribution.
1038716Smsmith *
1138716Smsmith * Jordan K. Hubbard
1238716Smsmith * 29 August 1998
1338716Smsmith *
1438716Smsmith * Routine for doing backslash elimination.
1538716Smsmith */
1638716Smsmith
17119483Sobrien#include <sys/cdefs.h>
18119483Sobrien__FBSDID("$FreeBSD$");
19119483Sobrien
2038716Smsmith#include <stand.h>
2138716Smsmith#include <string.h>
2264187Sjhb#include "bootstrap.h"
2338716Smsmith
2438716Smsmith#define DIGIT(x) (isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
2538716Smsmith
2638716Smsmith/*
2738716Smsmith * backslash: Return malloc'd copy of str with all standard "backslash
2838716Smsmith * processing" done on it.  Original can be free'd if desired.
2938716Smsmith */
3038716Smsmithchar *
3138716Smsmithbackslash(char *str)
3238716Smsmith{
3338716Smsmith    /*
3438716Smsmith     * Remove backslashes from the strings. Turn \040 etc. into a single
3538716Smsmith     * character (we allow eight bit values). Currently NUL is not
3638716Smsmith     * allowed.
3738716Smsmith     *
3838716Smsmith     * Turn "\n" and "\t" into '\n' and '\t' characters. Etc.
3938716Smsmith     *
4038716Smsmith     */
4138716Smsmith    char *new_str;
4238716Smsmith    int seenbs = 0;
4338716Smsmith    int i = 0;
4438716Smsmith
4538716Smsmith    if ((new_str = strdup(str)) == NULL)
4638716Smsmith	return NULL;
4738716Smsmith
4838716Smsmith    while (*str) {
4938716Smsmith	if (seenbs) {
5038716Smsmith	    seenbs = 0;
5138716Smsmith	    switch (*str) {
5238716Smsmith	    case '\\':
5338716Smsmith		new_str[i++] = '\\';
5438716Smsmith		str++;
5538716Smsmith		break;
5638716Smsmith
5742465Smsmith	    /* preserve backslashed quotes, dollar signs */
5838765Sjkh	    case '\'':
5938765Sjkh	    case '"':
6042465Smsmith	    case '$':
6138765Sjkh		new_str[i++] = '\\';
6238765Sjkh		new_str[i++] = *str++;
6338765Sjkh		break;
6438765Sjkh
6538716Smsmith	    case 'b':
6638716Smsmith		new_str[i++] = '\b';
6738716Smsmith		str++;
6838716Smsmith		break;
6938716Smsmith
7038716Smsmith	    case 'f':
7138716Smsmith		new_str[i++] = '\f';
7238716Smsmith		str++;
7338716Smsmith		break;
7438716Smsmith
7538716Smsmith	    case 'r':
7638716Smsmith		new_str[i++] = '\r';
7738716Smsmith		str++;
7838716Smsmith		break;
7938716Smsmith
8038716Smsmith	    case 'n':
8138716Smsmith		new_str[i++] = '\n';
8238716Smsmith		str++;
8338716Smsmith		break;
8438716Smsmith
8538716Smsmith	    case 's':
8638716Smsmith		new_str[i++] = ' ';
8738716Smsmith		str++;
8838716Smsmith		break;
8938716Smsmith
9038716Smsmith	    case 't':
9138716Smsmith		new_str[i++] = '\t';
9238716Smsmith		str++;
9338716Smsmith		break;
9438716Smsmith
9538716Smsmith	    case 'v':
9638716Smsmith		new_str[i++] = '\13';
9738716Smsmith		str++;
9838716Smsmith		break;
9938716Smsmith
10038716Smsmith	    case 'z':
10138716Smsmith		str++;
10238716Smsmith		break;
10338716Smsmith
10438716Smsmith	    case '0': case '1': case '2': case '3': case '4':
10538716Smsmith	    case '5': case '6': case '7': case '8': case '9': {
10638716Smsmith		char val;
10738716Smsmith
10838716Smsmith		/* Three digit octal constant? */
10938716Smsmith		if (*str >= '0' && *str <= '3' &&
11038716Smsmith		    *(str + 1) >= '0' && *(str + 1) <= '7' &&
11138716Smsmith		    *(str + 2) >= '0' && *(str + 2) <= '7') {
11238716Smsmith
11338716Smsmith		    val = (DIGIT(*str) << 6) + (DIGIT(*(str + 1)) << 3) +
11438716Smsmith			DIGIT(*(str + 2));
11538716Smsmith
11638716Smsmith		    /* Allow null value if user really wants to shoot
11738716Smsmith                       at feet, but beware! */
11838716Smsmith		    new_str[i++] = val;
11938716Smsmith		    str += 3;
12038716Smsmith		    break;
12138716Smsmith		}
12238716Smsmith
12338716Smsmith		/* One or two digit hex constant?
12438716Smsmith		 * If two are there they will both be taken.
12538716Smsmith		 * Use \z to split them up if this is not wanted.
12638716Smsmith		 */
12738716Smsmith		if (*str == '0' &&
12838716Smsmith		    (*(str + 1) == 'x' || *(str + 1) == 'X') &&
12938716Smsmith		    isxdigit(*(str + 2))) {
13038716Smsmith		    val = DIGIT(*(str + 2));
13138716Smsmith		    if (isxdigit(*(str + 3))) {
13238716Smsmith			val = (val << 4) + DIGIT(*(str + 3));
13338716Smsmith			str += 4;
13438716Smsmith		    }
13538716Smsmith		    else
13638716Smsmith			str += 3;
13738716Smsmith		    /* Yep, allow null value here too */
13838716Smsmith		    new_str[i++] = val;
13938716Smsmith		    break;
14038716Smsmith		}
14138716Smsmith	    }
14238716Smsmith	    break;
14338716Smsmith
14438716Smsmith	    default:
14538716Smsmith		new_str[i++] = *str++;
14638716Smsmith		break;
14738716Smsmith	    }
14838716Smsmith	}
14938716Smsmith        else {
15038716Smsmith            if (*str == '\\') {
15138716Smsmith                seenbs = 1;
15238716Smsmith                str++;
15338716Smsmith            }
15438716Smsmith	    else
15538716Smsmith		new_str[i++] = *str++;
15638716Smsmith        }
15738716Smsmith    }
15838716Smsmith
15938716Smsmith    if (seenbs) {
16038716Smsmith        /*
16138716Smsmith         * The final character was a '\'. Put it in as a single backslash.
16238716Smsmith         */
16338716Smsmith	new_str[i++] = '\\';
16438716Smsmith    }
16538716Smsmith    new_str[i] = '\0';
16638716Smsmith    return new_str;
16738716Smsmith}
168