/**
 * @file    myFunc.c
 * @brief   基础工具函数实现 — 65 个函数、7 大类
 * @details 从零编写，功能对齐 RTU 原工程但不复制其代码
 */

#include "myFunc.h"
#include "myBase.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <ctype.h>
#include <sys/ipc.h>
#include <sys/msg.h>

/* ==== 1. 校验计算：CRC16/CRC32/累加校验和/文件CRC ==== */

LOCAL const uint16_t _crc16_tab[256] = {
	0x0000,0xc0c1,0xc181,0x0140,0xc301,0x03c0,0x0280,0xc241,0xc601,0x06c0,0x0780,0xc741,0x0500,0xc5c1,0xc481,0x0440,
	0xcc01,0x0cc0,0x0d80,0xcd41,0x0f00,0xcfc1,0xce81,0x0e40,0x0a00,0xcac1,0xcb81,0x0b40,0xc901,0x09c0,0x0880,0xc841,
	0xd801,0x18c0,0x1980,0xd941,0x1b00,0xdbc1,0xda81,0x1a40,0x1e00,0xdec1,0xdf81,0x1f40,0xdd01,0x1dc0,0x1c80,0xdc41,
	0x1400,0xd4c1,0xd581,0x1540,0xd701,0x17c0,0x1680,0xd641,0xd201,0x12c0,0x1380,0xd341,0x1100,0xd1c1,0xd081,0x1040,
	0xf001,0x30c0,0x3180,0xf141,0x3300,0xf3c1,0xf281,0x3240,0x3600,0xf6c1,0xf781,0x3740,0xf501,0x35c0,0x3480,0xf441,
	0x3c00,0xfcc1,0xfd81,0x3d40,0xff01,0x3fc0,0x3e80,0xfe41,0xfa01,0x3ac0,0x3b80,0xfb41,0x3900,0xf9c1,0xf881,0x3840,
	0x2800,0xe8c1,0xe981,0x2940,0xeb01,0x2bc0,0x2a80,0xea41,0xee01,0x2ec0,0x2f80,0xef41,0x2d00,0xedc1,0xec81,0x2c40,
	0xe401,0x24c0,0x2580,0xe541,0x2700,0xe7c1,0xe681,0x2640,0x2200,0xe2c1,0xe381,0x2340,0xe101,0x21c0,0x2080,0xe041,
	0xa001,0x60c0,0x6180,0xa141,0x6300,0xa3c1,0xa281,0x6240,0x6600,0xa6c1,0xa781,0x6740,0xa501,0x65c0,0x6480,0xa441,
	0x6c00,0xacc1,0xad81,0x6d40,0xaf01,0x6fc0,0x6e80,0xae41,0xaa01,0x6ac0,0x6b80,0xab41,0x6900,0xa9c1,0xa881,0x6840,
	0x7800,0xb8c1,0xb981,0x7940,0xbb01,0x7bc0,0x7a80,0xba41,0xbe01,0x7ec0,0x7f80,0xbf41,0x7d00,0xbdc1,0xbc81,0x7c40,
	0xb401,0x74c0,0x7580,0xb541,0x7700,0xb7c1,0xb681,0x7640,0x7200,0xb2c1,0xb381,0x7340,0xb101,0x71c0,0x7080,0xb041,
	0x5000,0x90c1,0x9181,0x5140,0x9301,0x53c0,0x5280,0x9241,0x9601,0x56c0,0x5780,0x9741,0x5500,0x95c1,0x9481,0x5440,
	0x9c01,0x5cc0,0x5d80,0x9d41,0x5f00,0x9fc1,0x9e81,0x5e40,0x5a00,0x9ac1,0x9b81,0x5b40,0x9901,0x59c0,0x5880,0x9841,
	0x8801,0x48c0,0x4980,0x8941,0x4b00,0x8bc1,0x8a81,0x4a40,0x4e00,0x8ec1,0x8f81,0x4f40,0x8d01,0x4dc0,0x4c80,0x8c41,
	0x4400,0x84c1,0x8581,0x4540,0x8701,0x47c0,0x4680,0x8641,0x8201,0x42c0,0x4380,0x8341,0x4100,0x81c1,0x8081,0x4040,
};

