1
0
mirror of https://github.com/adtools/clib2.git synced 2025-12-08 14:59:05 +00:00

fputs() and puts() now share the same common code. Added abort checks in order to avoid turning the memcpy() operations into an uninterruptable sequence.

This commit is contained in:
Olaf Barthel
2023-09-06 13:24:15 +02:00
parent 45d118101a
commit a7389454bb
2 changed files with 135 additions and 109 deletions

View File

@@ -41,12 +41,14 @@
/****************************************************************************/ /****************************************************************************/
/* Both fputs() and puts() share this function. */
int int
fputs(const char *s, FILE *stream) __fputs(const char *s, int line_feed, FILE *stream)
{ {
struct iob * file = (struct iob *)stream; struct iob * file = (struct iob *)stream;
size_t total_size; size_t total_size;
int result = EOF; int result = EOF;
int buffer_mode;
int c; int c;
ENTER(); ENTER();
@@ -78,14 +80,14 @@ fputs(const char *s, FILE *stream)
if (__fputc_check(stream) < 0) if (__fputc_check(stream) < 0)
goto out; goto out;
total_size = strlen(s); assert( 0 <= file->iob_BufferWriteBytes );
if(total_size > 0) assert( file->iob_BufferWriteBytes <= file->iob_BufferSize );
{ assert( file->iob_BufferPosition <= file->iob_BufferSize );
int buffer_mode;
/* We perform line buffering to improve readability of the /* We perform line buffering to improve readability of the
buffered text if buffering was disabled and the output * buffered text if buffering was disabled and the output
goes to an interactive stream. */ * goes to an interactive stream.
*/
buffer_mode = (file->iob_Flags & IOBF_BUFFER_MODE); buffer_mode = (file->iob_Flags & IOBF_BUFFER_MODE);
if (buffer_mode == IOBF_BUFFER_MODE_NONE) if (buffer_mode == IOBF_BUFFER_MODE_NONE)
{ {
@@ -99,33 +101,54 @@ fputs(const char *s, FILE *stream)
__fd_unlock(fd); __fd_unlock(fd);
} }
total_size = strlen(s);
if (total_size > 0)
{
if (buffer_mode == IOBF_BUFFER_MODE_LINE) if (buffer_mode == IOBF_BUFFER_MODE_LINE)
{ {
while (total_size > 0) while (total_size > 0)
{ {
/* Is there still room in the write buffer to store /* Is there still room in the write buffer to store
more of the string? */ * more of the string?
*/
if (file->iob_BufferWriteBytes < file->iob_BufferSize) if (file->iob_BufferWriteBytes < file->iob_BufferSize)
{ {
unsigned char * buffer = &file->iob_Buffer[file->iob_BufferWriteBytes]; unsigned char * buffer = &file->iob_Buffer[file->iob_BufferWriteBytes];
size_t num_buffer_bytes; size_t num_buffer_bytes;
const char * lf; const char * lf;
/* Give the user a chance to abort what could otherwise
* become an uninterrupted series of copying operations.
*/
if (__check_abort_enabled)
__check_abort();
/* Store only as many characters as will fit into the write buffer. */ /* Store only as many characters as will fit into the write buffer. */
assert( file->iob_BufferSize >= file->iob_BufferWriteBytes );
num_buffer_bytes = file->iob_BufferSize - file->iob_BufferWriteBytes; num_buffer_bytes = file->iob_BufferSize - file->iob_BufferWriteBytes;
if (total_size < num_buffer_bytes) if (total_size < num_buffer_bytes)
num_buffer_bytes = total_size; num_buffer_bytes = total_size;
/* Try to find a line feed in the string. If there is one, /* Try to find a line feed in the string. If there is one,
reduce the number of characters to write to the sequence * reduce the number of characters to write to the sequence
which ends with the line feed character. */ * which ends with the line feed character.
*/
lf = memchr(s, '\n', num_buffer_bytes); lf = memchr(s, '\n', num_buffer_bytes);
if (lf != NULL) if (lf != NULL)
{
assert( (size_t)(lf + 1 - s) <= num_buffer_bytes );
num_buffer_bytes = lf + 1 - s; num_buffer_bytes = lf + 1 - s;
}
assert( num_buffer_bytes > 0 );
memmove(buffer, s, num_buffer_bytes); memmove(buffer, s, num_buffer_bytes);
s += num_buffer_bytes; s += num_buffer_bytes;
assert( file->iob_BufferWriteBytes + num_buffer_bytes <= file->iob_BufferSize );
file->iob_BufferWriteBytes += num_buffer_bytes; file->iob_BufferWriteBytes += num_buffer_bytes;
/* Write the buffer to disk if it's full or contains a line feed. */ /* Write the buffer to disk if it's full or contains a line feed. */
@@ -136,12 +159,15 @@ fputs(const char *s, FILE *stream)
} }
/* Stop as soon as no further data needs to be written. */ /* Stop as soon as no further data needs to be written. */
assert( total_size >= num_buffer_bytes );
total_size -= num_buffer_bytes; total_size -= num_buffer_bytes;
if (total_size == 0) if (total_size == 0)
break; break;
/* If there is again room in the output buffer, /* If there is again room in the output buffer,
repeat this optimization. */ * repeat this optimization.
*/
if (file->iob_BufferWriteBytes < file->iob_BufferSize) if (file->iob_BufferWriteBytes < file->iob_BufferSize)
continue; continue;
} }
@@ -171,8 +197,9 @@ fputs(const char *s, FILE *stream)
while (total_size > 0) while (total_size > 0)
{ {
/* If there is more data to be written than the write buffer will hold /* If there is more data to be written than the write buffer will hold
and the write buffer is empty anyway, then we'll bypass the write * and the write buffer is empty anyway, then we'll bypass the write
buffer entirely. */ * buffer entirely.
*/
if (file->iob_BufferWriteBytes == 0 && total_size >= (size_t)file->iob_BufferSize) if (file->iob_BufferWriteBytes == 0 && total_size >= (size_t)file->iob_BufferSize)
{ {
ssize_t num_bytes_written; ssize_t num_bytes_written;
@@ -189,20 +216,33 @@ fputs(const char *s, FILE *stream)
} }
/* Is there still room in the write buffer to store /* Is there still room in the write buffer to store
more of the string? */ * more of the string?
*/
if (file->iob_BufferWriteBytes < file->iob_BufferSize) if (file->iob_BufferWriteBytes < file->iob_BufferSize)
{ {
unsigned char * buffer = &file->iob_Buffer[file->iob_BufferWriteBytes]; unsigned char * buffer = &file->iob_Buffer[file->iob_BufferWriteBytes];
size_t num_buffer_bytes; size_t num_buffer_bytes;
/* Give the user a chance to abort what could otherwise
* become an uninterrupted series of copying operations.
*/
if (__check_abort_enabled)
__check_abort();
/* Store only as many characters as will fit into the write buffer. */ /* Store only as many characters as will fit into the write buffer. */
assert( file->iob_BufferSize >= file->iob_BufferWriteBytes );
num_buffer_bytes = file->iob_BufferSize - file->iob_BufferWriteBytes; num_buffer_bytes = file->iob_BufferSize - file->iob_BufferWriteBytes;
if (total_size < num_buffer_bytes) if (total_size < num_buffer_bytes)
num_buffer_bytes = total_size; num_buffer_bytes = total_size;
assert( num_buffer_bytes > 0 );
memmove(buffer, s, num_buffer_bytes); memmove(buffer, s, num_buffer_bytes);
s += num_buffer_bytes; s += num_buffer_bytes;
assert( file->iob_BufferWriteBytes + num_buffer_bytes <= file->iob_BufferSize );
file->iob_BufferWriteBytes += num_buffer_bytes; file->iob_BufferWriteBytes += num_buffer_bytes;
/* Write a full buffer to disk. */ /* Write a full buffer to disk. */
@@ -213,12 +253,15 @@ fputs(const char *s, FILE *stream)
} }
/* Stop as soon as no further data needs to be written. */ /* Stop as soon as no further data needs to be written. */
assert( total_size >= num_buffer_bytes );
total_size -= num_buffer_bytes; total_size -= num_buffer_bytes;
if (total_size == 0) if (total_size == 0)
break; break;
/* If there is again room in the output buffer, /* If there is again room in the output buffer,
try this optimization again. */ * try this optimization again.
*/
if (file->iob_BufferWriteBytes < file->iob_BufferSize) if (file->iob_BufferWriteBytes < file->iob_BufferSize)
continue; continue;
} }
@@ -233,14 +276,18 @@ fputs(const char *s, FILE *stream)
} }
} }
if (line_feed != 0 && __putc(line_feed, stream, buffer_mode) == EOF)
goto out;
result = OK; result = OK;
out: out:
/* Note: if buffering is disabled for this stream, then we still /* Note: if buffering is disabled for this stream, then we still
may have buffered data around, queued to be printed right now. * may have buffered data around, queued to be printed right now.
This is intended to improve performance as it takes more effort * This is intended to improve performance as it takes more effort
to write a single character to a file than to write a bunch. */ * to write a single character to a file than to write a bunch.
*/
if (result == 0 && (file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE) if (result == 0 && (file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
{ {
if (__iob_write_buffer_is_valid(file) && __flush_iob_write_buffer(file) < 0) if (__iob_write_buffer_is_valid(file) && __flush_iob_write_buffer(file) < 0)
@@ -256,3 +303,36 @@ fputs(const char *s, FILE *stream)
RETURN(result); RETURN(result);
return(result); return(result);
} }
/****************************************************************************/
int
fputs(const char *s, FILE *stream)
{
int result;
ENTER();
SHOWSTRING(s);
SHOWPOINTER(stream);
assert( s != NULL && stream != NULL );
if (__check_abort_enabled)
__check_abort();
#if defined(CHECK_FOR_NULL_POINTERS)
{
if (s == NULL || stream == NULL)
{
__set_errno(EFAULT);
goto out;
}
}
#endif /* CHECK_FOR_NULL_POINTERS */
result = __fputs(s, 0, stream);
RETURN(result);
return(result);
}

View File

@@ -44,11 +44,7 @@
int int
puts(const char *s) puts(const char *s)
{ {
FILE * stream = stdout;
struct iob * file = (struct iob *)stream;
int result = EOF; int result = EOF;
int buffer_mode;
int c;
ENTER(); ENTER();
@@ -56,11 +52,6 @@ puts(const char *s)
assert( s != NULL ); assert( s != NULL );
if(__check_abort_enabled)
__check_abort();
flockfile(stream);
#if defined(CHECK_FOR_NULL_POINTERS) #if defined(CHECK_FOR_NULL_POINTERS)
{ {
if(s == NULL) if(s == NULL)
@@ -71,58 +62,13 @@ puts(const char *s)
} }
#endif /* CHECK_FOR_NULL_POINTERS */ #endif /* CHECK_FOR_NULL_POINTERS */
assert( __is_valid_iob(file) ); if (__fputs(s, '\n', stdout) == EOF)
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
assert( file->iob_BufferSize > 0 );
/* If buffering is disabled for an interactive stream
switch to line buffering to improve the readability of
the output: instead of pumping out the entire buffer
break it up into individual lines. */
buffer_mode = (file->iob_Flags & IOBF_BUFFER_MODE);
if(buffer_mode == IOBF_BUFFER_MODE_NONE)
{
struct fd * fd = __fd[file->iob_Descriptor];
__fd_lock(fd);
if(FLAG_IS_SET(fd->fd_Flags,FDF_IS_INTERACTIVE))
buffer_mode = IOBF_BUFFER_MODE_LINE;
__fd_unlock(fd);
}
if(__fputc_check(stream) < 0)
goto out;
while((c = (*s++)) != '\0')
{
if(__putc(c,stream,buffer_mode) == EOF)
goto out;
}
if(__putc('\n',stream,buffer_mode) == EOF)
goto out; goto out;
result = OK; result = OK;
out: out:
/* Note: if buffering is disabled for this stream, then we still
may have buffered data around, queued to be printed right now.
This is intended to improve performance as it takes more effort
to write a single character to a file than to write a bunch. */
if(result == 0 && (file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
{
if(__iob_write_buffer_is_valid(file) && __flush_iob_write_buffer(file) < 0)
{
SHOWMSG("couldn't flush the write buffer");
result = EOF;
}
}
funlockfile(stream);
RETURN(result); RETURN(result);
return(result); return(result);
} }