[@TODO PHP-SRC 5.3] fgets 및fread 함수 분석
> fread:
핵심 함수:
_php_stream_read
핵심 소스 코드 단서:./ext/standard/file.c
./main/php_streams.h
./main/streams/streams.c
먼저 구조체를 보십시오.
struct _php_stream {
php_stream_ops *ops;
void *abstract; /* convenience pointer for abstraction */
php_stream_filter_chain readfilters, writefilters;
php_stream_wrapper *wrapper; /* which wrapper was used to open the stream */
void *wrapperthis; /* convenience pointer for a instance of a wrapper */
zval *wrapperdata; /* fgetwrapperdata retrieves this */
int fgetss_state; /* for fgetss to handle multiline tags */
int is_persistent;
char mode[16]; /* "rwb" etc. ala stdio */
int rsrc_id; /* used for auto-cleanup */
int in_free; /* to prevent recursion during free */
/* so we know how to clean it up correctly. This should be set to
* PHP_STREAM_FCLOSE_XXX as appropriate */
int fclose_stdiocast;
FILE *stdiocast; /* cache this, otherwise we might leak! */
#if ZEND_DEBUG
int __exposed; /* non-zero if exposed as a zval somewhere */
#endif
char *orig_path;
php_stream_context *context;
int flags; /* PHP_STREAM_FLAG_XXX */
/* buffer */
off_t position; /* of underlying stream */
unsigned char *readbuf;
size_t readbuflen;
off_t readpos;
off_t writepos;
/* how much data to read when filling buffer */
size_t chunk_size;
int eof; // ps kimi: eof end of file
#if ZEND_DEBUG
char *open_filename;
uint open_lineno;
#endif
}; /* php_stream */
주요 소스 코드:
./ext/standard/file.c:
/* {{{ proto string fread(resource fp, int length)
Binary-safe file read */
PHPAPI PHP_FUNCTION(fread)
{
zval *arg1;
long len;
php_stream *stream;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &arg1, &len) == FAILURE) {
RETURN_FALSE;
}
PHP_STREAM_TO_ZVAL(stream, &arg1);
if (len <= 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length parameter must be greater than 0");
RETURN_FALSE;
}
Z_STRVAL_P(return_value) = emalloc(len + 1);
Z_STRLEN_P(return_value) = php_stream_read(stream, Z_STRVAL_P(return_value), len);
/* needed because recv/read/gzread doesnt put a null at the end*/
Z_STRVAL_P(return_value)[Z_STRLEN_P(return_value)] = 0;
if (PG(magic_quotes_runtime)) {
Z_STRVAL_P(return_value) = php_addslashes(Z_STRVAL_P(return_value),
Z_STRLEN_P(return_value), &Z_STRLEN_P(return_value), 1 TSRMLS_CC);
}
Z_TYPE_P(return_value) = IS_STRING;
}
/* }}} */
./main/streams/streams.c:
PHPAPI size_t _php_stream_read(php_stream *stream, char *buf, size_t size TSRMLS_DC)
{
size_t toread = 0, didread = 0;
while (size > 0) {
/* take from the read buffer first.
* It is possible that a buffered stream was switched to non-buffered, so we
* drain the remainder of the buffer before using the "raw" read mode for
* the excess */
if (stream->writepos > stream->readpos) {
toread = stream->writepos - stream->readpos;
if (toread > size) {
toread = size;
}
memcpy(buf, stream->readbuf + stream->readpos, toread);
stream->readpos += toread;
size -= toread;
buf += toread;
didread += toread;
}
/* ignore eof here; the underlying state might have changed */
if (size == 0) {
break;
}
if (!stream->readfilters.head && (stream->flags & PHP_STREAM_FLAG_NO_BUFFER || stream->chunk_size == 1)) {
toread = stream->ops->read(stream, buf, size TSRMLS_CC);
} else {
php_stream_fill_read_buffer(stream, size TSRMLS_CC);
toread = stream->writepos - stream->readpos;
if (toread > size) {
toread = size;
}
if (toread > 0) {
memcpy(buf, stream->readbuf + stream->readpos, toread);
stream->readpos += toread;
}
}
if (toread > 0) {
didread += toread;
buf += toread;
size -= toread;
} else {
/* EOF, or temporary end of data (for non-blocking mode). */
break;
}
/* just break anyway, to avoid greedy read */
if (stream->wrapper != &php_plain_files_wrapper) {
break;
}
}
if (didread > 0) {
stream->position += didread;
}
return didread;
}
> fgets:
핵심 함수:
_php_stream_get_line
핵심 소스 코드 단서:./ext/standard/file.c
./main/php_streams.h
./main/streams/streams.c
주요 소스 코드:
./ext/standard/file.c:
Get a line from file pointer */
PHPAPI PHP_FUNCTION(fgets)
{
zval *arg1;
long len = 1024;
char *buf = NULL;
int argc = ZEND_NUM_ARGS();
size_t line_len = 0;
php_stream *stream;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &arg1, &len) == FAILURE) {
RETURN_FALSE;
}
PHP_STREAM_TO_ZVAL(stream, &arg1);
if (argc == 1) {
/* ask streams to give us a buffer of an appropriate size */
buf = php_stream_get_line(stream, NULL, 0, &line_len);
if (buf == NULL) {
goto exit_failed;
}
} else if (argc > 1) {
if (len <= 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length parameter must be greater than 0");
RETURN_FALSE;
}
buf = ecalloc(len + 1, sizeof(char));
if (php_stream_get_line(stream, buf, len, &line_len) == NULL) {
goto exit_failed;
}
}
if (PG(magic_quotes_runtime)) {
Z_STRVAL_P(return_value) = php_addslashes(buf, line_len, &Z_STRLEN_P(return_value), 1 TSRMLS_CC);
Z_TYPE_P(return_value) = IS_STRING;
} else {
ZVAL_STRINGL(return_value, buf, line_len, 0);
/* resize buffer if it's much larger than the result.
* Only needed if the user requested a buffer size. */
if (argc > 1 && Z_STRLEN_P(return_value) < len / 2) {
Z_STRVAL_P(return_value) = erealloc(buf, line_len + 1);
}
}
return;
exit_failed:
RETVAL_FALSE;
if (buf) {
efree(buf);
}
}
/* }}} */
및 함수:
PHPAPI char *php_stream_locate_eol(php_stream *stream, char *buf, size_t buf_len TSRMLS_DC)
{
size_t avail;
char *cr, *lf, *eol = NULL; // ps kimi: eol end of line
char *readptr;
if (!buf) {
readptr = stream->readbuf + stream->readpos;
avail = stream->writepos - stream->readpos;
} else {
readptr = buf;
avail = buf_len;
}
/* Look for EOL */
if (stream->flags & PHP_STREAM_FLAG_DETECT_EOL) {
cr = memchr(readptr, '\r', avail);
lf = memchr(readptr, '
', avail);
if (cr && lf != cr + 1 && !(lf && lf < cr)) {
/* mac */
stream->flags ^= PHP_STREAM_FLAG_DETECT_EOL;
stream->flags |= PHP_STREAM_FLAG_EOL_MAC;
eol = cr;
} else if ((cr && lf && cr == lf - 1) || (lf)) {
/* dos or unix endings */
stream->flags ^= PHP_STREAM_FLAG_DETECT_EOL;
eol = lf;
}
} else if (stream->flags & PHP_STREAM_FLAG_EOL_MAC) {
eol = memchr(readptr, '\r', avail);
} else {
/* unix (and dos) line endings */
eol = memchr(readptr, '
', avail);
}
return eol;
}
./main/streams/streams.c:
/* If buf == NULL, the buffer will be allocated automatically and will be of an
* appropriate length to hold the line, regardless of the line length, memory
* permitting */
PHPAPI char *_php_stream_get_line(php_stream *stream, char *buf, size_t maxlen,
size_t *returned_len TSRMLS_DC)
{
size_t avail = 0;
size_t current_buf_size = 0;
size_t total_copied = 0;
int grow_mode = 0;
char *bufstart = buf;
if (buf == NULL) {
grow_mode = 1;
} else if (maxlen == 0) {
return NULL;
}
/*
* If the underlying stream operations block when no new data is readable,
* we need to take extra precautions.
*
* If there is buffered data available, we check for a EOL. If it exists,
* we pass the data immediately back to the caller. This saves a call
* to the read implementation and will not block where blocking
* is not necessary at all.
*
* If the stream buffer contains more data than the caller requested,
* we can also avoid that costly step and simply return that data.
*/
for (;;) {
avail = stream->writepos - stream->readpos;
if (avail > 0) {
size_t cpysz = 0;
char *readptr;
char *eol;
int done = 0;
readptr = stream->readbuf + stream->readpos;
eol = php_stream_locate_eol(stream, NULL, 0 TSRMLS_CC);
if (eol) {
cpysz = eol - readptr + 1;
done = 1;
} else {
cpysz = avail;
}
if (grow_mode) {
/* allow room for a NUL. If this realloc is really a realloc
* (ie: second time around), we get an extra byte. In most
* cases, with the default chunk size of 8K, we will only
* incur that overhead once. When people have lines longer
* than 8K, we waste 1 byte per additional 8K or so.
* That seems acceptable to me, to avoid making this code
* hard to follow */
bufstart = erealloc(bufstart, current_buf_size + cpysz + 1);
current_buf_size += cpysz + 1;
buf = bufstart + total_copied;
} else {
if (cpysz >= maxlen - 1) {
cpysz = maxlen - 1;
done = 1;
}
}
memcpy(buf, readptr, cpysz);
stream->position += cpysz;
stream->readpos += cpysz;
buf += cpysz;
maxlen -= cpysz;
total_copied += cpysz;
if (done) {
break;
}
} else if (stream->eof) {
break;
} else {
/* XXX: Should be fine to always read chunk_size */
size_t toread;
if (grow_mode) {
toread = stream->chunk_size;
} else {
toread = maxlen - 1;
if (toread > stream->chunk_size) {
toread = stream->chunk_size;
}
}
php_stream_fill_read_buffer(stream, toread TSRMLS_CC);
if (stream->writepos - stream->readpos == 0) {
break;
}
}
}
if (total_copied == 0) {
if (grow_mode) {
assert(bufstart == NULL);
}
return NULL;
}
buf[0] = '\0';
if (returned_len) {
*returned_len = total_copied;
}
return bufstart;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.