Cleanup and simplify get_reason() and related functions

Rename randreason() to fread_random() to better reflect its function,
and change it to a one-pass algorithm.  Have it write into a caller-provided
buffer instead of a static buffer.  Fixes a file leak when an empty
file is given to this function.

Change freadln() so that it never returns an empty line - it only returns
0 at end-of-file now.  This simplifies its callers.

Factor out some common code from the several get_reason()-type functions,
which greatly simplifies them.
This commit is contained in:
Kevin Easton 2015-06-27 00:38:40 +10:00
parent 5f4429bf7b
commit 27e32a0319
3 changed files with 55 additions and 66 deletions

View File

@ -130,8 +130,7 @@ ChannelList * BX_prepare_command (int *, char *, int);
void set_nslookupfd(fd_set *);
long print_nslookup(fd_set *);
void auto_nslookup();
int freadln(FILE *, char *);
int freadln(FILE *, char *, size_t);
void BX_close_socketread(int);
int BX_add_socketread(int, int, unsigned long, char *, void (*func_read)(int), void (*func_write)(int));

View File

@ -4012,10 +4012,10 @@ FILE *f;
{
char *hst = NULL;
buffer = alloca(sb.st_size+1);
freadln(f, buffer);
freadln(f, buffer, sb.st_size + 1);
while(!feof(f))
{
if ((freadln(f, buffer)))
if ((freadln(f, buffer, sb.st_size + 1)))
{
if (*buffer == '#')
continue;

View File

@ -1734,99 +1734,89 @@ void error_not_opped(const char *channel)
reset_display_target();
}
int freadln(FILE *stream, char *lin)
/* Reads a single non-empty line from a file. Ignores lines beginning with # */
int freadln(FILE *stream, char *lin, size_t len)
{
char *p;
do
p = fgets(lin, IRCD_BUFFER_SIZE/4, stream);
while (p && (*lin == '#'));
p = fgets(lin, len, stream);
while (p && (*lin == '#' || *lin == '\n'));
if (!p)
return 0;
chop(lin, 1);
if (!*lin)
return 0;
return 1;
}
char *randreason(char *filename)
/* Open a file and read a random non-empty, non-comment line from it. */
static char *fread_random(const char *filename, char *line, size_t len)
{
int count, min, i;
FILE *bleah;
char *f = NULL;
static char buffer[IRCD_BUFFER_SIZE/4 + 1];
int count = 0;
int i = 0;
FILE *reason_file;
char *f = m_strdup(filename);
char buffer[2][IRCD_BUFFER_SIZE];
min = 1;
count = 0;
buffer[0] = '\0';
f = m_strdup(filename);
if (filename && (bleah = uzfopen(&f, get_string_var(LOAD_PATH_VAR), 0)))
/* This is an algorithm that lets us choose an evenly-distributed
* random line with one pass through the file. At line N, we replace
* the previously chosen line with this line, with probability 1/N.
*/
if ((reason_file = uzfopen(&f, get_string_var(LOAD_PATH_VAR), 0)))
{
while (!feof(bleah))
if (freadln(bleah, buffer))
count++;
if (!count)
while (freadln(reason_file, buffer[i], sizeof buffer[i]))
{
strcpy(buffer, "No Reason");
new_free(&f);
return buffer;
count++;
if (getrandom(0, count - 1) == 0)
i = !i;
}
i = getrandom(1, count);
count = 0;
fclose(bleah);
bleah = uzfopen(&f, get_string_var(LOAD_PATH_VAR), 0);
while (!feof(bleah) && (count < i))
if (freadln(bleah, buffer))
count++;
fclose(bleah);
fclose(reason_file);
}
new_free(&f);
if (*buffer)
return buffer;
if (count > 0)
{
strlcpy(line, buffer[!i], len);
return line;
}
return NULL;
}
/* Read a random text format from a file, convert it and strip it. A default
format is supplied if a format cannot be read from the file.
arg0 and arg1 replace $0 and $1 in the format. */
static char *random_text(const char *filename, const char *arg0,
const char *arg1, const char *default_format)
{
char line[IRCD_BUFFER_SIZE];
const char *format = fread_random(filename, line, sizeof line);
if (!format)
format = default_format;
return stripansicodes(convert_output_format(format, "%s %s", arg0, arg1));
}
char *get_reason(char *nick, char *file)
{
char *temp;
char *filename = NULL;
if (file && *file)
malloc_strcpy(&filename, file);
else
malloc_sprintf(&filename, "%s", DEFAULT_BITCHX_KICK_FILE);
temp = randreason(filename);
new_free(&filename);
if ((!temp || !*temp) && get_string_var(DEFAULT_REASON_VAR))
temp = get_string_var(DEFAULT_REASON_VAR);
return (stripansicodes(convert_output_format(temp, "%s %s", nick? nick: "error", get_server_nickname(from_server) )));
char *filename = file;
if (!file || !*file)
filename = DEFAULT_BITCHX_KICK_FILE;
return random_text(filename, nick ? nick : "error", get_server_nickname(from_server), get_string_var(DEFAULT_REASON_VAR));
}
char *get_realname(char *nick)
{
char *temp;
char *filename = NULL;
malloc_sprintf(&filename, "%s", DEFAULT_BITCHX_IRCNAME_FILE);
temp = randreason(filename);
new_free(&filename);
if ((!temp || !*temp))
temp = "Who cares?";
return (stripansicodes(convert_output_format(temp, "%s %s", nick? nick: "error", get_server_nickname(from_server) )));
return random_text(DEFAULT_BITCHX_IRCNAME_FILE, nick, nick, "Who cares?");
}
char *get_signoffreason(char *nick)
{
char *temp;
char *filename = NULL;
malloc_sprintf(&filename, "%s", DEFAULT_BITCHX_QUIT_FILE);
temp = randreason(filename);
new_free(&filename);
if (!temp || !*temp)
temp = "$0 has no reason";
return (stripansicodes(convert_output_format(temp, "%s %s", nick? nick: "error", get_server_nickname(from_server))));
return random_text(DEFAULT_BITCHX_QUIT_FILE, nick, nick, "$0 has no reason");
}
#ifdef WANT_NSLOOKUP