<URL: http://bugs.freeciv.org/Ticket/Display.html?id=40552 >
Attached patch moves the voting code out of stdinhand.[ch] and into its own code modules voting.[ch]. ----------------------------------------------------------------------- いざという時は、誰に投票するの?
commit c4c237468058e1b40f85af7c36139d10db2a5406 Author: Madeline Book <[EMAIL PROTECTED]> Date: Thu Nov 6 16:02:37 2008 -0500 Voting cleanup. --- server/Makefile.am | 4 +- server/sernet.c | 1 + server/srv_main.c | 4 + server/stdinhand.c | 463 +++---------------------------------------------- server/stdinhand.h | 3 - server/voting.c | 490 ++++++++++++++++++++++++++++++++++++++++++++++++++++ server/voting.h | 58 ++++++ 7 files changed, 583 insertions(+), 440 deletions(-) diff --git a/server/Makefile.am b/server/Makefile.am index 793975e..09f5812 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -85,7 +85,9 @@ libcivserver_a_SOURCES = \ unithand.c \ unithand.h \ unittools.c \ - unittools.h + unittools.h \ + voting.c \ + voting.h # hand_gen.c & hand_gen.h are generated files, but as they are generated # outside this directory (when building common) there's no point in diff --git a/server/sernet.c b/server/sernet.c index fe56b5f..4801e4b 100644 --- a/server/sernet.c +++ b/server/sernet.c @@ -83,6 +83,7 @@ #include "plrhand.h" #include "srv_main.h" #include "stdinhand.h" +#include "voting.h" #include "sernet.h" diff --git a/server/srv_main.c b/server/srv_main.c index 9a98491..433b9f8 100644 --- a/server/srv_main.c +++ b/server/srv_main.c @@ -99,6 +99,7 @@ #include "techtools.h" #include "unithand.h" #include "unittools.h" +#include "voting.h" #include "advdiplomacy.h" #include "advmilitary.h" @@ -876,6 +877,7 @@ static void end_turn(void) update_diplomatics(); make_history_report(); stdinhand_turn(); + voting_turn(); send_player_turn_notifications(NULL); freelog(LOG_DEBUG, "Gamenextyear"); @@ -1054,6 +1056,7 @@ void server_quit(void) #endif /* HAVE_AUTH */ stdinhand_free(); + voting_free(); close_connections_and_socket(); exit(EXIT_SUCCESS); } @@ -1940,6 +1943,7 @@ static void srv_prepare(void) con_flush(); stdinhand_init(); + voting_init(); diplhand_init(); /* init network */ diff --git a/server/stdinhand.c b/server/stdinhand.c index e9de673..26d1c1c 100644 --- a/server/stdinhand.c +++ b/server/stdinhand.c @@ -67,6 +67,7 @@ #include "settings.h" #include "srv_main.h" #include "stdinhand.h" +#include "voting.h" #include "advmilitary.h" /* assess_danger_player() */ #include "ailog.h" @@ -96,62 +97,11 @@ static bool detach_command(struct connection *caller, char *name, bool check); static bool end_command(struct connection *caller, char *str, bool check); static bool surrender_command(struct connection *caller, char *str, bool check); -enum vote_type { - VOTE_ABSTAIN = 0, - VOTE_YES, - VOTE_NO, - - NUM_VOTE_TYPES -}; - -struct vote_cast { - enum vote_type vote_cast; - int conn_id; -}; - -#define SPECLIST_TAG vote_cast -#define SPECLIST_TYPE struct vote_cast -#include "speclist.h" -#define vote_cast_list_iterate(alist, pvc) \ - TYPED_LIST_ITERATE(struct vote_cast, alist, pvc) -#define vote_cast_list_iterate_end LIST_ITERATE_END - -struct vote { - int caller_id; /* caller connection id */ - char command[MAX_LEN_CONSOLE_LINE]; /* [0] == \0 if none in action */ - struct vote_cast_list *votes_cast; - int vote_no; /* place in the queue */ - int yes, no, abstain; +/* Vote command helpers. NB: Must match enum vote_type. */ +static const char *const vote_args[] = { + "abstain", "yes", "no", NULL }; -#define SPECLIST_TAG vote -#define SPECLIST_TYPE struct vote -#include "speclist.h" -#define vote_list_iterate(alist, pvote) \ - TYPED_LIST_ITERATE(struct vote, alist, pvote) -#define vote_list_iterate_end LIST_ITERATE_END - -static struct vote_list *vote_list = 0; -static int vote_number_sequence = 0; - -static void voting_init(void); -static void voting_turn(void); -static void voting_free(void); -static int count_voters(void); -static bool connection_can_vote(struct connection *pconn); -static void connection_vote(struct connection *pconn, struct vote *pvote, - enum vote_type type); -static struct vote *vote_new(struct connection *caller, - const char *full_command); -static void free_vote(struct vote *pvote); -static struct vote *get_vote_by_no(int vote_no); -static struct vote *get_vote_by_caller(const struct connection *caller); -static void remove_vote(struct vote *pvote); -static struct vote_cast *vote_cast_new(struct vote *pvote); -static void remove_vote_cast(struct vote *pvote, struct vote_cast *pvc); -static struct vote_cast *find_vote_cast(struct vote *pvote, int conn_id); - - static const char horiz_line[] = "------------------------------------------------------------------------------"; @@ -232,363 +182,7 @@ static enum command_id command_named(const char *token, bool accept_ambiguity) **************************************************************************/ void stdinhand_init(void) { - voting_init(); -} - -/************************************************************************** - Initialize voting related data structures. -**************************************************************************/ -static void voting_init(void) -{ - if (!vote_list) { - vote_list = vote_list_new(); - vote_number_sequence = 0; - } -} - -/************************************************************************** - Cannot vote if: - * is not connected - * access level < info - * isn't a living player -**************************************************************************/ -static bool connection_can_vote(struct connection *pconn) -{ - if (pconn != NULL && pconn->playing != NULL && !pconn->observer - && pconn->playing->is_alive && pconn->access_level >= ALLOW_INFO) { - return TRUE; - } - return FALSE; -} - -/************************************************************************** - Returns the total number of users that are allowed to vote. -**************************************************************************/ -static int count_voters(void) -{ - int num_voters = 0; - - conn_list_iterate(game.est_connections, pconn) { - if (connection_can_vote(pconn)) { - num_voters++; - } - } conn_list_iterate_end; - - return num_voters; -} - -/************************************************************************** - Check if we satisfy the criteria for resolving a vote, and resolve it - if these critera are indeed met. Updates yes and no variables in voting - struct as well. - - Criteria: - Accepted immediately if: > 50% of votes for - Rejected immediately if: >= 50% of votes against -**************************************************************************/ -static void check_vote(struct vote *pvote) -{ - struct connection *pconn = NULL; - int num_cast = 0, num_voters = 0, voting_base; - bool resolve = FALSE, passed = FALSE; - char cmdline[MAX_LEN_CONSOLE_LINE]; - - pvote->yes = 0; - pvote->no = 0; - pvote->abstain = 0; - - num_voters = count_voters(); - - vote_cast_list_iterate(pvote->votes_cast, pvc) { - if (!(pconn = find_conn_by_id(pvc->conn_id)) - || !connection_can_vote(pconn)) { - continue; - } - num_cast++; - - switch (pvc->vote_cast) { - case VOTE_YES: - pvote->yes++; - break; - case VOTE_NO: - pvote->no++; - break; - case VOTE_ABSTAIN: - pvote->abstain++; - break; - default: - break; - } - } vote_cast_list_iterate_end; - - voting_base = num_voters - pvote->abstain; - - /* Check if we should resolve the vote */ - if ((voting_base > 0 && (pvote->yes > voting_base / 2 - || pvote->no >= (voting_base + 1) / 2)) - || num_cast >= num_voters) { - /* Yep, resolve this one */ - resolve = TRUE; - } - - if (!resolve) { - return; - } - - if (pvote->yes > voting_base / 2) { - passed = TRUE; - } - - if (passed) { - notify_conn(NULL, NULL, E_SETTING, - _("Vote \"%s\" is passed %d to %d with %d " - "abstentions and %d that did not vote."), - pvote->command, pvote->yes, pvote->no, - pvote->abstain, num_voters - num_cast); - sz_strlcpy(cmdline, pvote->command); - } else { - notify_conn(NULL, NULL, E_SETTING, - _("Vote \"%s\" failed with %d against, %d for, " - "%d abstentions, and %d that did not vote."), - pvote->command, pvote->no, pvote->yes, - pvote->abstain, num_voters - num_cast); - } - - remove_vote(pvote); - - if (passed) { - handle_stdin_input(NULL, cmdline, FALSE); - } -} - -/************************************************************************** - Remove the given vote. -**************************************************************************/ -void remove_vote(struct vote *pvote) -{ - if (!pvote) { - return; - } - - if (vote_list) { - vote_list_unlink(vote_list, pvote); - } - - free_vote(pvote); -} - -/************************************************************************** - Free the memory used by the vote structure. -**************************************************************************/ -static void free_vote(struct vote *pvote) -{ - if (!pvote) { - return; - } - - if (pvote->votes_cast) { - vote_cast_list_iterate(pvote->votes_cast, pvc) { - free(pvc); - } vote_cast_list_iterate_end; - vote_cast_list_free(pvote->votes_cast); - pvote->votes_cast = NULL; - } - free(pvote); -} - -/************************************************************************** - Check votes at end of turn. -**************************************************************************/ -static void voting_turn(void) -{ - vote_list_iterate(vote_list, pvote) { - check_vote(pvote); - } vote_list_iterate_end; -} - -/************************************************************************** - Free vote related data structures. -**************************************************************************/ -static void voting_free(void) -{ - clear_all_votes(); - vote_list_free(vote_list); - vote_list = NULL; -} - -/************************************************************************** - Remove all votes. -**************************************************************************/ -void clear_all_votes(void) -{ - if (!vote_list) { - return; - } - - vote_list_iterate(vote_list, pvote) { - free_vote(pvote); - } vote_list_iterate_end; - vote_list_clear(vote_list); -} - -/************************************************************************** - Returns the vote associated to the given vote number. -**************************************************************************/ -static struct vote *get_vote_by_no(int vote_no) -{ - if (!vote_list) { - return NULL; - } - - vote_list_iterate(vote_list, pvote) { - if (pvote->vote_no == vote_no) { - return pvote; - } - } vote_list_iterate_end; - - return NULL; -} - -/************************************************************************** - Find the vote made by the given user. -**************************************************************************/ -static struct vote *get_vote_by_caller(const struct connection *caller) -{ - if (vote_list == NULL || caller == NULL) { - return NULL; - } - - vote_list_iterate(vote_list, pvote) { - if (pvote->caller_id == caller->id) { - return pvote; - } - } vote_list_iterate_end; - - return NULL; -} - -/************************************************************************** - Register a vote of type 'type' on the vote 'pvote' made by the user - 'pconn'. -**************************************************************************/ -void connection_vote(struct connection *pconn, - struct vote *pvote, - enum vote_type type) -{ - assert(vote_list != NULL); - - struct vote_cast *pvc; - - if (!connection_can_vote(pconn)) { - return; - } - - /* Try to find a previous vote */ - if ((pvc = find_vote_cast(pvote, pconn->id))) { - pvc->vote_cast = type; - } else if ((pvc = vote_cast_new(pvote))) { - pvc->vote_cast = type; - pvc->conn_id = pconn->id; - } else { - /* Must never happen */ - assert(0); - } - check_vote(pvote); -} - -/************************************************************************** - Cancel the votes of a lost or a detached connection... -**************************************************************************/ -void cancel_connection_votes(struct connection *pconn) -{ - if (!pconn || !vote_list) { - return; - } - - remove_vote(get_vote_by_caller(pconn)); - - vote_list_iterate(vote_list, pvote) { - remove_vote_cast(pvote, find_vote_cast(pvote, pconn->id)); - } vote_list_iterate_end; -} - -/************************************************************************** - Create a new vote. -**************************************************************************/ -static struct vote *vote_new(struct connection *caller, - const char *full_command) -{ - struct vote *pvote; - - assert(vote_list != NULL); - - if (!connection_can_vote(caller)) { - return NULL; - } - - /* Cancel previous vote */ - remove_vote(get_vote_by_caller(caller)); - - /* Make a new vote */ - pvote = fc_calloc(1, sizeof(*pvote)); - pvote->caller_id = caller->id; - - sz_strlcpy(pvote->command, full_command); - - pvote->votes_cast = vote_cast_list_new(); - pvote->vote_no = ++vote_number_sequence; - - vote_list_append(vote_list, pvote); - - return pvote; -} - -/************************************************************************** - Find the vote cast for the user id conn_id in a vote. -**************************************************************************/ -static struct vote_cast *find_vote_cast(struct vote *pvote, int conn_id) -{ - assert(vote_list != NULL); - - vote_cast_list_iterate(pvote->votes_cast, pvc) { - if (pvc->conn_id == conn_id) { - return pvc; - } - } vote_cast_list_iterate_end; - - return NULL; -} -/************************************************************************** - Return a new vote cast. -**************************************************************************/ -static struct vote_cast *vote_cast_new(struct vote *pvote) -{ - assert(vote_list != NULL); - - struct vote_cast *pvc = fc_malloc(sizeof(struct vote_cast)); - - pvc->conn_id = -1; - pvc->vote_cast = VOTE_ABSTAIN; - - vote_cast_list_append(pvote->votes_cast, pvc); - - return pvc; -} - -/************************************************************************** - Remove a vote cast. -**************************************************************************/ -static void remove_vote_cast(struct vote *pvote, struct vote_cast *pvc) -{ - assert(vote_list != NULL); - - if (!pvc) { - return; - } - - vote_cast_list_unlink(pvote->votes_cast, pvc); - free(pvc); - check_vote(pvote); /* Maybe can pass */ + /* Nothing at the moment. */ } /************************************************************************** @@ -597,7 +191,7 @@ static void remove_vote_cast(struct vote *pvote, struct vote_cast *pvc) **************************************************************************/ void stdinhand_turn(void) { - voting_turn(); + /* Nothing at the moment. */ } /************************************************************************** @@ -605,7 +199,7 @@ void stdinhand_turn(void) **************************************************************************/ void stdinhand_free(void) { - voting_free(); + /* Nothing at the moment. */ } /************************************************************************** @@ -2495,16 +2089,9 @@ static bool team_command(struct connection *caller, char *str, bool check) return res; } - /****************************************************************** - Vote command helpers. NB: Must match enum vote_type. + Vote command argument accessor. ******************************************************************/ -static const char *const vote_args[] = { - "abstain", - "yes", - "no", - NULL -}; static const char *vote_arg_accessor(int i) { return vote_args[i]; @@ -2535,15 +2122,18 @@ static bool vote_command(struct connection *caller, char *str, if (ntokens <= 0) { int num_voters, vote_count; - num_voters = count_voters(); - vote_count = vote_list_size(vote_list); + num_voters = voting_get_voter_count(); + vote_count = voting_get_vote_count(); - vote_list_iterate(vote_list, pvote) { + vote_list_iterate(voting_get_vote_list(), pvote) { cmd_reply(CMD_VOTE, caller, C_COMMENT, _("Vote %d \"%s\": %d for, " "%d against, and %d abstained out of %d voters."), - pvote->vote_no, pvote->command, - pvote->yes, pvote->no, pvote->abstain, num_voters); + vote_number(pvote), vote_cmdline(pvote), + vote_cast_count(pvote, VOTE_YES), + vote_cast_count(pvote, VOTE_NO), + vote_cast_count(pvote, VOTE_ABSTAIN), + num_voters); } vote_list_iterate_end; if (vote_count == 0) { @@ -2576,10 +2166,12 @@ static bool vote_command(struct connection *caller, char *str, if (ntokens == 1) { /* Applies to last vote */ - if (vote_number_sequence > 0 && get_vote_by_no(vote_number_sequence)) { - vote_no = vote_number_sequence; + + pvote = voting_get_last_vote(); + if (pvote != NULL) { + vote_no = vote_number(pvote); } else { - int num_votes = vote_list_size(vote_list); + int num_votes = voting_get_vote_count(); if (num_votes == 0) { cmd_reply(CMD_VOTE, caller, C_FAIL, _("There are no votes running.")); @@ -2599,23 +2191,23 @@ static bool vote_command(struct connection *caller, char *str, } } - if (!(pvote = get_vote_by_no(vote_no))) { + if (!(pvote = voting_get_vote_by_no(vote_no))) { cmd_reply(CMD_VOTE, caller, C_FAIL, _("No such vote (%d)."), vote_no); goto CLEANUP; } if (i == VOTE_YES) { cmd_reply(CMD_VOTE, caller, C_COMMENT, _("You voted for \"%s\""), - pvote->command); + vote_cmdline(pvote)); connection_vote(caller, pvote, VOTE_YES); } else if (i == VOTE_NO) { cmd_reply(CMD_VOTE, caller, C_COMMENT, _("You voted against \"%s\""), - pvote->command); + vote_cmdline(pvote)); connection_vote(caller, pvote, VOTE_NO); } else if (i == VOTE_ABSTAIN) { cmd_reply(CMD_VOTE, caller, C_COMMENT, _("You abstained from voting on \"%s\""), - pvote->command); + vote_cmdline(pvote)); connection_vote(caller, pvote, VOTE_ABSTAIN); } else { freelog(LOG_FATAL, "Bad vote type %d in /vote command.", i); @@ -4015,7 +3607,7 @@ bool handle_stdin_input(struct connection *caller, char *str, bool check) /* If we already have a vote going, cancel it in favour of the new * vote command (it will be cancelled by vote_new()). You can only * have one vote at a time. */ - if (get_vote_by_caller(caller)) { + if (voting_get_vote_by_caller(caller)) { cmd_reply(CMD_VOTE, caller, C_COMMENT, _("Your new vote cancelled your previous vote.")); } @@ -4025,8 +3617,7 @@ bool handle_stdin_input(struct connection *caller, char *str, bool check) && (pvote = vote_new(caller, full_command))) { notify_conn(NULL, NULL, E_SETTING, _("New vote (number %d) by %s: %s."), - pvote->vote_no, - caller->username, + vote_number(pvote), caller->username, full_command); /* Vote on your own suggestion. */ diff --git a/server/stdinhand.h b/server/stdinhand.h index 33aa18b..b2b331f 100644 --- a/server/stdinhand.h +++ b/server/stdinhand.h @@ -52,7 +52,4 @@ char **freeciv_completion(char *text, int start, int end); #endif #endif -void clear_all_votes(void); -void cancel_connection_votes(struct connection *pconn); - #endif /* FC__STDINHAND_H */ diff --git a/server/voting.c b/server/voting.c new file mode 100644 index 0000000..ca32e67 --- /dev/null +++ b/server/voting.c @@ -0,0 +1,490 @@ +/********************************************************************** + Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold + 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, or (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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "fciconv.h" +#include "fcintl.h" +#include "mem.h" + +#include "connection.h" +#include "game.h" +#include "player.h" + +#include "console.h" +#include "plrhand.h" +#include "stdinhand.h" +#include "voting.h" + +struct vote_cast { + enum vote_type vote_cast; + int conn_id; +}; + +#define SPECLIST_TAG vote_cast +#define SPECLIST_TYPE struct vote_cast +#include "speclist.h" +#define vote_cast_list_iterate(alist, pvc) \ + TYPED_LIST_ITERATE(struct vote_cast, alist, pvc) +#define vote_cast_list_iterate_end LIST_ITERATE_END + +struct vote { + int caller_id; /* caller connection id */ + char command[MAX_LEN_CONSOLE_LINE]; /* [0] == \0 if none in action */ + struct vote_cast_list *votes_cast; + int vote_no; + int yes, no, abstain; +}; + +struct vote_list *vote_list = 0; +int vote_number_sequence = 0; + + +static void check_vote(struct vote *pvote); +static void remove_vote(struct vote *pvote); +static void vote_free(struct vote *pvote); +static struct vote_cast *find_vote_cast(struct vote *pvote, int conn_id); +static struct vote_cast *vote_cast_new(struct vote *pvote); +static void remove_vote_cast(struct vote *pvote, struct vote_cast *pvc); + + +/************************************************************************** + Initialize voting related data structures. +**************************************************************************/ +void voting_init(void) +{ + if (!vote_list) { + vote_list = vote_list_new(); + vote_number_sequence = 0; + } +} + +/************************************************************************** + Cannot vote if: + * is not connected + * access level < info + * isn't a living player +**************************************************************************/ +bool connection_can_vote(struct connection *pconn) +{ + if (pconn != NULL && pconn->playing != NULL && !pconn->observer + && pconn->playing->is_alive && pconn->access_level >= ALLOW_INFO) { + return TRUE; + } + return FALSE; +} + +/************************************************************************** + Returns the total number of users that are allowed to vote. +**************************************************************************/ +int voting_get_voter_count(void) +{ + int num_voters = 0; + + conn_list_iterate(game.est_connections, pconn) { + if (connection_can_vote(pconn)) { + num_voters++; + } + } conn_list_iterate_end; + + return num_voters; +} + +/************************************************************************** + Check if we satisfy the criteria for resolving a vote, and resolve it + if these critera are indeed met. Updates yes and no variables in voting + struct as well. + + Criteria: + Accepted immediately if: > 50% of votes for + Rejected immediately if: >= 50% of votes against +**************************************************************************/ +static void check_vote(struct vote *pvote) +{ + struct connection *pconn = NULL; + int num_cast = 0, num_voters = 0, voting_base; + bool resolve = FALSE, passed = FALSE; + char cmdline[MAX_LEN_CONSOLE_LINE]; + + pvote->yes = 0; + pvote->no = 0; + pvote->abstain = 0; + + num_voters = voting_get_voter_count(); + + vote_cast_list_iterate(pvote->votes_cast, pvc) { + if (!(pconn = find_conn_by_id(pvc->conn_id)) + || !connection_can_vote(pconn)) { + continue; + } + num_cast++; + + switch (pvc->vote_cast) { + case VOTE_YES: + pvote->yes++; + break; + case VOTE_NO: + pvote->no++; + break; + case VOTE_ABSTAIN: + pvote->abstain++; + break; + default: + break; + } + } vote_cast_list_iterate_end; + + voting_base = num_voters - pvote->abstain; + + /* Check if we should resolve the vote */ + if ((voting_base > 0 && (pvote->yes > voting_base / 2 + || pvote->no >= (voting_base + 1) / 2)) + || num_cast >= num_voters) { + /* Yep, resolve this one */ + resolve = TRUE; + } + + if (!resolve) { + return; + } + + if (pvote->yes > voting_base / 2) { + passed = TRUE; + } + + if (passed) { + notify_conn(NULL, NULL, E_SETTING, + _("Vote \"%s\" is passed %d to %d with %d " + "abstentions and %d that did not vote."), + pvote->command, pvote->yes, pvote->no, + pvote->abstain, num_voters - num_cast); + sz_strlcpy(cmdline, pvote->command); + } else { + notify_conn(NULL, NULL, E_SETTING, + _("Vote \"%s\" failed with %d against, %d for, " + "%d abstentions, and %d that did not vote."), + pvote->command, pvote->no, pvote->yes, + pvote->abstain, num_voters - num_cast); + } + + remove_vote(pvote); + + if (passed) { + handle_stdin_input(NULL, cmdline, FALSE); + } +} + +/************************************************************************** + Remove the given vote. +**************************************************************************/ +static void remove_vote(struct vote *pvote) +{ + if (!pvote) { + return; + } + + if (vote_list) { + vote_list_unlink(vote_list, pvote); + } + + vote_free(pvote); +} + +/************************************************************************** + Free the memory used by the vote structure. +**************************************************************************/ +static void vote_free(struct vote *pvote) +{ + if (!pvote) { + return; + } + + if (pvote->votes_cast) { + vote_cast_list_iterate(pvote->votes_cast, pvc) { + free(pvc); + } vote_cast_list_iterate_end; + vote_cast_list_free(pvote->votes_cast); + pvote->votes_cast = NULL; + } + free(pvote); +} + +/************************************************************************** + Check votes at end of turn. +**************************************************************************/ +void voting_turn(void) +{ + vote_list_iterate(vote_list, pvote) { + check_vote(pvote); + } vote_list_iterate_end; +} + +/************************************************************************** + Free vote related data structures. +**************************************************************************/ +void voting_free(void) +{ + clear_all_votes(); + vote_list_free(vote_list); + vote_list = NULL; +} + +/************************************************************************** + Remove all votes. +**************************************************************************/ +void clear_all_votes(void) +{ + if (!vote_list) { + return; + } + + vote_list_iterate(vote_list, pvote) { + vote_free(pvote); + } vote_list_iterate_end; + vote_list_clear(vote_list); +} + +/************************************************************************** + Returns the vote associated to the given vote number. +**************************************************************************/ +struct vote *voting_get_vote_by_no(int vote_no) +{ + if (!vote_list) { + return NULL; + } + + vote_list_iterate(vote_list, pvote) { + if (pvote->vote_no == vote_no) { + return pvote; + } + } vote_list_iterate_end; + + return NULL; +} + +/************************************************************************** + Find the vote made by the given user. +**************************************************************************/ +struct vote *voting_get_vote_by_caller(const struct connection *caller) +{ + if (vote_list == NULL || caller == NULL) { + return NULL; + } + + vote_list_iterate(vote_list, pvote) { + if (pvote->caller_id == caller->id) { + return pvote; + } + } vote_list_iterate_end; + + return NULL; +} + +/************************************************************************** + Register a vote of type 'type' on the vote 'pvote' made by the user + 'pconn'. +**************************************************************************/ +void connection_vote(struct connection *pconn, + struct vote *pvote, + enum vote_type type) +{ + assert(vote_list != NULL); + + struct vote_cast *pvc; + + if (!connection_can_vote(pconn)) { + return; + } + + /* Try to find a previous vote */ + if ((pvc = find_vote_cast(pvote, pconn->id))) { + pvc->vote_cast = type; + } else if ((pvc = vote_cast_new(pvote))) { + pvc->vote_cast = type; + pvc->conn_id = pconn->id; + } else { + /* Must never happen */ + assert(0); + } + check_vote(pvote); +} + +/************************************************************************** + Cancel the votes of a lost or a detached connection... +**************************************************************************/ +void cancel_connection_votes(struct connection *pconn) +{ + if (!pconn || !vote_list) { + return; + } + + remove_vote(voting_get_vote_by_caller(pconn)); + + vote_list_iterate(vote_list, pvote) { + remove_vote_cast(pvote, find_vote_cast(pvote, pconn->id)); + } vote_list_iterate_end; +} + +/************************************************************************** + Create a new vote. +**************************************************************************/ +struct vote *vote_new(struct connection *caller, + const char *full_command) +{ + struct vote *pvote; + + assert(vote_list != NULL); + + if (!connection_can_vote(caller)) { + return NULL; + } + + /* Cancel previous vote */ + remove_vote(voting_get_vote_by_caller(caller)); + + /* Make a new vote */ + pvote = fc_calloc(1, sizeof(*pvote)); + pvote->caller_id = caller->id; + + sz_strlcpy(pvote->command, full_command); + + pvote->votes_cast = vote_cast_list_new(); + pvote->vote_no = ++vote_number_sequence; + + vote_list_append(vote_list, pvote); + + return pvote; +} + +/************************************************************************** + Find the vote cast for the user id conn_id in a vote. +**************************************************************************/ +static struct vote_cast *find_vote_cast(struct vote *pvote, int conn_id) +{ + assert(vote_list != NULL); + + vote_cast_list_iterate(pvote->votes_cast, pvc) { + if (pvc->conn_id == conn_id) { + return pvc; + } + } vote_cast_list_iterate_end; + + return NULL; +} +/************************************************************************** + Return a new vote cast. +**************************************************************************/ +static struct vote_cast *vote_cast_new(struct vote *pvote) +{ + assert(vote_list != NULL); + + struct vote_cast *pvc = fc_malloc(sizeof(struct vote_cast)); + + pvc->conn_id = -1; + pvc->vote_cast = VOTE_ABSTAIN; + + vote_cast_list_append(pvote->votes_cast, pvc); + + return pvc; +} + +/************************************************************************** + Remove a vote cast. +**************************************************************************/ +static void remove_vote_cast(struct vote *pvote, struct vote_cast *pvc) +{ + assert(vote_list != NULL); + + if (!pvc) { + return; + } + + vote_cast_list_unlink(pvote->votes_cast, pvc); + free(pvc); + check_vote(pvote); /* Maybe can pass */ +} + +/************************************************************************** + Return the number of currently active votes. +**************************************************************************/ +int voting_get_vote_count(void) +{ + if (!vote_list) { + return 0; + } + return vote_list_size(vote_list); +} + +/************************************************************************** + Return the command line that will be executed if this vote passes. +**************************************************************************/ +const char *vote_cmdline(const struct vote *pvote) +{ + if (!pvote) { + return NULL; + } + return pvote->command; +} + +/************************************************************************** + Return the number of votes cast of the given type. +**************************************************************************/ +int vote_cast_count(const struct vote *pvote, enum vote_type vt) +{ + if (!pvote) { + return 0; + } + switch (vt) { + case VOTE_YES: + return pvote->yes; + break; + case VOTE_NO: + return pvote->no; + break; + case VOTE_ABSTAIN: + return pvote->abstain; + break; + default: + break; + } + return 0; +} + +/************************************************************************** + Return the unique identifier number for this vote. +**************************************************************************/ +int vote_number(const struct vote *pvote) +{ + return pvote->vote_no; +} + +/************************************************************************** + Return a const pointer to the global vote list. +**************************************************************************/ +const struct vote_list *voting_get_vote_list(void) +{ + return vote_list; +} + +/************************************************************************** + Returns the last vote that was made, or NULL if none. We use the last + vote according to 'vote_number_sequence' rather than the last vote in + 'vote_list' so that users do not mistakenly vote for the wrong vote if + the list is changed while they are voting. +**************************************************************************/ +struct vote *voting_get_last_vote(void) +{ + return voting_get_vote_by_no(vote_number_sequence); +} diff --git a/server/voting.h b/server/voting.h new file mode 100644 index 0000000..8a75299 --- /dev/null +++ b/server/voting.h @@ -0,0 +1,58 @@ +/********************************************************************** + Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold + 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, or (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. +***********************************************************************/ +#ifndef FC__VOTE_H +#define FC__VOTE_H + +enum vote_type { + VOTE_ABSTAIN = 0, + VOTE_YES, + VOTE_NO, + + NUM_VOTE_TYPES +}; + +struct connection; +struct vote; + +struct vote *vote_new(struct connection *caller, + const char *full_command); +int vote_number(const struct vote *pvote); +int vote_cast_count(const struct vote *pvote, enum vote_type vt); +const char *vote_cmdline(const struct vote *pvote); + +#define SPECLIST_TAG vote +#define SPECLIST_TYPE struct vote +#include "speclist.h" +#define vote_list_iterate(alist, pvote) \ + TYPED_LIST_ITERATE(struct vote, alist, pvote) +#define vote_list_iterate_end LIST_ITERATE_END + +void voting_init(void); +void voting_turn(void); +void voting_free(void); +int voting_get_voter_count(void); +int voting_get_vote_count(void); +struct vote *voting_get_last_vote(void); +struct vote *voting_get_vote_by_no(int vote_no); +struct vote *voting_get_vote_by_caller(const struct connection *caller); +const struct vote_list *voting_get_vote_list(void); + +bool connection_can_vote(struct connection *pconn); +void connection_vote(struct connection *pconn, struct vote *pvote, + enum vote_type type); + +void clear_all_votes(void); +void cancel_connection_votes(struct connection *pconn); + + +#endif /* FC__VOTE_H */
_______________________________________________ Freeciv-dev mailing list Freeciv-dev@gna.org https://mail.gna.org/listinfo/freeciv-dev