From 089ae11181e0bdfdda4820425b7e3c4179ab43d3 Mon Sep 17 00:00:00 2001 From: obarthel Date: Sat, 24 Aug 2019 13:55:31 +0200 Subject: [PATCH] Improvements for better read performance. gets() now tries to copy as much data from the read buffer as possible, and will fall back onto using the __getc() macro only if necessary. This should improve performance on long lines, or crash faster if the read buffer happens to be too short. This is probably wasted on gets(), but you never know... --- library/stdio_gets.c | 56 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/library/stdio_gets.c b/library/stdio_gets.c index c470a90..f1bb135 100644 --- a/library/stdio_gets.c +++ b/library/stdio_gets.c @@ -1,10 +1,8 @@ /* - * $Id: stdio_gets.c,v 1.6 2006-01-08 12:04:24 obarthel Exp $ - * * :ts=4 * * Portable ISO 'C' (1994) runtime library for the Amiga computer - * Copyright (c) 2002-2015 by Olaf Barthel + * Copyright (c) 2002-2019 by Olaf Barthel * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,6 +44,8 @@ char * gets(char *s) { + FILE * stream = stdin; + struct iob * file = (struct iob *)stream; char * result = s; int c; @@ -53,16 +53,16 @@ gets(char *s) SHOWPOINTER(s); - assert( s != NULL && stdin != NULL ); + assert( s != NULL ); if(__check_abort_enabled) __check_abort(); - flockfile(stdin); + flockfile(stream); #if defined(CHECK_FOR_NULL_POINTERS) { - if(s == NULL || stdin == NULL) + if(s == NULL) { SHOWMSG("invalid parameters"); @@ -77,21 +77,55 @@ gets(char *s) /* Take care of the checks and data structure changes that * need to be handled only once for this stream. */ - if(__fgetc_check(stdin) < 0) + if(__fgetc_check(stream) < 0) { result = NULL; goto out; } /* So that we can tell error and 'end of file' conditions apart. */ - clearerr(stdin); + clearerr(stream); while(TRUE) { - c = __getc(stdin); + /* If there is data in the buffer, try to copy it directly + into the string buffer. If there is a line feed in the + buffer, too, try to conclude the read operation. */ + if(file->iob_BufferPosition < file->iob_BufferReadBytes) + { + size_t num_bytes_in_buffer = file->iob_BufferReadBytes - file->iob_BufferPosition; + const unsigned char * buffer = &file->iob_Buffer[file->iob_BufferPosition]; + const unsigned char * lf; + + /* Try to find a line feed character which could conclude + the read operation if the remaining buffer data, including + the line feed character, fit into the string buffer. */ + lf = (unsigned char *)memchr(buffer, '\n', num_bytes_in_buffer); + if(lf != NULL) + { + size_t num_characters_in_line = lf + 1 - buffer; + + /* Copy the remainder of the read buffer into the + string buffer, including the terminating line + feed character. */ + memmove(s, buffer, num_characters_in_line); + + file->iob_BufferPosition += num_characters_in_line; + + /* And that concludes the line read operation. */ + break; + } + + memmove(s, buffer, num_bytes_in_buffer); + s += num_bytes_in_buffer; + + file->iob_BufferPosition += num_bytes_in_buffer; + } + + c = __getc(stream); if(c == EOF) { - if(ferror(stdin)) + if(ferror(stream)) { /* Just to be on the safe side. */ (*s) = '\0'; @@ -120,7 +154,7 @@ gets(char *s) out: - funlockfile(stdin); + funlockfile(stream); RETURN(result); return(result);