LOCAL const uint32_t _crc32_tab[256] = {
	0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,
	0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,
	0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,
	0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,
	0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,
	0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
	0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,
	0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,
	0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,
	0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,
	0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,
	0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
	0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,
	0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,
	0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,
	0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,
	0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,
	0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
	0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,
	0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,
	0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,
	0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,
	0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,
	0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
	0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,
	0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,
	0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,
	0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,
	0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,
	0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
	0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,
	0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,
};

uint8_t func_cal_sum_byte(const uint8_t *d, uint32_t n)
{
	if (!d || !n)
	{
		return 0;
	}

	uint8_t s = 0;
	for (uint32_t i = 0; i < n; i++)
	{
		s += d[i];
	}

	return s;
}

uint16_t func_cal_sum_word(const uint8_t *d, uint32_t n)
{
	if (!d || !n)
	{
		return 0;
	}

	uint16_t s = 0;
	for (uint32_t i = 0; i < n; i++)
	{
		s += d[i];
	}

	return s;
}

uint16_t func_cal_crc16(const uint8_t *d, uint32_t n)
{
	if (!d || !n)
	{
		return 0xFFFF;
	}

	uint16_t crc = 0xFFFF;

	for (uint32_t i = 0; i < n; i++)
	{
		crc = (crc >> 8) ^ _crc16_tab[(uint8_t)(crc ^ d[i])];
	}

	return crc;
}

uint32_t func_cal_crc32(const uint8_t *d, uint32_t n)
{
	if (!d || !n)
	{
		return 0xFFFFFFFF;
	}

	uint32_t crc = 0xFFFFFFFF;

	for (uint32_t i = 0; i < n; i++)
	{
		crc = (crc >> 8) ^ _crc32_tab[(uint8_t)(crc ^ d[i])];
	}

	return crc ^ 0xFFFFFFFF;
}

uint16_t func_cal_file_crc16(const char *path)
{
	if (!path)
	{
		return 0;
	}

	FILE *fp = fopen(path, "rb");
	if (!fp)
	{
		return 0;
	}

	uint16_t crc = 0xFFFF;
	uint8_t buf[4096];
	size_t n;
	while ((n = fread(buf, 1, sizeof(buf), fp)) > 0)
	{
		for (size_t i = 0; i < n; i++)
		{
			crc = (crc >> 8) ^ _crc16_tab[(uint8_t)(crc ^ buf[i])];
		}
	}

	fclose(fp);

	return crc;
}

uint32_t func_cal_file_crc32(const char *path)
{
	if (!path)
	{
		return 0;
	}

	FILE *fp = fopen(path, "rb");
	if (!fp)
	{
		return 0;
	}

	uint32_t crc = 0xFFFFFFFF;
	uint8_t buf[4096];
	size_t n;
	while ((n = fread(buf, 1, sizeof(buf), fp)) > 0)
	{
		for (size_t i = 0; i < n; i++)
		{
			crc = (crc >> 8) ^ _crc32_tab[(uint8_t)(crc ^ buf[i])];
		}
	}

	fclose(fp);

	return crc ^ 0xFFFFFFFF;
}

/* ==== 2. 字符串转换 ==== */

uint8_t func_hex_ch(char c)
{
	if (c >= '0' && c <= '9')
	{
		return (uint8_t)(c - '0');
	}

	if (c >= 'a' && c <= 'f')
	{
		return (uint8_t)(c - 'a' + 10);
	}

	if (c >= 'A' && c <= 'F')
	{
		return (uint8_t)(c - 'A' + 10);
	}

	return 0;
}

