1 Star 0 Fork 0

yanghuangsheng / sdebug

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
usefulstuff.c 20.06 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
/*
+----------------------------------------------------------------------+
| Xdebug |
+----------------------------------------------------------------------+
| Copyright (c) 2002-2018 Derick Rethans |
+----------------------------------------------------------------------+
| This source file is subject to version 1.01 of the Xdebug license, |
| that is bundled with this package in the file LICENSE, and is |
| available at through the world-wide-web at |
| https://xdebug.org/license.php |
| If you did not receive a copy of the Xdebug license and are unable |
| to obtain it through the world-wide-web, please send a note to |
| derick@xdebug.org so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Derick Rethans <derick@xdebug.org> |
+----------------------------------------------------------------------+
*/
#include <stdlib.h>
#include <string.h>
#ifndef WIN32
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/file.h>
#else
#define PATH_MAX MAX_PATH
#include <winsock2.h>
#include <io.h>
#include "win32/time.h"
#include <process.h>
#endif
#include "php_xdebug.h"
#include "xdebug_mm.h"
#include "xdebug_str.h"
#include "usefulstuff.h"
#include "ext/standard/php_lcg.h"
#include "ext/standard/flock_compat.h"
#include "main/php_ini.h"
#ifndef NAME_MAX
# ifdef _AIX
# include <unistd.h>
# define NAME_MAX pathconf("/dev/null",_PC_NAME_MAX)
# else
# define NAME_MAX (MAXNAMELEN-1)
# endif
#endif
ZEND_EXTERN_MODULE_GLOBALS(xdebug)
#define READ_BUFFER_SIZE 128
char* xdebug_fd_read_line_delim(int socketfd, fd_buf *context, int type, unsigned char delim, int *length)
{
int size = 0, newl = 0, nbufsize = 0;
char *tmp;
char *tmp_buf = NULL;
char *ptr;
char buffer[READ_BUFFER_SIZE + 1];
if (!context->buffer) {
context->buffer = calloc(1,1);
context->buffer_size = 0;
}
while (context->buffer_size < 1 || context->buffer[context->buffer_size - 1] != delim) {
ptr = context->buffer + context->buffer_size;
if (type == FD_RL_FILE) {
newl = read(socketfd, buffer, READ_BUFFER_SIZE);
} else {
newl = recv(socketfd, buffer, READ_BUFFER_SIZE, 0);
}
if (newl > 0) {
context->buffer = realloc(context->buffer, context->buffer_size + newl + 1);
memcpy(context->buffer + context->buffer_size, buffer, newl);
context->buffer_size += newl;
context->buffer[context->buffer_size] = '\0';
} else if (newl == -1 && errno == EINTR) {
continue;
} else {
free(context->buffer);
context->buffer = NULL;
context->buffer_size = 0;
return NULL;
}
}
ptr = memchr(context->buffer, delim, context->buffer_size);
size = ptr - context->buffer;
/* Copy that line into tmp */
tmp = malloc(size + 1);
tmp[size] = '\0';
memcpy(tmp, context->buffer, size);
/* Rewrite existing buffer */
if ((nbufsize = context->buffer_size - size - 1) > 0) {
tmp_buf = malloc(nbufsize + 1);
memcpy(tmp_buf, ptr + 1, nbufsize);
tmp_buf[nbufsize] = 0;
}
free(context->buffer);
context->buffer = tmp_buf;
context->buffer_size = context->buffer_size - (size + 1);
/* Return normal line */
if (length) {
*length = size;
}
return tmp;
}
xdebug_str* xdebug_join(const char *delim, xdebug_arg *args, int begin, int end)
{
int i;
xdebug_str *ret = xdebug_str_new();
if (begin < 0) {
begin = 0;
}
if (end > args->c - 1) {
end = args->c - 1;
}
for (i = begin; i < end; i++) {
xdebug_str_add(ret, args->args[i], 0);
xdebug_str_add(ret, delim, 0);
}
xdebug_str_add(ret, args->args[end], 0);
return ret;
}
void xdebug_explode(const char *delim, char *str, xdebug_arg *args, int limit)
{
char *p1, *p2, *endp;
endp = str + strlen(str);
p1 = str;
p2 = xdebug_memnstr(str, delim, strlen(delim), endp);
if (p2 == NULL) {
args->c++;
args->args = (char**) xdrealloc(args->args, sizeof(char*) * args->c);
args->args[args->c - 1] = (char*) xdmalloc(strlen(str) + 1);
memcpy(args->args[args->c - 1], p1, strlen(str));
args->args[args->c - 1][strlen(str)] = '\0';
} else {
do {
args->c++;
args->args = (char**) xdrealloc(args->args, sizeof(char*) * args->c);
args->args[args->c - 1] = (char*) xdmalloc(p2 - p1 + 1);
memcpy(args->args[args->c - 1], p1, p2 - p1);
args->args[args->c - 1][p2 - p1] = '\0';
p1 = p2 + strlen(delim);
} while ((p2 = xdebug_memnstr(p1, delim, strlen(delim), endp)) != NULL && (limit == -1 || --limit > 1));
if (p1 <= endp) {
args->c++;
args->args = (char**) xdrealloc(args->args, sizeof(char*) * args->c);
args->args[args->c - 1] = (char*) xdmalloc(endp - p1 + 1);
memcpy(args->args[args->c - 1], p1, endp - p1);
args->args[args->c - 1][endp - p1] = '\0';
}
}
}
char* xdebug_memnstr(char *haystack, const char *needle, int needle_len, char *end)
{
char *p = haystack;
char first = *needle;
/* let end point to the last character where needle may start */
end -= needle_len;
while (p <= end) {
while (*p != first)
if (++p > end)
return NULL;
if (memcmp(p, needle, needle_len) == 0)
return p;
p++;
}
return NULL;
}
char* xdebug_strrstr(const char* haystack, const char* needle)
{
char *loc = NULL;
char *found = NULL;
size_t pos = 0;
while ((found = strstr(haystack + pos, needle)) != 0) {
loc = found;
pos = (found - haystack) + 1;
}
return loc;
}
double xdebug_get_utime(void)
{
#ifdef HAVE_GETTIMEOFDAY
struct timeval tp;
long sec = 0L;
double msec = 0.0;
if (gettimeofday((struct timeval *) &tp, NULL) == 0) {
sec = tp.tv_sec;
msec = (double) (tp.tv_usec / MICRO_IN_SEC);
if (msec >= 1.0) {
msec -= (long) msec;
}
return msec + sec;
}
#endif
return 0;
}
char* xdebug_get_time(void)
{
time_t cur_time;
char *str_time;
str_time = xdmalloc(24);
cur_time = time(NULL);
strftime(str_time, 24, "%Y-%m-%d %H:%M:%S", gmtime (&cur_time));
return str_time;
}
/* not all versions of php export this */
static int xdebug_htoi(char *s)
{
int value;
int c;
c = s[0];
if (isupper(c)) {
c = tolower(c);
}
value = (c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10) * 16;
c = s[1];
if (isupper(c)) {
c = tolower(c);
}
value += c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10;
return value;
}
/* not all versions of php export this */
int xdebug_raw_url_decode(char *str, int len)
{
char *dest = str;
char *data = str;
while (len--) {
if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1)) && isxdigit((int) *(data + 2))) {
*dest = (char) xdebug_htoi(data + 1);
data += 2;
len -= 2;
} else {
*dest = *data;
}
data++;
dest++;
}
*dest = '\0';
return dest - str;
}
static unsigned char hexchars[] = "0123456789ABCDEF";
char *xdebug_raw_url_encode(char const *s, int len, int *new_length, int skip_slash)
{
register int x, y;
unsigned char *str;
str = (unsigned char *) xdmalloc(3 * len + 1);
for (x = 0, y = 0; len--; x++, y++) {
str[y] = (unsigned char) s[x];
if ((str[y] < '0' && str[y] != '-' && str[y] != '.' && (str[y] != '/' || !skip_slash)) ||
(str[y] < 'A' && str[y] > '9' && str[y] != ':') ||
(str[y] > 'Z' && str[y] < 'a' && str[y] != '_' && (str[y] != '\\' || !skip_slash)) ||
(str[y] > 'z'))
{
str[y++] = '%';
str[y++] = hexchars[(unsigned char) s[x] >> 4];
str[y] = hexchars[(unsigned char) s[x] & 15];
}
}
str[y] = '\0';
if (new_length) {
*new_length = y;
}
return ((char *) str);
}
/* fake URI's per IETF RFC 1738 and 2396 format */
char *xdebug_path_from_url(const char *fileurl TSRMLS_DC)
{
/* deal with file: url's */
char *dfp = NULL;
const char *fp = NULL, *efp = fileurl;
#ifdef PHP_WIN32
int l = 0;
int i;
#endif
char *tmp = NULL, *ret = NULL;
dfp = xdstrdup(efp);
fp = dfp;
xdebug_raw_url_decode(dfp, strlen(dfp));
tmp = strstr(fp, "file://");
if (tmp) {
fp = tmp + 7;
if (fp[0] == '/' && fp[2] == ':') {
fp++;
}
ret = xdstrdup(fp);
#ifdef PHP_WIN32
l = strlen(ret);
/* convert '/' to '\' */
for (i = 0; i < l; i++) {
if (ret[i] == '/') {
ret[i] = '\\';
}
}
#endif
} else {
ret = xdstrdup(fileurl);
}
free(dfp);
return ret;
}
/* fake URI's per IETF RFC 1738 and 2396 format */
char *xdebug_path_to_url(const char *fileurl TSRMLS_DC)
{
int l, i, new_len;
char *tmp = NULL;
char *encoded_fileurl;
/* encode the url */
encoded_fileurl = xdebug_raw_url_encode(fileurl, strlen(fileurl), &new_len, 1);
if (strncmp(fileurl, "phar://", 7) == 0) {
/* ignore, phar is cool */
tmp = xdstrdup(fileurl);
} else if (fileurl[0] != '/' && fileurl[0] != '\\' && fileurl[1] != ':') {
/* convert relative paths */
cwd_state new_state;
char cwd[MAXPATHLEN];
char *result;
result = VCWD_GETCWD(cwd, MAXPATHLEN);
if (!result) {
cwd[0] = '\0';
}
new_state.cwd = estrdup(cwd);
new_state.cwd_length = strlen(cwd);
if (!virtual_file_ex(&new_state, fileurl, NULL, 1 TSRMLS_CC)) {
char *s = estrndup(new_state.cwd, new_state.cwd_length);
tmp = xdebug_sprintf("file://%s",s);
efree(s);
}
efree(new_state.cwd);
} else if (fileurl[1] == '/' || fileurl[1] == '\\') {
/* convert UNC paths (eg. \\server\sharepath) */
/* See http://blogs.msdn.com/ie/archive/2006/12/06/file-uris-in-windows.aspx */
tmp = xdebug_sprintf("file:%s", encoded_fileurl);
} else if (fileurl[0] == '/' || fileurl[0] == '\\') {
/* convert *nix paths (eg. /path) */
tmp = xdebug_sprintf("file://%s", encoded_fileurl);
} else if (fileurl[1] == ':') {
/* convert windows drive paths (eg. c:\path) */
tmp = xdebug_sprintf("file:///%s", encoded_fileurl);
} else {
/* no clue about it, use it raw */
tmp = xdstrdup(encoded_fileurl);
}
l = strlen(tmp);
/* convert '\' to '/' */
for (i = 0; i < l; i++) {
if (tmp[i] == '\\') {
tmp[i]='/';
}
}
xdfree(encoded_fileurl);
return tmp;
}
long xdebug_crc32(const char *string, int str_len)
{
unsigned int crc = ~0;
int len;
len = 0 ;
for (len += str_len; str_len--; ++string) {
XDEBUG_CRC32(crc, *string);
}
return ~crc;
}
#ifndef PHP_WIN32
static FILE *xdebug_open_file(char *fname, const char *mode, const char *extension, char **new_fname)
{
FILE *fh;
char *tmp_fname;
if (extension) {
tmp_fname = xdebug_sprintf("%s.%s", fname, extension);
} else {
tmp_fname = xdstrdup(fname);
}
fh = fopen(tmp_fname, mode);
if (fh && new_fname) {
*new_fname = tmp_fname;
} else {
xdfree(tmp_fname);
}
return fh;
}
static FILE *xdebug_open_file_with_random_ext(char *fname, const char *mode, const char *extension, char **new_fname)
{
FILE *fh;
char *tmp_fname;
TSRMLS_FETCH();
if (extension) {
tmp_fname = xdebug_sprintf("%s.%06x.%s", fname, (long) (1000000 * php_combined_lcg(TSRMLS_C)), extension);
} else {
tmp_fname = xdebug_sprintf("%s.%06x", fname, (long) (1000000 * php_combined_lcg(TSRMLS_C)), extension);
}
fh = fopen(tmp_fname, mode);
if (fh && new_fname) {
*new_fname = tmp_fname;
} else {
xdfree(tmp_fname);
}
return fh;
}
FILE *xdebug_fopen(char *fname, const char *mode, const char *extension, char **new_fname)
{
int r;
FILE *fh;
struct stat buf;
char *tmp_fname = NULL;
int filename_len = 0;
/* We're not doing any tricks for append mode... as that has atomic writes
* anyway. And we ignore read mode as well. */
if (mode[0] == 'a' || mode[0] == 'r') {
return xdebug_open_file(fname, mode, extension, new_fname);
}
/* Make sure we don't open a file with a path that's too long */
filename_len += (fname ? strlen(fname) : 0); /* filename */
filename_len += (extension ? strlen(extension) : 0) + 1; /* extension (+ ".") */
filename_len += 8; /* possible random extension (+ ".") */
if (filename_len > NAME_MAX) {
fname[NAME_MAX - (extension ? strlen(extension) : 0 )] = '\0';
}
/* In write mode however we do have to do some stuff. */
/* 1. Check if the file exists */
if (extension) {
tmp_fname = xdebug_sprintf("%s.%s", fname, extension);
} else {
tmp_fname = xdstrdup(fname);
}
r = stat(tmp_fname, &buf);
/* We're not freeing "tmp_fname" as that is used in the freopen as well. */
if (r == -1) {
/* 2. Cool, the file doesn't exist so we can open it without probs now. */
fh = xdebug_open_file(fname, "w", extension, new_fname);
goto lock;
}
/* 3. It exists, check if we can open it. */
fh = xdebug_open_file(fname, "r+", extension, new_fname);
if (!fh) {
/* 4. If fh == null we couldn't even open the file, so open a new one with a new name */
fh = xdebug_open_file_with_random_ext(fname, "w", extension, new_fname);
goto lock;
}
/* 5. It exists and we can open it, check if we can exclusively lock it. */
r = flock(fileno(fh), LOCK_EX | LOCK_NB);
if (r == -1) {
if (errno == EWOULDBLOCK) {
fclose(fh);
/* 6. The file is in use, so we open one with a new name. */
fh = xdebug_open_file_with_random_ext(fname, "w", extension, new_fname);
goto lock;
}
}
/* 7. We established a lock, now we truncate and return the handle */
fh = freopen(tmp_fname, "w", fh);
lock: /* Yes yes, an evil goto label here!!! */
if (fh) {
/* 8. We have to lock again after the reopen as that basically closes
* the file and opens it again. There is a small race condition here...
*/
flock(fileno(fh), LOCK_EX | LOCK_NB);
}
xdfree(tmp_fname);
return fh;
}
#else
FILE *xdebug_fopen(char *fname, char *mode, char *extension, char **new_fname)
{
char *tmp_fname;
FILE *ret;
if (extension) {
tmp_fname = xdebug_sprintf("%s.%s", fname, extension);
} else {
tmp_fname = xdstrdup(fname);
}
ret = fopen(tmp_fname, mode);
if (new_fname) {
*new_fname = tmp_fname;
} else {
xdfree(tmp_fname);
}
return ret;
}
#endif
int xdebug_format_output_filename(char **filename, char *format, char *script_name)
{
xdebug_str fname = XDEBUG_STR_INITIALIZER;
char cwd[128];
TSRMLS_FETCH();
while (*format)
{
if (*format != '%') {
xdebug_str_addl(&fname, (char *) format, 1, 0);
} else {
format++;
switch (*format)
{
case 'c': /* crc32 of the current working directory */
if (VCWD_GETCWD(cwd, 127)) {
xdebug_str_add(&fname, xdebug_sprintf("%lu", xdebug_crc32(cwd, strlen(cwd))), 1);
}
break;
case 'p': /* pid */
xdebug_str_add(&fname, xdebug_sprintf("%ld", getpid()), 1);
break;
case 'r': /* random number */
xdebug_str_add(&fname, xdebug_sprintf("%06x", (long) (1000000 * php_combined_lcg(TSRMLS_C))), 1);
break;
case 's': { /* script fname */
char *char_ptr, *script_name_tmp;
/* we do not always have script_name available, so if we
* don't have it and this format specifier is used then we
* simple do nothing for this specifier */
if (!script_name) {
break;
}
/* create a copy to work on */
script_name_tmp = xdstrdup(script_name);
/* replace slashes, whitespace and colons with underscores */
while ((char_ptr = strpbrk(script_name_tmp, "/\\: ")) != NULL) {
char_ptr[0] = '_';
}
/* replace .php with _php */
char_ptr = strrchr(script_name_tmp, '.');
if (char_ptr) {
char_ptr[0] = '_';
}
xdebug_str_add(&fname, script_name_tmp, 0);
xdfree(script_name_tmp);
} break;
case 't': { /* timestamp (in seconds) */
time_t the_time = time(NULL);
xdebug_str_add(&fname, xdebug_sprintf("%ld", the_time), 1);
} break;
case 'u': { /* timestamp (in microseconds) */
char *char_ptr, *utime_str = xdebug_sprintf("%F", xdebug_get_utime());
/* Replace . with _ (or should it be nuked?) */
char_ptr = strrchr(utime_str, '.');
if (char_ptr) {
char_ptr[0] = '_';
}
xdebug_str_add(&fname, utime_str, 1);
} break;
case 'H': /* $_SERVER['HTTP_HOST'] */
case 'U': /* $_SERVER['UNIQUE_ID'] */
case 'R': { /* $_SERVER['REQUEST_URI'] */
char *char_ptr, *strval;
zval *data = NULL;
if (Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY) {
switch (*format) {
case 'H':
data = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_HOST", sizeof("HTTP_HOST") - 1);
break;
case 'R':
data = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "REQUEST_URI", sizeof("REQUEST_URI") - 1);
break;
case 'U':
data = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "UNIQUE_ID", sizeof("UNIQUE_ID") - 1);
break;
}
if (data) {
strval = estrdup(Z_STRVAL_P(data));
/* replace slashes, dots, question marks, plus
* signs, ampersands, spaces and other evil chars
* with underscores */
while ((char_ptr = strpbrk(strval, "/\\.?&+:*\"<>| ")) != NULL) {
char_ptr[0] = '_';
}
xdebug_str_add(&fname, strval, 0);
efree(strval);
}
}
} break;
case 'S': { /* session id */
zval *data;
char *char_ptr, *strval;
char *sess_name;
sess_name = zend_ini_string((char*) "session.name", sizeof("session.name"), 0);
if (sess_name && Z_TYPE(PG(http_globals)[TRACK_VARS_COOKIE]) == IS_ARRAY &&
((data = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_COOKIE]), sess_name, strlen(sess_name))) != NULL) &&
Z_STRLEN_P(data) < 100 /* Prevent any unrealistically long data being set as filename */
) {
strval = estrdup(Z_STRVAL_P(data));
/* replace slashes, dots, question marks, plus signs,
* ampersands and spaces with underscores */
while ((char_ptr = strpbrk(strval, "/\\.?&+ ")) != NULL) {
char_ptr[0] = '_';
}
xdebug_str_add(&fname, strval, 0);
efree(strval);
}
} break;
case '%': /* literal % */
xdebug_str_addl(&fname, "%", 1, 0);
break;
}
}
format++;
}
*filename = fname.d;
return fname.l;
}
int xdebug_format_file_link(char **filename, const char *error_filename, int error_lineno TSRMLS_DC)
{
xdebug_str fname = XDEBUG_STR_INITIALIZER;
char *format = XG(file_link_format);
while (*format)
{
if (*format != '%') {
xdebug_str_addl(&fname, (char *) format, 1, 0);
} else {
format++;
switch (*format)
{
case 'f': /* filename */
xdebug_str_add(&fname, xdebug_sprintf("%s", error_filename), 1);
break;
case 'l': /* line number */
xdebug_str_add(&fname, xdebug_sprintf("%d", error_lineno), 1);
break;
case '%': /* literal % */
xdebug_str_addl(&fname, "%", 1, 0);
break;
}
}
format++;
}
*filename = fname.d;
return fname.l;
}
int xdebug_format_filename(char **formatted_name, const char *fmt, const char *default_fmt, const char *filename TSRMLS_DC)
{
xdebug_str fname = XDEBUG_STR_INITIALIZER;
char *name;
xdebug_str *parent, *ancester;
const char *full = filename;
xdebug_arg *parts = (xdebug_arg*) xdmalloc(sizeof(xdebug_arg));
char *slash = xdebug_sprintf("%c", DEFAULT_SLASH);
const char *format = fmt && fmt[0] ? fmt : default_fmt; /* If the format is empty, we use the default */
/* Create pointers for the format chars */
xdebug_arg_init(parts);
xdebug_explode(slash, (char*) filename, parts, -1);
name = parts->args[parts->c - 1];
parent = parts->c > 1 ?
xdebug_join(slash, parts, parts->c - 2, parts->c - 1) :
xdebug_str_create_from_char(name);
ancester = parts->c > 2 ?
xdebug_join(slash, parts, parts->c - 3, parts->c - 1) :
xdebug_str_copy(parent);
while (*format)
{
if (*format != '%') {
xdebug_str_addl(&fname, (char *) format, 1, 0);
} else {
format++;
switch (*format)
{
case 'n': /* filename */
xdebug_str_add(&fname, xdebug_sprintf("%s", name), 1);
break;
case 'p': /* parent */
xdebug_str_add(&fname, xdebug_sprintf("%s", parent->d), 1);
break;
case 'a': /* ancester */
xdebug_str_add(&fname, xdebug_sprintf("%s", ancester->d), 1);
break;
case 'f': /* full path */
xdebug_str_add(&fname, xdebug_sprintf("%s", full), 1);
break;
case 's': /* slash */
xdebug_str_add(&fname, xdebug_sprintf("%c", DEFAULT_SLASH), 1);
break;
case '%': /* literal % */
xdebug_str_addl(&fname, "%", 1, 0);
break;
}
}
format++;
}
xdfree(slash);
xdebug_str_free(ancester);
xdebug_str_free(parent);
xdebug_arg_dtor(parts);
*formatted_name = fname.d;
return fname.l;
}
1
https://gitee.com/yanghuangsheng_admin/sdebug.git
git@gitee.com:yanghuangsheng_admin/sdebug.git
yanghuangsheng_admin
sdebug
sdebug
master

搜索帮助