merge usingfix

ansi.md fix
    ADD: pro/tool/makefile add  example one
    FIX: libs.md  self log
    .vimrc fix auto makefile use Tab
    lib.md string delete
This commit is contained in:
rangersly 2025-05-14 19:39:08 +08:00
parent 63a85cd79f
commit e558ee3788
5 changed files with 342 additions and 27 deletions

View File

@ -5,7 +5,7 @@
## index ## index
- [C](#c) - [C](#c)
- [输入/输出 stdio](#stdio) - [输入/输出 stdio](../universal/io.md)
- [资源管理和系统交互 stdlib](#stdlib) - [资源管理和系统交互 stdlib](#stdlib)
- [字符串处理 string](../universal/cstring.md) - [字符串处理 string](../universal/cstring.md)
- [数学函数 math](#math) - [数学函数 math](#math)
@ -34,12 +34,7 @@
- [string hash](./self/string_hash.c) - [string hash](./self/string_hash.c)
- [thread pool](./self/thread-pool.cpp) - [thread pool](./self/thread-pool.cpp)
- [BIT](./self/bit.h) - [BIT](./self/bit.h)
- [LOG](./self/log/log.h)
---
## **stdio**
大部分内容已经完善,请参阅这里[IO](../universal/io.md)
--- ---

View File

@ -0,0 +1,167 @@
#include "log.h"
#ifdef NDEBUG
#define POINT_STR(str)
#define PERROR(str)
#else
#define POINT_STR(str) for(int i = 0; i < strlen(str); i++) { \
printf("%c --- %d\n", (char)str[i], (int)str[i]);}
#define PERROR(str) printf(str);return
#endif
static int low_show_level = LOG_INFO;
static int log_number = 1;
static FILE *log_out_fp = NULL;
static char log_head_format[LOG_HEAD_MAX_FORMAT] = "[%y-%m-%d-%n]";
static char log_head[LOG_HEAD_MAX_FORMAT << 3];
static int
get_loghead(void);
// 根据 log_head_format 生成日志头 log_head
// 有无法识别的符号返回 -1 成功返回0
static void
int_to_str(int num, char *restrict str);
// 将int 型数据转换成str
// 需要注意 str 要大于 int 的位数,否则将溢出
void
log_setoutfile(const char *restrict filename) {
if((log_out_fp = fopen(filename, "w")) == NULL)
PERROR("LOG: log_setoutfile open file fail !\n");
return;
}
void
log_setlevel(int level) {
if(level < LOG_INFO || level > LOG_FATAL) { // 检测最低日志等级
low_show_level = LOG_INFO;
PERROR("LOG: log_setlevel level is > LOG_FATAL or < LOG_INFO\n");
}
low_show_level = level;
return;
}
void
log_sethead(const char *restrict head) {
if(strlen(head) >= LOG_HEAD_MAX_FORMAT)
PERROR("LOG: log_sethead head so long!\n");
strncpy(log_head_format, head, LOG_HEAD_MAX_FORMAT);
if(get_loghead())
PERROR("LOG: log_sethead have fail char !\n");
return;
}
void
log_print(int level, const char *restrict message) {
if(log_out_fp == NULL) // 未设置输出文件
log_out_fp = stdout;
if(level < LOG_INFO || level > LOG_FATAL) // 日志等级不在范围内
PERROR("LOG: log_print level out of range !\n");
if(level < low_show_level) // 低于最低等级的log不进行打印
return;
if(get_loghead() != 0) // 生成日志头
PERROR("LOG: log_print get_loghead error\n");
if(!fputs(log_head, log_out_fp)) // 打印日志头
PERROR("LOG: log_print fputs_head error\n");
switch(level) { // 打印错误等级
case LOG_INFO:
if(fputs("INFO:", log_out_fp))
break;
case LOG_WARNING:
if(fputs("WARNING:", log_out_fp))
break;
case LOG_ERROR:
if(fputs("ERROR:", log_out_fp))
break;
case LOG_FATAL:
if(fputs("FATAL:", log_out_fp))
break;
default:
PERROR("LOG: log_print out level is untrue !\n");
}
if(!fputs(message, log_out_fp)) // 打印message
PERROR("LOG: log_head fputs fail !\n");
fputc('\n', log_out_fp);
log_number++; // 日志计数++
return;
}
int
get_loghead(void) {
char buf[64];
time_t now_time = time(NULL);
clock_t core_time = clock() / CLOCKS_PER_SEC; // 以 s 为单位的 cpu 时间
struct tm *tm_time = localtime(&now_time);
int temp;
memset(log_head, '\0', sizeof(log_head)); // 重置日志头
for(int i = 0; i < strlen(log_head_format); i++) {
if(log_head_format[i] != '%') { // 非特殊字符则按正常复制
log_head[strlen(log_head)] = log_head_format[i];
continue;
}
i++;
switch(log_head_format[i]) { // 特殊字符转换
case 'y' :
strftime(buf, 64, "%Y", tm_time);
break;
case 'm' :
strftime(buf, 64, "%m", tm_time);
break;
case 'd' :
strftime(buf, 64, "%d", tm_time);
break;
case 'h' :
strftime(buf, 64, "%H", tm_time);
break;
case 'M' :
strftime(buf, 64, "%M", tm_time);
break;
case 's' :
strftime(buf, 64, "%S", tm_time);
break;
case 'n' :
int_to_str(log_number, buf);
break;
case 'c' :
int_to_str(core_time, buf);
break;
default:
return -1;
}
strcat(log_head, buf);
}
return 0;
}
void
int_to_str(int num, char *restrict str) {
if(num < 0)
return; // 日志编号不可能小于 0
// 逐位提取数字(反向存储)
int start = 0;
do {
str[start++] = num % 10 + '0';
num /= 10;
} while (num > 0);
str[start] = '\0';
// 反转数字部分
char buf[16];
strncpy(buf, str, 16);
for(int i = 0; i < strlen(buf); i++)
str[--start] = buf[i];
return;
}
#undef POINT_STR
#undef PERROR

View File

@ -0,0 +1,71 @@
// Copyright(c) 2025 Rangersly All rights reserved.
//
// function :
// Output log
//
// Author:
// Rangersly
//
// Versions:
// - 1.0 base function
#pragma once
#include <stdio.h>
#include <string.h>
#include <time.h>
#define LOG_INFO 0
#define LOG_WARNING 1
#define LOG_ERROR 2
#define LOG_FATAL 3
#define LOG_HEAD_MAX_FORMAT 32
// 如果未定义 NDEBUG 宏,错误发生时将打印错误信息
extern void
log_setoutfile(const char *restrict filename);
// 设置输出文件
// 默认输出为 stdout
extern void
log_setlevel(int level);
// 设置最低输出日志等级,低于最低等级的日志将忽略
extern void
log_sethead(const char *restrict head);
// 设置日志头,最大不可超过15个字符
// 符号表
// %y year
// %m month
// %d day
// %h hour
// %M minute
// %s second
// %n number
// %c core time .3f
extern void
log_print(int level, const char *restrict message);
// 输出日志 ^---等级 ^---输出信息
// EXAMPLE
/*
#include <stdio.h>
#include "log.h"
int main(void) {
log_setoutfile("log.out");
log_setlevel(LOG_ERROR);
log_sethead("#%d-%h-%M-%s-%n-%c#");
log_print(LOG_INFO, " hello");
log_print(LOG_WARNING, " hello");
log_print(LOG_ERROR, " hello");
log_print(LOG_FATAL, " hello");
return 0;
}
*/

View File

@ -5,7 +5,7 @@
--- ---
## **1. 文本样式控制** ## **文本样式控制**
| 转义码 | 效果 | 说明 | | 转义码 | 效果 | 说明 |
|---------------|--------------------|--------------------------| |---------------|--------------------|--------------------------|
| `\033[0m` | 重置所有样式 | 关闭所有颜色和特效 | | `\033[0m` | 重置所有样式 | 关闭所有颜色和特效 |
@ -20,7 +20,7 @@
--- ---
## **2. 前景色(文本颜色)** ## **前景色**
| 转义码 | 颜色 | 转义码(亮色) | | 转义码 | 颜色 | 转义码(亮色) |
|---------------|-----------|----------------| |---------------|-----------|----------------|
| `\033[30m` | 黑色 | `\033[90m` | | `\033[30m` | 黑色 | `\033[90m` |
@ -34,7 +34,7 @@
--- ---
## **3. 背景色** ## **背景色**
| 转义码 | 颜色 | 转义码(亮色) | | 转义码 | 颜色 | 转义码(亮色) |
|---------------|-----------|----------------| |---------------|-----------|----------------|
| `\033[40m` | 黑色 | `\033[100m` | | `\033[40m` | 黑色 | `\033[100m` |
@ -48,23 +48,7 @@
--- ---
## **4. 光标控制** ## **RGB 颜色**
| 转义码 | 作用 |
|-------------------------|--------------------------|
| `\033[<n>A` | 光标上移 `<n>` 行 |
| `\033[<n>B` | 光标下移 `<n>` 行 |
| `\033[<n>C` | 光标右移 `<n>` 列 |
| `\033[<n>D` | 光标左移 `<n>` 列 |
| `\033[<y>;<x>H` | 光标移动到第 `<y>` 行、第 `<x>` 列 |
| `\033[2J` | 清屏(整个屏幕) |
| `\033[K` | 清除从光标到行尾的内容 |
| `\033[2K` | 清除全行的内容 |
| `\033[s` | 保存光标位置 |
| `\033[u` | 恢复光标位置 |
---
## **5. RGB 颜色(部分终端支持)**
如果终端支持 **24-bit 真彩色**,可以使用: 如果终端支持 **24-bit 真彩色**,可以使用:
```c ```c
printf("\033[38;2;<r>;<g>;<b>m"); // 设置前景色RGB printf("\033[38;2;<r>;<g>;<b>m"); // 设置前景色RGB
@ -74,3 +58,70 @@ printf("\033[48;2;<r>;<g>;<b>m"); // 设置背景色RGB
```c ```c
printf("\033[38;2;255;100;0m这是橙红色文字\033[0m\n"); printf("\033[38;2;255;100;0m这是橙红色文字\033[0m\n");
``` ```
---
## **光标控制**
| 转义码 | 作用 |
|-------------------------|--------------------------|
| `\033[<n>A` | 光标上移 `<n>` 行 |
| `\033[<n>B` | 光标下移 `<n>` 行 |
| `\033[<n>C` | 光标右移 `<n>` 列 |
| `\033[<n>D` | 光标左移 `<n>` 列 |
| `\033[<y>;<x>H` | 光标移动到第 `<y>` 行、第 `<x>` 列 |
| `\033[J` | 清屏(光标以后) |
| `\033[1J` | 清屏(光标以前) |
| `\033[2J` | 清屏(整个屏幕) |
| `\033[K` | 清除从光标到行尾的内容 |
| `\033[1K` | 清除从光标到行首的内容 |
| `\033[2K` | 清除全行的内容 |
| `\033[s` | 保存光标位置 |
| `\033[u` | 恢复光标位置 |
## **example**
```
#include <stdio.h>
#if __STDC__ != 1
#error "NO ansi !"
#endif
int main(void) {
printf("-----TEXT STYLE-----\n");
printf("\033[0m\\033[0m\033[0m\n");
printf("\033[1m\\033[1m\033[0m\n");
printf("\033[2m\\033[2m\033[0m\n");
printf("\033[3m\\033[3m\033[0m\n");
printf("\033[4m\\033[4m\033[0m\n");
printf("\033[5m\\033[5m\033[0m\n");
printf("\033[6m\\033[6m\033[0m\n");
printf("\033[7m\\033[7m\033[0m\n");
printf("\033[8m\\033[8m\033[0m\n");
printf("\033[9m\\033[9m\033[0m\n");
printf("\n-----COLOR-----\n");
printf("\033[30m\\033[30m\033[0m - \033[90m\\033[90m\033[0m\n");
printf("\033[31m\\033[31m\033[0m - \033[91m\\033[91m\033[0m\n");
printf("\033[32m\\033[32m\033[0m - \033[92m\\033[92m\033[0m\n");
printf("\033[33m\\033[33m\033[0m - \033[93m\\033[93m\033[0m\n");
printf("\033[34m\\033[34m\033[0m - \033[94m\\033[94m\033[0m\n");
printf("\033[35m\\033[35m\033[0m - \033[95m\\033[95m\033[0m\n");
printf("\033[36m\\033[36m\033[0m - \033[96m\\033[96m\033[0m\n");
printf("\033[37m\\033[37m\033[0m - \033[97m\\033[97m\033[0m\n");
printf("\033[38;2;112;223;234m\\033[38;2;112;223;234m\033[0m\n");
printf("\033[40m\\033[40m\033[0m - \033[100m\\033[100m\033[0m\n");
printf("\033[41m\\033[41m\033[0m - \033[101m\\033[101m\033[0m\n");
printf("\033[42m\\033[42m\033[0m - \033[102m\\033[102m\033[0m\n");
printf("\033[43m\\033[43m\033[0m - \033[103m\\033[103m\033[0m\n");
printf("\033[44m\\033[44m\033[0m - \033[104m\\033[104m\033[0m\n");
printf("\033[45m\\033[45m\033[0m - \033[105m\\033[105m\033[0m\n");
printf("\033[46m\\033[46m\033[0m - \033[106m\\033[106m\033[0m\n");
printf("\033[47m\\033[47m\033[0m - \033[107m\\033[107m\033[0m\n");
printf("\033[48;2;112;223;234m\\033[48;2;112;223;234m\033[0m\n");
printf("\033[0m\n");
return 0;
}
```

View File

@ -22,6 +22,7 @@
- [使用循环](#使用循环) - [使用循环](#使用循环)
- [执行外部命令](#执行外部命令) - [执行外部命令](#执行外部命令)
- [](#) - [](#)
- [EXAMPLE](#example)
--- ---
@ -471,3 +472,33 @@ FILE = ../file.c
REAL_PATH = $(realpath $(FILE)) REAL_PATH = $(realpath $(FILE))
``` ```
---
## **example**
1. 通用模板
```makefile
# 定义编译器和编译选项
CC = gcc
CFLAGS = -c
LDFLAGS =
# 定义目标可执行文件名
TARGET = main
# 获取所有.c文件对应的.o文件
OBJS = $(patsubst %.c, %.o, $(wildcard *.c))
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(LDFLAGS) $^ -o $@
%.o: %.c
$(CC) $(CFLAGS) $< -o $@
clean:
rm -f *.o *.out $(TARGET)
```