uint8_t func_dec_ch(char c)
{
	if (c >= '0' && c <= '9')
	{
		return (uint8_t)(c - '0');
	}

	return 0;
}

/**
 * @brief  Hex string to decimal int
 */
int func_hex2dec(char *s)
{
	if (!s)
	{
		return 0;
	}

	int v = 0;
	while (*s)
	{
		v = (v << 4) | func_hex_ch(*s);
		s++;
	}

	return v;
}

/**
 * @brief  Dec string to int (supports leading minus)
 */
int func_dec2dec(char *s)
{
	if (!s)
	{
		return 0;
	}

	int v = 0;
	int sign = 1;
	if (*s == '-')
	{
		sign = -1;
		s++;
	}

	while (*s >= '0' && *s <= '9')
	{
		v = v * 10 + (*s - '0');
		s++;
	}

	return v * sign;
}

/**
 * @brief  Hex string to byte buffer
 */
int func_hex2buf(const char *s, char *dst, int *len)
{
	if (!s || !dst || !len)
	{
		return -1;
	}

	int n = (int)strlen(s);
	if (n & 1)
	{
		return -1;
	}

	for (int i = 0; i < n / 2; i++)
	{
		dst[i] = (char)((func_hex_ch(s[i * 2]) << 4) | func_hex_ch(s[i * 2 + 1]));
	}

	*len = n / 2;

	return 0;
}

/**
 * @brief  Int to right-aligned zero-padded dec string
 */
char *func_dec2str(char *buf, int sz, int val, int width)
{
	if (!buf || sz < 2)
	{
		return NULL;
	}

	char fmt[16];
	snprintf(fmt, sizeof(fmt), "%%0%dd", width);
	snprintf(buf, sz, fmt, val);

	return buf;
}

/**
 * @brief  Int to hex string
 */
char *func_hex2str(char *buf, int sz, int val, int width)
{
	if (!buf || sz < 2)
	{
		return NULL;
	}

	if (width)
	{
		snprintf(buf, sz, "%0*X", width, val);
	}

	else
	{
		snprintf(buf, sz, "%X", val);
	}

	return buf;
}

/**
 * @brief  Float to string
 */
char *func_float2str(char *buf, int sz, float f, int width)
{
	if (!buf || sz < 2)
	{
		return NULL;
	}

	if (width)
	{
		snprintf(buf, sz, "%*.*f", width, width > 2 ? width - 2 : 1, f);
	}

	else
	{
		snprintf(buf, sz, "%.6g", (double)f);
	}

	return buf;
}

/**
 * @brief  Byte array to upper hex string
 */
char *func_buf2str(char *buf, int sz, const char *src, int n)
{
	if (!buf || sz < 2 || !src)
	{
		return NULL;
	}

	int pos = 0;
	for (int i = 0; i < n && pos + 3 < sz; i++)
	{
		pos += snprintf(buf + pos, sz - pos, "%02X", (unsigned char)src[i]);
	}

	return buf;
}

/**
 * @brief  Split string by whitespace into argc/argv
 */
int func_str2argv(char *s, uint8_t *argc, char *argv[], uint8_t max)
{
	if (!s || !argc || !argv)
	{
		return -1;
	}

	*argc = 0;
	while (*s && *argc < max)
	{
		while (*s && isspace((unsigned char)*s))
		{
			s++;
		}
		if (!*s)
		{
			break;
		}
		argv[(*argc)++] = s;
		while (*s && !isspace((unsigned char)*s))
		{
			s++;
		}
		if (*s)
		{
			*s = '\0';
			s++;
		}
	}

	return 0;
}

/* ==== 3. 时间处理 ==== */

/**
 * @brief  stru_time_sys to formatted time string
 */
char *func_time_sys2str(char *buf, int sz, stru_time_sys *t)
{
	if (!buf || sz < 20 || !t)
	{
		return NULL;
	}

	snprintf(buf, sz, "%04u-%02u-%02u %02u:%02u:%02u.%03u",
	         t->year, t->month, t->day,
	         t->hour, t->min, t->ms / 1000,
	         t->ms % 1000);

	return buf;
}

