整体的实现思路就是传入一个字符串以及需要的参数(可变参数),通过对%的处理来获取我们所需要的类型,从而实现格式化字符串的操作( ("Hello %s world", "nginx") -> "Hello nginx world"),主要是细节的处理,比如有无符号类型,以及16进制转换和保留小数等问题,需要仔细思考。
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h> // 可变参
#include <stdint.h>
#include <string.h>
#include "ngx_global.h"
#include "ngx_macro.h"
#include "ngx_func.h"
static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero, uintptr_t hexadecimal, uintptr_t width);
// 用于调用主要的ngx_vslprintf()函数
u_char *ngx_slprintf(u_char *buf, u_char *last, const char *fmt, ...){
va_list args; // 定义可变参的变量
u_char *p;
va_start(args, fmt); // 使args指向起始的参数
p = ngx_vslprintf(buf, last, fmt, args);
va_end(args); // 释放args
return p;
}
// 自定义的格式化输出
// buf:存储数据 last:最大的内存地址 fmt:可变参数开头(format)
u_char *ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args){
u_char zero; // 占位符号 0或者空格
uintptr_t width, sign, hex, frac_width, scale, n; // 需要用到的临时变量
int64_t i64; // 保存%d
uint64_t ui64; // 保存%ud
u_char *p; // 保存%s
double f; // 保存%f
uint64_t frac; // 用于%.2f参数 保存保留的小数部分 %.2f 12.457 此时frac = 46
// 处理fmt字符串
while(*fmt && buf < last){
if(*fmt == '%'){ // 表示该位置需要被替换
// -----------------------初始化变量----------------------
zero = (u_char)((*++fmt == '0') ? '0' : ' '); // 判断%后面是否用0占位 如果