From 0b7200f97e02e338395af0c8cf1bfe77c5c1830f Mon Sep 17 00:00:00 2001 From: Terence Denning <terrencedenning@gmail.com> Date: Sun, 28 Apr 2019 09:57:15 -0700 Subject: [PATCH] print guesses on the webpage --- http-server.c | 118 +++++++++++++++++++++++++++++++++++--------------- image_tagger | Bin 23152 -> 23344 bytes 2 files changed, 84 insertions(+), 34 deletions(-) diff --git a/http-server.c b/http-server.c index d9ee97b..4b96446 100644 --- a/http-server.c +++ b/http-server.c @@ -31,6 +31,8 @@ void set_user(int sockfd); void user_ready(int sockfd); void print_details(); void check_win(int user, char *keyword); +char *substring(char *string, int position, int length); +void insert_substring(char *a, char *b, int position); // constants static char const * const HTTP_200_FORMAT = "HTTP/1.1 200 OK\r\n\ @@ -117,8 +119,11 @@ static bool handle_http_request(int sockfd) if (method == GET) { - + // get the size of the file + struct stat st; + if( strstr(buff, "start=Start") != NULL ){ + if( strcmp(webpage, "html/2_start.html") ){ user_ready(sockfd); } @@ -131,16 +136,10 @@ static bool handle_http_request(int sockfd) gameover = 0; } webpage = "html/3_first_turn.html"; - } else if( strstr(buff, "Cookie:") != NULL ) { - webpage = "html/1_intro.html"; } else { webpage = "html/1_intro.html"; } - - - // get the size of the file - struct stat st; stat(webpage, &st); n = sprintf(buff, HTTP_200_FORMAT, st.st_size); @@ -165,7 +164,6 @@ static bool handle_http_request(int sockfd) return false; } close(filefd); - } else if (method == POST) { @@ -217,30 +215,40 @@ static bool handle_http_request(int sockfd) size = st.st_size + added_length; n = sprintf(buff, HTTP_200_FORMAT_WITH_COOKIE, username, size); } - else if(strstr(buff, "guess=Guess") != NULL) { - + else if(strstr(buff, "guess=Guess") != NULL) { char *keyword = strstr(buff, "keyword=")+8; int keyword_length = strlen(keyword); keyword[keyword_length-12] = '\0'; - - if (sockfd == user1){ + + if (sockfd == user1){ /* if other player is ready then accept guesses */ - if( user2_start == 1 ){ + if( user2_start == 1 ){ webpage = "html/4_accepted.html"; strcpy(user1_guesses[user1_guess_number], keyword); user1_guess_number++; - check_win(1, keyword); + check_win(1, keyword); + + username_length = strlen(username); + added_length = username_length + 2; + size = st.st_size + added_length; + n = sprintf(buff, HTTP_200_FORMAT_WITH_COOKIE, username, size); } else if( gameover == 1 ){ webpage = "html/6_endgame.html"; } else { webpage = "html/5_discarded.html"; } } else if(sockfd == user2){ + if( user1_start == 1 ){ webpage = "html/4_accepted.html"; strcpy(user2_guesses[user2_guess_number], keyword); user2_guess_number++; check_win(2, keyword); + + username_length = strlen(username); + added_length = username_length + 2; + size = st.st_size + added_length; + n = sprintf(buff, HTTP_200_FORMAT_WITH_COOKIE, username, size); } else if( gameover == 1){ webpage = "html/6_endgame.html"; } else { @@ -275,8 +283,26 @@ static bool handle_http_request(int sockfd) } close(filefd); - - if( strcmp(webpage, "html/4_accepted.html") == 0 ){ + + if((strlen(username) > 0) && (strstr(buff, "user=") != NULL) ){ + // move the trailing part backward + int p1, p2; + for (p1 = size - 1, p2 = p1 - added_length; p1 >= size - 25; --p1, --p2) + buff[p1] = buff[p2]; + ++p2; + + buff[p2++] = ' '; + buff[p2++] = ' '; + + + // copy the username + strncpy(buff + p2, username, username_length); + if (write(sockfd, buff, size) < 0) + { + perror("write"); + return false; + } + } else if( strcmp(webpage, "html/4_accepted.html") == 0 ){ if(sockfd == user1){ memset(user1_current_guesses, '\0', 10100); for(int i=0; i<100; i++){ @@ -285,6 +311,7 @@ static bool handle_http_request(int sockfd) strncat(user1_current_guesses, ", ", 3); } } + insert_substring(buff, user1_current_guesses, 587); } else if(sockfd == user2){ memset(user2_current_guesses, '\0', 10100); @@ -294,30 +321,17 @@ static bool handle_http_request(int sockfd) strncat(user2_current_guesses, ", ", 3); } } + insert_substring(buff, user2_current_guesses, 587); + } - - printf("User1 guesses: %s, User2 guesses: %s\n", user1_current_guesses, user2_current_guesses); - - } - - if((strlen(username) > 0) && (strstr(buff, "user=") != NULL) ){ - // move the trailing part backward - int p1, p2; - for (p1 = size - 1, p2 = p1 - added_length; p1 >= size - 25; --p1, --p2) - buff[p1] = buff[p2]; - ++p2; - // put the separator - buff[p2++] = ' '; - buff[p2++] = ' '; - - // copy the username - strncpy(buff + p2, username, username_length); - if (write(sockfd, buff, size) < 0) + if (write(sockfd, buff, st.st_size) < 0) { perror("write"); return false; } + + printf("\nUser1 guesses: %s\n User2 guesses: %s\n", user1_current_guesses, user2_current_guesses); } else { if (write(sockfd, buff, st.st_size) < 0) { @@ -518,6 +532,42 @@ void check_win(int user, char *keyword){ } } +void insert_substring(char *a, char *b, int position) +{ + char *f, *e; + int length; + + length = strlen(a); + + f = substring(a, 1, position - 1 ); + e = substring(a, position, length-position+1); + + strcpy(a, ""); + strcat(a, f); + free(f); + strcat(a, b); + strcat(a, e); + free(e); +} + +char *substring(char *string, int position, int length) +{ + char *pointer; + int c; + + pointer = malloc(length+1); + + if( pointer == NULL ) + exit(EXIT_FAILURE); + + for( c = 0 ; c < length ; c++ ) + *(pointer+c) = *((string+position-1)+c); + + *(pointer+c) = '\0'; + + return pointer; +} + void print_details(){ printf("User1: %d, User2: %d, User1_start: %d, User2_start: %d\n\n", user1, user2, user1_start, user2_start); } diff --git a/image_tagger b/image_tagger index 2287ea3f927d89952185630747eb603cacb866a2..f57b2ea9ce8e6f63aafe76988dda1177b9b0d928 100755 GIT binary patch delta 8146 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 T$wE<PoJ)fsYPcs)43P%_oBqMp delta 7558 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 CV7Wg4 -- GitLab