/**
 * @brief  String to stru_time_sys
 */
int func_str2time_sys(const char *s, stru_time_sys *t)
{
	if (!s || !t)
	{
		return -1;
	}

	memset(t, 0, sizeof(*t));
	uint32_t y, mo, d, h, mi, sec, ms = 0;
	if (sscanf(s, "%u-%u-%u %u:%u:%u.%u",
	           &y, &mo, &d, &h, &mi, &sec, &ms) < 6)
	{
		return -1;
	}

	t->year  = y - 1900;
	t->month = mo;
	t->day   = d;
	t->hour  = h;
	t->min   = mi;
	t->ms    = (uint16_t)(sec * 1000 + ms);

	return 0;
}

/**
 * @brief  Get current time (type: 1=sys, 2=cal)
 */
int func_get_time(void *t, int type)
{
	if (!t)
	{
		return -1;
	}

	struct timeval tv;
	gettimeofday(&tv, NULL);
	if (type == 1)
	{
		stru_time_sys *ts = (stru_time_sys *)t;
		struct tm *g = localtime(&tv.tv_sec);
		if (!g)
		{
			return -1;
		}
		ts->year  = (uint32_t)(g->tm_year + 1900);
		ts->month = (uint32_t)(g->tm_mon + 1);
		ts->day   = (uint32_t)g->tm_mday;
		ts->hour  = (uint32_t)g->tm_hour;
		ts->min   = (uint32_t)g->tm_min;
		ts->ms    = (uint16_t)(g->tm_sec * 1000 + tv.tv_usec / 1000);
	}

	else
	{
		stru_time_cal *tc = (stru_time_cal *)t;
		tc->sec  = tv.tv_sec;
		tc->usec = tv.tv_usec;
	}

	return 0;
}

/**
 * @brief  Set system time (requires root)
 */
int func_set_time(void *t, int type)
{
	if (!t)
	{
		return -1;
	}

	struct timeval tv;
	if (type == 1)
	{
		stru_time_sys *ts = (stru_time_sys *)t;
		struct tm g = {0};
		g.tm_year = (int)ts->year - 1900;
		g.tm_mon  = (int)ts->month - 1;
		g.tm_mday = (int)ts->day;
		g.tm_hour = (int)ts->hour;
		g.tm_min  = (int)ts->min;
		g.tm_sec  = (int)(ts->ms / 1000);
		tv.tv_sec  = mktime(&g);
		tv.tv_usec = (ts->ms % 1000) * 1000;
	}

	else
	{
		stru_time_cal *tc = (stru_time_cal *)t;
		tv.tv_sec  = tc->sec;
		tv.tv_usec = tc->usec;
	}

	return settimeofday(&tv, NULL);
}

/**
 * @brief  stru_time_sys to stru_time_cal
 */
void func_time_sys2cal(stru_time_sys *src, stru_time_cal *dst)
{
	if (!src || !dst)
	{
		return;
	}

	struct tm g = {0};
	g.tm_year = (int)src->year - 1900;
	g.tm_mon  = (int)src->month - 1;
	g.tm_mday = (int)src->day;
	g.tm_hour = (int)src->hour;
	g.tm_min  = (int)src->min;
	g.tm_sec  = (int)(src->ms / 1000);
	dst->sec  = mktime(&g);
	dst->usec = (src->ms % 1000) * 1000;
}

/**
 * @brief  stru_time_cal to stru_time_sys
 */
void func_time_cal2sys(stru_time_cal *src, stru_time_sys *dst)
{
	if (!src || !dst)
	{
		return;
	}

	struct tm *g = localtime(&src->sec);
	if (!g)
	{
		return;
	}

	dst->year  = g->tm_year + 1900;
	dst->month = g->tm_mon + 1;
	dst->day   = g->tm_mday;
	dst->hour  = g->tm_hour;
	dst->min   = g->tm_min;
	dst->ms    = (uint16_t)(g->tm_sec * 1000 + src->usec / 1000);
}

