-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinput.c
133 lines (102 loc) · 3.31 KB
/
input.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include "input.h"
#include "control.h"
#include "sender.h"
#include "threadsafelist.h"
static pthread_t s_threadInput;
static bool s_threadHasExited = false;
// Free any remaining memory
static void cleanup(void* args) {
char** inputMessageAddress = args;
char* inputMessage = *inputMessageAddress;
if (inputMessage != NULL) {
free(inputMessage);
}
return;
}
// The thread to handle keyboard input
static void* inputThread(void* args) {
int status = 0;
InputThreadArguments* inputArguments = args;
List* pSendingMessagesList = inputArguments->pSendingMessagesList;
bool isFirstSegment = true;
char* input = NULL;
char* inputMessage = NULL;
char** inputMessageAddress = &inputMessage;
pthread_cleanup_push(cleanup, inputMessageAddress);
while (1) {
inputMessage = malloc(MESSAGE_MAX_SIZE);
if (inputMessage == NULL) {
fputs("[Error]: could not allocate memory for input message\n", stdout);
exit(1);
}
// Necessary to detect if received message is a new line or part of an existing line
memset(inputMessage, 0, MESSAGE_MAX_SIZE);
// Get keyboard input from the user
input = fgets(inputMessage, MESSAGE_MAX_SIZE, stdin);
// If EOF has been reached from a piped file without a !<enter>,
// send the exit command anyways
if (input == NULL) {
strcpy(inputMessage, TERMINATE);
} else {
input = NULL;
}
// Detect if the program should be terminated, and if the current input is the
// start of a new line (the first segment), or continues an existing line
if (isFirstSegment && strcmp(inputMessage, TERMINATE) == 0) {
s_threadHasExited = true;
} else if (inputMessage[MESSAGE_MAX_SIZE - 2] != 0 && inputMessage[MESSAGE_MAX_SIZE - 2] != '\n') {
isFirstSegment = false;
} else {
isFirstSegment = true;
}
// Add input to the end of the sending messages queue
status = ThreadSafeList_prepend(pSendingMessagesList, inputMessage);
if (status == -1) {
fputs("[Error]: could not add the message to sending messages list\n", stdout);
free(inputMessage);
s_threadHasExited = false;
}
inputMessage = NULL;
// Signal the sender thread that there is a message to send
Sender_signalMessageToSend();
if (s_threadHasExited) {
fputs("[You have sent the exit command]\n", stdout);
fflush(stdout);
break;
}
}
pthread_cleanup_pop(1);
s_threadHasExited = true;
// Signal the main thread that the program should terminate
Control_signalTermination();
return NULL;
}
// Initializes the input thread
void Input_init(InputThreadArguments* pInputArguments) {
int status = 0;
status = pthread_create(&s_threadInput, NULL, inputThread, (void*) pInputArguments);
if (status) {
fputs("[Error]: could not create input thread\n", stdout);
exit(1);
}
return;
}
// Shutdowns the input thread and performs necessary cleanup
void Input_shutdown() {
int status = 0;
if (!s_threadHasExited) {
status = pthread_cancel(s_threadInput);
}
if (status) {
fputs("[Error]: could not cancel input thread\n", stdout);
}
status = pthread_join(s_threadInput, NULL);
if (status) {
fputs("[Error]: could not join with input thread\n", stdout);
}
return;
}