diff --git a/Makefile b/Makefile
index 00738dc..3f21dfe 100644
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,12 @@ BIN=cts
all: main
+staticgen: colors.o src/dbquery.c
+ echo "\nCompiling executable as static page generator\n"
+ gcc -c src/dbquery.c $(CFLAGS) -DSTATICGEN
+ gcc -c src/main.c $(CFLAGS) -DSTATICGEN
+ gcc colors.o dbquery.o main.o -lsqlite3 -o $(BIN)
+
main: main.o
gcc colors.o dbquery.o main.o -lsqlite3 -o $(BIN)
@@ -19,4 +25,4 @@ testcolor: src/colors.c src/tcolor.c
gcc src/colors.c src/tcolor.c -o tcolor -I"includes" -g
clean:
- rm *.o *.log $(BIN)
+ rm *.o
diff --git a/README.md b/README.md
index 484212b..9ee6039 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,23 @@
-C CGI Xonotic DeFrag
------------------
-A CGI program written in C to display data related to Race CTS leaderboards of Xonotic servers.
+# xdfcgi
+
+A common gateway inferface (CGI) program written in C to display Race CTS leaderboards of Xonotic servers. It can also be a static page generator.
## Requirements
-* SQLite3
+ sqlite-devel python3 python-sqlite
+
+The first is only needed for compilation of the C program. The latter two are only for the auxiliary script `allmaps.py`.
+
+## Compiling
+`make` makes a CGI program.
+
+`make staticgen` makes a static page generator.
+
+## Usage: CGI Query Strings
+The program queries the database `db/cts.db` (`./src/dbquery.c`, function `static bool executequery`)
-## Web Server Queries
* `(none)`
- Query file: `queries/mranks.sql`
- - Requests the maplist of the server and related data.
+ - Requests the map list of the server and related data.
* `?map=[map name]`
- Query file: `queries/mleaderboard-ojoin.sql`
@@ -18,11 +27,25 @@ A CGI program written in C to display data related to Race CTS leaderboards of X
- Query file: `queries/rplayers.sql`
- Requests a player's ranks for all maps leaderboards s/he is present on.
+## Usage: Static Page Generation
+
+ python scripts/allmaps.py
+
+The CGI program is still invoked in static generation. The files `allmaps.py`, `output/leaderboard.css`, `overview.html`, `map.html` produce the output.
+
+Before executing `allmaps.py`, copy and modify the templates.
+
+ cp templates/overview.html .
+ cp templates/map.html .
+
+`allmaps.py` outputs an html file for all distinct maps in the database. The leaderboards for each map (equivalent to `?map=[map name]`) are in `output/maps/`.
+
## Game Versions Used Under:
* Xonotic 0.8.1
* Xonotic 0.8.2
## Compilers
+* gcc (GCC) 10.2.1
* MinGW, GCC 4.7.1
__________________
diff --git a/output/leaderboard.css b/output/leaderboard.css
new file mode 100644
index 0000000..030da72
--- /dev/null
+++ b/output/leaderboard.css
@@ -0,0 +1,17 @@
+footer {
+ text-align:center;
+}
+table, th, td {
+ border: 1px solid grey;
+ border-collapse: collapse;
+}
+table {
+ width:100%;
+}
+th, td {
+ width:auto;
+ text-align:center;
+ word-wrap: break-word;
+ margin: 1em 1em 1em 1em;
+}
+
diff --git a/queries/mranks.sql b/queries/mranks.sql
index 1331a22..9d69e1f 100644
--- a/queries/mranks.sql
+++ b/queries/mranks.sql
@@ -5,4 +5,4 @@ where Cts_ranks.mapid = Cts_times.mapid
and cryptokey = idvalue
and idrank = 1
group by Cts_ranks.mapid
-order by max(trank);
\ No newline at end of file
+order by count(trank) DESC;
diff --git a/scripts/allmaps.py b/scripts/allmaps.py
new file mode 100644
index 0000000..b184cd1
--- /dev/null
+++ b/scripts/allmaps.py
@@ -0,0 +1,67 @@
+import sqlite3 as sql
+import subprocess, traceback
+
+# get all maps in database
+def getmaps(database):
+ output = []
+ con = sql.connect(database)
+ with con:
+ cursor = con.cursor()
+ try:
+ cursor.execute("select distinct mapid from Cts_times;")
+ output = cursor.fetchall()
+ except sql.Error:
+ print("Shit is fucked.")
+ return output
+
+# if there is no query then it outputs the index file.
+def getcontent(query=None):
+ cmd = [("./cts")]
+ proc = subprocess.Popen(cmd, env=query, stdout=subprocess.PIPE, shell=True)
+ # communicate returns 'bytes' class with function 'decode'
+ return proc.communicate()[0].decode('utf-8')
+
+def renderindex(template):
+ # no env variable
+ table = getcontent()
+ filename = "./output/index.html"
+ with open(filename, 'w+') as fout:
+ fout.write(template % (table))
+ fout.close
+ pass
+
+def main():
+ template = ""
+ with open("overview.html", 'r') as fin:
+ template = fin.read()
+ renderindex(template)
+ maps = getmaps("db/cts.db")
+ with open("map.html", 'r') as fin:
+ template = fin.read()
+ # for each map generate an html file.
+ for game_map in maps:
+ # game_map is a tuple obj.
+ map_name = game_map[0]
+ query = {"QUERY_STRING" : ("map=%s" % map_name)}
+ table = getcontent(query)
+ filename = ("./output/maps/%s.html" % map_name)
+ with open(filename, 'w+') as fout:
+ title = map_name
+ fout.write(template.format(
+ title=title,
+ map_name=map_name,
+ table=table)
+ )
+ # fout.write(template % (title, map_name, table))
+ return True
+
+if __name__ == "__main__":
+ success = False
+ try:
+ success = main()
+ except FileNotFoundError:
+ traceback.print_exc()
+ print("\n\t The script probably didn't find the page templates needed to generate a page. You can copy minimal working examples from the repository at templates/.")
+ if success:
+ print("allmaps.py - Generated pages for all maps.")
+ pass
diff --git a/src/dbquery.c b/src/dbquery.c
index 7ae8dbb..7b331ec 100644
--- a/src/dbquery.c
+++ b/src/dbquery.c
@@ -31,7 +31,7 @@ static inline void print_tblheader(const char *c) {
char *labels;
switch (*c) {
default:
- labels = "