/* ==== 4. 文件目录操作 ==== */

/**
 * @brief  Check if directory exists
 */
int func_dir_exist(const char *p)
{
	if (!p)
	{
		return 0;
	}

	struct stat st;
	if (stat(p, &st) == 0 && S_ISDIR(st.st_mode))
	{
		return 1;
	}

	return 0;
}

LOCAL int _mkdir(const char *p)
{
	if (!p)
	{
		return -1;
	}

	char tmp[256];
	strncpy(tmp, p, sizeof(tmp) - 1);
	tmp[sizeof(tmp) - 1] = '\0';
	for (char *x = tmp + 1; *x; x++)
	{
		if (*x == '/')
		{
			*x = '\0';
			mkdir(tmp, 0755);
			*x = '/';
		}
	}

	return mkdir(tmp, 0755);
}

/**
 * @brief  Recursively create directories
 */
int func_make_dirs(const char *p)
{
	return _mkdir(p);
}

LOCAL int _rmdir(const char *p)
{
	if (!p)
	{
		return -1;
	}

	DIR *d = opendir(p);
	if (!d)
	{
		return remove(p);
	}

	struct dirent *e;
	while ((e = readdir(d)))
	{
		if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0)
		{
			continue;
		}
		char full[512];
		snprintf(full, sizeof(full), "%s/%s", p, e->d_name);
		_rmdir(full);
	}

	closedir(d);

	return rmdir(p);
}

/**
 * @brief  Recursively delete directory tree
 */
int func_del_dirs(const char *p)
{
	return _rmdir(p);
}

/**
 * @brief  Recursively delete directory tree
 */
/**
 * @brief  Delete directory via rm -rf shell command
 */
int func_del_dirs_cmd(const char *p)
{
	if (!p)
	{
		return -1;
	}

	char cmd[512];
	snprintf(cmd, sizeof(cmd), "rm -rf '%s'", p);

	return system(cmd);
}

/**
 * @brief  Check if regular file exists
 */
int func_file_exist(const char *p)
{
	if (!p)
	{
		return 0;
	}

	struct stat st;
	if (stat(p, &st) == 0 && S_ISREG(st.st_mode))
	{
		return 1;
	}

	return 0;
}

uint32_t func_file_size(const char *p)
{
	if (!p)
	{
		return 0;
	}

	struct stat st;
	if (stat(p, &st) == 0)
	{
		return (uint32_t)st.st_size;
	}

	return 0;
}

/**
 * @brief  Read file into pre-allocated buffer
 */
int func_read_file(const char *p, char *buf, uint32_t cap, uint32_t *out)
{
	if (!p || !buf || !cap || !out)
	{
		return -1;
	}

	FILE *fp = fopen(p, "rb");
	if (!fp)
	{
		return -1;
	}

	*out = (uint32_t)fread(buf, 1, cap, fp);
	fclose(fp);

	return 0;
}

uint8_t *func_read_file_alloc(const char *p, uint32_t *out)
{
	if (!p || !out)
	{
		return NULL;
	}

	*out = 0;
	struct stat st;
	if (stat(p, &st) != 0)
	{
		return NULL;
	}

	uint8_t *buf = (uint8_t *)malloc((size_t)st.st_size + 1);
	if (!buf)
	{
		return NULL;
	}

	FILE *fp = fopen(p, "rb");
	if (!fp)
	{
		free(buf);

		return NULL;
	}

	*out = (uint32_t)fread(buf, 1, (size_t)st.st_size, fp);
	buf[*out] = '\0';
	fclose(fp);

	return buf;
}

/**
 * @brief  Write buffer to file (overwrite mode)
 */
