Keep prompt at bottom of screen for messaging app

267 Views Asked by At

I'm trying to develop a CLI messaging app in C on mac for network programming practice but I'm not sure how to effectively manipulate the command line to make it usable. Currently the prompt will display "Enter a message: " but if a message comes in before the user finished typing their message something like this could happen: "Enter a message: Hello wClient: I'm interupting youorld".

The solution I'd like to have would be to have the "Enter a message" prompt always at the bottom of the screen with the incoming and outgoing messages coming down from the top as you'd have in basically any messenger, though I have no idea how to glue something to the bottom of the terminal or how to visually affect the terminal in any way.

Here's the entirety of the code so far:

Server

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>

int main() {

  int listenfd = 0, connfd = 0;

  struct sockaddr_in serv_addr;

  char sendBuff[1025];
  char recvBuff[1025] = "test"; 

  listenfd = socket(AF_INET, SOCK_STREAM, 0);

  memset(&serv_addr, '0', sizeof(serv_addr));
  memset(sendBuff, '0', sizeof(sendBuff));

  serv_addr.sin_family = AF_INET;    
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
  serv_addr.sin_port = htons(5000);    

  bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

  if (listen(listenfd, 10) == -1) {
    printf("Failed to listen\n");
    return -1;
  }

  connfd = accept(listenfd, (struct sockaddr*)NULL ,NULL);

  pid_t pid = fork();
  if (pid) {
    while (strncmp(recvBuff, "exit", 4) != 0) {
      if(recv(connfd, recvBuff, sizeof(recvBuff)-1, 0) < 0)
        printf("Error: Recieve\nErrno: %d\n", errno);
      recvBuff[1024] = 0;

      printf("Client: %s", recvBuff);
    }

    wait(&pid);
    close(connfd);

  } else {
    while (strncmp(sendBuff, "exit", 4) != 0) {
      fputs("Enter a message: ", stdout);
      fgets(sendBuff, sizeof(sendBuff), stdin);

      if(send(connfd, sendBuff, sizeof(sendBuff), 0) < 0)
      printf("Error: Send\nErrno: %d\n", errno);
    }
    close(connfd);
    exit(0);
  }

  close(listenfd); 

  return 0;    

}

Client

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>

int main(void)
{
  int sockfd = 0;
  char recvBuff[1024];
  char sendBuff[1024] = "";
  struct sockaddr_in serv_addr;

  memset(recvBuff, '0' ,sizeof(recvBuff));
  if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    printf("\n Error : Could not create socket \n");
    return 1;
  }

  serv_addr.sin_family = AF_INET;
  serv_addr.sin_port = htons(5000);
  serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

  if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
    printf("\n Error : Connect Failed \n");
    return 1;
  }

  pid_t pid = fork();
  if (pid) {
    while (strncmp(recvBuff, "exit", 4) != 0) {
      if(recv(sockfd, recvBuff, sizeof(recvBuff)-1, 0) < 0)
        printf("Error: Receive\nErrno: %d\n", errno);
      recvBuff[1024] = 0;

      printf("Server: %s", recvBuff);
    }

    wait(&pid);
    close(sockfd);

  } else {
    while (strncmp(sendBuff, "exit", 4) != 0) {
      fputs("Enter a message: ", stdout);
      fgets(sendBuff, sizeof(sendBuff), stdin);

      if(send(sockfd, sendBuff, sizeof(sendBuff), 0) < 0)
        printf("Error: Send\nErrno: %d\n", errno);
    }
    close(sockfd);
    exit(0);
  }

  return 0;
}

Also any side notes about coding style or networking techniques are appreciated too. Thanks.

2

There are 2 best solutions below

0
On

I'd advise you use a library called Ncurses. It was made for creating nice terminal interfaces without wanting to smash your keyboard. You would create 2 windows, one for the server chat and one for the client chat.

If you can't use external libraries, your best bet would be to use escape codes to move the cursor. Some pseudo code might look like:

when server message is received
  Move cursor up one
  Write message
  Move back down

when user enters message
  print on regular line

This is a major pain to handle with though, and platform specific. So if possible, ncurses all the way.

0
On

there are lots of 'escape' sequences for handling a terminal.

suggest reading: http://en.wikipedia.org/wiki/ANSI_escape_code

Using those escape sequences, the program can save/restore the current cursor position.

turn OFF the keyboard echo.

when a char is entered by the user.

save current cursor position
jump to next available position in user input line
echo the char
return to the prior cursor position