From 647d9c762d4bc6211dca80af51415a30120814ed Mon Sep 17 00:00:00 2001
From: Augustin Fabre <augustin@augfab.fr>
Date: Fri, 24 Apr 2020 08:53:54 +0200
Subject: [PATCH] Declare function prototypes explicitly

This make it easier to manage separate compilation units (static functions and
global variables, local type definitions, etc.)

The generated header file `functions.h' caused a circular dependency problem;
it wasn't updated automatically when changes were made to the sources (e.g.
new function definition). The sources can't be in the dependency list of
`functions.h' in the Makefile, because `functions.h' is in the dependency list
of each source file. GNU make is able to ignore the circular dependency but not
BSD make.

At any rate, keeping the prototype list up-to-date is easy, because the
compiler will complain if a function is used in a compilation unit but defined
in an other one.

It also makes static analysis easier out of the box.
---
 .gitignore        |  1 -
 Makefile          | 12 +-----------
 src/file.c        |  2 +-
 src/gophernicus.c |  8 ++++----
 src/gophernicus.h | 45 ++++++++++++++++++++++++++++++++++++++++++++-
 src/menu.c        | 10 +++++-----
 src/options.c     |  2 +-
 src/session.c     |  2 +-
 8 files changed, 57 insertions(+), 25 deletions(-)

diff --git a/.gitignore b/.gitignore
index 25ca48e..c744658 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,6 @@
 src/*.o
 src/files.h
 src/filetypes.h
-src/functions.h
 src/bin2c
 src/gophernicus
 
diff --git a/Makefile b/Makefile
index da171b9..8fb6baf 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ VERSION = 3.1
 CODENAME = Dungeon Edition
 
 SOURCES = src/$(NAME).c src/file.c src/menu.c src/string.c src/platform.c src/session.c src/options.c
-HEADERS = src/functions.h src/files.h src/filetypes.h
+HEADERS = src/files.h src/filetypes.h
 OBJECTS = $(SOURCES:.c=.o)
 README = README.md
 DOCS = LICENSE README.md INSTALL.md changelog README.gophermap gophertag
@@ -66,16 +66,6 @@ src/$(BINARY): $(OBJECTS)
 .c.o:
 	$(CC) -c $(CFLAGS) -DVERSION="\"$(VERSION)\"" -DCODENAME="\"$(CODENAME)\"" -DDEFAULT_ROOT="\"$(ROOT)\"" $< -o $@
 
-src/functions.h:
-	echo "/* Automatically generated function definitions */" > $@
-	echo >> $@
-	grep -h "^[a-z]" $(SOURCES) | \
-		grep -v "int main" | \
-		grep -v "strlc" | \
-		grep -vi "[a-z]:" | \
-		sed -e "s/ =.*$$//" -e "s/ *$$/;/" >> $@
-	@echo
-
 src/filetypes.h: src/filetypes.conf
 	sh src/filetypes.sh < src/filetypes.conf > $@
 
diff --git a/src/file.c b/src/file.c
index 9910285..2e1e31a 100644
--- a/src/file.c
+++ b/src/file.c
@@ -365,7 +365,7 @@ void setenv_cgi(state *st, char *script)
 /*
  * Execute a CGI script
  */