int func_write_file(const char *p, const char *buf, uint32_t n)
{
	if (!p || !buf)
	{
		return -1;
	}

	FILE *fp = fopen(p, "wb");
	if (!fp)
	{
		return -1;
	}

	fwrite(buf, 1, n, fp);
	fclose(fp);

	return 0;
}

/**
 * @brief  Read file into pre-allocated buffer
 */
/**
 * @brief  Read structured file info header (256B)
 */
int func_read_file_info(const char *p, stru_file_info *info, int check)
{
	if (!p || !info)
	{
		return -1;
	}

	FILE *fp = fopen(p, "rb");
	if (!fp)
	{
		return -1;
	}

	if (fread(info, 1, sizeof(*info), fp) != sizeof(*info))
	{
		fclose(fp);

		return -1;
	}

	fclose(fp);
	if (check)
	{
		if (info->flag != 0xA55AA55AA55AA55AULL)
		{
			return -1;
		}
		uint16_t saved = info->crc;
		info->crc = 0;
		uint16_t calced = func_cal_crc16((uint8_t *)info, sizeof(*info));
		info->crc = saved;
		if (saved != calced)
		{
			return -1;
		}
	}

	return 0;
}

/* ==== 5. 进程管理（基于 Linux /proc） ==== */

/**
 * @brief  Get current process name via /proc/self/comm
 */
int func_proc_self_name(char *buf, uint32_t sz)
{
	if (!buf || sz == 0)
	{
		return -1;
	}

	FILE *fp = fopen("/proc/self/comm", "r");
	if (!fp)
	{
		return -1;
	}

	if (!fgets(buf, (int)sz, fp))
	{
		fclose(fp);

		return -1;
	}

	size_t len = strlen(buf);
	if (len > 0 && buf[len - 1] == '\n')
	{
		buf[len - 1] = '\0';
	}

	fclose(fp);

	return 0;
}

/**
 * @brief  Get process name by PID
 */
int func_proc_name_by_pid(int pid, char *buf, uint32_t sz)
{
	if (!buf || sz == 0)
	{
		return -1;
	}

	char path[64];
	snprintf(path, sizeof(path), "/proc/%d/comm", pid);
	FILE *fp = fopen(path, "r");
	if (!fp)
	{
		return -1;
	}

	if (!fgets(buf, (int)sz, fp))
	{
		fclose(fp);

		return -1;
	}

	size_t len = strlen(buf);
	if (len > 0 && buf[len - 1] == '\n')
	{
		buf[len - 1] = '\0';
	}

	fclose(fp);

	return 0;
}

/**
 * @brief  Get current process PID
 */
int func_proc_pid(void)
{
	return (int)getpid();
}

/**
 * @brief  Get current process PID
 */
/**
 * @brief  Find PID by process name (scan /proc)
 */
int func_proc_pid_by_name(const char *name)
{
	if (!name)
	{
		return -1;
	}

	DIR *d = opendir("/proc");
	if (!d)
	{
		return -1;
	}

	struct dirent *e;
	while ((e = readdir(d)))
	{
		if (!isdigit((unsigned char)e->d_name[0]))
		{
			continue;
		}
		char comm[64];
		char path[384];
		snprintf(path, sizeof(path), "/proc/%s/comm", e->d_name);
		FILE *fp = fopen(path, "r");
		if (!fp)
		{
			continue;
		}
		if (fgets(comm, sizeof(comm), fp))
		{
			size_t len = strlen(comm);
			if (len > 0 && comm[len - 1] == '\n')
			{
				comm[len - 1] = '\0';
			}
			if (strcmp(comm, name) == 0)
			{
				fclose(fp);
				closedir(d);

				return atoi(e->d_name);
			}
		}
		fclose(fp);
	}

	closedir(d);

	return -1;
}

/**
 * @brief  Check if process exists by PID
 */
