@@ -400,3 +400,84 @@
return exitcode;
}
+
+/* The yield next step. Getting the next entry. */
+int hg_fetch_entry(hg_stream_buffer *stream, int (*detect_byte)(char *buff,
+ int buf_size, int data_on_pipe), int func_type)
+{
+ hg_header *head;
+ int exitcode, bc;
+ char read_data[BUFF_SIZE];
+
+ /* Erase the first entry from stream pointer.
+ * This entry was already pass to user.*/
+ if(stream->buf_size){
+ stream->buf_size = erase_entry(&stream->buffer, stream->buf_size,
+ stream->first_entry_size);
+ }
+
+ while(!detect_byte(stream->buffer + func_type, stream->buf_size, 1))
+ {
+ head = hg_read_header(stream->handle);
+ if(head->channel == r)
+ break;
+ /* trash output data, handle error data, return -1
+ **/
+ else if(head->channel == e){
+ trash_data(stream->handle, stream->callback);
+ free(stream->command);
+ free(stream->buffer);
+ free(stream);
+ return -1;
+ }
+
+ if(bc = hg_rawread(stream->handle, read_data, BUFF_SIZE), bc < 0)
+ return -1;
+ append_data(&stream->buffer, read_data, stream->buf_size, bc);
+ stream->buf_size += bc;
+
+ }
+ if(func_type == 1){
+ if(stream->buffer[0] != '\0'){
+ bc = detect_null_byte(stream->buffer, stream->buf_size, 0);
+ stream->buf_size = erase_entry(&stream->buffer,
+ stream->buf_size, bc);
+ }
+ }
+ if(bc = detect_byte(stream->buffer + func_type, stream->buf_size, 0),
+ bc > 0){
+ stream->first_entry_size = bc;
+ return 1;
+ }
+
+ exitcode = hg_exitcode(stream->handle);
+ free(stream->command);
+ free(stream->buffer);
+ free(stream);
+ if(exitcode)
+ return -1;
+ return 0;
+}
+
+/* The cbuf next step. Getting the next changeset. */
+int hg_fetch_cset_entry(hg_csetstream_buffer *cbuf, hg_cset_entry *centry)
+{
+ int exitcode = hg_fetch_entry(cbuf, &detect_null_byte, 1);
+ if (exitcode == 1){
+ cbuf->first_entry_size ++;
+ /* Parse first cset from data. */
+ parse_changeset(cbuf->buffer + 1, centry);
+ }
+ return exitcode;
+}
+
+/* The lbuf next step. Getting the next changeset. */
+int hg_fetch_line_entry(hg_linestream_buffer *lbuf, char **lentry)
+{
+ int exitcode = hg_fetch_entry(lbuf, &detect_endline_byte, 0);
+ if (exitcode == 1){
+ lbuf->buffer[lbuf->first_entry_size - 1] = '\0';
+ *lentry = lbuf->buffer;
+ }
+ return exitcode;
+}
@@ -89,6 +89,58 @@
} hg_handle;
/**
+ * \struct hg_csetstream_buffer
+ * \brief This structure will be use to create the yield-like mechanism. In this
+ * structure all the necessary informations about the current command will be
+ * maintained
+ *
+ * \var hg_csetstream_buffer::handle
+ * The handle of the connection, wherewith I want to communicate
+ * \var hg_csetstream_buffer::callback
+ * A function that will handle error data.
+ * \var hg_csetstream_buffer::command
+ * The command sended to cmdserver.
+ * \var hg_csetstream_buffer::buffer
+ * Place where the data will be maintained until is passed to user and used.
+ * \var hg_csetstream_buffer::buf_size
+ * The size for the buffer.
+ * \var hg_csetstream_buffer::first_cset_size
+ * The size for the first cset, maintained in buffer.
+ *
+ * \typedef hg_csetstream_buffer
+ * \brief This structure will be use to create the yield-like mechanism. In this
+ * structure all the necessary informations about the current command will be
+ * maintained
+ *
+ * \param handle
+ * The handle of the connection, wherewith I want to communicate
+ * \param callback
+ * A function that will handle error data.
+ * \param command
+ * The command sended to cmdserver.
+ * \param buffer
+ * Place where the data will be maintained until is passed to user and used.
+ * \param buf_size
+ * The size for the buffer.
+ * \param first_cset_size
+ * The size for the first cset, maintained in buffer.
+ * */
+typedef struct hg_stream_buffer{
+ hg_handle *handle;
+ int (*callback)(const char *msg, size_t len);
+ char **command;
+ char *buffer;
+ int buf_size;
+ int first_entry_size;
+}hg_stream_buffer;
+
+/**
+ * Same as hg_stream_buffer structure.
+ **/
+typedef struct hg_stream_buffer hg_linestream_buffer;
+typedef struct hg_stream_buffer hg_csetstream_buffer;
+
+/**
* \brief Reading the header from cmdsrv.
*
* The function will read the header from the command server and will save it to
@@ -295,4 +347,77 @@
int hg_addremove(hg_handle *handle, int(*callback)(const char *msg, size_t len),
char *argument[]);
+/**
+ * \brief The yield mechanism that will get the next entry.
+ *
+ * This function is used inside of hg_fetch_cset_entry() and hg_fetch_line_entry()
+ * function. This function represent the modularized function of those two.
+ *
+ * \param hg_stream_buffer The stream structure to store entry data.
+ * \param detect_byte The function to detect the size of the next entry.
+ * \param func_type The type for function that will use this function:
+ * - 0 for hg_fetch_cset_entry() used with detect_null_byte() function
+ * - 1 for hg_fetch_line_entry() used with detect_endline_byte() function
+ * \retval 1 Succesful operation, pass the first find cset to centry structure
+ * \retval 0 To indicate the end of log_command, everything works well.
+ * \retval -1 to indicate an error, with errno set appropriately.
+ *
+ * errno can be:
+ * - EINVAL - Invalid argument (handle it's set to a null pointer)
+ * - read(2) command errors
+ * - read_header error
+ * */
+int hg_fetch_entry(hg_stream_buffer *stream, int (*detect_byte)(char *buff,
+ int buf_size, int data_on_pipe), int func_type);
+
+/**
+ * \brief The yield mechanism that will get the next changeset.
+ *
+ * The revision history could have a huge mass of data. You cannot pass the
+ * entire history in one call, so we use an iterator-like mechanism. Calling
+ * the hg_fetch_log_entry. The next changeset will be read from cmd-server,
+ * parse and pass to hg_cset_entry structure.
+ * The cset_entry structure will handle a changeset with the following string
+ * fields:
+ * - rev
+ * - node
+ * - tags (space delimited)
+ * - branch
+ * - author
+ * - desc
+ *
+ * \param hg_csetstream_buffer The buffer structure to store cset data.
+ * \param centry The hg_cset_entry structure where the changeset will be stored
+ * and pass
+ * \retval 1 Succesful operation, pass the first find cset to centry structure
+ * \retval 0 To indicate the end of log_command, everything works well.
+ * \retval -1 to indicate an error, with errno set appropriately.
+ *
+ * errno can be:
+ * - EINVAL - Invalid argument (handle it's set to a null pointer)
+ * - read(2) command errors
+ * - read_header error
+ * */
+int hg_fetch_cset_entry(hg_csetstream_buffer *cbuf, hg_cset_entry *centry);
+
+/**
+ * \brief The yield mechanism that will get the next line.
+ *
+ * Some commands could perform huge amount of data, to pass this data to users
+ * in a parse way mode I provide this function. This function will return a line
+ * in a single call.
+ *
+ * \param hg_linestream_buffer The buffer structure to store line data.
+ * \param string Address where a line will be placed.
+ * \retval 1 Succesful operation, pass the first find line to lentry pointer.
+ * \retval 0 To indicate the end of command, everything works well.
+ * \retval -1 to indicate an error, with errno set appropriately.
+ *
+ * errno can be:
+ * - EINVAL - Invalid argument (handle it's set to a null pointer)
+ * - read(2) command errors
+ * - read_header error
+ * */
+int hg_fetch_line_entry(hg_linestream_buffer *lbuf, char **lentry);
+
#endif
@@ -82,3 +82,55 @@
memcpy(*dest + dsize, source, ssize + 1);
return 0;
}
+
+/*
+ * Erase the top entry from buff pointer.
+ * */
+int erase_entry(char **buff, int buf_size, int first_entry_size)
+{
+ int new_buff_size = buf_size - first_entry_size;
+ char *new_buff = malloc(new_buff_size + 1);
+ memcpy(new_buff, *buff + first_entry_size, new_buff_size + 1);
+ free(*buff);
+ *buff = new_buff;
+ return new_buff_size;
+}
+
+/*
+ * Detect the first null byte.
+ * */
+int detect_null_byte(char *buffer, int buf_size, int data_on_pipe)
+{
+ if(buffer == NULL)
+ return 0;
+ char *char_ptr;
+
+ for(char_ptr = buffer; char_ptr < buffer + buf_size; ++char_ptr)
+ if( *char_ptr == '\0')
+ break;
+
+ if((char_ptr - buffer + 1 < buf_size && data_on_pipe) ||
+ (char_ptr - buffer + 1 <= buf_size && !data_on_pipe))
+ return char_ptr - buffer;
+
+ return 0;
+}
+
+/*
+ * Detect the first endline byte.
+ * */
+int detect_endline_byte(char *buffer, int buf_size, int data_on_pipe)
+{
+ if(buffer == NULL)
+ return 0;
+ char *char_ptr;
+
+ for(char_ptr = buffer; char_ptr < buffer + buf_size; ++char_ptr)
+ if( *char_ptr == '\n')
+ break;
+ if((char_ptr - buffer + 1 < buf_size && data_on_pipe) ||
+ (char_ptr - buffer + 1 <= buf_size && !data_on_pipe))
+ return char_ptr - buffer + 1;
+
+ return 0;
+}
@@ -51,4 +51,60 @@
* */
int append_data(char **dest, char *source, int dsize, int ssize);
+/**
+ * \brief Erase the some data from a pointer.
+ *
+ * After an entry is send to the user I don't need any more that
+ * data, so I create space for the incoming data.
+ *
+ * \param buff The pointer that I wished to resize.
+ * \param buf_size The size of the pointer
+ * \param first_entry_size The size that I want to erase.
+ * \retval integer The new size of the pointer.
+ * */
+int erase_entry(char **buff, int buf_size, int first_entry_size);
+
+/**
+ * \brief Detect the first null byte.
+ *
+ * Sometimes I will store data that will contain more null bytes,
+ * and I would like to know the length to the first null byte.
+ *
+ * Also this function will tell me if the buffer contain more null
+ * bytes. (if data_on_pipe is set to 1 I want to know the length to
+ * the first entry, also if data_on_pipe is set to 0 I want to know
+ * the length to the first entry or length to the end).
+ *
+ * \param buffer The pointer where I want to make de evaluation.
+ * \param buf_size The size of the pointer
+ * \param data_on_pipe
+ * - Is 1 if I want to know the lenght to the first entry.
+ * - Is 0 if I want to know the lenght to the first entry or the
+ * length to the end.
+ * \retval length The length of the first entry.
+ * */
+int detect_null_byte(char *buffer, int buf_size, int data_on_pipe);
+
+/**
+ * \brief Detect the first endline byte.
+ *
+ * Sometimes I will store data that will contain more endline bytes,
+ * and I would like to know the length to the first endline byte.
+ *
+ * Also this function will tell me if the buffer contain more endline
+ * bytes. (if data_on_pipe is set to 1 I want to know the length to
+ * the first entry, also if data_on_pipe is set to 0 I want to know
+ * the length to the first entry or length to the end).
+ *
+ * \param buffer The pointer where I want to make de evaluation.
+ * \param buf_size The size of the pointer
+ * \param data_on_pipe
+ * - Is 1 if I want to know the lenght to the first entry.
+ * - Is 0 if I want to know the lenght to the first entry or the
+ * length to the end.
+ * \retval length The length of the first entry.
+ * */
+int detect_endline_byte(char *buffer, int buf_size, int data_on_pipe);
+
+
#endif