aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md43
-rw-r--r--FICS/algcheck.c15
-rw-r--r--FICS/board.c5
-rw-r--r--FICS/build.mk34
-rw-r--r--FICS/command.c6
-rw-r--r--FICS/comproc.c33
-rw-r--r--FICS/formula.c2
-rw-r--r--FICS/gamedb.c24
-rw-r--r--FICS/gamedb.h7
-rw-r--r--FICS/gameproc.c6
-rw-r--r--FICS/lists.c9
-rw-r--r--FICS/matchproc.c5
-rw-r--r--FICS/network.c3
-rw-r--r--FICS/obsproc.c35
-rw-r--r--FICS/playerdb.c90
-rw-r--r--FICS/ratings.c74
-rw-r--r--FICS/ratings.h5
-rw-r--r--FICS/talkproc.c6
-rw-r--r--FICS/utils.c54
-rw-r--r--FICS/utils.h6
-rw-r--r--FICS/vers.c2
-rw-r--r--GNUmakefile3
-rw-r--r--README.md14
-rw-r--r--include/colors.h81
-rw-r--r--maketargets/tidy.mk9
25 files changed, 426 insertions, 145 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6138424..8aab73c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,27 +3,32 @@
All notable changes to this fork of FICS version 1.6.2 will be
documented in this file.
-## [Unreleased] ##
-- Changed the addplayer program to output a restart notice if an admin
+## [1.4.5] - 2025-04-09 ##
+- **Changed** the addplayer program to output a restart notice if an admin
account is created.
-- Changed the program to avoid calculating the same string multiple
+- **Changed** the program to avoid calculating the same string multiple
times. Multiple occurrences, found by PVS-Studio.
-- Fixed `-Wshadow` warnings. Multiple occurrences.
-- Fixed calls of risky functions.
-- Fixed double `free()` in `process_login()`.
-- Fixed memory leak in `process_login()`.
-- Fixed negative array index read in `accept_match()`.
-- Fixed null pointer dereferences.
-- Fixed out-of-bounds array access in `has_legal_move()`.
-- Fixed overflowed array index read/write. Multiple occurrences.
-- Fixed overflowed return value in `player_search()`.
-- Fixed possible buffer overflow in `FindHistory2()`.
-- Fixed truncated stdio return value in `ReadGameState()`.
-- Fixed unchecked function return values. Multiple occurrences.
-- Fixed uninitialized variables.
-- Fixed untrusted array indices.
-- Fixed untrusted loop bounds.
-- Fixed use of 32-bit `time_t`. Y2K38 safety. Multiple occurrences.
+- **Fixed** `-Wshadow` warnings. Multiple occurrences.
+- **Fixed** calls of risky functions.
+- **Fixed** constant expression result in `tell()`.
+- **Fixed** double `free()` in `process_login()`.
+- **Fixed** excessive checks.
+- **Fixed** improper use of negative values.
+- **Fixed** memory leak in `process_login()`.
+- **Fixed** _multiple_ Clang Tidy warnings.
+- **Fixed** negative array index read in `accept_match()`.
+- **Fixed** null pointer dereferences.
+- **Fixed** out-of-bounds array access in `has_legal_move()`.
+- **Fixed** overflowed array index read/write. Multiple occurrences.
+- **Fixed** overflowed return value in `player_search()`.
+- **Fixed** possible buffer overflow in `FindHistory2()`.
+- **Fixed** possible memory corruptions and incorrect computations.
+- **Fixed** truncated stdio return value in `ReadGameState()`.
+- **Fixed** unchecked function return values. Multiple occurrences.
+- **Fixed** uninitialized variables.
+- **Fixed** untrusted array indices.
+- **Fixed** untrusted loop bounds.
+- **Fixed** use of 32-bit `time_t`. Y2K38 safety. Multiple occurrences.
## [1.4.4] - 2024-12-07 ##
- **Added** an autorun script suitable to be run as a cron job.
diff --git a/FICS/algcheck.c b/FICS/algcheck.c
index 250c129..15642fd 100644
--- a/FICS/algcheck.c
+++ b/FICS/algcheck.c
@@ -21,11 +21,16 @@
name email yy/mm/dd Change
Richard Nash 93/10/22 Created
Markus Uhlin 24/05/05 Revised
+ Markus Uhlin 25/04/05 alg_parse_move:
+ return ambiguous move on
+ out-of-bounds array read/write.
*/
#include "stdinclude.h"
#include "common.h"
+#include <err.h>
+
#include "algcheck.h"
#include "board.h"
#include "maxxes-utils.h"
@@ -250,6 +255,11 @@ alg_parse_move(char *mstr, game_state_t *gs, move_t *mt)
NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
if ((ff != ALG_UNKNOWN) && (ff != f))
continue;
+ if (r < 0 || r >= 8) {
+ warnx("%s: out-of-bounds array read/write: "
+ "r=%d", __func__, r);
+ return MOVE_AMBIGUOUS;
+ }
if (piecetype(gs->board[f][r]) != piece)
continue;
if (gs->onMove == WHITE) {
@@ -257,6 +267,11 @@ alg_parse_move(char *mstr, game_state_t *gs, move_t *mt)
} else {
tmpr = r - 1;
}
+ if (tmpr < 0 || tmpr >= 8) {
+ warnx("%s: out-of-bounds array read/write: "
+ "tmpr=%d", __func__, tmpr);
+ return MOVE_AMBIGUOUS;
+ }
if (gs->board[tf][tmpr] == NOPIECE) {
if ((gs->ep_possible[((gs->onMove == WHITE) ?
diff --git a/FICS/board.c b/FICS/board.c
index f687b3e..d0b65a2 100644
--- a/FICS/board.c
+++ b/FICS/board.c
@@ -25,6 +25,7 @@
Markus Uhlin 24/04/13 Added usage of the functions
from 'maxxes-utils.h'.
Markus Uhlin 24/06/01 Added and made use of brand().
+ Markus Uhlin 25/04/06 Fixed Clang Tidy warnings.
*/
#include "stdinclude.h"
@@ -1133,7 +1134,7 @@ board_read_file(char *category, char *gname, game_state_t *gs)
case 'g':
case 'h':
onFile = (c - 'a');
- onRank = -1;
+ onRank = -1; // NOLINT: dead store
break;
case '1':
case '2':
@@ -1161,7 +1162,7 @@ board_read_file(char *category, char *gname, game_state_t *gs)
onColor = -1;
onPiece = -1;
onFile = -1;
- onRank = -1;
+ onRank = -1; // NOLINT: dead store
break;
default:
break;
diff --git a/FICS/build.mk b/FICS/build.mk
index f8c7d05..834ebef 100644
--- a/FICS/build.mk
+++ b/FICS/build.mk
@@ -37,6 +37,40 @@ OBJS = $(SRC_DIR)adminproc.o\
$(SRC_DIR)variable.o\
$(SRC_DIR)vers.o
+SRCS = $(SRC_DIR)adminproc.c\
+ $(SRC_DIR)algcheck.c\
+ $(SRC_DIR)assert_error.c\
+ $(SRC_DIR)board.c\
+ $(SRC_DIR)command.c\
+ $(SRC_DIR)comproc.c\
+ $(SRC_DIR)eco.c\
+ $(SRC_DIR)fics_getsalt.cpp\
+ $(SRC_DIR)ficslim.cpp\
+ $(SRC_DIR)ficsmain.c\
+ $(SRC_DIR)formula.c\
+ $(SRC_DIR)gamedb.c\
+ $(SRC_DIR)gameproc.c\
+ $(SRC_DIR)iset.cpp\
+ $(SRC_DIR)legal.c\
+ $(SRC_DIR)legal2.c\
+ $(SRC_DIR)lists.c\
+ $(SRC_DIR)matchproc.c\
+ $(SRC_DIR)maxxes-utils.c\
+ $(SRC_DIR)movecheck.c\
+ $(SRC_DIR)multicol.c\
+ $(SRC_DIR)network.c\
+ $(SRC_DIR)obsproc.c\
+ $(SRC_DIR)playerdb.c\
+ $(SRC_DIR)rating_conv.c\
+ $(SRC_DIR)ratings.c\
+ $(SRC_DIR)rmalloc.c\
+ $(SRC_DIR)shutdown.c\
+ $(SRC_DIR)sought.cpp\
+ $(SRC_DIR)talkproc.c\
+ $(SRC_DIR)utils.c\
+ $(SRC_DIR)variable.c\
+ $(SRC_DIR)vers.c
+
AP_OBJS = $(SRC_DIR)fics_addplayer.o
MR_OBJS = $(SRC_DIR)makerank.o
diff --git a/FICS/command.c b/FICS/command.c
index 528bdf9..569c27a 100644
--- a/FICS/command.c
+++ b/FICS/command.c
@@ -132,7 +132,11 @@ parse_command(char *com_string, char **comm, char **parameters)
PUBLIC int
alias_lookup(char *tmp, alias_type *alias_list, int numalias)
{
- for (int i = 0; (alias_list[i].comm_name && i < numalias); i++) {
+ if (numalias >= MAX_ALIASES)
+ return -1;
+ for (int i = 0;
+ (i < numalias && alias_list[i].comm_name != NULL);
+ i++) {
if (!strcmp(tmp, alias_list[i].comm_name))
return i;
}
diff --git a/FICS/comproc.c b/FICS/comproc.c
index 31f6064..2b5a04e 100644
--- a/FICS/comproc.c
+++ b/FICS/comproc.c
@@ -1320,10 +1320,7 @@ com_who(int p, param_list param)
sel_bits |= WHO_REGISTERED;
break;
case 'l': // Sort order
- cmp_func = alpha_cmp;
- sort_type = none;
- break;
- case 'A': // Sort order
+ case 'A':
cmp_func = alpha_cmp;
sort_type = none;
break;
@@ -1810,10 +1807,9 @@ FindAndShowFile(int p, param_list param, char *dir)
{
char *iwant, *filenames[1000];
int i;
- static char nullify = '\0';
if (param[0].type == TYPE_NULL) {
- iwant = &nullify;
+ iwant = NULL;
} else {
iwant = param[0].val.word;
@@ -1827,8 +1823,9 @@ FindAndShowFile(int p, param_list param, char *dir)
i = search_directory(dir, iwant, filenames, ARRAY_SIZE(filenames));
if (i == 0) {
- pprintf(p, "No information available on \"%s\".\n", iwant);
- } else if (i == 1 || !strcmp(*filenames, iwant)) {
+ pprintf(p, "No information available on \"%s\".\n",
+ (iwant ? iwant : ""));
+ } else if (i == 1 || !strcmp(*filenames, iwant ? iwant : "")) {
if (psend_file(p, dir, *filenames)) {
/*
* We should never reach this unless the file
@@ -1839,7 +1836,7 @@ FindAndShowFile(int p, param_list param, char *dir)
"Thank you.\n");
}
} else {
- if (*iwant)
+ if (iwant && *iwant)
pprintf(p, "Matches:\n");
display_directory(p, filenames, i);
}
@@ -1867,7 +1864,6 @@ com_mailsource(int p, param_list param)
char fname[MAX_FILENAME_SIZE];
char subj[120];
int count;
- static char nullify = '\0';
if (!parray[p].registered) {
pprintf(p, "Only registered people can use the mailsource "
@@ -1876,14 +1872,15 @@ com_mailsource(int p, param_list param)
}
if (param[0].type == TYPE_NULL)
- iwant = &nullify;
+ iwant = NULL;
else
iwant = param[0].val.word;
if ((count = search_directory(source_dir, iwant, buffer,
ARRAY_SIZE(buffer))) == 0) {
- pprintf(p, "Found no source file matching \"%s\".\n", iwant);
- } else if ((count == 1) || !strcmp(iwant, *buffer)) {
+ pprintf(p, "Found no source file matching \"%s\".\n",
+ (iwant ? iwant : ""));
+ } else if ((count == 1) || !strcmp(iwant ? iwant : "", *buffer)) {
snprintf(subj, sizeof subj, "FICS source file from server "
"%s: %s",
fics_hostname,
@@ -1899,7 +1896,7 @@ com_mailsource(int p, param_list param)
} else {
pprintf(p, "Found %d source files matching that:\n", count);
- if (*iwant) {
+ if (iwant && *iwant) {
display_directory(p, buffer, count);
} else { // this junk is to get *.c *.h
char *s;
@@ -1930,7 +1927,6 @@ com_mailhelp(int p, param_list param)
char subj[120];
int count;
int lang = parray[p].language;
- static char nullify = '\0';
if (!parray[p].registered) {
pprintf(p, "Only registered people can use the mailhelp "
@@ -1939,7 +1935,7 @@ com_mailhelp(int p, param_list param)
}
if (param[0].type == TYPE_NULL)
- iwant = &nullify;
+ iwant = NULL;
else
iwant = param[0].val.word;
@@ -1960,8 +1956,9 @@ com_mailhelp(int p, param_list param)
}
if (count == 0) {
- pprintf(p, "Found no help file matching \"%s\".\n", iwant);
- } else if (count == 1 || !strcmp(*buffer, iwant)) {
+ pprintf(p, "Found no help file matching \"%s\".\n",
+ (iwant ? iwant : ""));
+ } else if (count == 1 || !strcmp(*buffer, iwant ? iwant : "")) {
snprintf(subj, sizeof subj, "FICS help file from server %s: %s",
fics_hostname,
*buffer);
diff --git a/FICS/formula.c b/FICS/formula.c
index 5f9fdb7..dd5ff23 100644
--- a/FICS/formula.c
+++ b/FICS/formula.c
@@ -574,7 +574,7 @@ ChooseClauses(player *who, char *formula)
return ret;
for (i = 0; formula[i] != '\0' && formula[i] != '#'; i++) {
- if (formula[i] != 'f' || (i > 0 && isalnum(formula[i - 1])) ||
+ if ((i > 0 && isalnum(formula[i - 1])) || formula[i] != 'f' ||
!isdigit(formula[i + 1]) ||
sscanf(&formula[i], "f%d", &which) != 1)
continue;
diff --git a/FICS/gamedb.c b/FICS/gamedb.c
index 7d094c2..2656447 100644
--- a/FICS/gamedb.c
+++ b/FICS/gamedb.c
@@ -42,6 +42,7 @@
Markus Uhlin 25/04/01 Fixed call of risky function
Markus Uhlin 25/04/01 ReadV1GameFmt: guard num half
moves.
+ Markus Uhlin 25/04/06 Fixed Clang Tidy warnings.
*/
#include "stdinclude.h"
@@ -1067,10 +1068,16 @@ got_attr_value(int g, char *attr, char *value, FILE *fp, char *file)
} else if (!strcmp(attr, "type:")) {
garray[g].type = atoi(value);
} else if (!strcmp(attr, "halfmoves:")) {
- garray[g].numHalfMoves = atoi(value);
-
- if (garray[g].numHalfMoves == 0)
+ if ((garray[g].numHalfMoves = atoi(value)) == 0)
return 0;
+ else if (garray[g].numHalfMoves < 0 ||
+ (size_t)garray[g].numHalfMoves > INT_MAX / sizeof(move_t)) {
+ warnx("%s: num half moves out-of-bounds (%d)", __func__,
+ garray[g].numHalfMoves);
+ return -1;
+ } else {
+ /* null */;
+ }
garray[g].moveListSize = garray[g].numHalfMoves;
garray[g].moveList = reallocarray(NULL, sizeof(move_t),
@@ -1275,8 +1282,10 @@ ReadV1GameFmt(game *g, FILE *fp, const char *file, int version)
_Static_assert(17 < ARRAY_SIZE(g->black_name), "Unexpected array size");
ret[0] = fscanf(fp, "%17s %17s", g->white_name, g->black_name);
- ret[1] = fscanf(fp, "%d %d", &g->white_rating, &g->black_rating);
- ret[2] = fscanf(fp, "%d %d %d %d",
+ ret[1] = fscanf(fp, "%d %d", // NOLINT
+ &g->white_rating,
+ &g->black_rating);
+ ret[2] = fscanf(fp, "%d %d %d %d", // NOLINT
&g->wInitTime,
&g->wIncrement,
&g->bInitTime,
@@ -1319,7 +1328,7 @@ ReadV1GameFmt(game *g, FILE *fp, const char *file, int version)
ret[0] = fscanf(fp, "%d %d %d %d", &g->private, &g->type, &g->rated,
&g->clockStopped);
- ret[1] = fscanf(fp, "%d", &g->numHalfMoves);
+ ret[1] = fscanf(fp, "%d", &g->numHalfMoves); // NOLINT
if (ret[0] != 4 || ret[1] != 1) {
warnx("%s: fscanf error: %s", __func__, file);
return -1;
@@ -1639,10 +1648,9 @@ RemoveHistGame(char *file, int maxlines)
char Opponent[MAX_LOGIN_NAME + 1] = { '\0' };
char line[MAX_LINE_SIZE] = { '\0' };
int count = 0;
- long int When, oppWhen;
+ long int When = 0, oppWhen = 0;
_Static_assert(20 < ARRAY_SIZE(Opponent), "Not within bounds");
- When = oppWhen = 0;
if ((fp = fopen(file, "r")) == NULL) {
return;
diff --git a/FICS/gamedb.h b/FICS/gamedb.h
index 2d0edc8..8dc84d3 100644
--- a/FICS/gamedb.h
+++ b/FICS/gamedb.h
@@ -27,6 +27,7 @@
#ifndef _GAMEDB_H
#define _GAMEDB_H
+#include <stdint.h>
#include <time.h>
#include "board.h"
@@ -140,9 +141,9 @@ typedef struct _game {
move_t *examMoveList; // Extra movelist for examine
int examMoveListSize;
- unsigned int startTime; // The relative time the game started
- unsigned int lastMoveTime; // Last time a move was made
- unsigned int lastDecTime; // Last time a players clock was
+ uint64_t startTime; // The relative time the game started
+ uint64_t lastMoveTime; // Last time a move was made
+ uint64_t lastDecTime; // Last time a players clock was
// decremented
int result;
diff --git a/FICS/gameproc.c b/FICS/gameproc.c
index eea5205..cd6398e 100644
--- a/FICS/gameproc.c
+++ b/FICS/gameproc.c
@@ -1834,7 +1834,11 @@ com_goboard(int p, param_list param)
}
on = parray[p].simul_info.onBoard;
- g = parray[p].simul_info.boards[on];
+
+ if ((g = parray[p].simul_info.boards[on]) < 0) {
+ pprintf(p, "Internal error! Unexpected negative value!\n");
+ return COM_OK;
+ }
if (p1 == garray[g].black) {
pprintf(p, "You are already at that board!\n");
diff --git a/FICS/lists.c b/FICS/lists.c
index d9879d4..e3f2873 100644
--- a/FICS/lists.c
+++ b/FICS/lists.c
@@ -60,7 +60,14 @@ list_find(int p, enum ListWhich l)
int personal;
personal = ListArray[l].rights == P_PERSONAL;
- starter = (personal ? &parray[p].lists : &firstGlobalList);
+
+ if (personal) {
+ if (p < 0)
+ return NULL;
+ starter = &parray[p].lists;
+ } else {
+ starter = &firstGlobalList;
+ }
for (tempList = *starter; tempList != NULL; tempList = tempList->next) {
if (l == tempList->which) {
diff --git a/FICS/matchproc.c b/FICS/matchproc.c
index fb13439..1b1eab8 100644
--- a/FICS/matchproc.c
+++ b/FICS/matchproc.c
@@ -1079,7 +1079,10 @@ com_match(int p, param_list param)
.wt = wt,
};
- print_bughouse(p, p1, &ctx, colorstr);
+ if (ctx.white >= 0)
+ print_bughouse(p, p1, &ctx, colorstr);
+ else
+ warnx("%s: cannot print bughouse", __func__);
}
if (in_list(p, L_COMPUTER, parray[p].name)) {
diff --git a/FICS/network.c b/FICS/network.c
index b795e99..1e97e20 100644
--- a/FICS/network.c
+++ b/FICS/network.c
@@ -267,7 +267,7 @@ net_send_string(int fd, char *str, int format)
if ((which = findConnection(fd)) < 0)
return -1;
while (*str) {
- const int upbound = strlen(str);
+ const int upbound = (int)strlen(str);
for (i = 0; i < upbound && str[i] >= ' '; i++) {
/* null */;
@@ -314,6 +314,7 @@ net_send_string(int fd, char *str, int format)
break;
case '\033':
con[which].outPos -= 3;
+ // XXX: fallthrough here?
default:
sendme(which, str, 1);
}
diff --git a/FICS/obsproc.c b/FICS/obsproc.c
index 966e30e..2353c60 100644
--- a/FICS/obsproc.c
+++ b/FICS/obsproc.c
@@ -32,6 +32,7 @@
Markus Uhlin 25/01/18 Fixed -Wshadow
Markus Uhlin 25/03/15 Fixed possible buffer overflow
in FindHistory2().
+ Markus Uhlin 25/04/06 Fixed Clang Tidy warnings.
*/
#include "stdinclude.h"
@@ -152,6 +153,9 @@ com_games(int p, param_list param)
wp = garray[i].white;
bp = garray[i].black;
+ UNUSED_VAR(wp);
+ UNUSED_VAR(bp);
+
if ((!selected) &&
s &&
strncasecmp(s, garray[i].white_name, slen) &&
@@ -380,9 +384,8 @@ com_allobservers(int p, param_list param)
start = 0;
end = g_num;
} else if ((obgame >= g_num) ||
- ((obgame < g_num) &&
- ((garray[obgame].status != GAME_ACTIVE) &&
- (garray[obgame].status != GAME_EXAMINE)))) {
+ (garray[obgame].status != GAME_ACTIVE &&
+ garray[obgame].status != GAME_EXAMINE)) {
pprintf(p, "There is no such game.\n");
return COM_OK;
} else {
@@ -980,11 +983,16 @@ FindHistory(int p, int p1, int p_game)
ret = fscanf(fpHist, "%d %*c %*d %*c %*d %*s %*s %*d %*d %*d "
"%*d %*s %*s %ld", &index, &when);
- if (ret != 2)
- warn("%s: %s: corrupt", __func__, &fileName[0]);
- } while (!feof(fpHist) && index != p_game);
+ if (ret != 2) {
+ warnx("%s: %s: corrupt", __func__, fileName);
+ fclose(fpHist);
+ return NULL;
+ }
+ } while (!feof(fpHist) &&
+ !ferror(fpHist) &&
+ index != p_game);
- if (feof(fpHist)) {
+ if (feof(fpHist) || ferror(fpHist)) {
pprintf(p, "There is no history game %d for %s.\n", p_game,
parray[p1].name);
fclose(fpHist);
@@ -1019,11 +1027,16 @@ FindHistory2(int p, int p1, int p_game, char *End, const size_t End_size)
"%%*d %%*d %%*d %%*s %%%zus %%ld\n", (End_size - 1));
do {
- if (fscanf(fpHist, fmt, &index, End, &when) != 3)
- warn("%s: %s: corrupt", __func__, &fileName[0]);
- } while (!feof(fpHist) && index != p_game);
+ if (fscanf(fpHist, fmt, &index, End, &when) != 3) {
+ warnx("%s: %s: corrupt", __func__, fileName);
+ fclose(fpHist);
+ return NULL;
+ }
+ } while (!feof(fpHist) &&
+ !ferror(fpHist) &&
+ index != p_game);
- if (feof(fpHist)) {
+ if (feof(fpHist) || ferror(fpHist)) {
pprintf(p, "There is no history game %d for %s.\n", p_game,
parray[p1].name);
fclose(fpHist);
diff --git a/FICS/playerdb.c b/FICS/playerdb.c
index 06694ab..c85ec0c 100644
--- a/FICS/playerdb.c
+++ b/FICS/playerdb.c
@@ -45,6 +45,7 @@
read/write.
Markus Uhlin 25/04/02 add_to_list: added an upper
limit for the list size.
+ Markus Uhlin 25/04/06 Fixed Clang Tidy warnings.
*/
#include "stdinclude.h"
@@ -412,8 +413,8 @@ add_to_list(FILE *fp, enum ListWhich lw, int *size, int p)
#define SCAN_STR "%1023s"
if (*size <= 0 || *size > MAX_GLOBAL_LIST_SIZE) {
- warnx("%s: illegal list size (%d)", __func__, *size);
- return -1;
+// warnx("%s: illegal list size (%d)", __func__, *size);
+ return -2;
}
while ((*size)-- > 0 && fscanf(fp, SCAN_STR, buf) == 1)
@@ -441,7 +442,7 @@ ReadV1PlayerFmt(int p, player *pp, FILE *fp, char *file, int version)
/*
* Name
*/
- if (fgets(tmp2, sizeof tmp2, fp) != NULL &&
+ if (fgets(tmp2, sizeof tmp2, fp) != NULL && // NOLINT
strcmp(tmp2, "NONE\n") != 0) {
tmp2[strcspn(tmp2, "\n")] = '\0';
pp->name = xstrdup(tmp2);
@@ -452,7 +453,7 @@ ReadV1PlayerFmt(int p, player *pp, FILE *fp, char *file, int version)
/*
* Full name
*/
- if (fgets(tmp2, sizeof tmp2, fp) != NULL &&
+ if (fgets(tmp2, sizeof tmp2, fp) != NULL && // NOLINT
strcmp(tmp2, "NONE\n") != 0) {
tmp2[strcspn(tmp2, "\n")] = '\0';
pp->fullName = xstrdup(tmp2);
@@ -463,7 +464,7 @@ ReadV1PlayerFmt(int p, player *pp, FILE *fp, char *file, int version)
/*
* Password
*/
- if (fgets(tmp2, sizeof tmp2, fp) != NULL &&
+ if (fgets(tmp2, sizeof tmp2, fp) != NULL && // NOLINT
strcmp(tmp2, "NONE\n") != 0) {
tmp2[strcspn(tmp2, "\n")] = '\0';
pp->passwd = xstrdup(tmp2);
@@ -474,7 +475,7 @@ ReadV1PlayerFmt(int p, player *pp, FILE *fp, char *file, int version)
/*
* Email
*/
- if (fgets(tmp2, sizeof tmp2, fp) != NULL &&
+ if (fgets(tmp2, sizeof tmp2, fp) != NULL && // NOLINT
strcmp(tmp2, "NONE\n") != 0) {
tmp2[strcspn(tmp2, "\n")] = '\0';
pp->emailAddress = xstrdup(tmp2);
@@ -482,7 +483,9 @@ ReadV1PlayerFmt(int p, player *pp, FILE *fp, char *file, int version)
pp->emailAddress = NULL;
}
- if (fscanf(fp, "%d %d %d %d %d %d %jd %d %jd %d %d %d %d %d %d %jd %d %jd "
+ if (feof(fp) ||
+ ferror(fp) ||
+ fscanf(fp, "%d %d %d %d %d %d %jd %d %jd %d %d %d %d %d %d %jd %d %jd "
"%d %d %d %d %d %d %jd %d %jd %d %d %d %d %d %d %jd %d %jd %d %d %d %d "
"%d %d %jd %d %jd %u\n",
&pp->s_stats.num, &pp->s_stats.win, &pp->s_stats.los,
@@ -584,17 +587,17 @@ ReadV1PlayerFmt(int p, player *pp, FILE *fp, char *file, int version)
pp->timeOfReg = array[0];
pp->totalTime = array[1];
- if (pp->num_plan > MAX_PLAN) {
+ if (pp->num_plan >= MAX_PLAN) {
warnx("Player %s is corrupt\nToo many plans (%d)",
parray[p].name,
pp->num_plan);
return;
- } else if (pp->num_formula > MAX_FORMULA) {
+ } else if (pp->num_formula >= MAX_FORMULA) {
warnx("Player %s is corrupt\nToo many formulas (%d)",
parray[p].name,
pp->num_formula);
return;
- } else if (pp->numAlias > MAX_ALIASES) {
+ } else if (pp->numAlias >= MAX_ALIASES) {
warnx("Player %s is corrupt\nToo many aliases (%d)",
parray[p].name,
pp->numAlias);
@@ -665,14 +668,13 @@ ReadV1PlayerFmt(int p, player *pp, FILE *fp, char *file, int version)
return;
}
- if (!(len = strlen(tmp2))) {
+ if (!strlen(tmp2)) { // XXX
fprintf(stderr, "FICS: Error bad alias in "
"file %s\n", file);
i--;
pp->numAlias--;
} else {
tmp2[strcspn(tmp2, "\n")] = '\0';
- tmp = tmp2;
tmp = eatword(tmp2);
*tmp = '\0';
tmp++;
@@ -857,9 +859,11 @@ got_attr_value_player(int p, char *attr, char *value, FILE *fp, char *file)
* num_plan
*/
- parray[p].num_plan = atoi(value);
-
- if (parray[p].num_plan > 0) {
+ if ((parray[p].num_plan = atoi(value)) >= MAX_PLAN) {
+ warnx("%s: %s: too many plans (%d)", __func__, file,
+ parray[p].num_plan);
+ return -1;
+ } else if (parray[p].num_plan > 0) {
for (i = 0; i < parray[p].num_plan; i++) {
if (fgets(tmp, sizeof tmp, fp) == NULL) {
@@ -881,15 +885,19 @@ got_attr_value_player(int p, char *attr, char *value, FILE *fp, char *file)
xstrdup(tmp) : NULL);
}
}
+ } else {
+ /* null */;
}
} else if (!strcmp(attr, "num_formula:")) {
/*
* num_formula
*/
- parray[p].num_formula = atoi(value);
-
- if (parray[p].num_formula > 0) {
+ if ((parray[p].num_formula = atoi(value)) >= MAX_FORMULA) {
+ warnx("%s: %s: too many formulas (%d)", __func__, file,
+ parray[p].num_formula);
+ return -1;
+ } else if (parray[p].num_formula > 0) {
for (i = 0; i < parray[p].num_formula; i++) {
if (fgets(tmp, sizeof tmp, fp) == NULL) {
warnx("%s: bad formula: feof %s",
@@ -910,6 +918,8 @@ got_attr_value_player(int p, char *attr, char *value, FILE *fp, char *file)
xstrdup(tmp) : NULL);
}
}
+ } else {
+ /* null */;
}
} else if (!strcmp(attr, "formula:")) {
/*
@@ -922,9 +932,11 @@ got_attr_value_player(int p, char *attr, char *value, FILE *fp, char *file)
* num_alias
*/
- parray[p].numAlias = atoi(value);
-
- if (parray[p].numAlias > 0) {
+ if ((parray[p].numAlias = atoi(value)) >= MAX_ALIASES) {
+ warnx("%s: %s: too many aliases (%d)", __func__, file,
+ parray[p].numAlias);
+ return -1;
+ } else if (parray[p].numAlias > 0) {
for (i = 0; i < parray[p].numAlias; i++) {
if (fgets(tmp, sizeof tmp, fp) == NULL) {
warnx("%s: bad alias: feof %s",
@@ -932,7 +944,7 @@ got_attr_value_player(int p, char *attr, char *value, FILE *fp, char *file)
return -1;
}
- if (!(len = strlen(tmp))) {
+ if (!strlen(tmp)) { // XXX
fprintf(stderr, "FICS: Error bad alias "
"in file %s\n", file);
i--;
@@ -951,13 +963,21 @@ got_attr_value_player(int p, char *attr, char *value, FILE *fp, char *file)
xstrdup(tmp1);
}
}
+ } else {
+ /* null */;
}
} else if (!strcmp(attr, "num_censor:")) {
/*
* num_censor
*/
- i = atoi(value);
+ if ((i = atoi(value)) < 0) {
+ warnx("%s: num censor negative", __func__);
+ return -1;
+ } else if (i > MAX_CENSOR) {
+ warnx("%s: num censor too large", __func__);
+ return -1;
+ }
while (i--) {
if (fgets(tmp, sizeof tmp, fp) == NULL) {
@@ -976,7 +996,13 @@ got_attr_value_player(int p, char *attr, char *value, FILE *fp, char *file)
}
}
} else if (!strcmp(attr, "num_notify:")) {
- i = atoi(value);
+ if ((i = atoi(value)) < 0) {
+ warnx("%s: num notify negative", __func__);
+ return -1;
+ } else if (i > MAX_NOTIFY) {
+ warnx("%s: num notify too large", __func__);
+ return -1;
+ }
while (i--) {
if (fgets(tmp, sizeof tmp, fp) == NULL) {
@@ -995,7 +1021,10 @@ got_attr_value_player(int p, char *attr, char *value, FILE *fp, char *file)
}
}
} else if (!strcmp(attr, "num_noplay:")) {
- i = atoi(value);
+ if ((i = atoi(value)) < 0) {
+ warnx("%s: num noplay negative", __func__);
+ return -1;
+ }
while (i--) {
if (fgets(tmp, sizeof tmp, fp) == NULL) {
@@ -1014,7 +1043,10 @@ got_attr_value_player(int p, char *attr, char *value, FILE *fp, char *file)
}
}
} else if (!strcmp(attr, "num_gnotify:")) {
- i = atoi(value);
+ if ((i = atoi(value)) < 0) {
+ warnx("%s: num gnotify negative", __func__);
+ return -1;
+ }
while (i--) {
if (fgets(tmp, sizeof tmp, fp) == NULL) {
@@ -2338,7 +2370,6 @@ player_goto_next_board(int p)
on = parray[p].simul_info.onBoard;
start = on;
- g = -1;
do {
on++;
@@ -2367,7 +2398,6 @@ player_goto_prev_board(int p)
on = parray[p].simul_info.onBoard;
start = on;
- g = -1;
do {
--on;
@@ -2806,7 +2836,7 @@ player_show_messages(int p)
PUBLIC int
ShowMsgsBySender(int p, param_list param)
{
- int nFrom, nTo;
+ int nFrom = -1, nTo = -1;
int p1, connected;
textlist *Head;
@@ -2819,8 +2849,6 @@ ShowMsgsBySender(int p, param_list param)
return -1; /* no need to disconnect */
}
- nFrom = nTo = -1;
-
if (p != p1) {
if ((nTo = LoadMsgs(p1, p + 1, &Head)) <= 0) {
pprintf(p, "%s has no messages from you.\n",
diff --git a/FICS/ratings.c b/FICS/ratings.c
index 3a7cdd0..e445c51 100644
--- a/FICS/ratings.c
+++ b/FICS/ratings.c
@@ -32,6 +32,7 @@
fixed ignored retvals.
Markus Uhlin 24/11/28 Added null checks
Markus Uhlin 25/03/16 Fixed use of 32-bit 'time_t'.
+ Markus Uhlin 25/04/06 Fixed Clang Tidy warnings.
*/
#include "stdinclude.h"
@@ -39,6 +40,7 @@
#include <err.h>
#include <errno.h>
+#include <limits.h>
#include <stdint.h>
#include "command.h"
@@ -347,49 +349,52 @@ load_ratings(void)
return;
}
- for (int i = 0; i < MAXHIST; i++) {
- int ret, errno_save;
+ for (int i = 0; i < MAXHIST && !feof(fp) && !ferror(fp); i++) {
+ int ret;
sHist[i] = bHist[i] = wHist[i] = lHist[i] = 0;
- errno = 0;
ret = fscanf(fp, "%d %d %d %d", &sHist[i], &bHist[i], &wHist[i],
&lHist[i]);
- errno_save = errno;
if (ret != 4) {
- if (feof(fp) || ferror(fp))
- break;
- errno = errno_save;
- warn("%s: too few items assigned (iteration: %d)",
- __func__, i);
+ warnx("%s: %s: too few items assigned (iteration: %d)",
+ __func__, fname, i);
+ fclose(fp);
+ return;
}
}
+ if (ferror(fp)) {
+ warnx("%s: %s: the error indicator is set", __func__, fname);
+ fclose(fp);
+ return;
+ }
+
fclose(fp);
- if (Rs_count) {
- Ratings_S_StdDev = sqrt(Rs_S / Rs_count);
+ if (Rs_count != 0) {
+ Ratings_S_StdDev = sqrt(Rs_S / Rs_count); // NOLINT
Ratings_S_Average = (Rs_total / (double)Rs_count);
} else {
Ratings_S_StdDev = 0;
Ratings_S_Average = 0;
}
- if (Rb_count) {
- Ratings_B_StdDev = sqrt(Rb_S / Rb_count);
+ if (Rb_count != 0) {
+ Ratings_B_StdDev = sqrt(Rb_S / Rb_count); // NOLINT
Ratings_B_Average = (Rb_total / (double)Rb_count);
} else {
Ratings_B_StdDev = 0;
Ratings_B_Average = 0;
}
- if (Rw_count) {
- Ratings_W_StdDev = sqrt(Rw_S / Rw_count);
+ if (Rw_count != 0) {
+ Ratings_W_StdDev = sqrt(Rw_S / Rw_count); // NOLINT
Ratings_W_Average = (Rw_total / (double)Rw_count);
} else {
Ratings_W_StdDev = 0;
Ratings_W_Average = 0;
}
- if (Rl_count) {
- Ratings_L_StdDev = sqrt(Rl_S / Rl_count);
+ if (Rl_count != 0) {
+ Ratings_L_StdDev = sqrt(Rl_S / Rl_count); // NOLINT
Ratings_L_Average = (Rl_total / (double)Rl_count);
} else {
Ratings_L_StdDev = 0;
@@ -1303,6 +1308,18 @@ com_statistics(int p, param_list param)
return COM_OK;
}
+/*
+ * Return the difference of 'a - b'
+ */
+PUBLIC int
+int_diff(const char *fn, const int a, const int b)
+{
+ if ((b > 0 && a < INT_MIN + b) ||
+ (b < 0 && a > INT_MAX + b))
+ errx(1, "%s: integer overflow (%d - %d)", fn, a, b);
+ return (a - b);
+}
+
PUBLIC int
com_fixrank(int p, param_list param)
{
@@ -1582,16 +1599,20 @@ PositionFilePtr(FILE *fp, int count, int *last, int *nTied, int showComp)
return;
rating = nGames = is_computer = 0;
+ errno = 0;
rewind(fp);
+ if (errno) {
+ warn("%s: rewind", __func__);
+ return;
+ }
for (int i = 1; i < count; i++) {
do {
_Static_assert(ARRAY_SIZE(login) > 19,
"'login' too small");
- if (fgets(line, sizeof line, fp) == NULL ||
- feof(fp) ||
- ferror(fp))
+ if (feof(fp) || ferror(fp) ||
+ fgets(line, sizeof line, fp) == NULL)
break;
else if (sscanf(line, "%19s %d %d %d", login, &rating,
&nGames, &is_computer) != 4) {
@@ -1600,6 +1621,11 @@ PositionFilePtr(FILE *fp, int count, int *last, int *nTied, int showComp)
}
} while (!CountRankLine(showComp, login, nGames, is_computer));
+ if (ferror(fp)) {
+ warnx("%s: the error indicator is set", __func__);
+ return;
+ }
+
if (rating != *last) {
*nTied = 1;
*last = rating;
@@ -1618,7 +1644,7 @@ ShowRankEntry(int p, FILE *fp, int count, int comp, char *target,
// XXX
rating = 0;
- findable = (count > 0 && !feof(fp));
+ findable = (count > 0 && !feof(fp) && !ferror(fp));
nGames = 0;
is_comp = 0;
@@ -1815,9 +1841,9 @@ DisplayTargetRank(int p, char *target, int show, int showComp)
numAbove = CountAbove(numToShow, blitzRank, stdRank, wildRank, show);
- blitzCount = (blitzRank - numAbove);
- stdCount = (stdRank - numAbove);
- wildCount = (wildRank - numAbove);
+ blitzCount = int_diff(__func__, blitzRank, numAbove);
+ stdCount = int_diff(__func__, stdRank, numAbove);
+ wildCount = int_diff(__func__, wildRank, numAbove);
ShowRankLines(p, fb, fs, fw, blitzCount, stdCount, wildCount, numToShow,
showComp, show, target);
diff --git a/FICS/ratings.h b/FICS/ratings.h
index 4cf47a8..7f2a521 100644
--- a/FICS/ratings.h
+++ b/FICS/ratings.h
@@ -26,6 +26,8 @@
#ifndef _RATINGS_H
#define _RATINGS_H
+#include "common.h"
+
#define STATS_VERSION 2
#define RESULT_WIN 0
@@ -49,6 +51,7 @@ typedef struct _rateStruct {
int rating;
} rateStruct;
+__FICS_BEGIN_DECLS
extern int Best(int, param_list, int);
extern int DisplayRank(int, param_list, int);
extern int DisplayRankedPlayers(int, int, int, int, int);
@@ -61,6 +64,7 @@ extern int com_hbest(int, param_list);
extern int com_hrank(int, param_list);
extern int com_rank(int, param_list);
extern int com_statistics(int, param_list);
+extern int int_diff(const char *, const int, const int);
extern int is_active(int);
extern int rating_delta(int, int, int, int, int);
extern int rating_update(int);
@@ -72,5 +76,6 @@ extern void rating_recalc(void);
extern void rating_remove(int, int);
extern void rating_sterr_delta(int, int, int, time_t, int, int *, double *);
extern void save_ratings(void);
+__FICS_END_DECLS
#endif /* _RATINGS_H */
diff --git a/FICS/talkproc.c b/FICS/talkproc.c
index 3d16be1..601f43b 100644
--- a/FICS/talkproc.c
+++ b/FICS/talkproc.c
@@ -34,6 +34,8 @@
Markus Uhlin 24/04/14 Refactored and reformatted ALL
functions.
Markus Uhlin 25/01/18 Fixed -Wshadow
+ Markus Uhlin 25/04/04 tell: fixed constant expression
+ result
*/
#include "stdinclude.h"
@@ -296,8 +298,8 @@ tell(int p, int p1, char *msg, int why, int ch)
}
if (player_censored(p1, p) && parray[p].adminLevel == 0) {
- if (why != TELL_KIBITZ ||
- why != TELL_WHISPER ||
+ if (why != TELL_KIBITZ &&
+ why != TELL_WHISPER &&
why != TELL_CHANNEL) {
pprintf(p, "Player \"%s\" is censoring you.\n",
parray[p1].name);
diff --git a/FICS/utils.c b/FICS/utils.c
index ce02a5d..fd0a8e3 100644
--- a/FICS/utils.c
+++ b/FICS/utils.c
@@ -38,6 +38,7 @@
in truncate_file().
Markus Uhlin 25/03/09 truncate_file:
fixed null ptr dereference.
+ Markus Uhlin 25/04/06 Fixed Clang Tidy warnings.
*/
#include "stdinclude.h"
@@ -275,10 +276,10 @@ pcommand(int p, char *comstr, ...)
return retval;
}
-PUBLIC int
+PUBLIC void
pprintf(int p, const char *format, ...)
{
- char tmp[10 * MAX_LINE_SIZE];
+ char tmp[10 * MAX_LINE_SIZE] = { '\0' };
int retval;
va_list ap;
@@ -286,8 +287,8 @@ pprintf(int p, const char *format, ...)
retval = vsnprintf(tmp, sizeof tmp, format, ap);
va_end(ap);
+ UNUSED_VAR(retval);
net_send_string(parray[p].socket, tmp, 1);
- return retval;
}
PRIVATE void
@@ -393,7 +394,7 @@ pprintf_noformat(int p, char *format, ...)
}
PUBLIC int
-psend_raw_file(int p, char *dir, char *file)
+psend_raw_file(int p, const char *dir, const char *file)
{
FILE *fp;
char fname[MAX_FILENAME_SIZE] = { '\0' };
@@ -408,9 +409,18 @@ psend_raw_file(int p, char *dir, char *file)
if ((fp = fopen(fname, "r")) == NULL)
return -1;
- while ((num = fread(tmp, sizeof(char), MAX_LINE_SIZE - 1, fp)) > 0) {
- tmp[num] = '\0';
- net_send_string(parray[p].socket, tmp, 1);
+ while (!feof(fp) && !ferror(fp)) {
+ if ((num = fread(tmp, sizeof(char), MAX_LINE_SIZE - 1,
+ fp)) > 0) {
+ tmp[num] = '\0';
+ net_send_string(parray[p].socket, tmp, 1);
+ }
+ }
+
+ if (ferror(fp)) {
+ warnx("%s: %s: the error indicator is set", __func__, fname);
+ fclose(fp);
+ return -1;
}
fclose(fp);
@@ -418,7 +428,7 @@ psend_raw_file(int p, char *dir, char *file)
}
PUBLIC int
-psend_file(int p, char *dir, char *file)
+psend_file(int p, const char *dir, const char *file)
{
FILE *fp;
char fname[MAX_FILENAME_SIZE] = { '\0' };
@@ -445,6 +455,12 @@ psend_file(int p, char *dir, char *file)
}
if (!feof(fp)) {
+ if (ferror(fp)) {
+ warnx("%s: %s: the error indicator is set", __func__,
+ fname);
+ fclose(fp);
+ return -1;
+ }
parray[p].last_file = xstrdup(fname);
parray[p].last_file_byte = ftell(fp);
pprintf(p, "Type [next] to see next page.\n");
@@ -513,8 +529,17 @@ pmore_file(int p)
}
if (!feof(fp)) {
- parray[p].last_file_byte = ftell(fp);
- pprintf(p, "Type [next] to see next page.\n");
+ if (ferror(fp)) {
+ warnx("%s: %s: the error indicator is set", __func__,
+ parray[p].last_file);
+ fclose(fp);
+ return -1;
+ } else if ((parray[p].last_file_byte = ftell(fp)) == -1) {
+ warn("%s: %s: ftell", __func__, parray[p].last_file);
+ fclose(fp);
+ return -1;
+ } else
+ pprintf(p, "Type [next] to see next page.\n");
} else {
rfree(parray[p].last_file);
parray[p].last_file = NULL;
@@ -964,10 +989,11 @@ ratstrii(int rat, int reg)
* Fill 't_buffer' with anything matching "want*" in file tree
*/
PRIVATE void
-t_sft(char *want, struct t_tree *t)
+t_sft(const char *want, struct t_tree *t)
{
if (t) {
- int cmp = strncmp(want, t->name, strlen(want));
+ const char *v_want = (want ? want : "");
+ int cmp = strncmp(v_want, t->name, strlen(v_want));
if (cmp <= 0) // If 'want' <= this one, look left
t_sft(want, t->left);
@@ -1050,7 +1076,6 @@ PUBLIC int
search_directory(char *dir, char *filter, char **buffer, int buffersize)
{
int cmp;
- static char nullify = '\0';
static struct t_dirs *ramdirs = NULL;
struct stat statbuf;
struct t_dirs** i;
@@ -1059,9 +1084,6 @@ search_directory(char *dir, char *filter, char **buffer, int buffersize)
t_buffersize = buffersize;
if (!stat(dir, &statbuf)) {
- if (filter == NULL) // NULL becomes pointer to null string
- filter = &nullify;
-
i = &ramdirs;
while (*i) { // Find dir in dir tree
diff --git a/FICS/utils.h b/FICS/utils.h
index 5342be2..8f53882 100644
--- a/FICS/utils.h
+++ b/FICS/utils.h
@@ -90,15 +90,15 @@ extern int mail_string_to_address(char *, char *, char *);
extern int mail_string_to_user(int, char *, char *);
extern int pcommand(int, char *, ...) PRINTFLIKE(2);
extern int pmore_file(int);
-extern int pprintf(int, const char *, ...) PRINTFLIKE(2);
+extern void pprintf(int, const char *, ...) PRINTFLIKE(2);
extern int pprintf_highlight(int, char *, ...) PRINTFLIKE(2);
extern int pprintf_noformat(int, char *, ...) PRINTFLIKE(2);
extern int pprintf_prompt(int, char *, ...) PRINTFLIKE(2);
extern int printablestring(char *);
extern int psend_command(int, char *, char *);
-extern int psend_file(int, char *, char *);
+extern int psend_file(int, const char *, const char *);
extern int psend_logoutfile(int, char *, char *);
-extern int psend_raw_file(int, char *, char *);
+extern int psend_raw_file(int, const char *, const char *);
extern int psprintf_highlight(int, char *, size_t, char *, ...)
PRINTFLIKE(4);
extern int safechar(int);
diff --git a/FICS/vers.c b/FICS/vers.c
index d556d4a..c6dd99c 100644
--- a/FICS/vers.c
+++ b/FICS/vers.c
@@ -1,5 +1,5 @@
#include "vers.h"
const char SGS_VERS[] = "";
-const char VERS_NUM[] = "rpblc-1.4.4";
+const char VERS_NUM[] = "rpblc-1.4.5";
const char COMP_DATE[] = __DATE__;
diff --git a/GNUmakefile b/GNUmakefile
index f94b0a4..cf29782 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -14,7 +14,8 @@ include FICS/build.mk
# common rules
include common.mk
-.PHONY: clean install-init install
+.PHONY: clean install-init install tidy
include $(TARGETS_DIR)clean.mk
include $(TARGETS_DIR)install.mk
+include $(TARGETS_DIR)tidy.mk
diff --git a/README.md b/README.md
index b41219d..676df1a 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# README #
+![Coverity Scan Build Status](https://scan.coverity.com/projects/31462/badge.svg)
+
## About ##
This is a fork of FICS(Free Internet Chess Server) version 1.6.2 made
@@ -12,6 +14,18 @@ The main goal of the fork is to modernize the codebase, improve the
security and fix bugs. New features, for example, other chess variants
will be added in a later stage.
+### Public chess server ###
+
+[IRCNow](https://ircnow.org/)
+provides a
+[public chess server](https://wiki.ircnow.org/index.php?n=Chess.Chess)
+for everyone to use!
+
+To connect to the server by using
+[XBoard](https://www.gnu.org/software/xboard/), try:
+
+ $ xboard -ics -icshost rpblc.net
+
### IPv6 ###
IPv6 connections are at the moment not supported.
diff --git a/include/colors.h b/include/colors.h
new file mode 100644
index 0000000..6902138
--- /dev/null
+++ b/include/colors.h
@@ -0,0 +1,81 @@
+/* Copyright (c) 2019 Markus Uhlin <markus.uhlin@icloud.com>
+ All rights reserved.
+
+ Permission to use, copy, modify, and distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef _COLORS_H_
+#define _COLORS_H_
+
+/*
+ * Reset all attributes to their defaults
+ */
+#define NORMAL "\x1b[0m"
+
+#define UNDERLINE_ON "\x1b[4m"
+#define UNDERLINE_OFF "\x1b[24m"
+
+#define BLINK_ON "\x1b[5m"
+#define BLINK_OFF "\x1b[25m"
+
+/*
+ * Reverse video
+ */
+#define REVVID_ON "\x1b[7m"
+#define REVVID_OFF "\x1b[27m"
+
+#define BLACK "\x1b[30m"
+#define RED "\x1b[31m"
+#define GREEN "\x1b[32m"
+#define BROWN "\x1b[33m"
+#define BLUE "\x1b[34m"
+#define MAGENTA "\x1b[35m"
+#define CYAN "\x1b[36m"
+#define WHITE "\x1b[37m"
+
+#define BOLDBLACK "\x1b[1;30m"
+#define BOLDRED "\x1b[1;31m"
+#define BOLDGREEN "\x1b[1;32m"
+#define BOLDBROWN "\x1b[1;33m"
+#define BOLDBLUE "\x1b[1;34m"
+#define BOLDMAGENTA "\x1b[1;35m"
+#define BOLDCYAN "\x1b[1;36m"
+#define BOLDWHITE "\x1b[1;37m"
+
+#define UNDERSCORE_ON "\x1b[38m"
+#define UNDERSCORE_OFF "\x1b[39m"
+
+#define BGBLACK "\x1b[40m"
+#define BGRED "\x1b[41m"
+#define BGGREEN "\x1b[42m"
+#define BGBROWN "\x1b[43m"
+#define BGBLUE "\x1b[44m"
+#define BGMAGENTA "\x1b[45m"
+#define BGCYAN "\x1b[46m"
+#define BGWHITE "\x1b[47m"
+#define BGDEFAULT "\x1b[49m"
+
+#if defined(_WIN32) && defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+static void
+VirtualTerminalProcessing(void)
+{
+ HANDLE output_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+ DWORD modes = 0;
+
+ GetConsoleMode(output_handle, &modes);
+ modes |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
+ SetConsoleMode(output_handle, modes);
+}
+#endif
+
+#endif
diff --git a/maketargets/tidy.mk b/maketargets/tidy.mk
new file mode 100644
index 0000000..e52abe2
--- /dev/null
+++ b/maketargets/tidy.mk
@@ -0,0 +1,9 @@
+# The 'tidy' target
+
+TIDY = clang-tidy
+TIDYFLAGS = -checks=-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling -quiet
+FICS_CLANG_TIDYFLAGS ?=
+
+tidy: $(INCLUDE_DIR)ficspaths.h
+ $(TIDY) $(SRCS) $(TIDYFLAGS) $(FICS_CLANG_TIDYFLAGS) -- \
+ -I $(INCLUDE_DIR) $(CPPFLAGS)