int func_proc_exist_by_pid(int pid)
{
	char path[64];
	snprintf(path, sizeof(path), "/proc/%d", pid);
	struct stat st;
	if (stat(path, &st) == 0)
	{
		return 1;
	}

	return 0;
}

/**
 * @brief  Check if process exists by name
 */
int func_proc_exist_by_name(const char *name)
{
	if (func_proc_pid_by_name(name) > 0)
	{
		return 1;
	}

	return 0;
}

/**
 * @brief  Get executable path by PID
 */
int func_proc_path_by_pid(int pid, char *buf, uint32_t sz)
{
	if (!buf || sz == 0)
	{
		return -1;
	}

	char link[64];
	snprintf(link, sizeof(link), "/proc/%d/exe", pid);
	ssize_t n = readlink(link, buf, sz - 1);
	if (n < 0)
	{
		return -1;
	}

	buf[n] = '\0';

	return 0;
}

/**
 * @brief  Get current process executable path
 */
int func_proc_self_path(char *buf, uint32_t sz)
{
	return func_proc_path_by_pid(func_proc_pid(), buf, sz);
}

/**
 * @brief  Get current process directory
 */
int func_proc_self_dir(char *buf, uint32_t sz)
{
	if (func_proc_self_path(buf, sz) != 0)
	{
		return -1;
	}

	char *slash = strrchr(buf, '/');
	if (slash)
	{
		*slash = '\0';
	}

	return 0;
}

/* ==== 6. 环境变量路径 ==== */

/**
 * @brief  Get WORK_PATH env var
 */
int func_get_work_path(char *b, uint32_t s)
{
	const char *v = getenv("WORK_PATH");
	if (!v)
	{
		return -1;
	}

	snprintf(b, s, "%s", v);

	return 0;
}

/**
 * @brief  Get SYS_CFG_PATH env var
 */
int func_get_syscfg_path(char *b, uint32_t s)
{
	const char *v = getenv("SYS_CFG_PATH");
	if (!v)
	{
		return -1;
	}

	snprintf(b, s, "%s", v);

	return 0;
}

/**
 * @brief  Get APP_ROOT_PATH env var
 */
int func_get_app_root(char *b, uint32_t s)
{
	const char *v = getenv("APP_ROOT_PATH");
	if (!v)
	{
		return -1;
	}

	snprintf(b, s, "%s", v);

	return 0;
}

/**
 * @brief  Get HIS_ROOT_PATH env var
 */
int func_get_his_root(char *b, uint32_t s)
{
	const char *v = getenv("HIS_ROOT_PATH");
	if (!v)
	{
		return -1;
	}

	snprintf(b, s, "%s", v);

	return 0;
}

/**
 * @brief  Get LOG_ROOT_PATH env var
 */
int func_get_log_root(char *b, uint32_t s)
{
	const char *v = getenv("LOG_ROOT_PATH");
	if (!v)
	{
		return -1;
	}

	snprintf(b, s, "%s", v);

	return 0;
}

/**
 * @brief  Get DBC_ROOT_PATH env var
 */
int func_get_dbc_root(char *b, uint32_t s)
{
	const char *v = getenv("DBC_ROOT_PATH");
	if (!v)
	{
		return -1;
	}

	snprintf(b, s, "%s", v);

	return 0;
}

/**
 * @brief  Get SHELL_PATH env var
 */
int func_get_shell_path(char *b, uint32_t s)
{
	const char *v = getenv("SHELL_PATH");
	if (!v)
	{
		return -1;
	}

	snprintf(b, s, "%s", v);

	return 0;
}

/**
 * @brief  Get UPDATE_PATH env var
 */
int func_get_update_path(char *b, uint32_t s)
{
	const char *v = getenv("UPDATE_PATH");
	if (!v)
	{
		return -1;
	}

	snprintf(b, s, "%s", v);

	return 0;
}

