Add basic APIs including var_int32 getter and setters
authorAhmet Artu Yildirim <ahmet@artulab.com>
Sun, 18 Dec 2022 09:34:56 +0000 (01:34 -0800)
committerAhmet Artu Yildirim <ahmet@artulab.com>
Wed, 21 Dec 2022 09:52:05 +0000 (01:52 -0800)
12 files changed:
.gitignore
build-debug.sh [new file with mode: 0755]
build-release.sh [new file with mode: 0755]
configure.ac
scripts/clean.sh
scripts/format.sh
src/Makefile.am
src/check_progbuf.c [new file with mode: 0644]
src/common.h
src/progbuf.c
src/progbuf.h
src/test_progbuf.c [deleted file]

index 0da60c7..ad1001a 100644 (file)
@@ -26,8 +26,13 @@ src/.libs/
 src/Makefile
 src/libprogbuf.la
 src/libprogbuf.lo
-src/test_progbuf
 src/*.o
+src/check_progbuf
+src/check_progbuf.log
+src/check_progbuf.trs
+src/progbuf.lo
+src/test-suite.log
+test-driver
 stamp-h1
-.idea/
+.vscode/
 build/
diff --git a/build-debug.sh b/build-debug.sh
new file mode 100755 (executable)
index 0000000..e70a968
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+./configure CPPFLAGS=-DDEBUG CFLAGS="-g -O0" && make
diff --git a/build-release.sh b/build-release.sh
new file mode 100755 (executable)
index 0000000..5bb11df
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+./configure && make
index c840754..a29fb11 100644 (file)
@@ -3,6 +3,7 @@ AM_INIT_AUTOMAKE([-Wall -Werror gnu])
 AC_PROG_CC
 AM_PROG_AR
 LT_INIT
+PKG_CHECK_MODULES([CHECK], [check])
 AC_CONFIG_MACRO_DIRS([m4])
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_FILES([
index bdb3380..18ff4c4 100755 (executable)
@@ -1,3 +1,3 @@
 #!/bin/sh
 
-rm -rf aclocal.m4 config.sub configure depcomp m4 ar-lib compile config.guess config.h install-sh Makefile Makefile.in autom4te.cache config.h.in ltmain.sh missing libtool config.status config.log INSTALL stamp-h1 src/Makefile.in src/.libs src/.deps src/*.o src/Makefile src/libprogbuf.la src/progbuf.lo src/test_progbuf build config.h.in~
+rm -rf aclocal.m4 config.sub configure depcomp m4 ar-lib compile config.guess config.h install-sh test-driver Makefile Makefile.in autom4te.cache config.h.in ltmain.sh missing libtool config.status config.log INSTALL stamp-h1 src/Makefile.in src/.libs src/.deps src/*.o src/Makefile src/libprogbuf.la src/progbuf.lo src/check_progbuf build config.h.in~
index 718c9f5..ee3a1dd 100755 (executable)
@@ -1,4 +1,4 @@
 #!/bin/sh
 
-find src -iname *.h -o -iname *.c | xargs clang-format -style=GNU -i
+find ./src -iname *.h -o -iname *.c | xargs clang-format -style=GNU -i
 
index ad6cdfe..4d4941b 100644 (file)
@@ -3,6 +3,9 @@ libprogbuf_la_SOURCES = progbuf.c
 libprogbuf_la_LDFLAGS = -version-info 0:1:0
 include_HEADERS = progbuf.h
 
-bin_PROGRAMS = test_progbuf
-test_progbuf_SOURCES = test_progbuf.c
-test_progbuf_LDADD = libprogbuf.la
+noinst_PROGRAMS = check_progbuf
+TESTS = check_progbuf
+check_progbuf_SOURCES = check_progbuf.c
+check_progbuf_CFLAGS = $(CFLAGS) $(CHECK_CFLAGS)
+check_progbuf_LDADD = libprogbuf.la $(LDFLAGS) $(CHECK_LIBS)
+check_progbuf_LDFLAGS = -no-install
diff --git a/src/check_progbuf.c b/src/check_progbuf.c
new file mode 100644 (file)
index 0000000..756b3a4
--- /dev/null
@@ -0,0 +1,372 @@
+#include <check.h>
+#include <stdlib.h>
+
+#include "common.h"
+#include "progbuf.h"
+
+START_TEST (test_progbuf_alloc_version)
+{
+  int ret;
+  long message_tag;
+
+  ret = progbuf_get_message_tag (NULL, &message_tag);
+  ck_assert (ret == PROGBUF_ERROR_NULL_PARAM);
+
+  progbuf_h buf = progbuf_alloc (1);
+
+  ck_assert (buf);
+
+  ret = progbuf_get_message_tag (buf, NULL);
+  ck_assert (ret == PROGBUF_ERROR_NULL_PARAM);
+
+  ret = progbuf_get_message_tag (buf, &message_tag);
+
+  ck_assert (ret == PROGBUF_SUCCESS);
+  ck_assert (message_tag == 1);
+
+  size_t size;
+  ret = progbuf_get_message_buffer (buf, NULL, &size);
+
+  ck_assert (ret == PROGBUF_SUCCESS);
+
+  ck_assert (size == 1);
+
+  ret = progbuf_free (buf);
+  ck_assert (ret == PROGBUF_SUCCESS);
+}
+END_TEST
+
+void
+parametric_test_progbuf_write_read_long (const long val,
+                                         const int expected_val_size)
+{
+  progbuf_h buf = progbuf_alloc (1);
+
+  ck_assert (buf);
+
+  long p_val = val;
+
+  int ret = progbuf_set_long (buf, p_val);
+
+  ck_assert (ret == PROGBUF_SUCCESS);
+
+  size_t size;
+  ret = progbuf_get_message_buffer (buf, NULL, &size);
+
+  ck_assert (ret == PROGBUF_SUCCESS);
+
+  ck_assert (size == 1 + 1 + expected_val_size);
+
+  progbuf_it_h iter = progbuf_iter_alloc (buf);
+
+  ck_assert (iter);
+
+  ret = progbuf_get_long (iter, &p_val);
+
+  ck_assert (ret == PROGBUF_SUCCESS);
+  ck_assert (val == p_val);
+
+  struct progbuf_it_s *iter_internal = iter;
+
+  ck_assert (iter_internal->read_pos == 1 + 1 + expected_val_size);
+
+  ret = progbuf_iter_free (iter);
+  ck_assert (ret == PROGBUF_SUCCESS);
+
+  ret = progbuf_free (buf);
+  ck_assert (ret == PROGBUF_SUCCESS);
+}
+
+START_TEST (test_progbuf_write_read_positive_long)
+{
+  parametric_test_progbuf_write_read_long (0, 1);
+  parametric_test_progbuf_write_read_long (1, 1);
+  parametric_test_progbuf_write_read_long (0x3F, 1);
+
+  parametric_test_progbuf_write_read_long (0x7F, 2);
+  parametric_test_progbuf_write_read_long (0x1FFF, 2);
+
+  parametric_test_progbuf_write_read_long (0x3FFF, 3);
+  parametric_test_progbuf_write_read_long (0xFFFFF, 3);
+
+  parametric_test_progbuf_write_read_long (0x1FFFFF, 4);
+  parametric_test_progbuf_write_read_long (0x7FFFFFF, 4);
+
+  parametric_test_progbuf_write_read_long (0xFFFFFFF, 5);
+  parametric_test_progbuf_write_read_long (0x7FFFFFFF, 5);
+}
+END_TEST
+
+START_TEST (test_progbuf_write_read_negative_long)
+{
+  parametric_test_progbuf_write_read_long (-1, 1);
+  parametric_test_progbuf_write_read_long (-0x3F, 1);
+
+  parametric_test_progbuf_write_read_long (-0x7F, 2);
+  parametric_test_progbuf_write_read_long (-0x1FFF, 2);
+
+  parametric_test_progbuf_write_read_long (-0x3FFF, 3);
+  parametric_test_progbuf_write_read_long (-0xFFFFF, 3);
+
+  parametric_test_progbuf_write_read_long (-0x1FFFFF, 4);
+  parametric_test_progbuf_write_read_long (-0x7FFFFFF, 4);
+
+  parametric_test_progbuf_write_read_long (-0xFFFFFFF, 5);
+  parametric_test_progbuf_write_read_long (-0x7FFFFFFF, 5);
+}
+END_TEST
+
+START_TEST (test_progbuf_write_read_ulong)
+{
+  progbuf_h buf = progbuf_alloc (1);
+
+  ck_assert (buf);
+
+  unsigned long val = 0xFFFFFFFF;
+  unsigned long p_val = val;
+
+  int ret = progbuf_set_ulong (buf, p_val);
+
+  ck_assert (ret == PROGBUF_SUCCESS);
+
+  size_t size;
+
+  ret = progbuf_get_message_buffer (NULL, NULL, NULL);
+  ck_assert (ret == PROGBUF_ERROR_NULL_PARAM);
+
+  ret = progbuf_get_message_buffer (NULL, NULL, &size);
+  ck_assert (ret == PROGBUF_ERROR_NULL_PARAM);
+
+  ret = progbuf_get_message_buffer (buf, NULL, NULL);
+  ck_assert (ret == PROGBUF_ERROR_NULL_PARAM);
+
+  ret = progbuf_get_message_buffer (buf, NULL, &size);
+  ck_assert (ret == PROGBUF_SUCCESS);
+
+  ck_assert (size == 1 + 6);
+
+  progbuf_it_h iter = progbuf_iter_alloc (buf);
+
+  ck_assert (iter);
+
+  ret = progbuf_get_ulong (iter, &p_val);
+
+  ck_assert (ret == PROGBUF_SUCCESS);
+  ck_assert (val == p_val);
+
+  struct progbuf_it_s *iter_internal = iter;
+
+  ck_assert (iter_internal->read_pos == 1 + 6);
+
+  ret = progbuf_iter_free (iter);
+  ck_assert (ret == PROGBUF_SUCCESS);
+
+  ret = progbuf_free (buf);
+  ck_assert (ret == PROGBUF_SUCCESS);
+}
+END_TEST
+
+void
+parametric_test_progbuf_write_read_longlong (const long long val,
+                                             const int expected_val_size)
+{
+  progbuf_h buf = progbuf_alloc (1);
+
+  ck_assert (buf);
+
+  long long p_val = val;
+
+  int ret = progbuf_set_longlong (buf, p_val);
+
+  ck_assert (ret == PROGBUF_SUCCESS);
+
+  size_t size;
+  ret = progbuf_get_message_buffer (buf, NULL, &size);
+
+  ck_assert (ret == PROGBUF_SUCCESS);
+
+  ck_assert (size == 1 + 1 + expected_val_size);
+
+  progbuf_it_h iter = progbuf_iter_alloc (buf);
+
+  ck_assert (iter);
+
+  ret = progbuf_get_longlong (iter, &p_val);
+
+  ck_assert (ret == PROGBUF_SUCCESS);
+  ck_assert (val == p_val);
+
+  struct progbuf_it_s *iter_internal = iter;
+
+  ck_assert (iter_internal->read_pos == 1 + 1 + expected_val_size);
+
+  ret = progbuf_iter_free (iter);
+  ck_assert (ret == PROGBUF_SUCCESS);
+
+  ret = progbuf_free (buf);
+  ck_assert (ret == PROGBUF_SUCCESS);
+}
+
+START_TEST (test_progbuf_write_read_positive_longlong)
+{
+  parametric_test_progbuf_write_read_longlong (0, 1);
+  parametric_test_progbuf_write_read_longlong (1, 1);
+  parametric_test_progbuf_write_read_longlong (0x3F, 1);
+
+  parametric_test_progbuf_write_read_longlong (0x7F, 2);
+  parametric_test_progbuf_write_read_longlong (0x1FFF, 2);
+
+  parametric_test_progbuf_write_read_longlong (0x3FFF, 3);
+  parametric_test_progbuf_write_read_longlong (0xFFFFF, 3);
+
+  parametric_test_progbuf_write_read_longlong (0x1FFFFF, 4);
+  parametric_test_progbuf_write_read_longlong (0x7FFFFFF, 4);
+
+  parametric_test_progbuf_write_read_longlong (0xFFFFFFF, 5);
+  parametric_test_progbuf_write_read_longlong (0x3FFFFFFFF, 5);
+
+  parametric_test_progbuf_write_read_longlong (0x7FFFFFFFF, 6);
+  parametric_test_progbuf_write_read_longlong (0x1FFFFFFFFFF, 6);
+
+  parametric_test_progbuf_write_read_longlong (0x3FFFFFFFFFF, 7);
+  parametric_test_progbuf_write_read_longlong (0xFFFFFFFFFFFF, 7);
+
+  parametric_test_progbuf_write_read_longlong (0x1FFFFFFFFFFFF, 8);
+  parametric_test_progbuf_write_read_longlong (0x7FFFFFFFFFFFFF, 8);
+
+  parametric_test_progbuf_write_read_longlong (0xFFFFFFFFFFFFFF, 9);
+  parametric_test_progbuf_write_read_longlong (0x3FFFFFFFFFFFFFFF, 9);
+
+  parametric_test_progbuf_write_read_longlong (0x7FFFFFFFFFFFFFFF, 10);
+}
+END_TEST
+
+START_TEST (test_progbuf_write_read_negative_longlong)
+{
+  parametric_test_progbuf_write_read_longlong (-1, 1);
+  parametric_test_progbuf_write_read_longlong (-0x3F, 1);
+
+  parametric_test_progbuf_write_read_longlong (-0x7F, 2);
+  parametric_test_progbuf_write_read_longlong (-0x1FFF, 2);
+
+  parametric_test_progbuf_write_read_longlong (-0x3FFF, 3);
+  parametric_test_progbuf_write_read_longlong (-0xFFFFF, 3);
+
+  parametric_test_progbuf_write_read_longlong (-0x1FFFFF, 4);
+  parametric_test_progbuf_write_read_longlong (-0x7FFFFFF, 4);
+
+  parametric_test_progbuf_write_read_longlong (-0xFFFFFFF, 5);
+  parametric_test_progbuf_write_read_longlong (-0x7FFFFFFF, 5);
+
+  parametric_test_progbuf_write_read_longlong (-0x7FFFFFFFF, 6);
+  parametric_test_progbuf_write_read_longlong (-0x1FFFFFFFFFF, 6);
+
+  parametric_test_progbuf_write_read_longlong (-0x3FFFFFFFFFF, 7);
+  parametric_test_progbuf_write_read_longlong (-0xFFFFFFFFFFFF, 7);
+
+  parametric_test_progbuf_write_read_longlong (-0x1FFFFFFFFFFFF, 8);
+  parametric_test_progbuf_write_read_longlong (-0x7FFFFFFFFFFFFF, 8);
+
+  parametric_test_progbuf_write_read_longlong (-0xFFFFFFFFFFFFFF, 9);
+  parametric_test_progbuf_write_read_longlong (-0x3FFFFFFFFFFFFFFF, 9);
+
+  parametric_test_progbuf_write_read_longlong (-0x7FFFFFFFFFFFFFFF, 10);
+}
+END_TEST
+
+START_TEST (test_progbuf_write_read_ulonglong)
+{
+  progbuf_h buf = progbuf_alloc (1);
+
+  ck_assert (buf);
+
+  unsigned long long val = 0xFFFFFFFFFFFFFFFF;
+  unsigned long long p_val = val;
+
+  int ret = progbuf_set_ulonglong (buf, p_val);
+
+  ck_assert (ret == PROGBUF_SUCCESS);
+
+  size_t size;
+
+  ret = progbuf_get_message_buffer (NULL, NULL, NULL);
+  ck_assert (ret == PROGBUF_ERROR_NULL_PARAM);
+
+  ret = progbuf_get_message_buffer (NULL, NULL, &size);
+  ck_assert (ret == PROGBUF_ERROR_NULL_PARAM);
+
+  ret = progbuf_get_message_buffer (buf, NULL, NULL);
+  ck_assert (ret == PROGBUF_ERROR_NULL_PARAM);
+
+  ret = progbuf_get_message_buffer (buf, NULL, &size);
+  ck_assert (ret == PROGBUF_SUCCESS);
+
+  ck_assert (size == 1 + 1 + 10);
+
+  progbuf_it_h iter = progbuf_iter_alloc (buf);
+
+  ck_assert (iter);
+
+  ret = progbuf_get_ulonglong (iter, &p_val);
+
+  ck_assert (ret == PROGBUF_SUCCESS);
+  ck_assert (val == p_val);
+
+  struct progbuf_it_s *iter_internal = iter;
+
+  ck_assert (iter_internal->read_pos == 1 + 1 + 10);
+
+  ret = progbuf_iter_free (iter);
+  ck_assert (ret == PROGBUF_SUCCESS);
+
+  ret = progbuf_free (buf);
+  ck_assert (ret == PROGBUF_SUCCESS);
+}
+END_TEST
+
+static Suite *
+progbuf_suite (void)
+{
+  Suite *s;
+  TCase *tc_basic, *tc_long, *tc_longlong;
+
+  s = suite_create ("progbuf test suite");
+
+  tc_basic = tcase_create ("basic");
+
+  tcase_add_test (tc_basic, test_progbuf_alloc_version);
+
+  tc_long = tcase_create ("encode_long");
+
+  tcase_add_test (tc_long, test_progbuf_write_read_positive_long);
+  tcase_add_test (tc_long, test_progbuf_write_read_negative_long);
+  tcase_add_test (tc_long, test_progbuf_write_read_ulong);
+
+  tc_longlong = tcase_create ("encode_longlong");
+
+  tcase_add_test (tc_longlong, test_progbuf_write_read_positive_longlong);
+  tcase_add_test (tc_longlong, test_progbuf_write_read_negative_longlong);
+  tcase_add_test (tc_longlong, test_progbuf_write_read_ulonglong);
+
+  suite_add_tcase (s, tc_basic);
+  suite_add_tcase (s, tc_long);
+  suite_add_tcase (s, tc_longlong);
+
+  return s;
+}
+
+int
+main ()
+{
+  int number_failed;
+  Suite *s;
+  SRunner *sr;
+
+  s = progbuf_suite ();
+  sr = srunner_create (s);
+
+  srunner_run_all (sr, CK_NORMAL);
+  number_failed = srunner_ntests_failed (sr);
+  srunner_free (sr);
+  return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
index 2a2e8ca..5d63f7e 100644 (file)
@@ -1,12 +1,31 @@
 #ifndef LIBPROGBUF_COMMON_H
 #define LIBPROGBUF_COMMON_H
 
+#include <stddef.h>
+
+#define ABS(N) ((N<0)?(-N):(N))
+
+#define PROGBUF_INIT_BUFSIZ       128
+
+#define PROGBUF_TYPE_VAR_INT     0x00
+#define PROGBUF_TYPE_FLOAT32     0x01
+#define PROGBUF_TYPE_FLOAT64     0x02
+#define PROGBUF_TYPE_BYTE        0x03
+#define PROGBUF_TYPE_ARRAY       0x04
+
 struct progbuf_s
 {
-  int message_tag;
-  int version;
   char *buffer;
-  int bufsiz;
+  long message_tag;
+  int header_size;
+  size_t capacity;
+  size_t size;
+};
+
+struct progbuf_it_s
+{
+  struct progbuf_s* buf;
+  size_t read_pos;
 };
 
 #endif // LIBPROGBUF_COMMON_H
index a300efe..47d450e 100644 (file)
 #include "common.h"
 
 #include <stdlib.h>
+#include <string.h>
+
+typedef unsigned int uint;
+typedef unsigned long ulong;
+typedef long long longlong;
+typedef unsigned long long ulonglong;
+
+#define DETERMINE_VAR_SIZE(type)                                              \
+  static inline int determine_var_##type##_size (type value)                  \
+  {                                                                           \
+    type mask;                                                                \
+    memset (&mask, 0xFF, sizeof (mask));                                      \
+                                                                              \
+    mask <<= 6;                                                               \
+                                                                              \
+    if ((value & mask) == 0)                                                  \
+      return 1;                                                               \
+                                                                              \
+    int s = 2;                                                                \
+    while (1)                                                                 \
+      {                                                                       \
+        mask <<= 7;                                                           \
+                                                                              \
+        if ((value & mask) == 0)                                              \
+          return s;                                                           \
+                                                                              \
+        s++;                                                                  \
+      }                                                                       \
+  }
+
+#define READ_VAR_SIZE(type)                                                   \
+  static inline int read_var_##type (progbuf_it_h iter, type *value,          \
+                                     int *negative)                           \
+  {                                                                           \
+    type tmp = 0;                                                             \
+    size_t prev_read_pos = iter->read_pos;                                    \
+                                                                              \
+    int i = 0;                                                                \
+    char byte;                                                                \
+    const int bitsize = sizeof (type) * 8;                                    \
+    while (i < bitsize)                                                       \
+      {                                                                       \
+        byte = iter->buf->buffer[iter->read_pos++];                           \
+        if (i == 0)                                                           \
+          {                                                                   \
+            *negative = byte & 0x40;                                          \
+            tmp |= (type)(byte & 0x3F) << i;                                  \
+            i += 6;                                                           \
+          }                                                                   \
+        else                                                                  \
+          {                                                                   \
+            tmp |= (type)(byte & 0x7F) << i;                                  \
+            i += 7;                                                           \
+          }                                                                   \
+                                                                              \
+        if ((byte & 0x80) == 0)                                               \
+          {                                                                   \
+            *value = tmp;                                                     \
+            return 0;                                                         \
+          }                                                                   \
+      }                                                                       \
+                                                                              \
+    iter->read_pos = prev_read_pos;                                           \
+    return -1;                                                                \
+  }
+
+#define WRITE_VAR_SIZE(type)                                                  \
+  static inline void write_var_##type (progbuf_h buf, type value, int size,   \
+                                       int negative)                          \
+  {                                                                           \
+    for (int i = 0; i < size - 1; ++i)                                        \
+      {                                                                       \
+        if (i == 0)                                                           \
+          {                                                                   \
+            if (negative)                                                     \
+              {                                                               \
+                buf->buffer[buf->size] = (char)((value & 0x3F) | 0xC0);       \
+              }                                                               \
+            else                                                              \
+              {                                                               \
+                buf->buffer[buf->size] = (char)((value & 0x3F) | 0x80);       \
+              }                                                               \
+            value = (type)((type)value >> 6);                                 \
+          }                                                                   \
+        else                                                                  \
+          {                                                                   \
+            buf->buffer[buf->size + i] = (char)((value & 0x7F) | 0x80);       \
+            value = (type)((type)value >> 7);                                 \
+          }                                                                   \
+      }                                                                       \
+                                                                              \
+    if (size == 1 && negative)                                                \
+      {                                                                       \
+        buf->buffer[buf->size] = (char)value | 0x40;                          \
+      }                                                                       \
+    else                                                                      \
+      {                                                                       \
+        buf->buffer[buf->size + (size - 1)] = (char)value;                    \
+      }                                                                       \
+                                                                              \
+    buf->size += size;                                                        \
+  }
+
+static inline int
+check_buffer_and_expand (progbuf_h buf, int size)
+{
+  if (buf->size + size > buf->capacity)
+    {
+      char *newbuf = malloc (buf->capacity * 2);
+      if (!newbuf)
+        return PROGBUF_ERROR_MEM_ALLOC;
+
+      memcpy (newbuf, buf->buffer, buf->capacity);
+      free (buf->buffer);
+      buf->buffer = newbuf;
+      buf->capacity *= 2;
+    }
+  return 0;
+}
+
+DETERMINE_VAR_SIZE (uint)
+READ_VAR_SIZE (uint)
+WRITE_VAR_SIZE (uint)
+
+DETERMINE_VAR_SIZE (ulong)
+READ_VAR_SIZE (ulong)
+WRITE_VAR_SIZE (ulong)
+
+DETERMINE_VAR_SIZE (ulonglong)
+READ_VAR_SIZE (ulonglong)
+WRITE_VAR_SIZE (ulonglong)
+
+#define PROGBUF_SET(type, utype)                                              \
+  int progbuf_set_##type (progbuf_h buf, type value)                          \
+  {                                                                           \
+    int val_size, ret;                                                        \
+                                                                              \
+    if (!buf)                                                                 \
+      return PROGBUF_ERROR_NULL_PARAM;                                        \
+                                                                              \
+    val_size = determine_var_##utype##_size (ABS (value));                    \
+    ret = check_buffer_and_expand (buf, val_size + 1);                        \
+    if (ret != 0)                                                             \
+      return ret;                                                             \
+                                                                              \
+    buf->buffer[buf->size] = PROGBUF_TYPE_VAR_INT;                            \
+    buf->size++;                                                              \
+                                                                              \
+    write_var_##utype (buf, ABS (value), val_size, value < 0);                \
+                                                                              \
+    return PROGBUF_SUCCESS;                                                   \
+  }
+
+#define PROGBUF_GET(type, utype)                                              \
+  int progbuf_get_##type (progbuf_it_h iter, type *value)                     \
+  {                                                                           \
+    if (!iter || !value)                                                      \
+      return PROGBUF_ERROR_NULL_PARAM;                                        \
+                                                                              \
+    if (iter->read_pos >= iter->buf->size)                                    \
+      return PROGBUF_ERROR_END_OF_ITER;                                       \
+                                                                              \
+    char val_type = iter->buf->buffer[iter->read_pos];                        \
+                                                                              \
+    if ((val_type & PROGBUF_TYPE_VAR_INT) != PROGBUF_TYPE_VAR_INT)            \
+      return PROGBUF_ERROR_UNEXPECTED_TYPE;                                   \
+                                                                              \
+    iter->read_pos++;                                                         \
+                                                                              \
+    utype u_value;                                                            \
+    int negative;                                                             \
+    if (read_var_##utype (iter, &u_value, &negative) != 0)                    \
+      {                                                                       \
+        iter->read_pos--;                                                     \
+        return PROGBUF_ERROR_READ;                                            \
+      }                                                                       \
+                                                                              \
+    *value = (negative ? -u_value : u_value);                                 \
+                                                                              \
+    return PROGBUF_SUCCESS;                                                   \
+  }
+
+PROGBUF_SET (int, uint)
+PROGBUF_GET (int, uint)
+
+PROGBUF_SET (uint, uint)
+PROGBUF_GET (uint, uint)
+
+PROGBUF_SET (long, ulong)
+PROGBUF_GET (long, ulong)
+
+PROGBUF_SET (ulong, ulong)
+PROGBUF_GET (ulong, ulong)
+
+PROGBUF_SET (longlong, ulonglong)
+PROGBUF_GET (longlong, ulonglong)
+
+PROGBUF_SET (ulonglong, ulonglong)
+PROGBUF_GET (ulonglong, ulonglong)
 
 progbuf_h
-progbuf_alloc (int message_tag, int version)
+progbuf_alloc (long message_tag)
 {
-  struct progbuf_s *buf = calloc (1, sizeof (struct progbuf_s));
+  struct progbuf_s *buf = malloc (sizeof (struct progbuf_s));
+
+  if (!buf)
+    return 0;
+
+  buf->buffer = malloc (PROGBUF_INIT_BUFSIZ);
+  if (!buf->buffer)
+    {
+      free (buf);
+      return 0;
+    }
+
+  buf->capacity = PROGBUF_INIT_BUFSIZ;
+  buf->size = 0;
+  buf->message_tag = message_tag;
+
+  int tag_size = determine_var_ulong_size (ABS (message_tag));
+  write_var_ulong (buf, ABS (message_tag), tag_size, message_tag < 0);
+  buf->header_size = tag_size;
+
   return buf;
 }
 
-void
+progbuf_it_h
+progbuf_iter_alloc (progbuf_h buf)
+{
+  if (!buf)
+    return 0;
+
+  struct progbuf_it_s *iter = malloc (sizeof (struct progbuf_it_s));
+
+  if (!iter)
+    return 0;
+
+  iter->buf = buf;
+  iter->read_pos = buf->header_size;
+
+  return iter;
+}
+
+int
 progbuf_free (progbuf_h buf)
 {
-  if (buf)
+  if (!buf)
+    return PROGBUF_ERROR_NULL_PARAM;
+
+  free (buf->buffer);
+  free (buf);
+
+  return PROGBUF_SUCCESS;
+}
+
+int
+progbuf_iter_free (progbuf_it_h iter)
+{
+  if (!iter)
+    return PROGBUF_ERROR_NULL_PARAM;
+
+  free (iter);
+
+  return PROGBUF_SUCCESS;
+}
+
+int
+progbuf_get_message_tag (progbuf_h buf, long *message_tag)
+{
+  if (!buf || !message_tag)
+    return PROGBUF_ERROR_NULL_PARAM;
+
+  *message_tag = buf->message_tag;
+
+  return PROGBUF_SUCCESS;
+}
+
+int
+progbuf_get_message_buffer (progbuf_h buf, char **buffer, size_t *size)
+{
+  if (!buf || (!buffer && !size))
+    return PROGBUF_ERROR_NULL_PARAM;
+
+  if (buffer)
     {
-      if (buf->buffer)
-        free (buf->buffer);
+      *buffer = buf->buffer;
+    }
 
-      free (buf);
+  if (size)
+    {
+      *size = buf->size;
     }
+
+  return 0;
 }
 
 int
-progbuf_set_int (progbuf_h buf, int value)
+progbuf_iter_reset (progbuf_it_h iter)
 {
-  return -1;
+  if (!iter)
+    return PROGBUF_ERROR_NULL_PARAM;
+
+  iter->read_pos = iter->buf->header_size;
+
+  return PROGBUF_SUCCESS;
 }
index da21548..8995862 100644 (file)
@@ -1,10 +1,42 @@
 #ifndef LIBPROGBUF_H
 #define LIBPROGBUF_H
 
+#include <stddef.h>
+
+#define PROGBUF_SUCCESS                  0
+#define PROGBUF_ERROR_NULL_PARAM        -1
+#define PROGBUF_ERROR_MEM_ALLOC         -2
+#define PROGBUF_ERROR_END_OF_ITER       -3
+#define PROGBUF_ERROR_UNEXPECTED_TYPE   -4
+#define PROGBUF_ERROR_READ              -5
+#define PROGBUF_ERROR_INCORRECT_SIGN    -6
+
 typedef struct progbuf_s *progbuf_h;
+typedef struct progbuf_it_s *progbuf_it_h;
+
+progbuf_h progbuf_alloc (long message_tag);
+
+int progbuf_get_message_tag (progbuf_h buf, long *message_tag);
+int progbuf_get_message_buffer (progbuf_h buf, char **buffer, size_t *size);
+int progbuf_free (progbuf_h buf);
 
-progbuf_h progbuf_alloc (int message_tag, int version);
-void progbuf_free (progbuf_h buf);
 int progbuf_set_int (progbuf_h buf, int value);
+int progbuf_get_int (progbuf_it_h iter, int *value);
+int progbuf_set_uint (progbuf_h buf, unsigned int value);
+int progbuf_get_uint (progbuf_it_h iter, unsigned int *value);
+
+int progbuf_set_long (progbuf_h buf, long value);
+int progbuf_get_long (progbuf_it_h iter, long *value);
+int progbuf_set_ulong (progbuf_h buf, unsigned long value);
+int progbuf_get_ulong (progbuf_it_h iter, unsigned long *value);
+
+int progbuf_set_longlong (progbuf_h buf, long long value);
+int progbuf_get_longlong (progbuf_it_h iter, long long *value);
+int progbuf_set_ulonglong (progbuf_h buf, unsigned long long value);
+int progbuf_get_ulonglong (progbuf_it_h iter, unsigned long long *value);
+
+progbuf_it_h progbuf_iter_alloc (progbuf_h buf);
+int progbuf_iter_free (progbuf_it_h iter);
+int progbuf_iter_reset (progbuf_it_h iter);
 
 #endif
diff --git a/src/test_progbuf.c b/src/test_progbuf.c
deleted file mode 100644 (file)
index f6956fe..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "progbuf.h"
-
-int
-main ()
-{
-  progbuf_h buf = progbuf_alloc (1, 1);
-  return 0;
-}