#include
#include
#include
#include “friends.h”
#define INPUT_BUFFER_SIZE 256
#define INPUT_ARG_MAX_NUM 12
#define DELIM ” \n”
* Print a formatted error message to stderr.
void error(char *msg) {
fprintf(stderr, “Error: %s\n”, msg);
* Read and process commands
* Return: -1 for quit command
* 0 otherwise
int process_args(int cmd_argc, char **cmd_argv, User **user_list_ptr) {
User *user_list = *user_list_ptr;
if (cmd_argc <= 0) {
} else if (strcmp(cmd_argv[0], "quit") == 0 && cmd_argc == 1) {
return -1;
} else if (strcmp(cmd_argv[0], "add_user") == 0 && cmd_argc == 2) {
switch (create_user(cmd_argv[1], user_list_ptr)) {
error("user by this name already exists");
error("username is too long");
} else if (strcmp(cmd_argv[0], "list_users") == 0 && cmd_argc == 1) {
list_users(user_list);
} else if (strcmp(cmd_argv[0], "make_friends") == 0 && cmd_argc == 3) {
switch (make_friends(cmd_argv[1], cmd_argv[2], user_list)) {
error("users are already friends");
error("at least one user you entered has the max number of friends");
error("you must enter two different users");
error("at least one user you entered does not exist");
} else if (strcmp(cmd_argv[0], "post") == 0 && cmd_argc >= 4) {
// first determine how long a string we need
int space_needed = 0;
for (int i = 3; i < cmd_argc; i++) {
space_needed += strlen(cmd_argv[i]) + 1;
// allocate the space
char *contents = malloc(space_needed);
if (contents == NULL) {
perror("malloc");
// copy in the bits to make a single string
strcpy(contents, cmd_argv[3]);
for (int i = 4; i < cmd_argc; i++) {
strcat(contents, " ");
strcat(contents, cmd_argv[i]);
User *author = find_user(cmd_argv[1], user_list);
User *target = find_user(cmd_argv[2], user_list);
switch (make_post(author, target, contents)) {
error("the users are not friends");
error("at least one user you entered does not exist");
} else if (strcmp(cmd_argv[0], "profile") == 0 && cmd_argc == 2) {
User *user = find_user(cmd_argv[1], user_list);
if (print_user(user) == 1) {
error("user not found");
error("Incorrect syntax");
* Tokenize the string stored in cmd.
* Return the number of tokens, and store the tokens in cmd_argv.
int tokenize(char *cmd, char **cmd_argv) {
int cmd_argc = 0;
char *next_token = strtok(cmd, DELIM);
while (next_token != NULL) {
if (cmd_argc >= INPUT_ARG_MAX_NUM – 1) {
error(“Too many arguments!”);
cmd_argc = 0;
cmd_argv[cmd_argc] = next_token;
cmd_argc++;
next_token = strtok(NULL, DELIM);
return cmd_argc;
int main(int argc, char* argv[]) {
int batch_mode = (argc == 2);
char input[INPUT_BUFFER_SIZE];
FILE *input_stream;
// Create the heads of the empty data structure
User *user_list = NULL;
if (batch_mode) {
input_stream = fopen(argv[1], “r”);
if (input_stream == NULL) {
perror(“Error opening file”);
// interactive mode
input_stream = stdin;
printf(“Welcome to FriendMe! (Local version)\nPlease type a command:\n> “);
while (fgets(input, INPUT_BUFFER_SIZE, input_stream) != NULL) {
// only echo the line in batch mode since in interactive mode the user
// just typed the line
if (batch_mode) {
printf(“%s”, input);
char *cmd_argv[INPUT_ARG_MAX_NUM];
int cmd_argc = tokenize(input, cmd_argv);
if (cmd_argc > 0 && process_args(cmd_argc, cmd_argv, &user_list) == -1) {
break; // can only reach if quit command was entered
printf(“> “);
if (batch_mode) {
fclose(input_stream);