-void run_cgi(state *st, char *script, char *arg)
+static void run_cgi(state *st, char *script, char *arg)
 {
 	if (st->opt_exec) {
 
diff --git a/src/gophernicus.c b/src/gophernicus.c
index 3788ff3..65544e2 100644
--- a/src/gophernicus.c
+++ b/src/gophernicus.c
@@ -197,7 +197,7 @@ void log_combined(state *st, int status)
 /*
  * Convert gopher selector to an absolute path
  */
-void selector_to_path(state *st)
+static void selector_to_path(state *st)
 {
 	DIR *dp;
 	struct dirent *dir;
@@ -309,7 +309,7 @@ void selector_to_path(state *st)
 /*
  * Get local IP address
  */
-char *get_local_address(void)
+static char *get_local_address(void)
 {
 #ifdef HAVE_IPv4
 	struct sockaddr_in addr;
@@ -350,7 +350,7 @@ char *get_local_address(void)
 /*
  * Get remote peer IP address
  */
-char *get_peer_address(void)
+static char *get_peer_address(void)
 {
 #ifdef HAVE_IPv4
 	struct sockaddr_in addr;
@@ -395,7 +395,7 @@ char *get_peer_address(void)
 /*
  * Initialize state struct to default/empty values
  */
-void init_state(state *st)
+static void init_state(state *st)
 {
 	static const char *filetypes[] = { FILETYPES };
 	char buf[BUFSIZE];
diff --git a/src/gophernicus.h b/src/gophernicus.h
index 65edbab..f332db5 100644
--- a/src/gophernicus.h
+++ b/src/gophernicus.h
@@ -437,8 +437,51 @@ typedef struct {
 /*
  * Include generated headers
  */
-#include "functions.h"
 #include "files.h"
 #include "filetypes.h"
 
+
+/* gophernicus.c */
+void info(state *st, char *str, char type);
+void footer(state *st);
+void die(state *st, const char *message, const char *description);
+void log_combined(state *st, int status);
+
+/* file.c */
+void send_binary_file(state *st);
+void send_text_file(state *st);
+void url_redirect(state *st);
+void server_status(state *st, shm_state *shm, int shmid);
+void caps_txt(state *st, shm_state *shm);
+void setenv_cgi(state *st, char *script);
+void gopher_file(state *st);
+
+/* menu.c */
+char gopher_filetype(state *st, char *file, char magic);
+void gopher_menu(state *st);
+
+/* string.c */
+void strrepeat(char *dest, char c, size_t num);
+void strreplace(char *str, char from, char to);
+size_t strcut(char *str, size_t width);
+char *strkey(char *header, char *key);
+char strlast(char *str);
+void chomp(char *str);
+char *strcharset(int charset);
+void strniconv(int charset, char *out, char *in, size_t outsize);
+void strnencode(char *out, const char *in, size_t outsize);
+void strndecode(char *out, char *in, size_t outsize);
+void strfsize(char *out, off_t size, size_t outsize);
+
+/* platform.c */
+void platform(state *st);
+float loadavg(void);
+
+/* session.c */
+void get_shm_session(state *st, shm_state *shm);
+void update_shm_session(state *st, shm_state *shm);
+
+/* options.c */
+void add_ftype_mapping(state *st, char *suffix);
+void parse_args(state *st, int argc, char *argv[]);
 #endif
diff --git a/src/menu.c b/src/menu.c
index 7a1be48..f9dd644 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -33,7 +33,7 @@
 /*
  * Alphabetic folders first sort for sortdir()
  */
-int foldersort(const void *a, const void *b)
+static int foldersort(const void *a, const void *b)
 {
 	mode_t amode;
 	mode_t bmode;
@@ -61,7 +61,7 @@ int datesort(const void *a, const void *b)
 /*
  * Scan, stat and sort a directory folders first (scandir replacement)
  */
-int sortdir(char *path, sdirent *list, int max)
+static int sortdir(char *path, sdirent *list, int max)
 {
 	DIR *dp;
 	struct dirent *d;
@@ -104,7 +104,7 @@ int sortdir(char *path, sdirent *list, int max)
  * Print a list of users with ~/public_gopher
  */
 #ifdef HAVE_PASSWD
-void userlist(state *st)
+static void userlist(state *st)
 {
 	struct passwd *pwd;
 	struct stat dir;
@@ -174,7 +174,7 @@ void userlist(state *st)
 /*
  * Print a list of available virtual hosts
  */
-void vhostlist(state *st)
+static void vhostlist(state *st)
 {
 	sdirent dir[MAX_SDIRENT];
 	struct tm *ltime;
@@ -298,7 +298,7 @@ char gopher_filetype(state *st, char *file, char magic)
 /*
  * Handle gophermaps
  */
-int gophermap(state *st, char *mapfile, int depth)
+static int gophermap(state *st, char *mapfile, int depth)
 {
 	FILE *fp;
 	struct stat file;
diff --git a/src/options.c b/src/options.c
index 2ead902..d9671e7 100644
--- a/src/options.c
+++ b/src/options.c
@@ -68,7 +68,7 @@ void add_ftype_mapping(state *st, char *suffix)
 /*
  * Add one selector rewrite mapping to the array
  */
-void add_rewrite_mapping(state *st, char *match)
+static void add_rewrite_mapping(state *st, char *match)
 {
 	char *replace;
 
diff --git a/src/session.c b/src/session.c
index dab6261..e7fced4 100644
--- a/src/session.c
+++ b/src/session.c
@@ -34,7 +34,7 @@
  * Locate shared memory session ID
  */
 #ifdef HAVE_SHMEM
-int get_shm_session_id(state *st, shm_state *shm)
+static int get_shm_session_id(state *st, shm_state *shm)
 {
 	time_t now;
 	int i;