#include "string_helpers.h" // 包含头文件

#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) // 如果内核版本小于4.7.0

/* stolen from lib/string_helpers.c */

#include <linux/slab.h> // 包含内核内存分配头文件
#include <linux/ctype.h> // 包含字符类型处理头文件

// 定义各种转义标志
#define ESCAPE_SPACE        0x01
#define ESCAPE_SPECIAL      0x02
#define ESCAPE_NULL         0x04
#define ESCAPE_OCTAL        0x08
#define ESCAPE_ANY          (ESCAPE_SPACE | ESCAPE_OCTAL | ESCAPE_SPECIAL | ESCAPE_NULL)
#define ESCAPE_NP           0x10
#define ESCAPE_ANY_NP       (ESCAPE_ANY | ESCAPE_NP)
#define ESCAPE_HEX          0x20

// 处理直接通过字符
static bool escape_passthrough(unsigned char c, char **dst, char *end)
{
	char *out = *dst;

	if (out < end)
		*out = c; // 直接复制字符
	*dst = out + 1;
	return true;
}

// 处理空白字符转义
static bool escape_space(unsigned char c, char **dst, char *end)
{
	char *out = *dst;
	unsigned char to;

	switch (c) {
	case '\n':
		to = 'n'; // 换行符转义为 \n
		break;
	case '\r':
		to = 'r'; // 回车符转义为 \r
		break;
	case '\t':
		to = 't'; // 制表符转义为 \t
		break;
	case '\v':
		to = 'v'; // 垂直制表符转义为 \v
		break;
	case '\f':
		to = 'f'; // 换页符转义为 \f
		break;
	default:
		return false; // 不是空白字符
	}

	if (out < end)
		*out = '\\'; // 添加转义符
	++out;
	if (out < end)
		*out = to; // 添加转义后的字符
	++out;

	*dst = out;
	return true;
}

// 处理特殊字符转义
static bool escape_special(unsigned char c, char **dst, char *end)
{
	char *out = *dst;
	unsigned char to;

	switch (c) {
	case '\\':
		to = '\\'; // 反斜杠转义为 \\
		break;
	case '\a':
		to = 'a'; // 响铃符转义为 \a
		break;
	case '\e':
		to = 'e'; // 转义符转义为 \e
		break;
	default:
		return false; // 不是特殊字符
	}

	if (out < end)
		*out = '\\'; // 添加转义符
	++out;
	if (out < end)
		*out = to; // 添加转义后的字符
	++out;

	*dst = out;
	return true;
}

// 处理空字符转义
static bool escape_null(unsigned char c, char **dst, char *end)
{
	char *out = *dst;

	if (c)
		return false; // 不是空字符

	if (out < end)
		*out = '\\'; // 添加转义符
	++out;
	if (out < end)
		*out = '0'; // 添加转义后的字符
	++out;

	*dst = out;
	return true;
}

// 处理八进制字符转义
static bool escape_octal(unsigned char c, char **dst, char *end)
{
	char *out = *dst;

	if (out < end)
		*out = '\\'; // 添加转义符
	++out;
	if (out < end)
		*out = ((c >> 6) & 0x07) + '0'; // 添加八进制字符的高三位
	++out;
	if (out < end)
		*out = ((c >> 3) & 0x07) + '0'; // 添加八进制字符的中三位
	++out;
	if (out < end)
		*out = ((c >> 0) & 0x07) + '0'; // 添加八进制字符的低三位
	++out;

	*dst = out;
	return true;
}

// 处理十六进制字符转义
static bool escape_hex(unsigned char c, char **dst, char *end)
{
	char *out = *dst;

	if (out < end)
		*out = '\\'; // 添加转义符
	++out;
	if (out < end)
		*out = 'x'; // 添加十六进制标识符
	++out;
	if (out < end)
		*out = hex_asc_hi(c); // 添加十六进制字符的高四位
	++out;
	if (out < end)
		*out = hex_asc_lo(c); // 添加十六进制字符的低四位
	++out;

	*dst = out;
	return true;
}

// 将字符串中的字符进行转义处理
int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz,
			  unsigned int flags, const char *only)
{
	char *p = dst;
	char *end = p + osz;
	bool is_dict = only && *only;

	while (isz--) {
		unsigned char c = *src++;

		/*
		 * 按以下顺序应用规则:
		 *	- 当 @flags 设置了 %ESCAPE_NP 位时，字符是可打印的
		 *	- 提供了 @only 字符串且不包含当前字符
		 *	- 字符不属于由给定 @flags 定义的符号类
		 * 在这些情况下，我们直接将字符传递到输出缓冲区。
		 */
		if ((flags & ESCAPE_NP && isprint(c)) ||
			(is_dict && !strchr(only, c))) {
			/* 不做任何处理 */
		} else {
			if (flags & ESCAPE_SPACE && escape_space(c, &p, end))
				continue;

			if (flags & ESCAPE_SPECIAL && escape_special(c, &p, end))
				continue;

			if (flags & ESCAPE_NULL && escape_null(c, &p, end))
				continue;

			/* ESCAPE_OCTAL 和 ESCAPE_HEX 总是最后处理 */
			if (flags & ESCAPE_OCTAL && escape_octal(c, &p, end))
				continue;

			if (flags & ESCAPE_HEX && escape_hex(c, &p, end))
				continue;
		}

		escape_passthrough(c, &p, end); // 直接通过字符
	}

	return p - dst; // 返回处理后的字符串长度
}

// 复制并转义字符串
char *kstrdup_quotable(const char *src, gfp_t gfp)
{
	size_t slen, dlen;
	char *dst;
	const int flags = ESCAPE_HEX;
	const char esc[] = "\f\n\r\t\v\a\e\\\"";

	if (!src)
		return NULL;
	slen = strlen(src);

	dlen = string_escape_mem(src, slen, NULL, 0, flags, esc); // 计算转义后的长度
	dst = kmalloc(dlen + 1, gfp); // 分配内存
	if (!dst)
		return NULL;

	WARN_ON(string_escape_mem(src, slen, dst, dlen, flags, esc) != dlen); // 转义字符串
	dst[dlen] = '\0'; // 添加字符串结束符

	return dst;
}

#include "util.h"

// 复制并转义命令行字符串
char *kstrdup_quotable_cmdline(struct task_struct *task, gfp_t gfp)
{
	char *buffer, *quoted;
	int i, res;

	buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); // 分配内存
	if (!buffer)
		return NULL;

	res = get_cmdline(task, buffer, PAGE_SIZE - 1); // 获取命令行
	buffer[res] = '\0'; // 添加字符串结束符

	/* 折叠尾随的 NULL，保留 res 指向最后一个非 NULL。 */
	while (--res >= 0 && buffer[res] == '\0')
		;

	/* 替换参数之间的 NULL。 */
	for (i = 0; i <= res; i++)
		if (buffer[i] == '\0')
			buffer[i] = ' ';

	/* 确保结果是可打印的。 */
	quoted = kstrdup_quotable(buffer, gfp); // 转义字符串
	kfree(buffer); // 释放内存
	return quoted;
}

#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
// 替换字符串中的字符
char *strreplace(char *s, char old, char new)
{
	for (; *s; ++s)
		if (*s == old)
			*s = new; // 替换字符
	return s;
}

#endif
#endif