LOCAL int _make_path(const char *key, const char *app, const char *pfx,
                     char *buf, uint32_t sz)
{
	if (!buf || sz == 0 || !app)
	{
		return -1;
	}

	char root[256];
	const char *v = getenv(key);
	if (!v)
	{
		v = "/tmp";
	}

	snprintf(root, sizeof(root), "%s", v);
	if (pfx && pfx[0])
	{
		snprintf(buf, sz, "%s/%s/%s", root, app, pfx);
	}

	else
	{
		snprintf(buf, sz, "%s/%s", root, app);
	}

	return 0;
}

/**
 * @brief  Build app path: root/app_name
 */
int func_get_app_path(const char *a, char *b, uint32_t s)
{
	return _make_path("APP_ROOT_PATH", a, NULL, b, s);
}

/**
 * @brief  Build app config path: root/app_name/ext
 */
int func_get_app_cfg(const char *a, const char *e, char *b, uint32_t s)
{
	return _make_path("APP_ROOT_PATH", a, e, b, s);
}

/**
 * @brief  Build app history path
 */
int func_get_app_his(const char *a, char *b, uint32_t s)
{
	return _make_path("HIS_ROOT_PATH", a, NULL, b, s);
}

/**
 * @brief  Build app log path
 */
int func_get_app_log(const char *a, char *b, uint32_t s)
{
	return _make_path("LOG_ROOT_PATH", a, NULL, b, s);
}

/* ==== 7. IPC 消息队列（System V） ==== */

/**
 * @brief  Create IPC message queue by process name
 */
int func_ipc_create_by_name(char *name, int *qid)
{
	if (!name || !qid)
	{
		return -1;
	}

	int pid = func_proc_pid_by_name(name);
	if (pid < 0)
	{
		return -1;
	}

	return func_ipc_create_by_pid(pid, qid);
}

/**
 * @brief  Create IPC message queue by PID
 */
int func_ipc_create_by_pid(int pid, int *qid)
{
	if (!qid || pid < 1)
	{
		return -1;
	}

	key_t k = ftok("/tmp", pid & 0xFF);
	*qid = msgget(k, IPC_CREAT | 0666);
	if (*qid >= 0)
	{
		return 0;
	}

	return -1;
}

/**
 * @brief  Get/create IPC message queue by name
 */
int func_ipc_get_by_name(const char *name, int *qid)
{
	return func_ipc_create_by_name((char *)name, qid);
}

/**
 * @brief  Get/create IPC message queue by PID
 */
int func_ipc_get_by_pid(int pid, int *qid)
{
	return func_ipc_create_by_pid(pid, qid);
}

/**
 * @brief  Send raw bytes to message queue
 */
int func_ipc_send_buf(int qid, uint8_t *tx, uint32_t n)
{
	if (!tx || n == 0)
	{
		return -1;
	}

	return msgsnd(qid, tx, n, 0);
}

/**
 * @brief  Receive raw bytes from message queue
 */
int func_ipc_recv_buf(int qid, uint8_t *rx, uint32_t n)
{
	if (!rx || n == 0)
	{
		return -1;
	}

	return (int)msgrcv(qid, rx, n, 0, 0);
}

/**
 * @brief  Send struct message to message queue
 */
int func_ipc_send_msg(int qid, stru_ipc_msg *m)
{
	if (!m)
	{
		return -1;
	}

	return msgsnd(qid, &m->t, sizeof(m->t) - sizeof(m->t.len) + (size_t)m->t.len, 0);
}

/**
 * @brief  Receive struct message from message queue
 */
int func_ipc_recv_msg(int qid, stru_ipc_msg *m)
{
	if (!m)
	{
		return -1;
	}

	ssize_t n = msgrcv(qid, &m->t, sizeof(m->t), m->id, 0);
	if (n < 0)
	{
		return -1;
	}

	m->id = (long)n;

	return 0;
}

/**
 * @brief  Delete message queue
 */
int func_ipc_delete(int qid)
{
	return msgctl(qid, IPC_RMID, NULL);
}
