Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

/*-
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * Jordan K. Hubbard
 * 29 August 1998
 *
 * Routine for doing backslash elimination.
 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

#include <stand.h>
#include <string.h>
#include "bootstrap.h"

#define	DIGIT(x) (isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')

/*
 * backslash: Return malloc'd copy of str with all standard "backslash
 * processing" done on it.  Original can be free'd if desired.
 */
char *
backslash(const char *str)
{
	/*
	 * Remove backslashes from the strings. Turn \040 etc. into a single
	 * character (we allow eight bit values). Currently NUL is not
	 * allowed.
	 *
	 * Turn "\n" and "\t" into '\n' and '\t' characters. Etc.
	 *
	 */
	char *new_str;
	int seenbs = 0;
	int i = 0;

	if ((new_str = strdup(str)) == NULL)
		return NULL;

	while (*str) {
		if (seenbs) {
			seenbs = 0;
			switch (*str) {
			case '\\':
				new_str[i++] = '\\';
				str++;
				break;

				/* preserve backslashed quotes, dollar signs */
			case '\'':
			case '"':
			case '$':
				new_str[i++] = '\\';
				new_str[i++] = *str++;
				break;

			case 'b':
				new_str[i++] = '\b';
				str++;
				break;

			case 'f':
				new_str[i++] = '\f';
				str++;
				break;

			case 'r':
				new_str[i++] = '\r';
				str++;
				break;

			case 'n':
				new_str[i++] = '\n';
				str++;
				break;

			case 's':
				new_str[i++] = ' ';
				str++;
				break;

			case 't':
				new_str[i++] = '\t';
				str++;
				break;

			case 'v':
				new_str[i++] = '\13';
				str++;
				break;

			case 'z':
				str++;
				break;

			case '0': case '1': case '2': case '3': case '4':
			case '5': case '6': case '7': case '8': case '9': {
				char val;

				/* Three digit octal constant? */
				if (*str >= '0' && *str <= '3' && 
				    *(str + 1) >= '0' && *(str + 1) <= '7' &&
				    *(str + 2) >= '0' && *(str + 2) <= '7') {

					val = (DIGIT(*str) << 6) + (DIGIT(*(str + 1)) << 3) + 
					    DIGIT(*(str + 2));

					/* Allow null value if user really wants to shoot
					   at feet, but beware! */
					new_str[i++] = val;
					str += 3;
					break;
				}

				/* One or two digit hex constant?
				 * If two are there they will both be taken.
				 * Use \z to split them up if this is not wanted.
				 */
				if (*str == '0' &&
				    (*(str + 1) == 'x' || *(str + 1) == 'X') &&
				    isxdigit(*(str + 2))) {
					val = DIGIT(*(str + 2));
					if (isxdigit(*(str + 3))) {
						val = (val << 4) + DIGIT(*(str + 3));
						str += 4;
					}
					else
						str += 3;
					/* Yep, allow null value here too */
					new_str[i++] = val;
					break;
				}
			}
				break;

			default:
				new_str[i++] = *str++;
				break;
			}
		}
		else {
			if (*str == '\\') {
				seenbs = 1;
				str++;
			}
			else
				new_str[i++] = *str++;
		}
	}

	if (seenbs) {
		/*
		 * The final character was a '\'. Put it in as a single backslash.
		 */
		new_str[i++] = '\\';
	}
	new_str[i] = '\0';
	return new_str;
}