diff --git a/commandline.c b/commandline.c
new file mode 100644
index 0000000..94d2c4f
--- /dev/null
+++ b/commandline.c
@@ -0,0 +1,151 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * AnnaConnect is a silly little text-based connect 4 game c:
+ * Copyright (C) 2025 Anna Snoeijs. anna.snoeijs@hotmail.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include
+#include
+#include
+#include "macros.h"
+#include "types.h"
+#include "commandline.h"
+
+// The LISENCE file
+// Not null-terminated so need pointers for both start and end
+extern char _binary_LICENSE_start[];
+extern char _binary_LICENSE_end[];
+
+int parseArgs(
+ int argc,
+ char *argv[],
+ board_t *board,
+ wins_t **wins,
+ FILE **outputfile,
+ char **filename,
+ bool *randomMoves
+){
+ // Parse options
+ for(;;){
+ // Allowed options
+ static struct option long_options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "license", no_argument, NULL, 'l' },
+ { "version", no_argument, NULL, '\0' },
+ { "columns", required_argument, NULL, 'c' },
+ { "rows", required_argument, NULL, 'r' },
+ { "output", required_argument, NULL, 'o' },
+ { "slow-calcWins", no_argument, NULL, '\0' },
+ { "random-moves", no_argument, NULL, '\0' },
+ { 0 }
+ };
+ // Index of current option
+ int option_index = 0;
+ // Get next option
+ char c = (char)getopt_long( argc, argv, "hlc:r:o:",
+ long_options, &option_index
+ );
+ if( c == -1 ) break;
+ // Handle option
+ switch( c ){
+ case '\0': // Any option without shorthand
+ switch( option_index ){
+ case 2: // --version
+ printf( VERSIONSTRING );
+ return 0;
+ case 6: // --slow-calcWins
+ free( *wins );
+ *wins = NULL;
+ break;
+ case 7: // --random-moves
+ *randomMoves = (bool)(true);
+ break;
+ default:
+ fprintf(
+ stderr,
+ "%s: unhandled option \'--%s\' \n",
+ argv[0],
+ long_options[ option_index ].name
+ );
+ return -1;
+ break;
+ }
+ break;
+ case 'h': // --help
+ printf( "Usage: %s [OPTIONS]\n\n", argv[0] );
+ printf(
+" -h --help Print this help text\n"
+" -l --license Print the LICENSE file\n"
+" --version Print the version string\n"
+"\n"
+" -c n --columns n Set the amount of columns\n"
+" -r n --rows n Set the amount of rows\n"
+"\n"
+" -o file --output file Ouput moves taken in game to file\n"
+"\n"
+" --slow-calcwins Use the reference implementation of calcWins()\n"
+" --random-moves Play random moves instead of asking for input\n"
+ );
+ return 0;
+ case 'l': // --license
+ for(
+ char *p = _binary_LICENSE_start;
+ p != _binary_LICENSE_end;
+ p++
+ ){
+ putchar( *p );
+ }
+ return 0;
+ case 'c': // --columns
+ board->columns = (columnsint_t)atoi(optarg);
+ break;
+ case 'r': // --rows
+ board->rows = (rowsint_t)atoi(optarg);
+ break;
+ case 'o':
+ // filename = strdup(optarg);
+ *filename = calloc( strlen( optarg ) + 1, sizeof(char) );
+ if( *filename != NULL ){
+ strcpy( *filename, optarg );
+ *outputfile = fopen( *filename, "w" );
+ }else{
+ fprintf( stderr, "ERR: COULD NOT ALLOCATE FILENAME\n" );
+ return -1;
+ }
+ break;
+ }
+ }
+ // Check for unhandled options
+ if( optind < argc ) {
+ fprintf( stderr, "non-option ARGV-elements: " );
+ while( optind < argc )
+ printf( "%s ", argv[optind++] );
+ putchar( '\n' );
+ return -1;
+ }
+ if( board->rows < 1 ){
+ fprintf( stderr, "ERR: AMOUT OF ROWS MUST BE AT LEAST 1\n" );
+ return -1;
+ }
+#define ROWOVERFLOW (rowsint_t)( sizeof(column_t) * CHAR_BIT - 1 )
+ if( board->rows >= ROWOVERFLOW ){
+ fprintf( stderr,
+ "ERR: AMOUT OF ROWS MUST BE LESS THAN %d\n", ROWOVERFLOW
+ );
+ return -1;
+ }
+ return 0;
+}
diff --git a/commandline.h b/commandline.h
new file mode 100644
index 0000000..7865fb8
--- /dev/null
+++ b/commandline.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#pragma once
+
+#include "macros.h"
+#include "types.h"
+#include "logic.h"
+
+extern int parseArgs(
+ int argc,
+ char *argv[],
+ board_t *board,
+ wins_t **wins,
+ FILE **outputfile,
+ char **filename,
+ bool *randomMoves
+);
diff --git a/connect4.c b/connect4.c
index f4ccdcb..fe991e9 100644
--- a/connect4.c
+++ b/connect4.c
@@ -20,33 +20,13 @@
#include
#include
#include
-#ifndef NO_OPTIONS
-#include
-#endif /* ! NO_OPTIONS */
#include
#include "macros.h"
#include "config.h"
#include "logic.h"
#include "types.h"
#include "ui.h"
-
-#define VERSION 0.3.1
-
-#ifndef GITHASH
-#define FULLVERSION VERSION
-#else
-#define FULLVERSION VERSION~git.GITHASH
-#endif
-
-#define VERSIONSTRING \
- "AnnaConnect version "XSTR(FULLVERSION)", Copyright (C) Anna Snoeijs\n"
-
-#ifndef NO_OPTIONS
-// The LISENCE file
-// Not null-terminated so need pointers for both start and end
-extern char _binary_LICENSE_start[];
-extern char _binary_LICENSE_end[];
-#endif /* ! NO_OPTIONS */
+#include "commandline.h"
int main(
#ifndef NO_OPTIONS // [[maybe_unused]] is unsupported in C99, so this will do
@@ -66,113 +46,21 @@ int main(
FILE *outputfile = NULL;
char *filename = NULL;
bool randomMoves = 0;
- // Parse options
- for(;;){
- // Allowed options
- static struct option long_options[] = {
- { "help", no_argument, NULL, 'h' },
- { "license", no_argument, NULL, 'l' },
- { "version", no_argument, NULL, '\0' },
- { "columns", required_argument, NULL, 'c' },
- { "rows", required_argument, NULL, 'r' },
- { "output", required_argument, NULL, 'o' },
- { "slow-calcWins", no_argument, NULL, '\0' },
- { "random-moves", no_argument, NULL, '\0' },
- { 0 }
- };
- // Index of current option
- int option_index = 0;
- // Get next option
- char c = (char)getopt_long( argc, argv, "hlc:r:o:",
- long_options, &option_index
- );
- if( c == -1 ) break;
- // Handle option
- switch( c ){
- case '\0': // Any option without shorthand
- switch( option_index ){
- case 2: // --version
- printf( VERSIONSTRING );
- return 0;
- case 6: // --slow-calcWins
- free( wins );
- wins = NULL;
- break;
- case 7: // --random-moves
- randomMoves = 1;
- break;
- default:
- fprintf(
- stderr,
- "%s: unhandled option \'--%s\' \n",
- argv[0],
- long_options[ option_index ].name
- );
- break;
- }
- break;
- case 'h': // --help
- printf( "Usage: %s [OPTIONS]\n\n", argv[0] );
- printf(
-" -h --help Print this help text\n"
-" -l --license Print the LICENSE file\n"
-" --version Print the version string\n"
-"\n"
-" -c n --columns n Set the amount of columns\n"
-" -r n --rows n Set the amount of rows\n"
-"\n"
-" -o file --output file Ouput moves taken in game to file\n"
-"\n"
-" --slow-calcwins Use the reference implementation of calcWins()\n"
-" --random-moves Play random moves instead of asking for input\n"
- );
- return 0;
- case 'l': // --license
- for(
- char *p = _binary_LICENSE_start;
- p != _binary_LICENSE_end;
- p++
- ){
- putchar( *p );
- }
- return 0;
- case 'c': // --columns
- playboard.columns = (columnsint_t)atoi(optarg);
- break;
- case 'r': // --rows
- playboard.rows = (rowsint_t)atoi(optarg);
- break;
- case 'o':
- // filename = strdup(optarg);
- filename = calloc( strlen( optarg ) + 1, sizeof(char) );
- if( filename != NULL ){
- strcpy( filename, optarg );
- outputfile = fopen( filename, "w" );
- }else{
- fprintf( stderr, "ERR: COULD NOT ALLOCATE FILENAME\n" );
- }
- break;
- }
+ switch(
+ parseArgs(
+ argc,
+ argv,
+ &playboard,
+ &wins,
+ &outputfile,
+ &filename,
+ &randomMoves
+ )
+ ){
+ case 0: break;
+ case 1: return 0;
+ default: return -1;
}
- // Check for unhandled options
- if( optind < argc ) {
- fprintf( stderr, "non-option ARGV-elements: " );
- while( optind < argc )
- printf( "%s ", argv[optind++] );
- putchar( '\n' );
- }
- if( playboard.rows < 1 ){
- fprintf( stderr, "ERR: AMOUT OF ROWS MUST BE AT LEAST 1\n" );
- return -1;
- }
-#define ROWOVERFLOW (rowsint_t)( sizeof(column_t) * CHAR_BIT - 1 )
- if( playboard.rows >= ROWOVERFLOW ){
- fprintf( stderr,
- "ERR: AMOUT OF ROWS MUST BE LESS THAN %d\n", ROWOVERFLOW
- );
- return -1;
- }
-#undef ROWOVERFLOW
#endif /* ! NO_OPTIONS */
// Start the actual program
printf(
diff --git a/macros.h b/macros.h
index 20b6cf4..2ecd282 100644
--- a/macros.h
+++ b/macros.h
@@ -7,3 +7,14 @@
#define XSTR(s) STR(s)
#define STR(s) #s
+
+#define VERSION 0.3.1
+
+#ifndef GITHASH
+#define FULLVERSION VERSION
+#else
+#define FULLVERSION VERSION~git.GITHASH
+#endif
+
+#define VERSIONSTRING \
+ "AnnaConnect version "XSTR(FULLVERSION)", Copyright (C) Anna Snoeijs\n"
diff --git a/makefile b/makefile
index c214f96..e6d05ca 100644
--- a/makefile
+++ b/makefile
@@ -108,19 +108,19 @@ $(TESTDIR)/test.log.slow: $(OUTDIR)/connect4_$(UI_TESTING).elf
# Compile specifically the ncurses version
# This one's special because it needs -lncursesw
-$(OUTDIR)/connect4_ncurses.elf: $(addprefix $(OBJDIR)/,ui_ncurses.o logic.o connect4.o LICENSE.o)
+$(OUTDIR)/connect4_ncurses.elf: $(addprefix $(OBJDIR)/,ui_ncurses.o logic.o connect4.o LICENSE.o commandline.o)
@echo $(MSG_LINKING) $@
@mkdir -p $(@D)
$(CC) $(FLAGS) -lncursesw -o $@ $^
# Compile the final excecutable for a given UI target
-$(OUTDIR)/connect4_%.elf: $(addprefix $(OBJDIR)/,ui_%.o logic.o connect4.o LICENSE.o)
+$(OUTDIR)/connect4_%.elf: $(addprefix $(OBJDIR)/,ui_%.o logic.o connect4.o LICENSE.o commandline.o)
@echo $(MSG_LINKING) $@
@mkdir -p $(@D)
$(CC) $(FLAGS) -o $@ $^
# Compile a windows excecutable
-$(OUTDIR)/connect4_%.exe: $(addprefix $(OBJDIR)/w64_,ui_%.o logic.o connect4.o LICENSE.o)
+$(OUTDIR)/connect4_%.exe: $(addprefix $(OBJDIR)/w64_,ui_%.o logic.o connect4.o LICENSE.o commandline.o)
@echo $(MSG_LINKING) $@
@mkdir -p $(@D)
$(CC_W64) $(FLAGS) -o $@ $^