new file mode 100644
@@ -0,0 +1,19 @@
+CC = gcc
+CFLAGS = -Wall -g -std=c89
+TARGET = main
+
+build: main
+
+main: main.c utils.o client.o
+ $(CC) $(CFLAGS) utils.o client.o -o $(TARGET) main.c
+
+client.o: client.c
+ $(CC) $(CFLAGS) -c client.c
+
+utils.o: utils.c
+ $(CC) $(CFLAGS) -c utils.c
+
+.PHONY: clean
+
+clean:
+ rm -f *.o *~ $(TARGET)
new file mode 100644
@@ -0,0 +1,285 @@
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+
+#include "client.h"
+#include "utils.h"
+
+#define HGPATH "hg"
+
+/*
+ * The function will read the header from the command server and will save it to
+ * the header parameter of the handle structure.
+ * \param handle The handle of the connection, wherewith I want to communicate
+ * \return 0 if succesfull
+ * -1 to indicate an error, with errno set appropriately
+ * */
+int read_header(hg_handle *handle)
+{
+ uint32_t length;
+ char ch_char;
+
+ if (!handle) {
+ return -1;
+ }
+
+ read(handle->p_read, &ch_char, 1);
+ read(handle->p_read, &length, sizeof(uint32_t));
+ handle->header.channel = ch_char;
+ handle->header.length = swap_uint32(length);
+
+ return 0;
+}
+
+/*
+ * After the connection, the command server sends a hello message.
+ * The message contains the command server capabilities and the messages
+ * encoding.
+ * \param handle The handle of the connection, wherewith I want to communicate
+ * \return 0 if succesfull
+ * -1 to indicate an error, with errno set appropriately
+ * */
+int read_hello(hg_handle *handle)
+{
+ char *buffer;
+ hg_header ch;
+
+ if (!handle) {
+ return -1;
+ }
+
+ read_header(handle);
+ ch = handle->header;
+
+ if(ch.length == 0)
+ return -1;
+
+ buffer = malloc(ch.length + 1);
+
+ read(handle->p_read, buffer, ch.length);
+ buffer[ch.length] = '\0';
+
+ printf("%c%u", ch.channel, ch.length);
+ printf("%s\n", buffer);
+
+ free(buffer);
+
+ return 0;
+}
+
+/*
+ * Open the connection with the mercurial command server.
+ * */
+hg_handle *hg_open(const char *path, char *encoding)
+{
+ hg_handle *handle = malloc(sizeof(hg_handle));
+ char command[100];
+ int wpipe[2];
+ int rpipe[2];
+ int c_write;
+ int c_read;
+
+ sprintf(command,
+ "%s serve --cmdserver pipe --config ui.interactive=True",
+ HGPATH);
+
+ if (path)
+ sprintf(command, "%s -R %s", command, path);
+
+ if (pipe(wpipe) < 0 || pipe(rpipe) < 0) {
+ printf("The connection failed\n");
+ }
+ handle->p_read = rpipe[0];
+ c_write = rpipe[1];
+ c_read = wpipe[0];
+ handle->p_write = wpipe[1];
+
+ if ((handle->childpid = fork()) < 0) {
+ printf("Fork failed\n");
+ return NULL;
+
+ } else if (handle->childpid == 0) { /* child */
+ close(handle->p_write);
+ close(handle->p_read);
+ dup2(c_read, STDIN_FILENO);
+ close(c_read);
+ dup2(c_write, STDOUT_FILENO);
+ close(c_write);
+ execl("/bin/sh", "sh", "-c", command, NULL);
+
+ } else { /* parent */
+ close(c_read);
+ close(c_write);
+ }
+
+ if(read_hello(handle) == -1)
+ return NULL;
+
+ return handle;
+}
+
+/*
+ * Close the connection for the given handle.
+ * */
+int hg_close(hg_handle **handle)
+{
+ if (!(*handle)) {
+ return -1;
+ }
+
+ kill((*handle)->childpid, SIGKILL);
+
+ close((*handle)->p_read);
+ close((*handle)->p_write);
+
+ free(*handle);
+ *handle = NULL;
+
+ return 0;
+}
+
+/*
+ * Prepare the command for sending process.
+ * Replace all the blank space with the '\0' character.
+ * \param command mercurial command with option parameters, separated through
+ * spaces
+ * \return Mercurial command with option parameters, separated through '\0'
+ * Ex:
+ * "tip -p" -> "tip\0-p"
+ * */
+char *cmd_prepare(char *const command[], size_t *cmd_size)
+{
+ size_t cmd_length = 0;
+ char *new_cmd;
+ int i;
+
+ for(i = 0; i < *cmd_size; ++i){
+ if(!command[i]){
+ *cmd_size = i;
+ break;
+ }
+ cmd_length += strlen(command[i]) + 1;
+ }
+
+ new_cmd = malloc(cmd_length + 1);
+
+ for(i = 0; i < *cmd_size; ++i){
+ strcpy(new_cmd, command[i]);
+ new_cmd += strlen(command[i]) + 1;
+ }
+ new_cmd -= cmd_length;
+
+ *cmd_size = cmd_length - 1;
+ return new_cmd;
+}
+
+/*
+ * Sending a command to the mercurial command server, through the given handle.
+ * */
+int hg_rawcommand(hg_handle *handle, char *const command[], size_t cmd_size)
+{
+ if (!handle) {
+ return -1;
+ }
+
+ char runcommand[] = "runcommand\n";
+ char *cmd_send = cmd_prepare(command, &cmd_size);
+ uint32_t big_endian_size = swap_uint32(cmd_size);
+
+ write(handle->p_write, runcommand, strlen(runcommand));
+ write(handle->p_write, &big_endian_size, sizeof(uint32_t));
+ write(handle->p_write, cmd_send, cmd_size);
+
+ read_header(handle);
+
+ free(cmd_send);
+ return 0;
+}
+
+/*
+ * Reading some unparse data from the server.
+ * */
+int hg_rawread(hg_handle *handle, char *buffer, size_t sizebuff)
+{
+ int length = handle->header.length;
+ if (!handle) {
+ return -1;
+ }
+ if(!(hg_channel(handle) == 'o' || hg_channel(handle) == 'e'))
+ return 0;
+
+ length = (length > sizebuff)? sizebuff : length;
+
+ read(handle->p_read, buffer, length);
+ buffer[length] = '\0';
+ handle->header.length -= length;
+
+ if(!handle->header.length)
+ read_header(handle);
+
+ return length;
+}
+
+/*
+ * Will write the buffer to the server.
+ * */
+int hg_rawwrite(hg_handle *handle, const char *buffer, size_t buff_size)
+{
+ int length = handle->header.length;
+ uint32_t swap_size;
+ if (!handle) {
+ return -1;
+ }
+ length = (length > buff_size)? buff_size : length;
+ swap_size = swap_uint32(length);
+
+ write(handle->p_write, &swap_size, sizeof(uint32_t));
+ write(handle->p_write, buffer, length);
+
+ read_header(handle);
+ return length;
+}
+
+/*
+ * The channel for the next chunk of data.
+ * */
+char hg_channel(hg_handle *handle)
+{
+ if (!handle) {
+ return -1;
+ }
+
+ return handle->header.channel;
+}
+
+/*
+ * The header for the next chunk of data.
+ * */
+hg_header hg_head(hg_handle *handle)
+{
+ return handle->header;
+}
+
+/*
+ * The exitcode for the current command.
+ * */
+int hg_exitcode(hg_handle *handle)
+{
+ int exitcode;
+
+ if (!handle) {
+ return -1;
+ }
+
+ read(handle->p_read, &exitcode, sizeof(int));
+
+ return exitcode;
+}
new file mode 100644
@@ -0,0 +1,14 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "utils.h"
+
+/*
+ * Byte swap unsigned int
+ * */
+uint32_t swap_uint32(uint32_t val)
+{
+ val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF);
+ return (val << 16) | (val >> 16);
+}
new file mode 100644
@@ -0,0 +1,12 @@
+#ifndef _UTILS_CHG_H_
+#define _UTILS_CHG_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+
+/*
+ * Byte swap unsigned int
+ * */
+uint32_t swap_uint32( uint32_t val );
+
+#endif