aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorM. Shulhan <ms@kilabit.org>2009-01-26 14:31:50 +0700
committerM. Shulhan <ms@kilabit.org>2009-01-26 14:31:50 +0700
commit8db65208771259e7c4329de32891a5fe37bde227 (patch)
treee78ce51fca993b70f5466669333b1764abd7c4f7
downloadvos-8db65208771259e7c4329de32891a5fe37bde227.tar.xz
Vos
-rw-r--r--LICENSE45
-rw-r--r--Makefile68
-rw-r--r--op/vos_Bucket.c433
-rw-r--r--op/vos_Bucket.h17
-rw-r--r--op/vos_Field.c99
-rw-r--r--op/vos_Field.h23
-rw-r--r--op/vos_File.c251
-rw-r--r--op/vos_File.h27
-rw-r--r--op/vos_Filter.c129
-rw-r--r--op/vos_Filter.h25
-rw-r--r--op/vos_LL.c82
-rw-r--r--op/vos_LL.h12
-rw-r--r--op/vos_Record.c722
-rw-r--r--op/vos_Record.h24
-rw-r--r--op/vos_Stmt.c142
-rw-r--r--op/vos_Stmt.h19
-rw-r--r--op/vos_StmtCreate.c58
-rw-r--r--op/vos_StmtCreate.h11
-rw-r--r--op/vos_StmtJoin.c182
-rw-r--r--op/vos_StmtJoin.h20
-rw-r--r--op/vos_StmtLoad.c41
-rw-r--r--op/vos_StmtLoad.h11
-rw-r--r--op/vos_StmtMeta.c115
-rw-r--r--op/vos_StmtMeta.h18
-rw-r--r--op/vos_StmtSet.c45
-rw-r--r--op/vos_StmtSet.h17
-rw-r--r--op/vos_StmtSort.c111
-rw-r--r--op/vos_StmtSort.h15
-rw-r--r--op/vos_String.c209
-rw-r--r--op/vos_String.h29
-rw-r--r--proc/vos_create.c269
-rw-r--r--proc/vos_create.h12
-rw-r--r--proc/vos_join.c244
-rw-r--r--proc/vos_join.h9
-rw-r--r--proc/vos_load.c20
-rw-r--r--proc/vos_load.h9
-rw-r--r--proc/vos_parser.c1307
-rw-r--r--proc/vos_parser.h10
-rw-r--r--proc/vos_set.c33
-rw-r--r--proc/vos_set.h9
-rw-r--r--proc/vos_sort.c396
-rw-r--r--proc/vos_sort.h10
-rw-r--r--proc/vos_sort_merge.c241
-rw-r--r--proc/vos_sort_merge.h12
-rw-r--r--type/vos_TBucket.h12
-rw-r--r--type/vos_TField.h42
-rw-r--r--type/vos_TFile.h27
-rw-r--r--type/vos_TFilter.h22
-rw-r--r--type/vos_TLL.h11
-rw-r--r--type/vos_TMNode.h15
-rw-r--r--type/vos_TProcCreate.h23
-rw-r--r--type/vos_TProcSort.h18
-rw-r--r--type/vos_TRecord.h16
-rw-r--r--type/vos_TStmt.h26
-rw-r--r--type/vos_TStmtJoin.h17
-rw-r--r--type/vos_TStmtMeta.h14
-rw-r--r--type/vos_TStmtSet.h18
-rw-r--r--type/vos_TString.h10
-rw-r--r--type/vos_TVos.h42
-rw-r--r--vos.c156
-rw-r--r--vos.h19
-rw-r--r--vos_errno.c27
-rw-r--r--vos_errno.h37
63 files changed, 6133 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..6e661a9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,45 @@
+Copyright (C) 2009 M. Shulhan (ms@kilabit.org). All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. All advertising materials mentioning features or use of this software must
+ display the following acknowledgment:
+ "This product includes software written by M. Shulhan (ms@kilabit.org)"
+
+4. The names "M. Shulhan" and "Vos" must not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+5. Products derived from this software may not be called "Vos" nor may "Vos"
+ appear in their names without prior written permission of the author.
+
+THIS SOFTWARE IS PROVIDED BY SHULHAN "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ --- --- --- --- --- --- ---
+
+ TT TT II BB AAAA LLLLLL II KKKKKKKK
+ TT TT II BB AA AA LL LL II KK
+ TTTT II BB AA AA LL LL II KK
+ TT TT II BB AAAAAAAA LLLLLL II KK
+ TT TT II BB AA AA LL LL II KK
+ TT TT II BBBBBBBB AA AA LLLLLL II KK
+
+Website: http://www.kilabit.org
+Contact: info@kilabit.org
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..6ad908c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,68 @@
+SRC_D = .
+SRC_OP_D = ${SRC_D}/op
+SRC_PROC_D = ${SRC_D}/proc
+
+BUILD_D = ../build
+BUILD_OP_D = ${BUILD_D}/op
+BUILD_PROC_D = ${BUILD_D}/proc
+
+CC = gcc
+CFLAGS = -Wall -O2 -I${SRC_D}
+CFLAGS_DEBUG = -Wall -g -O0 -I${SRC_D}
+LDFLAGS = -lpthread
+
+COMPILE = echo "[COMPILE] $@"; \
+ ${CC} ${CFLAGS} -c $< -o $@
+BUILD = echo "[_BUILD_] $@"; \
+ ${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@
+
+BIN = ${BUILD_D}/vos
+VOS_OBJS = \
+ ${BUILD_D}/vos_errno.o \
+ ${BUILD_OP_D}/vos_String.o \
+ ${BUILD_OP_D}/vos_File.o \
+ ${BUILD_OP_D}/vos_LL.o \
+ ${BUILD_OP_D}/vos_Filter.o \
+ ${BUILD_OP_D}/vos_Field.o \
+ ${BUILD_OP_D}/vos_Record.o \
+ ${BUILD_OP_D}/vos_Bucket.o \
+ ${BUILD_OP_D}/vos_StmtMeta.o \
+ ${BUILD_OP_D}/vos_Stmt.o \
+ ${BUILD_OP_D}/vos_StmtSet.o \
+ ${BUILD_OP_D}/vos_StmtLoad.o \
+ ${BUILD_OP_D}/vos_StmtCreate.o \
+ ${BUILD_OP_D}/vos_StmtSort.o \
+ ${BUILD_OP_D}/vos_StmtJoin.o \
+ ${BUILD_PROC_D}/vos_parser.o \
+ ${BUILD_PROC_D}/vos_set.o \
+ ${BUILD_PROC_D}/vos_load.o \
+ ${BUILD_PROC_D}/vos_sort_merge.o \
+ ${BUILD_PROC_D}/vos_sort.o \
+ ${BUILD_PROC_D}/vos_create.o \
+ ${BUILD_PROC_D}/vos_join.o \
+ ${BUILD_D}/vos.o
+
+all: clean prebuild ${BIN}
+
+debug: CFLAGS = ${CFLAGS_DEBUG}
+debug: clean prebuild ${BIN}
+
+prebuild:
+ @mkdir -p ${BUILD_D}
+ @mkdir -p ${BUILD_OP_D}
+ @mkdir -p ${BUILD_PROC_D}
+
+${BIN}: ${VOS_OBJS}
+ @${BUILD}
+
+${BUILD_D}/%.o: ${SRC_D}/%.c ${SRC_D}/%.h
+ @${COMPILE}
+
+${BUILD_OP_D}/%.o: ${SRC_OP_D}/%.c ${SRC_OP_D}/%.h
+ @${COMPILE}
+
+${BUILD_PROC_D}/%.o: ${SRC_PROC_D}/%.c ${SRC_PROC_D}/%.h
+ @${COMPILE}
+clean:
+ @echo "[_CLEAN_]"
+ @rm -f ${BIN} ${VOS_OBJS} valgrind.out *.tmp *.sort data.output
diff --git a/op/vos_Bucket.c b/op/vos_Bucket.c
new file mode 100644
index 0000000..f7985e2
--- /dev/null
+++ b/op/vos_Bucket.c
@@ -0,0 +1,433 @@
+#include "op/vos_Bucket.h"
+
+void bucket_print(struct Bucket *B, const int n)
+{
+ int i;
+ int empty = 1;
+
+ if (! B)
+ return;
+
+ for (i = 1; i < n; i++) {
+ if (! B[i].cnt) {
+ B[i].stat = 1;
+ empty++;
+ } else if (B[i].p == B[i].cnt) {
+ B[i].stat = 1;
+ empty++;
+ } else {
+ B[i].stat = 0;
+ B[i].p = B[i].cnt;
+ }
+ }
+
+ while (empty < n) {
+ for (i = 1; i < n; i++) {
+ if (! B[i].stat) {
+ printf("(%2d) \"%s\"|", B[i].p->idx,
+ B[i].p->v->buf);
+ B[i].p = B[i].p->row_next;
+ if (B[i].p == B[i].cnt->row_last || ! B[i].p) {
+ empty++;
+ B[i].stat = 1;
+ B[i].p = 0;
+ B[i].cnt->row_last = 0;
+ }
+ } else {
+ printf("\"\"|");
+ }
+ }
+ printf("\n");
+ }
+}
+
+/**
+ * @desc:
+ * move each field on Record 'R' into a bucket
+ */
+void record_to_bucket(struct Bucket *B, struct Record *R)
+{
+ struct Record *p = 0;
+
+ if (! B)
+ return;
+ if (R)
+ R->fld_last = 0;
+ while (R) {
+ p = R;
+ if (! B[R->idx].cnt) {
+ B[R->idx].cnt = R;
+ B[R->idx].cnt->row_next = 0;
+ } else {
+ B[R->idx].cnt->row_last->row_next = R;
+ }
+ B[R->idx].cnt->row_last = R;
+ R = R->fld_next;
+ p->fld_next = 0;
+ }
+}
+
+void bucket_empty(struct Bucket *B, const int n)
+{
+ int i;
+
+ if (! B)
+ return;
+ for (i = 1; i < n; i++) {
+ B[i].p = B[i].cnt;
+ while (B[i].p) {
+ str_prune(B[i].p->v);
+ B[i].p = B[i].p->row_next;
+ }
+ }
+}
+
+void bucket_destroy(struct Bucket *B, const int n)
+{
+ int i;
+
+ if (! B)
+ return;
+ for (i = 1; i < n; i++) {
+ record_destroy(&B[i].cnt);
+ B[i].p = 0;
+ }
+}
+
+static int record_write_once(struct Record *R, struct File *F, struct Field *frmt)
+{
+ int s;
+ long len = 0;
+ long len2 = 0;
+
+ /* set start position */
+ if (frmt->start_p) {
+ len = F->pos + frmt->start_p;
+ if (len < F->idx) {
+ while (F->idx > len) {
+ FCURC(F) = ' ';
+ F->idx--;
+ }
+ } else {
+ len2 = F->idx;
+ while (len2 < len) {
+ FCURC(F) = ' ';
+ F->idx++;
+ len2++;
+ if (F->idx >= F->size) {
+ s = file_write(F);
+ if (s)
+ return s;
+ }
+ }
+ }
+ }
+
+ /* write left quote */
+ if (frmt->left_q) {
+ FCURC(F) = frmt->left_q;
+ if (++F->idx >= F->size) {
+ s = file_write(F);
+ if (s)
+ return s;
+ }
+ }
+
+ /* write content of Record */
+ len = R->v->idx;
+ if (frmt->end_p) {
+ /* + 1, because we start from zero */
+ len2 = frmt->end_p - frmt->start_p + 1;
+ if (frmt->left_q)
+ len2--;
+ if (frmt->right_q)
+ len2--;
+ if (len2 < len)
+ len = len2;
+ }
+ if ((F->idx + len) >= F->size) {
+ s = file_write(F);
+ if (s)
+ return s;
+ }
+ if (len > 0) {
+ memcpy(&FCURC(F), R->v->buf, len);
+ F->idx += len;
+ str_prune(R->v);
+ }
+
+ /* write right quote */
+ if (frmt->right_q) {
+ FCURC(F) = frmt->right_q;
+ F->idx++;
+ if (F->idx >= F->size) {
+ s = file_write(F);
+ if (s)
+ return s;
+ }
+ }
+
+ /* set end position */
+ if (frmt->end_p) {
+ while (len < len2) {
+ FCURC(F) = ' ';
+ F->idx++;
+ len++;
+ if (F->idx >= F->size) {
+ s = file_write(F);
+ if (s)
+ return s;
+ }
+ }
+ }
+ /* write separator */
+ if (frmt->sep) {
+ FCURC(F) = frmt->sep;
+ F->idx++;
+ if (F->idx >= F->size) {
+ s = file_write(F);
+ if (s)
+ return s;
+ }
+ }
+
+ return 0;
+}
+
+int bucket_write(struct Bucket *B, const int n, struct File *F,
+ struct Field *flds)
+{
+ int s = 0;
+ int i = 0;
+ int empty = 1;
+ unsigned long nrow = 0;
+ struct Field *pfld = 0;
+ struct String snon = {0, 0, "\0"};
+ struct Record non = {0, 0, &snon, 0, 0, 0, 0};
+
+ for (i = 1; i < n; i++) {
+ if (! B[i].cnt) {
+ B[i].stat = 1;
+ empty++;
+ } else if (B[i].p == B[i].cnt) { /* p does not move */
+ B[i].stat = 1;
+ empty++;
+ } else {
+ B[i].stat = 0;
+ B[i].p = B[i].cnt;
+ }
+ }
+
+ while (empty < n) {
+ pfld = flds;
+ for (i = 1; i < n; i++) {
+ if (! B[i].stat) {
+ s = record_write_once(B[i].p, F, pfld);
+ if (s)
+ goto err;
+
+ B[i].p = B[i].p->row_next;
+ if (B[i].p == B[i].cnt->row_last || (! B[i].p)) {
+ empty++;
+ B[i].stat = 1;
+ B[i].p = B[i].cnt;
+ B[i].cnt->row_last = 0;
+ }
+ } else {
+ s = record_write_once(&non, F, pfld);
+ }
+ pfld = pfld->next;
+ }
+ if (F->idx >= F->size) {
+ s = file_write(F);
+ if (s)
+ goto err;
+ }
+ FCURC(F) = CH_NEWLINE;
+ F->idx++;
+ F->pos = F->idx;
+ nrow++;
+ }
+ file_write(F);
+err:
+ return s;
+}
+
+/**
+ * @return:
+ * < -1 : rejected
+ * < 0 : success, accepted
+ * < > 0 : fail
+ */
+int bucket_read_filtered(struct Bucket *B, struct File *F, struct Field *_fld)
+{
+ int len = 0;
+ int flen = 0;
+ int s = 0;
+ int reject = 0;
+ long int start_p = 0;
+ struct String *str = 0;
+ struct Field *fld = _fld;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ return s;
+ }
+
+ while (fld) {
+ if (fld->flag && ! reject)
+ str = B[fld->idx].p->v;
+
+ /* where do we start ? */
+ if (fld->start_p) {
+ if (start_p < fld->start_p) {
+ len = fld->start_p - start_p;
+ start_p += len;
+ flen = F->idx + len;
+ if (flen > F->size) {
+ len = flen - F->size;
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ F->idx += len;
+ }
+ if (fld->left_q) {
+ if (FCURC(F) == fld->left_q) {
+ F->idx++;
+ start_p++;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+
+ }
+ }
+ } else if (fld->left_q) {
+ if (FCURC(F) == fld->left_q) {
+ F->idx++;
+ start_p++;
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ } else
+ goto err;
+ }
+
+ if (fld->end_p) {
+ while (start_p <= fld->end_p) {
+ if (fld->flag && ! reject)
+ str_append_c(str, FCURC(F));
+
+ F->idx++;
+ start_p++;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ }
+ } else if (fld->right_q) {
+ if (fld->flag && ! reject)
+ s = file_fetch_until(F, str, fld->right_q);
+ else
+ s = file_skip_until(F, fld->right_q);
+ if (s)
+ goto err;
+
+ F->idx++;
+ start_p += str->idx + 1;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+
+ if (fld->sep) {
+ while (FCURC(F) != fld->sep) {
+ F->idx++;
+ start_p++;
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ }
+ F->idx++;
+ start_p++;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ }
+ } else if (fld->sep) {
+ if (fld->flag && !reject)
+ s = file_fetch_until(F, str, fld->sep);
+ else
+ s = file_skip_until(F, fld->sep);
+ if (s)
+ goto err;
+
+ F->idx++;
+ start_p += str->idx + 1;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ } else {
+ if (fld->flag && !reject)
+ s = file_fetch_until(F, str, CH_NEWLINE);
+ else
+ s = file_skip_until(F, CH_NEWLINE);
+ if (s)
+ goto err;
+ }
+
+ if ((fld->flag & FFLAG_FILTER) && !reject) {
+ s = fld->fop(fld->fltr_rule, str->buf,
+ fld->fltr_v);
+ /* reject this record */
+ if (s == 0) {
+ reject = 1;
+ /* prune later */
+ }
+ }
+
+ fld = fld->next;
+ }
+ if (FCURC(F) != CH_NEWLINE) {
+ s = file_fetch_until(F, str, CH_NEWLINE);
+ }
+ F->idx++;
+
+ fld = _fld;
+ if (reject) {
+ /* since we don't know in which field cause the row being
+ * rejected, we just reset all field content here */
+ s = -1;
+ while (fld) {
+ str_prune(B[fld->idx].p->v);
+ fld = fld->next;
+ }
+ } else {
+ s = 0;
+ /* move `p' to the next row in the bucket */
+ while (fld) {
+ B[fld->idx].p = B[fld->idx].p->row_next;
+ fld = fld->next;
+ }
+ }
+err:
+ return s;
+}
diff --git a/op/vos_Bucket.h b/op/vos_Bucket.h
new file mode 100644
index 0000000..87e2d89
--- /dev/null
+++ b/op/vos_Bucket.h
@@ -0,0 +1,17 @@
+#ifndef _VOS_BUCKET_H
+#define _VOS_BUCKET_H 1
+
+#include "type/vos_TBucket.h"
+#include "op/vos_Record.h"
+
+void bucket_print(struct Bucket *B, const int n);
+void record_to_bucket(struct Bucket *B, struct Record *R);
+void bucket_empty(struct Bucket *B, const int n);
+void bucket_destroy(struct Bucket *B, const int n);
+
+int bucket_write(struct Bucket *B, const int n, struct File *F,
+ struct Field *flds);
+int bucket_read_filtered(struct Bucket *B, struct File *F,
+ struct Field *fld);
+
+#endif
diff --git a/op/vos_Field.c b/op/vos_Field.c
new file mode 100644
index 0000000..6ec4e8b
--- /dev/null
+++ b/op/vos_Field.c
@@ -0,0 +1,99 @@
+#include "op/vos_Field.h"
+
+const char *_field_type[N_FIELD_TYPE] = {
+ "STRING\0",
+ "NUMBER\0",
+ "DATETIME\0"
+};
+
+const char *_fflag_sort[N_FFLAG_SORT] = {
+ "\0",
+ "ASC\0",
+ "DESC\0"
+};
+
+/**
+ * @desc:
+ * create new Field object 'cp' by copying properties of field 'fld',
+ * instead of allocating new field name and date_format, this new Field
+ * object only reference their value from 'fld'.
+ * @return:
+ * < 0 : success.
+ * < E_MEM : fail, out of memory.
+ */
+int field_soft_copy(struct Field *fld, struct Field **cp)
+{
+ (*cp) = (struct Field *) calloc(1, sizeof(struct Field));
+ if (! (*cp))
+ return E_MEM;
+
+ (*cp)->idx = 0;
+ (*cp)->flag = 0;
+ (*cp)->type = fld->type;
+ (*cp)->left_q = fld->left_q;
+ (*cp)->right_q = fld->right_q;
+ (*cp)->start_p = fld->start_p;
+ (*cp)->end_p = fld->end_p;
+ (*cp)->sep = fld->sep;
+ (*cp)->date_format = fld->date_format;
+ (*cp)->name = fld->name;
+ (*cp)->next = 0;
+
+ return 0;
+}
+
+void field_add(struct Field **fields, struct Field *f)
+{
+ struct Field *p = 0;
+
+ if (! (*fields)) {
+ (*fields) = f;
+ } else {
+ p = (*fields);
+ while (p->next)
+ p = p->next;
+ p->next = f;
+ }
+}
+
+void field_print(struct Field *fields)
+{
+ printf("(\n");
+ while (fields) {
+ printf("\t[%2d] '%c' : %s : '%c' : %3d : %3d : '%c' : %s : %s "\
+ "(%2d)\n",
+ fields->idx, fields->left_q,
+ fields->name ? fields->name : "\0",
+ fields->right_q, fields->start_p, fields->end_p,
+ fields->sep, _field_type[fields->type],
+ fields->date_format ? fields->date_format : "\0",
+ fields->flag);
+ if (fields->fltr_idx) {
+ printf("\tFILTER %d: %s (%p) %s\n", fields->fltr_idx,
+ _filter_rule[fields->fltr_rule],
+ fields->fop,
+ fields->fltr_v ? fields->fltr_v : "\0");
+ }
+ fields = fields->next;
+ }
+ printf(") ");
+}
+
+void _field_destroy(struct Field **field, const int soft)
+{
+ struct Field *next = 0;
+
+ while ((*field)) {
+ if (! soft) {
+ if ((*field)->date_format)
+ free((*field)->date_format);
+ if ((*field)->name)
+ free((*field)->name);
+ }
+ if ((*field)->fltr_v)
+ free((*field)->fltr_v);
+ next = (*field)->next;
+ free((*field));
+ (*field) = next;
+ }
+}
diff --git a/op/vos_Field.h b/op/vos_Field.h
new file mode 100644
index 0000000..0b3fccb
--- /dev/null
+++ b/op/vos_Field.h
@@ -0,0 +1,23 @@
+#ifndef _VOS_FIELD_H
+#define _VOS_FIELD_H 1
+
+#include <strings.h>
+#include "type/vos_TField.h"
+#include "op/vos_String.h"
+#include "op/vos_Filter.h"
+#include "vos.h"
+
+extern const char *_field_type[N_FIELD_TYPE];
+extern const char *_fflag_sort[N_FFLAG_SORT];
+
+#define field_get_type_idx(T) get_token_idx(_field_type, N_FIELD_TYPE, T)
+
+int field_soft_copy(struct Field *fld, struct Field **cp);
+void field_add(struct Field **fields, struct Field *f);
+void field_print(struct Field *fields);
+void _field_destroy(struct Field **fields, const int soft);
+
+#define field_destroy(F) _field_destroy((F),0)
+#define field_soft_destroy(F) _field_destroy((F),1)
+
+#endif
diff --git a/op/vos_File.c b/op/vos_File.c
new file mode 100644
index 0000000..5d0ffee
--- /dev/null
+++ b/op/vos_File.c
@@ -0,0 +1,251 @@
+#include "op/vos_File.h"
+
+/**
+ * @desc:
+ * FOPEN_RO : file not create if not exist, instead return an error
+ * FOPEN_WO : file will be create if not exist, and error if exist
+ * @return:
+ * < 0 : success
+ * < E_MEM : fail, out of memory
+ * < E_FILE_OPEN : fail, cannot open file 'f'
+ * < E_FILE_EXIST : fail, fail 'f' is exist
+ * < E_FILE_NOT_EXIST : fail, file 'f' is not exit
+ */
+int file_open(struct File **F, const char *f, int flag)
+{
+ int s = 0;
+
+ (*F) = (struct File *) calloc(1, sizeof(struct File));
+ if (! (*F))
+ return E_MEM;
+
+ switch (flag) {
+ case FOPEN_RO:
+ (*F)->d = open(f, O_RDONLY);
+ break;
+ case FOPEN_WO:
+ (*F)->size = _vos.file_buf_size;
+ (*F)->d = open(f, O_WRONLY | O_CREAT | O_EXCL,
+ S_IRUSR | S_IWUSR);
+ break;
+ }
+
+ if ((*F)->d < 0) {
+ str_raw_copy(f, &_vos.e_sparm0);
+
+ switch (errno) {
+ case ENOENT:
+ return E_FILE_NOT_EXIST;
+ case EEXIST:
+ return E_FILE_EXIST;
+ default:
+ return E_FILE_OPEN;
+ }
+ }
+
+ (*F)->name = f;
+ (*F)->buf = (char *) calloc(_vos.file_buf_size, sizeof(char));
+ if (! (*F)->buf) {
+ s = E_MEM;
+ file_close(F);
+ }
+
+ return s;
+}
+
+/**
+ * @desc:
+ * at first read, File size is zero.
+ * @return:
+ * < 0 : success
+ * < E_FILE_END : end of file
+ * < E_FILE_NOT_OPEN : fail, file is not open
+ * < E_FILE_READ : fail, error at reading file
+ */
+int file_read(struct File *F)
+{
+ if (! F)
+ return E_FILE_NOT_OPEN;
+
+ if (F->size) {
+ F->buf = memset(F->buf, FILE_DEF_SET, F->size);
+ F->pos += F->size;
+ F->idx = 0;
+ }
+
+ F->size = read(F->d, F->buf, _vos.file_buf_size);
+ if (F->size <= 0) {
+ if (F->size == 0)
+ return E_FILE_END;
+
+ str_raw_copy(F->name, &_vos.e_sparm0);
+ return E_FILE_READ;
+ }
+ return 0;
+}
+
+/**
+ * @desc:
+ * write contents of File buffer.
+ * @return:
+ * < 0 : success.
+ * < E_FILE_NOT_OPEN : fail, file is not open.
+ * < E_FILE_WRITE : fail, error at writing to file.
+ */
+int file_write(struct File *F)
+{
+ int s = 0;
+
+ if (! F)
+ return E_FILE_NOT_OPEN;
+ if (! F->idx)
+ return 0;
+
+ s = write(F->d, F->buf, F->idx);
+ if (s < 0) {
+ str_raw_copy(F->name, &_vos.e_sparm0);
+ return E_FILE_WRITE;
+ }
+
+ F->buf = memset(F->buf, FILE_DEF_SET, F->size);
+ F->pos += F->idx;
+ F->idx = 0;
+
+ return 0;
+}
+
+/**
+ * @desc:
+ * copy File buffer, from current File index, into String 'str' until
+ * character 'c' is found in File buffer.
+ * @return:
+ * < 0 : success
+ * < !0 : fail
+ */
+int file_fetch_until(struct File *F, struct String *str, int c)
+{
+ int s = 0;
+
+ while (F->idx < F->size && FCURC(F) != c) {
+ s = str_append_c(str, FCURC(F));
+ if (s)
+ return s;
+ F->idx++;
+ }
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s == 0)
+ s = file_fetch_until(F, str, c);
+ }
+ return s;
+}
+
+/**
+ * @desc:
+ * move forward File index until character 'c' is found in buffer.
+ * @return:
+ * < 0 : success
+ * < !0 : fail
+ */
+int file_skip_until(struct File *F, int c)
+{
+ int s = 0;
+
+ while (F->idx < F->size && FCURC(F) != c)
+ F->idx++;
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s == 0)
+ s = file_skip_until(F, c);
+ }
+ return s;
+}
+
+/**
+ * @desc:
+ * skip white-space character in File buffer.
+ * @return:
+ * < 0 : success
+ * < !0 : fail
+ */
+int file_skip_space(struct File *F)
+{
+ int s = 0;
+
+ while (F->idx < F->size && isspace(FCURC(F)))
+ F->idx++;
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s == 0)
+ s = file_skip_space(F);
+ }
+ return s;
+}
+
+void file_close(struct File **F)
+{
+ if ((*F)) {
+ if ((*F)->buf)
+ free((*F)->buf);
+ if ((*F)->d > 0)
+ close((*F)->d);
+ free((*F));
+ (*F) = 0;
+ }
+}
+
+/**
+ * @desc:
+ * get size of 'file'.
+ * @return:
+ * < 0 : success
+ * < E_FILE_OPEN : fail, cannot open file
+ * < E_FILE_SEEK : fail, cannot seek file
+ */
+int file_raw_get_size(const char *file, unsigned long *fsize)
+{
+ int fd = 0;
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0) {
+ str_raw_copy(file, &_vos.e_sparm0);
+ return E_FILE_OPEN;
+ }
+
+ *fsize = lseek(fd, 0, SEEK_END);
+ if (*fsize < 0) {
+ str_raw_copy(file, &_vos.e_sparm0);
+ return E_FILE_SEEK;
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+/**
+ * @desc:
+ * check if 'file' is exist.
+ * @return:
+ * < 1 : if 'file' is exist
+ * < 0 : if 'file' does not exist
+ * < -1 : error at opening file
+ */
+int file_raw_is_exist(const char *file)
+{
+ int s = 0;
+ int fd = 0;
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0) {
+ if (errno != ENOENT) {
+ perror(file);
+ s = -1;
+ }
+ } else {
+ close(fd);
+ s = 1;
+ }
+
+ return s;
+}
diff --git a/op/vos_File.h b/op/vos_File.h
new file mode 100644
index 0000000..90f8a22
--- /dev/null
+++ b/op/vos_File.h
@@ -0,0 +1,27 @@
+#ifndef _VOS_FILE_H
+#define _VOS_FILE_H 1
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include "type/vos_TFile.h"
+#include "vos.h"
+#include "op/vos_String.h"
+
+#define FILE_DEF_SET ' '
+
+#define FCURC(F) F->buf[F->idx]
+#define FCURP(F) (F->pos + F->idx)
+
+int file_open(struct File **F, const char *f, int flag);
+int file_read(struct File *F);
+int file_write(struct File *F);
+int file_fetch_until(struct File *F, struct String *str, int c);
+int file_skip_until(struct File *F, int c);
+int file_skip_space(struct File *F);
+void file_close(struct File **F);
+
+int file_raw_get_size(const char *file, unsigned long *fsize);
+int file_raw_is_exist(const char *file);
+
+#endif
diff --git a/op/vos_Filter.c b/op/vos_Filter.c
new file mode 100644
index 0000000..2c45e2f
--- /dev/null
+++ b/op/vos_Filter.c
@@ -0,0 +1,129 @@
+/***
+ * @desc: filter behavior: return 1 if true or 0 if false.
+ *
+ * if v operation with fltr is true
+ * return rule
+ * return !rule
+ *
+ * the return value is checked by filter caller,
+ * i.e by vos_Record.record_read()
+ *
+ * if (fltr(rule, v, fltr))
+ * accept this record
+ * else
+ * reject this record
+ */
+#include "op/vos_Filter.h"
+
+const char *_filter_op[N_FLTR_OP] = {
+ "=\0",
+ "==\0",
+ "!=\0",
+ "!==\0",
+ ">\0",
+ "<\0",
+ ">=\0",
+ "<=\0"
+};
+
+const char *_filter_rule[N_FLTR_RULE] = {
+ "REJECT\0",
+ "ACCEPT\0"
+};
+
+const void (*_filter_f[N_FLTR_OP]) = {
+ fltr_eq,
+ fltr_eqeq,
+ fltr_neq,
+ fltr_neqeq,
+ fltr_more,
+ fltr_less,
+ fltr_meq,
+ fltr_leq
+};
+
+/**
+ * @desc:
+ * case not sensitive
+ * @return:
+ * < 1 : true
+ * < 0 : false
+ */
+int fltr_eq(const int rule, const char *v, const char *fltr)
+{
+ int s;
+ s = strcasecmp(v, fltr);
+ if (s == 0)
+ return rule;
+ return !rule;
+}
+
+/**
+ * @desc:
+ * case sensitive
+ * @return:
+ * < 1 : true
+ * < 0 : false
+ */
+int fltr_eqeq(const int rule, const char *v, const char *fltr)
+{
+ int s;
+ s = strcmp(v, fltr);
+ if (0 == s)
+ return rule;
+ return !rule;
+}
+
+int fltr_neq(const int rule, const char *v, const char *fltr)
+{
+ int s;
+ s = strcasecmp(v, fltr);
+ if (s != 0)
+ return rule;
+ return !rule;
+}
+
+int fltr_neqeq(const int rule, const char *v, const char *fltr)
+{
+ int s;
+ s = strcmp(v, fltr);
+ if (s != 0)
+ return rule;
+ return !rule;
+}
+
+int fltr_more(const int rule, const char *v, const char *fltr)
+{
+ int s;
+ s = strcasecmp(v, fltr);
+ if (s > 0)
+ return rule;
+ return !rule;
+}
+
+int fltr_less(const int rule, const char *v, const char *fltr)
+{
+ int s;
+ s = strcasecmp(v, fltr);
+ if (s < 0)
+ return rule;
+ return !rule;
+}
+
+int fltr_meq(const int rule, const char *v, const char *fltr)
+{
+ int s;
+ s = strcasecmp(v, fltr);
+ if (s >= 0)
+ return rule;
+ return !rule;
+}
+
+int fltr_leq(const int rule, const char *v, const char *fltr)
+{
+ int s;
+ s = strcasecmp(v, fltr);
+ if (s < 0)
+ return rule;
+ return !rule;
+}
diff --git a/op/vos_Filter.h b/op/vos_Filter.h
new file mode 100644
index 0000000..cfe4a53
--- /dev/null
+++ b/op/vos_Filter.h
@@ -0,0 +1,25 @@
+#ifndef _VOS_FILTER_H
+#define _VOS_FILTER_H 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "type/vos_TFilter.h"
+
+extern const char *_filter_op[N_FLTR_OP];
+extern const char *_filter_rule[N_FLTR_RULE];
+extern const void (*_filter_f[N_FLTR_OP]);
+
+#define op_get_idx(T) get_token_idx(_filter_op,N_FLTR_OP,T)
+#define rule_get_idx(T) get_token_idx(_filter_rule,N_FLTR_RULE,T)
+
+int fltr_eq(const int rule, const char *v, const char *fltr);
+int fltr_eqeq(const int rule, const char *v, const char *fltr);
+int fltr_neq(const int rule, const char *v, const char *fltr);
+int fltr_neqeq(const int rule, const char *v, const char *fltr);
+int fltr_more(const int rule, const char *v, const char *fltr);
+int fltr_less(const int rule, const char *v, const char *fltr);
+int fltr_meq(const int rule, const char *v, const char *fltr);
+int fltr_leq(const int rule, const char *v, const char *fltr);
+
+#endif
diff --git a/op/vos_LL.c b/op/vos_LL.c
new file mode 100644
index 0000000..c726cb0
--- /dev/null
+++ b/op/vos_LL.c
@@ -0,0 +1,82 @@
+#include "op/vos_LL.h"
+
+/**
+ * @return:
+ * < 0 : success
+ * < E_MEM : fail, out of memory
+ */
+int ll_add(struct LL **ll, unsigned int num, const char *str)
+{
+ int s = 0;
+ struct LL *wen = 0;
+
+ wen = (struct LL *) calloc(1, sizeof(struct LL));
+ if (! wen)
+ return E_MEM;
+
+ s = str_raw_copy(str, &wen->str);
+ if (s) {
+ free(wen);
+ return s;
+ }
+
+ wen->num = num;
+
+ if (! (*ll))
+ (*ll) = wen;
+ else
+ (*ll)->last->next = wen;
+
+ (*ll)->last = wen;
+
+ return 0;
+}
+
+void ll_link(struct LL **l, struct LL *r)
+{
+ if (! r)
+ return;
+
+ if (! (*l))
+ (*l) = r;
+ else
+ (*l)->last->next = r;
+
+ if (r->last) {
+ (*l)->last = r->last;
+ if ((*l)->last != r->last)
+ r->last = 0;
+ } else {
+ while (r->next)
+ r = r->next;
+ (*l)->last = r;
+ }
+}
+
+void ll_print(struct LL *ll)
+{
+ unsigned long n;
+
+ while (ll) {
+ n = ll->num;
+ printf("%3lu ", n);
+ while (ll && n == ll->num) {
+ printf("%s ", ll->str);
+ ll = ll->next;
+ }
+ printf("\n");
+ }
+}
+
+void ll_destroy(struct LL **ll)
+{
+ struct LL *next = 0;
+
+ while ((*ll)) {
+ if ((*ll)->str)
+ free((*ll)->str);
+ next = (*ll)->next;
+ free((*ll));
+ (*ll) = next;
+ }
+}
diff --git a/op/vos_LL.h b/op/vos_LL.h
new file mode 100644
index 0000000..a4112d2
--- /dev/null
+++ b/op/vos_LL.h
@@ -0,0 +1,12 @@
+#ifndef _VOS_LL_H
+#define _VOS_LL_H 1
+
+#include "type/vos_TLL.h"
+#include "op/vos_String.h"
+
+int ll_add(struct LL **tok, unsigned int num, const char *str);
+void ll_link(struct LL **l, struct LL *r);
+void ll_print(struct LL *tok);
+void ll_destroy(struct LL **tok);
+
+#endif
diff --git a/op/vos_Record.c b/op/vos_Record.c
new file mode 100644
index 0000000..459b43f
--- /dev/null
+++ b/op/vos_Record.c
@@ -0,0 +1,722 @@
+#include "op/vos_Record.h"
+
+/**
+ * @return:
+ * < 0 : success
+ * < E_MEM : fail
+ */
+int record_new(struct Record **R, struct Field *fld, struct String *str)
+{
+ (*R) = (struct Record *) calloc(1, sizeof(struct Record));
+ if (! (*R))
+ return E_MEM;
+
+ (*R)->v = str;
+ (*R)->idx = fld->idx;
+ (*R)->flag = fld->flag;
+
+ return 0;
+}
+
+/**
+ * @return:
+ * < -1 : l < r
+ * < 0 : l == r
+ * < 1 : l > r
+ */
+int _record_cmp(struct Record *l, struct Record *r, const int idx)
+{
+ int s = 0;
+ struct Record *pl = l;
+ struct Record *pr = r;
+
+ if (! l && ! r)
+ return 0;
+ if (! l)
+ return -1;
+ if (! r)
+ return 1;
+
+ /* search for field index to compare */
+ while (l && (l->idx != idx))
+ l = l->fld_next;
+ while (r && (r->idx != idx))
+ r = r->fld_next;
+
+ if (!l || !r)
+ return 0;
+
+ if (_vos.proc_cmp_case == CMP_CASE_SENSITIVE)
+ s = strcmp(l->v->buf, r->v->buf);
+ else
+ s = strcasecmp(l->v->buf, r->v->buf);
+
+ if (s == 0) {
+ s = _record_cmp(pl, pr, idx + 1);
+ } else {
+ if (l->flag == FFLAG_SORT_DESC) {
+ if (s < 0)
+ return 1;
+ if (s > 0)
+ return -1;
+ }
+ }
+ return s;
+}
+
+void record_add_field(struct Record **R, struct Record *Rfld)
+{
+ if (! Rfld)
+ return;
+
+ if (! (*R))
+ (*R) = Rfld;
+ else
+ (*R)->fld_last->fld_next = Rfld;
+
+ (*R)->fld_last = Rfld;
+}
+
+void record_add_row(struct Record **R, struct Record *row)
+{
+ if (! row)
+ return;
+
+ if (! (*R))
+ (*R) = row;
+ else
+ (*R)->row_last->row_next = row;
+
+ (*R)->row_last = row;
+}
+
+void record_prune(struct Record *R)
+{
+ while (R) {
+ if (R->v)
+ str_prune(R->v);
+ R = R->fld_next;
+ }
+}
+
+void record_destroy(struct Record **R)
+{
+ struct Record *Rfld = 0;
+ struct Record *tmp = 0;
+
+ while ((*R)) {
+ Rfld = (*R)->fld_next;
+ while (Rfld) {
+ if (Rfld->v) {
+ str_destroy(&Rfld->v);
+ }
+ tmp = Rfld->fld_next;
+ free(Rfld);
+ Rfld = tmp;
+ }
+
+ if ((*R)->v) {
+ str_destroy(&(*R)->v);
+ (*R)->v = 0;
+ }
+ tmp = (*R)->row_next;
+ free((*R));
+ (*R) = tmp;
+ }
+
+ (*R) = 0;
+}
+
+void record_print(struct Record *R)
+{
+ while (R) {
+ printf("%s|", R->v->buf);
+ R = R->fld_next;
+ }
+ printf("\n");
+}
+
+int record_write(struct Record *R, struct File *F, struct Field *_frmt)
+{
+ int s = 0;
+ int start_p = 0;
+ int len = 0;
+ int len2 = 0;
+ struct Record *Rfld = 0;
+ struct Field *frmt = 0;
+
+ while (R) {
+ start_p = F->idx;
+ Rfld = R;
+ frmt = _frmt;
+ while (Rfld) {
+ /* set start position */
+ if (frmt->start_p) {
+ len = start_p + frmt->start_p;
+ if (len < F->idx) {
+ while (F->idx > len) {
+ FCURC(F) = ' ';
+ F->idx--;
+ }
+ } else {
+ F->idx = start_p + len;
+ if (F->idx >= F->size) {
+ s = file_write(F);
+ if (s)
+ return s;
+ }
+ }
+ }
+
+ /* write left quote */
+ if (frmt->left_q) {
+ FCURC(F) = frmt->left_q;
+ if (++F->idx >= F->size) {
+ s = file_write(F);
+ if (s)
+ return s;
+ }
+ }
+
+ /* write content of Record */
+ len = Rfld->v->idx;
+ if (frmt->end_p) {
+ len2 = frmt->end_p - frmt->start_p + 1;
+ if (frmt->left_q)
+ len2--;
+ if (frmt->right_q)
+ len2--;
+ if (len2 < len)
+ len = len2;
+ }
+ if ((F->idx + len) >= F->size) {
+ s = file_write(F);
+ if (s)
+ return s;
+ }
+ if (len > 0) {
+ memcpy(&FCURC(F), Rfld->v->buf, len);
+ F->idx += len;
+ str_prune(Rfld->v);
+ }
+
+ /* write right quote */
+ if (frmt->right_q) {
+ FCURC(F) = frmt->right_q;
+ F->idx++;
+ if (F->idx >= F->size) {
+ s = file_write(F);
+ if (s)
+ return s;
+ }
+ }
+
+ /* set end position */
+ if (frmt->end_p) {
+ while (len <= len2) {
+ FCURC(F) = ' ';
+ F->idx++;
+ len++;
+ if (F->idx >= F->size) {
+ s = file_write(F);
+ if (s)
+ return s;
+ }
+ }
+ }
+
+ /* write separator */
+ if (frmt->sep) {
+ FCURC(F) = frmt->sep;
+ F->idx++;
+ if (F->idx >= F->size) {
+ s = file_write(F);
+ if (s)
+ return s;
+ }
+ }
+
+ frmt = frmt->next;
+ Rfld = Rfld->fld_next;
+ }
+ if (F->idx >= F->size) {
+ s = file_write(F);
+ if (s)
+ goto err;
+ }
+ FCURC(F) = CH_NEWLINE;
+ F->idx++;
+
+ R = R->row_next;
+ }
+err:
+ return s;
+}
+
+/**
+ * @desc: touch if you dare!
+ * priority in reading a record:
+ * - start_p > left_q
+ * - end_p > right_q > sep
+ * @return:
+ * < 0 : success
+ * < !0 : fail. and R will be NULL
+ */
+int record_read(struct Record **R, struct File *F, struct Field *fld)
+{
+ int s = 0;
+ int len = 0;
+ int flen = 0;
+ long int start_p = 0;
+ struct String *str = 0;
+ struct Record *Rfld = 0;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ return s;
+ }
+
+ (*R) = 0;
+ while (fld) {
+ /* where do we start ? */
+ if (fld->start_p) {
+ if (start_p < fld->start_p) {
+ len = fld->start_p - start_p;
+ start_p += len;
+ flen = F->idx + len;
+ if (flen >= F->size) {
+ len = flen - F->size;
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ F->idx += len;
+ }
+ if (fld->left_q) {
+ if (FCURC(F) == fld->left_q) {
+ F->idx++;
+ start_p++;
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ }
+ }
+ } else if (fld->left_q) {
+ if (FCURC(F) == fld->left_q) {
+ F->idx++;
+ start_p++;
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ } else
+ goto err;
+ }
+
+ /* create string for field data */
+ s = str_create(&str);
+ if (s)
+ return s;
+
+ if (fld->end_p) {
+ while (start_p <= fld->end_p) {
+ str_append_c(str, FCURC(F));
+ F->idx++;
+ start_p++;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ }
+ } else if (fld->right_q) {
+ s = file_fetch_until(F, str, fld->right_q);
+ if (s)
+ goto err;
+
+ F->idx++;
+ start_p += str->idx + 1;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+
+ if (fld->sep) {
+ while (FCURC(F) != fld->sep) {
+ F->idx++;
+ start_p++;
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ }
+ F->idx++;
+ start_p++;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ }
+ } else if (fld->sep) {
+ s = file_fetch_until(F, str, fld->sep);
+ if (s)
+ goto err;
+
+ F->idx++;
+ start_p += str->idx + 1;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ } else {
+ s = file_fetch_until(F, str, CH_NEWLINE);
+ if (s)
+ goto err;
+ }
+
+ s = record_new(&Rfld, fld, str);
+ if (s)
+ goto err;
+
+ record_add_field(R, Rfld);
+ str = 0;
+ Rfld = 0;
+ fld = fld->next;
+ }
+ /* go to next row */
+ if (FCURC(F) != CH_NEWLINE) {
+ s = file_fetch_until(F, str, CH_NEWLINE);
+ }
+ F->idx++;
+ return 0;
+err:
+ str_destroy(&str);
+ if (s && s != E_FILE_END)
+ record_destroy(R);
+ return s;
+}
+
+/**
+ * @return:
+ * < 0 : success
+ * < > 0 : fail
+ */
+int record_read2(struct Record *R, struct File *F, struct Field *fld)
+{
+ int s = 0;
+ int len = 0;
+ int flen = 0;
+ long int start_p = 0;
+ struct String *str = 0;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ return s;
+ }
+
+ while (fld) {
+ str = R->v;
+ /* where do we start ? */
+ if (fld->start_p) {
+ if (start_p < fld->start_p) {
+ len = fld->start_p - start_p;
+ start_p += len;
+ flen = F->idx + len;
+ if (flen > F->size) {
+ len = flen - F->size;
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ F->idx += len;
+ }
+ if (fld->left_q) {
+ if (FCURC(F) == fld->left_q) {
+ F->idx++;
+ start_p++;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+
+ }
+ }
+ } else if (fld->left_q) {
+ if (FCURC(F) == fld->left_q) {
+ F->idx++;
+ start_p++;
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ } else
+ goto err;
+ }
+
+ if (fld->end_p) {
+ while (start_p <= fld->end_p) {
+ str_append_c(str, FCURC(F));
+ F->idx++;
+ start_p++;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ }
+ } else if (fld->right_q) {
+ s = file_fetch_until(F, str, fld->right_q);
+ if (s)
+ goto err;
+
+ F->idx++;
+ start_p += str->idx + 1;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+
+ if (fld->sep) {
+ while (FCURC(F) != fld->sep) {
+ F->idx++;
+ start_p++;
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ }
+ F->idx++;
+ start_p++;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ }
+ } else if (fld->sep) {
+ s = file_fetch_until(F, str, fld->sep);
+ if (s)
+ goto err;
+
+ F->idx++;
+ start_p += str->idx + 1;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ } else {
+ s = file_fetch_until(F, str, CH_NEWLINE);
+ if (s)
+ goto err;
+ }
+
+ fld = fld->next;
+ R = R->fld_next;
+ }
+ /* go to next row */
+ if (FCURC(F) != CH_NEWLINE) {
+ file_fetch_until(F, str, CH_NEWLINE);
+ }
+ F->idx++;
+ s = 0;
+err:
+ return s;
+}
+
+int record_read_filtered(struct Record **R, struct File *F, struct Field *fld)
+{
+ int len = 0;
+ int flen = 0;
+ int s = 0;
+ int reject = 0;
+ long int start_p = 0;
+ struct String *str = 0;
+ struct Record *Rfld = 0;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ return s;
+ }
+
+ (*R) = 0;
+ while (fld) {
+ /* where do we start ? */
+ if (fld->start_p) {
+ if (start_p < fld->start_p) {
+ len = fld->start_p - start_p;
+ start_p += len;
+ flen = F->idx + len;
+ if (flen >= F->size) {
+ len = flen - F->size;
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ F->idx += len;
+ }
+ if (fld->left_q) {
+ if (FCURC(F) == fld->left_q) {
+ F->idx++;
+ start_p++;
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ }
+ }
+ } else if (fld->left_q) {
+ if (FCURC(F) == fld->left_q) {
+ F->idx++;
+ start_p++;
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ } else
+ goto err;
+ }
+
+ if (! str) {
+ s = str_create(&str);
+ if (s)
+ goto err;
+ }
+
+ if (fld->end_p) {
+ while (start_p <= fld->end_p) {
+ if (fld->flag && ! reject)
+ str_append_c(str, FCURC(F));
+
+ F->idx++;
+ start_p++;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ }
+ } else if (fld->right_q) {
+ if (fld->flag && ! reject)
+ s = file_fetch_until(F, str, fld->right_q);
+ else
+ s = file_skip_until(F, fld->right_q);
+ if (s)
+ goto err;
+
+ F->idx++;
+ start_p += str->idx + 1;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+
+ if (fld->sep) {
+ while (FCURC(F) != fld->sep) {
+ F->idx++;
+ start_p++;
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ }
+ F->idx++;
+ start_p++;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ }
+ } else if (fld->sep) {
+ if (fld->flag && !reject)
+ s = file_fetch_until(F, str, fld->sep);
+ else
+ s = file_skip_until(F, fld->sep);
+ if (s)
+ goto err;
+
+ F->idx++;
+ start_p += str->idx + 1;
+
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+ } else {
+ if (fld->flag && !reject)
+ s = file_fetch_until(F, str, CH_NEWLINE);
+ else
+ s = file_skip_until(F, CH_NEWLINE);
+ if (s)
+ goto err;
+ }
+
+ if ((fld->flag & FFLAG_FILTER) && !reject) {
+ s = fld->fop(fld->fltr_rule, str->buf,
+ fld->fltr_v);
+ /* reject this record */
+ if (s == 0) {
+ reject = 1;
+ str_prune(str);
+ }
+ }
+
+ if (fld->flag & FFLAG_CREATE) {
+ if (! reject) {
+ s = record_new(&Rfld, fld, str);
+ if (s)
+ goto err;
+
+ record_add_field(R, Rfld);
+ str = 0;
+ Rfld = 0;
+ }
+ } else
+ str_prune(str);
+
+ fld = fld->next;
+ }
+ /* go to next row */
+ if (FCURC(F) != CH_NEWLINE) {
+ s = file_fetch_until(F, str, CH_NEWLINE);
+ }
+ F->idx++;
+ s = 0;
+err:
+ str_destroy(&str);
+ if ((s && s != E_FILE_END) || reject)
+ record_destroy(R);
+ return s;
+}
diff --git a/op/vos_Record.h b/op/vos_Record.h
new file mode 100644
index 0000000..b07f920
--- /dev/null
+++ b/op/vos_Record.h
@@ -0,0 +1,24 @@
+#ifndef _VOS_RECORD_H
+#define _VOS_RECORD_H 1
+
+#include "type/vos_TRecord.h"
+#include "op/vos_File.h"
+#include "op/vos_Field.h"
+
+int record_new(struct Record **R, struct Field *fld, struct String *str);
+int _record_cmp(struct Record *l, struct Record *r, const int idx);
+#define record_cmp(L,R) _record_cmp(L,R,1)
+
+void record_add_field(struct Record **R, struct Record *Rfld);
+void record_add_row(struct Record **R, struct Record *row);
+void record_prune(struct Record *R);
+void record_destroy(struct Record **R);
+void record_print(struct Record *R);
+
+int record_write(struct Record *R, struct File *F, struct Field *_fld);
+int record_read(struct Record **R, struct File *F, struct Field *fld);
+int record_read2(struct Record *R, struct File *F, struct Field *fld);
+int record_read_filtered(struct Record **R, struct File *F,
+ struct Field *fld);
+
+#endif
diff --git a/op/vos_Stmt.c b/op/vos_Stmt.c
new file mode 100644
index 0000000..41fc13c
--- /dev/null
+++ b/op/vos_Stmt.c
@@ -0,0 +1,142 @@
+#include "op/vos_Stmt.h"
+
+const char *_stmt_type[N_STMT_TYPE] = {
+ "SET\0",
+ "LOAD\0",
+ "CREATE\0",
+ "SORT\0",
+ "JOIN\0"
+};
+
+void stmt_add(struct Stmt **stmt, struct Stmt *new_stmt)
+{
+ if (! (*stmt)) {
+ (*stmt) = new_stmt;
+ (*stmt)->next = 0;
+ (*stmt)->prev = 0;
+ } else {
+ struct Stmt *p = (*stmt);
+
+ while (p->next)
+ p = p->next;
+
+ p->next = new_stmt;
+ new_stmt->prev = p;
+ }
+ (*stmt)->last = new_stmt;
+}
+
+struct Stmt * stmt_find_by_name(struct Stmt *stmt, const char *name)
+{
+ int s = 0;
+ struct Stmt *p = stmt->last;
+
+ while (p) {
+ switch (p->type) {
+ case STMT_LOAD:
+ s = strcasecmp(p->in->filename, name);
+ if (s == 0)
+ return p;
+
+ if (p->in->alias) {
+ s = strcasecmp(p->in->alias, name);
+ if (s == 0)
+ return p;
+ }
+ break;
+
+ case STMT_SORT:
+ s = strcasecmp(p->in->filename, name);
+ if (s == 0)
+ return p;
+
+ if (p->in->alias) {
+ s = strcasecmp(p->in->alias, name);
+ if (s == 0)
+ return p;
+ }
+ break;
+
+ case STMT_CREATE:
+ s = strcasecmp(p->out->filename, name);
+ if (s == 0)
+ return p;
+
+ if (p->out->alias) {
+ s = strcasecmp(p->out->alias, name);
+ if (s == 0)
+ return p;
+ }
+ break;
+
+ case STMT_JOIN:
+ s = strcasecmp(p->out->filename, name);
+ if (s == 0)
+ return p;
+
+ if (p->out->alias) {
+ s = strcasecmp(p->out->alias, name);
+ if (s == 0)
+ return p;
+ }
+ break;
+ }
+ p = p->prev;
+ }
+
+ return 0;
+}
+
+void stmt_print(struct Stmt *stmt)
+{
+ while (stmt) {
+ switch (stmt->type) {
+ case STMT_SET:
+ stmtset_print(stmt);
+ break;
+ case STMT_LOAD:
+ stmtload_print(stmt);
+ break;
+ case STMT_SORT:
+ stmtsort_print(stmt);
+ break;
+ case STMT_CREATE:
+ stmtcreate_print(stmt);
+ break;
+ case STMT_JOIN:
+ stmtjoin_print(stmt);
+ break;
+ }
+ stmt = stmt->next;
+ }
+}
+
+void stmt_destroy(struct Stmt **stmt)
+{
+ struct Stmt *p = (*stmt);
+ struct Stmt *pnext = 0;
+
+ while (p) {
+ pnext = p->next;
+
+ switch (p->type) {
+ case STMT_SET:
+ stmtset_destroy(&p);
+ break;
+ case STMT_LOAD:
+ stmtload_destroy(&p);
+ break;
+ case STMT_SORT:
+ stmtsort_destroy(&p);
+ break;
+ case STMT_CREATE:
+ stmtcreate_destroy(&p);
+ break;
+ case STMT_JOIN:
+ stmtjoin_destroy(&p);
+ break;
+ }
+ p = pnext;
+ }
+ (*stmt) = 0;
+}
diff --git a/op/vos_Stmt.h b/op/vos_Stmt.h
new file mode 100644
index 0000000..cbd589b
--- /dev/null
+++ b/op/vos_Stmt.h
@@ -0,0 +1,19 @@
+#ifndef _VOS_STMT_H
+#define _VOS_STMT_H 1
+
+#include "op/vos_StmtSet.h"
+#include "op/vos_StmtLoad.h"
+#include "vos_StmtSort.h"
+#include "vos_StmtCreate.h"
+#include "vos_StmtJoin.h"
+
+extern const char *_stmt_type[N_STMT_TYPE];
+
+#define stmt_get_type_idx(T) get_token_idx(_stmt_type, N_STMT_TYPE, T)
+
+void stmt_add(struct Stmt **stmt, struct Stmt *new_stmt);
+struct Stmt * stmt_find_by_name(struct Stmt *stmt, const char *name);
+void stmt_print(struct Stmt *stmt);
+void stmt_destroy(struct Stmt **stmt);
+
+#endif
diff --git a/op/vos_StmtCreate.c b/op/vos_StmtCreate.c
new file mode 100644
index 0000000..b9719be
--- /dev/null
+++ b/op/vos_StmtCreate.c
@@ -0,0 +1,58 @@
+#include "op/vos_StmtCreate.h"
+
+int stmtcreate_create(struct Stmt **create)
+{
+ (*create) = (struct Stmt *) calloc(1, sizeof(struct Stmt));
+ if (! (*create))
+ return E_MEM;
+
+ (*create)->out = (struct StmtMeta *) calloc(1, sizeof(struct StmtMeta));
+ if (! (*create)->out) {
+ free((*create));
+ (*create) = 0;
+ return E_MEM;
+ }
+ (*create)->type = STMT_CREATE;
+
+ return 0;
+}
+
+void stmtcreate_print(struct Stmt *create)
+{
+ int coma = 0;
+ struct StmtMeta *in = 0;
+
+ if (! create)
+ return;
+
+ printf("CREATE %s \nFROM ", create->out->filename);
+
+ in = create->in;
+ while (in) {
+ if (coma)
+ printf(",\n");
+ printf(" %s \n", in->filename);
+ field_print(in->fields);
+ coma++;
+ in = in->next;
+ }
+ printf("\n");
+
+ field_print(create->out->fields);
+
+ if (create->out->alias)
+ printf("AS %s;\n\n", create->out->alias);
+ else
+ printf(";\n\n");
+}
+
+void stmtcreate_destroy(struct Stmt **create)
+{
+ if (! (*create))
+ return;
+
+ stmtmeta_soft_destroy(&(*create)->in);
+ stmtmeta_destroy(&(*create)->out);
+ free((*create));
+ (*create) = 0;
+}
diff --git a/op/vos_StmtCreate.h b/op/vos_StmtCreate.h
new file mode 100644
index 0000000..2a86e81
--- /dev/null
+++ b/op/vos_StmtCreate.h
@@ -0,0 +1,11 @@
+#ifndef _VOS_STMT_CREATE_H
+#define _VOS_STMT_CREATE_H 1
+
+#include "type/vos_TStmt.h"
+#include "op/vos_StmtMeta.h"
+
+int stmtcreate_create(struct Stmt **create);
+void stmtcreate_print(struct Stmt *create);
+void stmtcreate_destroy(struct Stmt **create);
+
+#endif
diff --git a/op/vos_StmtJoin.c b/op/vos_StmtJoin.c
new file mode 100644
index 0000000..138c42d
--- /dev/null
+++ b/op/vos_StmtJoin.c
@@ -0,0 +1,182 @@
+#include "op/vos_StmtJoin.h"
+
+const char *_join_flag[N_JOIN_FLAG] = {
+ "\0",
+ "+\0",
+ "-\0"
+};
+
+const char *_join_sort_flag[N_JOIN_SORT_FLAG] = {
+ "\0",
+ "\0",
+ "\0",
+ "\0",
+ "UNSORTED\0",
+ "\0",
+ "\0",
+ "\0",
+ "SORTED\0"
+};
+
+int stmtjoin_create(struct Stmt **join)
+{
+ (*join) = (struct Stmt *) calloc(1, sizeof(struct Stmt));
+ if (! (*join))
+ return E_MEM;
+
+ (*join)->out = (struct StmtMeta *) calloc(1, sizeof(struct StmtMeta));
+ if (! (*join)->out) {
+ free((*join));
+ (*join) = 0;
+ return E_MEM;
+ }
+ (*join)->type = STMT_JOIN;
+ return 0;
+}
+
+int stmtjoin_init_output(struct Stmt *join)
+{
+ int s;
+ struct Field *field = 0;
+ struct Field *fld_new = 0;
+ struct String *str = 0;
+ struct StmtMeta *inr = 0;
+
+ if (! join)
+ return 0;
+
+ if (! join->out->filename) {
+ do {
+ s = str_raw_randomize(VOS_JOIN_OUT_FORMAT,
+ &join->out->filename);
+ if (s)
+ return s;
+
+ s = file_raw_is_exist(join->out->filename);
+ if (s)
+ free(join->out->filename);
+ } while (s);
+ } else {
+ s = file_raw_is_exist(join->out->filename);
+ if (s) {
+ str_raw_copy(join->out->filename, &_vos.e_sparm0);
+ return E_FILE_EXIST;
+ }
+ }
+
+ s = str_create(&str);
+ if (s)
+ return s;
+
+ field = join->in->fields;
+ while (field) {
+ fld_new = (struct Field *) calloc(1, sizeof(struct Field));
+ if (! fld_new) {
+ s = E_MEM;
+ goto err;
+ }
+
+ fld_new->type = field->type;
+ fld_new->sep = '|';
+ fld_new->date_format = field->date_format;
+
+ if (join->in->alias) {
+ str_append(str, join->in->alias);
+ str_append(str, ".");
+ }
+ str_append(str, field->name);
+ str_detach(str, &fld_new->name);
+
+ field_add(&join->out->fields, fld_new);
+ field = field->next;
+ }
+
+ inr = join->in->next;
+ field = inr->fields;
+ while (field) {
+ fld_new = (struct Field *) calloc(1, sizeof(struct Field));
+ if (! fld_new) {
+ s = E_MEM;
+ goto err;
+ }
+
+ fld_new->type = field->type;
+ if (field->next)
+ fld_new->sep = '|';
+ fld_new->date_format = field->date_format;
+
+ if (inr->alias) {
+ str_append(str, inr->alias);
+ str_append(str, ".");
+ }
+ str_append(str, field->name);
+ str_detach(str, &fld_new->name);
+
+ field_add(&join->out->fields, fld_new);
+ field = field->next;
+ }
+ s = 0;
+err:
+ str_destroy(&str);
+ return s;
+}
+
+void stmtjoin_print(struct Stmt *join)
+{
+ printf("JOIN %s (%2d) ", join->in->alias, join->in->flag);
+ field_print(join->in->fields);
+
+ printf("WITH %s (%2d) ", join->in->next->alias, join->in->next->flag);
+ field_print(join->in->next->fields);
+
+ printf("INTO %s ", join->out->filename);
+ field_print(join->out->fields);
+
+ if (join->out->alias)
+ printf(" AS %s ;\n", join->out->alias);
+ else
+ printf(";\n");
+}
+
+void stmtjoin_destroy(struct Stmt **join)
+{
+ struct StmtMeta *inl = 0;
+ struct StmtMeta *inr = 0;
+
+ if (! (*join))
+ return;
+
+ if ((*join)->in)
+ inl = (*join)->in;
+ if (inl)
+ inr = inl->next;
+
+ if (inr) {
+ if (inr->flag & JOIN_UNSORTED) {
+ if (inr->filename)
+ free(inr->filename);
+ if (inr->alias)
+ free(inr->alias);
+ field_soft_destroy(&inr->fields);
+ free(inr);
+ } else
+ stmtmeta_soft_destroy(&(*join)->in->next);
+ (*join)->in->next = 0;
+ }
+
+ if (inl) {
+ if (inl->flag & JOIN_UNSORTED) {
+ if (inl->filename)
+ free(inl->filename);
+ if (inl->alias)
+ free(inl->alias);
+ field_soft_destroy(&inl->fields);
+ free(inl);
+ } else
+ stmtmeta_soft_destroy(&(*join)->in);
+ }
+
+ stmtmeta_destroy(&(*join)->out);
+ free((*join));
+ (*join) = 0;
+}
diff --git a/op/vos_StmtJoin.h b/op/vos_StmtJoin.h
new file mode 100644
index 0000000..a360f91
--- /dev/null
+++ b/op/vos_StmtJoin.h
@@ -0,0 +1,20 @@
+#ifndef _VOS_STMTJOIN_H
+#define _VOS_STMTJOIN_H 1
+
+#include "type/vos_TStmtJoin.h"
+#include "type/vos_TStmt.h"
+#include "op/vos_StmtMeta.h"
+#include "op/vos_File.h"
+
+extern const char *_join_flag[N_JOIN_FLAG];
+extern const char *_join_sort_flag[N_JOIN_SORT_FLAG];
+
+#define join_get_flag(T) get_token_idx(_join_flag, N_JOIN_FLAG, T)
+#define join_get_sort_flag(T) get_token_idx(_join_sort_flag, N_JOIN_SORT_FLAG, T)
+
+int stmtjoin_create(struct Stmt **join);
+int stmtjoin_init_output(struct Stmt *join);
+void stmtjoin_print(struct Stmt *join);
+void stmtjoin_destroy(struct Stmt **join);
+
+#endif
diff --git a/op/vos_StmtLoad.c b/op/vos_StmtLoad.c
new file mode 100644
index 0000000..6bfcc23
--- /dev/null
+++ b/op/vos_StmtLoad.c
@@ -0,0 +1,41 @@
+#include "op/vos_StmtLoad.h"
+
+int stmtload_create(struct Stmt **load)
+{
+ (*load) = (struct Stmt *) calloc(1, sizeof(struct Stmt));
+ if (! (*load))
+ return E_MEM;
+
+ (*load)->in = (struct StmtMeta *) calloc(1, sizeof(struct StmtMeta));
+ if (! (*load)->in) {
+ free((*load));
+ (*load) = 0;
+ return E_MEM;
+ }
+ (*load)->type = STMT_LOAD;
+ return 0;
+}
+
+void stmtload_print(struct Stmt *load)
+{
+ if (! load && !load->in)
+ return;
+
+ printf("LOAD \"%s\" \n", load->in->filename);
+ field_print(load->in->fields);
+ if (load->in->alias)
+ printf("AS %s;\n\n", load->in->alias);
+ else
+ printf(";\n\n");
+}
+
+void stmtload_destroy(struct Stmt **load)
+{
+ if (! (*load))
+ return;
+
+ if ((*load)->in)
+ stmtmeta_destroy(&(*load)->in);
+ free((*load));
+ (*load) = 0;
+}
diff --git a/op/vos_StmtLoad.h b/op/vos_StmtLoad.h
new file mode 100644
index 0000000..2563fb6
--- /dev/null
+++ b/op/vos_StmtLoad.h
@@ -0,0 +1,11 @@
+#ifndef _VOS_STMTLOAD_H
+#define _VOS_STMTLOAD_H 1
+
+#include "type/vos_TStmt.h"
+#include "op/vos_StmtMeta.h"
+
+int stmtload_create(struct Stmt **load);
+void stmtload_destroy(struct Stmt **load);
+void stmtload_print(struct Stmt *load);
+
+#endif
diff --git a/op/vos_StmtMeta.c b/op/vos_StmtMeta.c
new file mode 100644
index 0000000..09aa311
--- /dev/null
+++ b/op/vos_StmtMeta.c
@@ -0,0 +1,115 @@
+#include "op/vos_StmtMeta.h"
+
+/**
+ * @return:
+ * < !0 : success
+ * < 0 : fail, filename not found
+ */
+struct StmtMeta * stmtmeta_search_filename(struct StmtMeta *meta,
+ const char *str)
+{
+ int s;
+
+ while (meta) {
+ s = strcasecmp(meta->filename, str);
+ if (s == 0)
+ return meta;
+ if (meta->alias) {
+ s = strcasecmp(meta->alias, str);
+ if (s == 0)
+ return meta;
+ }
+ meta = meta->next;
+ }
+
+ return 0;
+}
+
+/**
+ * @return:
+ * < 0 : success, fieldname found
+ * < E_PARSER_UNK_FIELDNAME : fail, fieldname not found
+ * < E_PARSER_AMB_FIELDNAME : fail, fieldname already declared
+ */
+int stmtmeta_search_field(struct StmtMeta *meta, const char *fldname,
+ struct Field **fld_r)
+{
+ int s;
+ struct Field *fld = 0;
+
+ while (meta) {
+ fld = meta->fields;
+ while (fld) {
+ s = strcasecmp(fld->name, fldname);
+ if (s == 0) {
+ if ((*fld_r))
+ return E_PARSER_AMB_FIELDNAME;
+ else
+ (*fld_r) = fld;
+ break;
+ }
+ fld = fld->next;
+ }
+ meta = meta->next;
+ }
+
+ if (! (*fld_r))
+ return E_PARSER_UNK_FIELDNAME;
+ return 0;
+}
+
+int stmtmeta_soft_copy(struct StmtMeta *meta, struct StmtMeta **cp)
+{
+ int s = 0;
+ struct Field *fld = 0;
+ struct Field *fcp = 0;
+
+ (*cp) = (struct StmtMeta *) calloc(1, sizeof(struct StmtMeta));
+ if (! (*cp))
+ return E_MEM;
+
+ str_raw_copy(meta->filename, &(*cp)->filename);
+ str_raw_copy(meta->alias, &(*cp)->alias);
+
+ fld = meta->fields;
+ while (fld) {
+ s = field_soft_copy(fld, &fcp);
+ if (s)
+ goto err;
+
+ field_add(&(*cp)->fields, fcp);
+ fld = fld->next;
+ }
+err:
+ if (s)
+ stmtmeta_soft_destroy(cp);
+ return s;
+}
+
+void stmtmeta_add(struct StmtMeta **meta, struct StmtMeta *n)
+{
+ if (! (*meta))
+ (*meta) = n;
+ else {
+ struct StmtMeta *p = (*meta);
+ while (p->next)
+ p = p->next;
+ p->next = n;
+ }
+}
+
+void _stmtmeta_destroy(struct StmtMeta **meta, const int soft)
+{
+ if (! (*meta))
+ return;
+
+ if ((*meta)->filename)
+ free((*meta)->filename);
+ if ((*meta)->alias)
+ free((*meta)->alias);
+ if ((*meta)->fields)
+ _field_destroy(&(*meta)->fields, soft);
+ _stmtmeta_destroy(&(*meta)->next, soft);
+ free((*meta));
+ (*meta) = 0;
+}
diff --git a/op/vos_StmtMeta.h b/op/vos_StmtMeta.h
new file mode 100644
index 0000000..3c4ab5d
--- /dev/null
+++ b/op/vos_StmtMeta.h
@@ -0,0 +1,18 @@
+#ifndef _VOS_STMTMETA_H
+#define _VOS_STMTMETA_H 1
+
+#include "type/vos_TStmtMeta.h"
+#include "op/vos_Field.h"
+
+struct StmtMeta * stmtmeta_search_filename(struct StmtMeta *meta,
+ const char *str);
+int stmtmeta_search_field(struct StmtMeta *meta, const char *fldname,
+ struct Field **fld_r);
+int stmtmeta_soft_copy(struct StmtMeta *meta, struct StmtMeta **cp);
+void stmtmeta_add(struct StmtMeta **meta, struct StmtMeta *n);
+void _stmtmeta_destroy(struct StmtMeta **meta, const int soft);
+
+#define stmtmeta_destroy(M) _stmtmeta_destroy(M,0)
+#define stmtmeta_soft_destroy(M) _stmtmeta_destroy(M,1)
+
+#endif
diff --git a/op/vos_StmtSet.c b/op/vos_StmtSet.c
new file mode 100644
index 0000000..d4e91e6
--- /dev/null
+++ b/op/vos_StmtSet.c
@@ -0,0 +1,45 @@
+#include "op/vos_StmtSet.h"
+
+const char *_stmt_set[N_SET] = {
+ "FILE_BUFFER_SIZE\0",
+ "PROCESS_COMPARE_CASE_SENSITIVE\0",
+ "PROCESS_COMPARE_CASE_NOTSENSITIVE\0",
+ "PROCESS_MAX\0",
+ "PROCESS_MAX_ROW\0"
+};
+
+int stmtset_create(struct Stmt **stmt)
+{
+ (*stmt) = (struct Stmt *) calloc(1, sizeof(struct Stmt));
+ if (! (*stmt))
+ return E_MEM;
+
+ (*stmt)->set = (struct StmtSet *) calloc(1, sizeof(struct StmtSet));
+ if (! (*stmt)->set) {
+ free((*stmt));
+ return E_MEM;
+ }
+ (*stmt)->type = STMT_SET;
+ return 0;
+}
+
+void stmtset_print(struct Stmt *stmt)
+{
+ if (stmt && stmt->set)
+ printf("SET %s %s;\n\n", _stmt_set[stmt->set->var_idx],
+ stmt->set->value ? stmt->set->value : "\0");
+}
+
+void stmtset_destroy(struct Stmt **stmt)
+{
+ if (! (*stmt))
+ return;
+
+ if ((*stmt)->set) {
+ if ((*stmt)->set->value)
+ free((*stmt)->set->value);
+ free((*stmt)->set);
+ free((*stmt));
+ (*stmt) = 0;
+ }
+}
diff --git a/op/vos_StmtSet.h b/op/vos_StmtSet.h
new file mode 100644
index 0000000..ea501b8
--- /dev/null
+++ b/op/vos_StmtSet.h
@@ -0,0 +1,17 @@
+#ifndef _VOS_STMTSET_H
+#define _VOS_STMTSET_H 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "vos_errno.h"
+#include "type/vos_TStmt.h"
+
+extern const char *_stmt_set[N_SET];
+
+#define set_get_var_idx(T) get_token_idx(_stmt_set, N_SET, T)
+
+int stmtset_create(struct Stmt **stmt);
+void stmtset_print(struct Stmt *stmt);
+void stmtset_destroy(struct Stmt **stmt);
+
+#endif
diff --git a/op/vos_StmtSort.c b/op/vos_StmtSort.c
new file mode 100644
index 0000000..a2d4bc8
--- /dev/null
+++ b/op/vos_StmtSort.c
@@ -0,0 +1,111 @@
+#include "op/vos_StmtSort.h"
+
+int stmtsort_create(struct Stmt **sort)
+{
+ (*sort) = (struct Stmt *) calloc(1, sizeof(struct Stmt));
+ if (! (*sort))
+ return E_MEM;
+
+ (*sort)->out = (struct StmtMeta *) calloc(1, sizeof(struct StmtMeta));
+ if (! (*sort)->out) {
+ free((*sort)->in);
+ free((*sort));
+ (*sort) = 0;
+ return E_MEM;
+ }
+ (*sort)->type = STMT_SORT;
+ return 0;
+}
+
+int stmtsort_init_output(struct Stmt *sort)
+{
+ int s = E_MEM;
+ struct Field *fld_in = 0;
+ struct Field *fld_out = 0;
+
+ if (! sort->out) {
+ sort->out = (struct StmtMeta *) calloc(1,
+ sizeof(struct StmtMeta));
+ if (! sort->out)
+ return E_MEM;
+ }
+
+ if (! sort->out->filename) {
+ do {
+ s = str_raw_randomize(VOS_SORT_OUT_FORMAT,
+ &sort->out->filename);
+ if (s)
+ return s;
+
+ s = file_raw_is_exist(sort->out->filename);
+ if (s)
+ free(sort->out->filename);
+ } while (s);
+ } else {
+ /* check if file output is exist */
+ s = file_raw_is_exist(sort->out->filename);
+ if (s) {
+ str_raw_copy(sort->out->filename, &_vos.e_sparm0);
+ return E_FILE_EXIST;
+ }
+ }
+
+ if (! sort->out->alias) {
+ s = str_raw_copy(sort->in->alias, &sort->out->alias);
+ if (s)
+ return s;
+ }
+
+ sort->out->flag = sort->in->flag;
+
+ fld_in = sort->in->fields;
+ while (fld_in) {
+ fld_out = (struct Field *) calloc(1, sizeof(struct Field));
+ if (! fld_out)
+ return E_MEM;
+
+ fld_out->idx = fld_in->idx;
+ fld_out->flag = fld_in->flag;
+ fld_out->type = fld_in->type;
+ if (fld_in->next)
+ fld_out->sep = '|';
+ fld_out->name = fld_in->name;
+ fld_out->date_format = fld_in->date_format;
+
+ field_add(&sort->out->fields, fld_out);
+ fld_in = fld_in->next;
+ }
+
+ return 0;
+}
+
+void stmtsort_print(struct Stmt *sort)
+{
+ if (! sort)
+ return;
+
+ printf("SORT %s ", sort->in->alias ? sort->in->alias
+ : sort->in->filename);
+ field_print(sort->in->fields);
+ printf(" BY \n");
+ field_print(sort->out->fields);
+ printf(";\n\n");
+}
+
+void stmtsort_destroy(struct Stmt **sort)
+{
+ if (! (*sort))
+ return;
+
+ stmtmeta_soft_destroy(&(*sort)->in);
+ if ((*sort)->out) {
+ if ((*sort)->out->filename)
+ free((*sort)->out->filename);
+ if ((*sort)->out->alias)
+ free((*sort)->out->alias);
+ field_soft_destroy(&(*sort)->out->fields);
+ free((*sort)->out);
+ }
+ free((*sort));
+ (*sort) = 0;
+}
diff --git a/op/vos_StmtSort.h b/op/vos_StmtSort.h
new file mode 100644
index 0000000..e167876
--- /dev/null
+++ b/op/vos_StmtSort.h
@@ -0,0 +1,15 @@
+#ifndef _VOS_STMTSORT_H
+#define _VOS_STMTSORT_H 1
+
+#include "type/vos_TStmt.h"
+#include "op/vos_File.h"
+#include "op/vos_StmtMeta.h"
+
+#define sort_get_idx(T) get_token_idx(_fflag_sort, N_FFLAG_SORT, T)
+
+int stmtsort_create(struct Stmt **sort);
+int stmtsort_init_output(struct Stmt *sort);
+void stmtsort_print(struct Stmt *sort);
+void stmtsort_destroy(struct Stmt **sort);
+
+#endif
diff --git a/op/vos_String.c b/op/vos_String.c
new file mode 100644
index 0000000..679e243
--- /dev/null
+++ b/op/vos_String.c
@@ -0,0 +1,209 @@
+#include "op/vos_String.h"
+
+const char _alnum[N_ALNUM] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', /* 10 */
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', /* 20 */
+ 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', /* 30 */
+ 'u', 'v', 'w', 'x', 'y', 'z', /* 36 */
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 46 */
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 56 */
+ 'U', 'V', 'W', 'X', 'Y', 'Z' /* 62 */
+};
+
+/**
+ * @desc:
+ * create a new string object.
+ * @return:
+ * < 0 : success.
+ * < E_MEM : fail, out of memory.
+ */
+int str_create(struct String **str)
+{
+ (*str) = (struct String *) calloc(1, sizeof(struct String));
+ if (! (*str))
+ return E_MEM;
+
+ (*str)->buf = (char *) calloc(STR_DEF_LEN + 1, sizeof(char));
+ if (! (*str)->buf) {
+ free((*str));
+ (*str) = 0;
+ return E_MEM;
+ }
+ (*str)->len = STR_DEF_LEN;
+ return 0;
+}
+
+/**
+ * @desc:
+ * append character 'c' to the end of String buffer.
+ * @return:
+ * < 0 : success.
+ * < E_MEM : fail, out of memory.
+ */
+int str_append_c(struct String *str, const int c)
+{
+ if (! str)
+ return 0;
+ if (str->idx == str->len) {
+ str->len += STR_DEF_REALLOC_LEN;
+ str->buf = realloc(str->buf, str->len + 1);
+ if (! str->buf)
+ return E_MEM;
+ }
+ str->buf[str->idx++] = c;
+ str->buf[str->idx] = '\0';
+ return 0;
+}
+
+/**
+ * @desc:
+ * append raw string 'str' to the end of String buffer.
+ * @return:
+ * < 0 : success.
+ * < E_MEM : fail, out of memory.
+ */
+int str_append(struct String *S, const char *str)
+{
+ int i;
+ int len;
+
+ if (! S)
+ return 0;
+ if (! str)
+ return 0;
+
+ len = strlen(str);
+ if (S->idx + len >= S->len) {
+ S->len += len;
+ S->buf = realloc(S->buf, S->len + 1);
+ if (! S->buf)
+ return E_MEM;
+ }
+ for (i = 0; i < len; i++)
+ S->buf[S->idx++] = str[i];
+
+ S->buf[S->idx] = '\0';
+
+ return 0;
+}
+
+/**
+ * @desc:
+ * Attach String buffer to 'buf', and reset 'str' back to zero with
+ * length leave untouch.
+ * warning: buffer pointed by 'buf' will be lost.
+ * @return:
+ * < 0 : success, or maybe str is empty.
+ * < E_MEM : fail, out of memory.
+ */
+int str_detach(struct String *str, char **buf)
+{
+ if (! str)
+ return 0;
+
+ (*buf) = (char *) calloc(str->idx + 1, sizeof(char));
+ if (! (*buf))
+ return E_MEM;
+
+ (*buf) = memcpy((*buf), str->buf, str->idx);
+ str->idx = 0;
+ str->buf[0] = '\0';
+ return 0;
+}
+
+/**
+ * @desc: reset String buffer to zero
+ */
+void str_prune(struct String *str)
+{
+ if (! str)
+ return;
+ if (str->idx) {
+ str->idx = 0;
+ str->buf[0] = '\0';
+ }
+}
+
+void str_destroy(struct String **str)
+{
+ if ((*str)) {
+ if ((*str)->buf)
+ free((*str)->buf);
+ free((*str));
+ (*str) = 0;
+ }
+}
+
+/**
+ * @desc:
+ * copy raw string 'str' into new 'buf'
+ * warning: buffer pointed by 'buf' will be lost.
+ * @return:
+ * < 0 : success, or maybe str is empty.
+ * < E_MEM : fail, out of memory.
+ */
+int str_raw_copy(const char *str, char **buf)
+{
+ size_t l;
+
+ if (! str)
+ return 0;
+
+ if ((*buf))
+ free((*buf));
+
+ l = strlen(str);
+ (*buf) = (char *) calloc(l + 1, sizeof(char));
+ if (! (*buf))
+ return E_MEM;
+
+ (*buf) = memcpy((*buf), str, l);
+ return 0;
+}
+
+/**
+ * @desc:
+ * replace each 'X' character on 'format' with random alphanumeric
+ * character.
+ * @return:
+ * < 0 : success, or maybe 'format' is empty.
+ * < E_MEM : fail, out of memory.
+ */
+int str_raw_randomize(const char *format, char **buf)
+{
+ int i;
+
+ if (! format)
+ return 0;
+
+ i = strlen(format);
+ (*buf) = (char *) calloc(i + 1, sizeof(char));
+ if (! (*buf))
+ return E_MEM;
+
+ i--;
+ while (i >= 0) {
+ if (format[i] == CH_2_REPLACE) {
+ (*buf)[i] = _alnum[rand() % N_ALNUM];
+ } else
+ (*buf)[i] = format[i];
+ i--;
+ }
+ return 0;
+}
+
+/**
+ * @desc:
+ * generate a hash from raw string 'str'
+ * @return:
+ * < hash : a hash value for string 'str'
+ */
+unsigned long str_raw_hash(char *str, unsigned long hash)
+{
+ while ((*str)) {
+ hash = *str + (hash << 6) + (hash << 16) - hash;
+ str++;
+ }
+
+ return hash;
+}
diff --git a/op/vos_String.h b/op/vos_String.h
new file mode 100644
index 0000000..062f388
--- /dev/null
+++ b/op/vos_String.h
@@ -0,0 +1,29 @@
+#ifndef _VOS_STRING_H
+#define _VOS_STRING_H 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "vos_errno.h"
+#include "type/vos_TString.h"
+
+#define CH_NEWLINE '\n'
+#define CH_2_REPLACE 'X'
+
+#define STR_DEF_LEN 15
+#define STR_DEF_REALLOC_LEN 15
+#define N_ALNUM 62
+
+int str_create(struct String **str);
+int str_append_c(struct String *str, const int c);
+int str_append(struct String *S, const char *str);
+int str_detach(struct String *str, char **buf);
+void str_prune(struct String *str);
+void str_destroy(struct String **str);
+
+int str_raw_copy(const char *str, char **buf);
+int str_raw_randomize(const char *format, char **buf);
+unsigned long str_raw_hash(char *str, unsigned long hash);
+
+#endif
diff --git a/proc/vos_create.c b/proc/vos_create.c
new file mode 100644
index 0000000..0f32de0
--- /dev/null
+++ b/proc/vos_create.c
@@ -0,0 +1,269 @@
+#include "proc/vos_create.h"
+
+static void * create_process(void *parm)
+{
+ int s;
+ unsigned long n_row = 0;
+ struct ProcCreate *cproc = 0;
+ struct File *F = 0;
+ struct Record *R = 0;
+ struct Field *fld = 0;
+
+ cproc = (struct ProcCreate *) parm;
+ s = file_open(&F, cproc->in->filename, FOPEN_RO);
+ if (s)
+ goto err;
+
+ s = file_read(F);
+ if (s)
+ goto err;
+
+ /* phase 1: create & fill bucket */
+ do {
+ s = record_read_filtered(&R, F, cproc->in->fields);
+ if (R) {
+ record_to_bucket(cproc->buckets, R);
+ n_row++;
+ R = 0;
+ }
+ } while (s == 0 && n_row < _vos.proc_max_row);
+ if (s && s != E_FILE_END)
+ goto err;
+
+ /* set row last to mark the end of row */
+ fld = cproc->in->fields;
+ while (fld) {
+ if (fld->idx) {
+ if (cproc->buckets[fld->idx].cnt) {
+ cproc->buckets[fld->idx].cnt->row_last =
+ cproc->buckets[fld->idx].cnt->row_last->row_next;
+ }
+ }
+ fld = fld->next;
+ }
+
+ if (_vos.debug & DBG_CREATE) {
+ printf("child: bucket full\n");
+ }
+
+ cproc->status = CPROC_BUCKETS_FULL;
+ while (cproc->status == CPROC_BUCKETS_FULL)
+ sleep(THREAD_TIME_WAIT);
+
+ if (cproc->status != CPROC_START)
+ goto out;
+ if (n_row < _vos.proc_max_row)
+ goto out;
+
+ if (_vos.debug & DBG_CREATE) {
+ printf("child: bucket empty\n");
+ }
+
+ /* phase 2:
+ * this is where bucket is already filled with size == _vos.proc_max_row
+ * but empty. so we just need to fill the empty row, no need to
+ * malloc/create it again.
+ */
+ n_row = 0;
+ do {
+ s = bucket_read_filtered(cproc->buckets, F,
+ cproc->in->fields);
+ if (s == 0) {
+ n_row++;
+ } else if (s > 0 && s != E_FILE_END)
+ goto err;
+
+ if (n_row >= _vos.proc_max_row) {
+ fld = cproc->in->fields;
+ while (fld) {
+ if (fld->idx) {
+ cproc->buckets[fld->idx].cnt->row_last
+ = cproc->buckets[fld->idx].p;
+ }
+ fld = fld->next;
+ }
+
+ if (_vos.debug & DBG_CREATE) {
+ printf("child: bucket full\n");
+ }
+
+ cproc->status = CPROC_BUCKETS_FULL;
+ while (cproc->status == CPROC_BUCKETS_FULL)
+ sleep(THREAD_TIME_WAIT);
+
+ if (cproc->status != CPROC_START)
+ goto out;
+
+ if (_vos.debug & DBG_CREATE) {
+ printf("child: bucket empty\n");
+ }
+
+ n_row = 0;
+ }
+ } while (s <= 0);
+
+ if (n_row) {
+ fld = cproc->in->fields;
+ while (fld) {
+ if (fld->idx) {
+ cproc->buckets[fld->idx].cnt->row_last =
+ cproc->buckets[fld->idx].p;
+ }
+ fld = fld->next;
+ }
+ }
+out:
+ s = 0;
+err:
+ switch (s) {
+ case E_FILE_OPEN:
+ case E_FILE_NOT_EXIST:
+ vos_error1(s, cproc->in->filename);
+ break;
+ case E_FILE_NOT_OPEN:
+ case E_FILE_READ:
+ vos_error0(s);
+ break;
+ }
+ cproc->status = CPROC_DONE;
+ file_close(&F);
+
+ cproc->retval = s;
+ return 0;
+}
+
+int vos_process_create(struct Stmt *create)
+{
+ int i = 0;
+ int s = 0;
+ int n_in = 0;
+ int n_done = 0;
+ int n_bucket = 1;
+ struct File *F = 0;
+ struct StmtMeta *pin = create->in;
+ struct ProcCreate *cproc = 0;
+ struct Bucket *buckets = 0;
+ struct Field *fld = 0;
+
+ /* how many input ? */
+ while (pin) {
+ n_in++;
+ pin = pin->next;
+ }
+
+ /* how many field output (bucket) ? */
+ fld = create->out->fields;
+ while (fld) {
+ n_bucket++;
+ fld = fld->next;
+ }
+
+ s = file_open(&F, create->out->filename, FOPEN_WO);
+ if (s)
+ goto err;
+
+ cproc = (struct ProcCreate *) calloc(n_in, sizeof(struct ProcCreate));
+ if (! cproc) {
+ s = E_MEM;
+ goto err;
+ }
+
+ buckets = (struct Bucket *) calloc(n_bucket, sizeof(struct Bucket));
+ if (! buckets) {
+ s = E_MEM;
+ goto err;
+ }
+
+ pin = create->in;
+ for (i = 0; i < n_in; i++) {
+ cproc[i].in = pin;
+ cproc[i].status = CPROC_START;
+ cproc[i].buckets = buckets;
+
+ pthread_create(&cproc[i].tid, 0, create_process,
+ (void *) &cproc[i]);
+ pin = pin->next;
+ }
+
+ /* phase 1: create & fill bucket */
+ for (i = 0; i < n_in; i++) {
+ /* wait until child fill the buckets */
+ while (cproc[i].status == CPROC_START)
+ sleep(THREAD_TIME_WAIT);
+
+ if (cproc[i].status == CPROC_DONE) {
+ pthread_join(cproc[i].tid, 0);
+ if (cproc[i].retval) {
+ s = cproc[i].retval;
+ goto err;
+ }
+
+ n_done++;
+ cproc[i].status = CPROC_END;
+ }
+ }
+
+ if (_vos.debug & DBG_CREATE) {
+ printf("parent: writing bucket\n");
+ bucket_print(buckets, n_bucket);
+ }
+ s = bucket_write(buckets, n_bucket, F, create->out->fields);
+ if (s)
+ goto err;
+
+ /* phase 2: fill the buckets */
+ while (n_done < n_in) {
+ for (i = 0; i < n_in; i++) {
+ /* restart threads */
+ if (cproc[i].status == CPROC_BUCKETS_FULL)
+ cproc[i].status = CPROC_START;
+
+ /* wait until child fill the buckets */
+ while (cproc[i].status == CPROC_START)
+ sleep(THREAD_TIME_WAIT);
+
+ if (cproc[i].status == CPROC_DONE) {
+ pthread_join(cproc[i].tid, 0);
+
+ /* catch error here */
+ if (cproc[i].retval) {
+ s = cproc[i].retval;
+ goto err;
+ }
+
+ n_done++;
+ cproc[i].status = CPROC_END;
+ }
+ }
+
+ if (_vos.debug & DBG_CREATE) {
+ printf("parent: writing bucket\n");
+ bucket_print(buckets, n_bucket);
+ }
+ s = bucket_write(buckets, n_bucket, F, create->out->fields);
+ if (s)
+ goto err;
+ }
+
+err:
+ if (s && cproc) {
+ /* cancel all thread */
+ for (i = 0; i < n_in; i++) {
+ if (cproc[i].status == CPROC_BUCKETS_FULL) {
+ cproc[i].status = CPROC_DONE;
+ pthread_join(cproc[i].tid,
+ (void *) &cproc[i].retval);
+ }
+ }
+ }
+
+ bucket_destroy(buckets, n_bucket);
+
+ if (buckets)
+ free(buckets);
+ if (cproc)
+ free(cproc);
+ if (F)
+ file_close(&F);
+ return s;
+}
diff --git a/proc/vos_create.h b/proc/vos_create.h
new file mode 100644
index 0000000..92def4e
--- /dev/null
+++ b/proc/vos_create.h
@@ -0,0 +1,12 @@
+#ifndef _VOS_PROCESS_CREATE_H
+#define _VOS_PROCESS_CREATE_H 1
+
+#include <pthread.h>
+#include "type/vos_TProcCreate.h"
+#include "op/vos_Bucket.h"
+
+#define THREAD_TIME_WAIT 0.1
+
+int vos_process_create(struct Stmt *create);
+
+#endif
diff --git a/proc/vos_join.c b/proc/vos_join.c
new file mode 100644
index 0000000..1da9736
--- /dev/null
+++ b/proc/vos_join.c
@@ -0,0 +1,244 @@
+#include "proc/vos_join.h"
+
+static int join_do_sort(struct Stmt *join)
+{
+ int s = 0;
+ struct Stmt *sort = 0;
+ struct StmtMeta *inr = join->in->next;
+
+ if (join->in->flag & JOIN_UNSORTED) {
+ s = stmtsort_create(&sort);
+ if (s)
+ return s;
+
+ join->in->next = 0;
+ sort->in = join->in;
+
+ s = stmtsort_init_output(sort);
+ if (s)
+ goto err;
+
+ s = vos_process_sort(sort);
+ if (s)
+ goto err;
+
+ join->in = sort->out;
+ join->in->next = inr;
+ sort->out = 0;
+
+ stmtmeta_soft_destroy(&sort->in);
+ }
+
+ if (inr->flag & JOIN_UNSORTED) {
+ if (! sort) {
+ s = stmtsort_create(&sort);
+ if (s)
+ return s;
+ }
+
+ sort->in = join->in->next;
+
+ s = stmtsort_init_output(sort);
+ if (s)
+ goto err;
+
+ s = vos_process_sort(sort);
+ if (s)
+ goto err;
+
+ join->in->next = sort->out;
+ sort->out = 0;
+ }
+err:
+ if (sort)
+ stmtsort_destroy(&sort);
+ return s;
+}
+
+int vos_process_join(struct Stmt *join)
+{
+ int s;
+ struct Field *field = 0;
+ struct File *F = 0;
+ struct File *FL = 0;
+ struct File *FR = 0;
+ struct Record *rowl = 0;
+ struct Record *rowr = 0;
+ struct Record *emptyl = 0;
+ struct Record *emptyr = 0;
+ struct Record *empty = 0;
+ struct StmtMeta *inl = join->in;
+ struct StmtMeta *inr = join->in->next;
+ struct String *str = 0;
+
+ /* prepare for empty fields */
+ if (inl->flag & JOIN_OUTER
+ || inl->flag & JOIN_ANTI
+ || inr->flag & JOIN_ANTI) {
+ field = inl->fields;
+ while (field) {
+ s = str_create(&str);
+ if (s)
+ goto err;
+
+ s = record_new(&empty, field, str);
+ if (s)
+ goto err;
+
+ record_add_field(&emptyr, empty);
+ empty = 0;
+ str = 0;
+ field = field->next;
+ }
+ }
+ if (inr->flag & JOIN_OUTER
+ || inr->flag & JOIN_ANTI
+ || inl->flag & JOIN_ANTI) {
+ field = inr->fields;
+ while (field) {
+ s = str_create(&str);
+ if (s)
+ goto err;
+
+ s = record_new(&empty, field, str);
+ if (s)
+ goto err;
+
+ record_add_field(&emptyl, empty);
+ empty = 0;
+ str = 0;
+ field = field->next;
+ }
+ }
+
+ s = join_do_sort(join);
+ if (s)
+ goto err;
+
+ inl = join->in;
+ inr = join->in->next;
+
+ s = file_open(&F, join->out->filename, FOPEN_WO);
+ if (s)
+ goto err;
+
+ s = file_open(&FL, inl->filename, FOPEN_RO);
+ if (s)
+ goto err;
+
+ s = file_open(&FR, inr->filename, FOPEN_RO);
+ if (s)
+ goto err;
+
+ s = file_read(FL);
+ if (s)
+ goto err;
+
+ s = file_read(FR);
+ if (s)
+ goto err;
+
+ s = record_read(&rowl, FL, inl->fields);
+ s = record_read(&rowr, FR, inr->fields);
+ while (s == 0) {
+ s = record_cmp(rowl, rowr);
+ if (s < 0) {
+ /* x+ || x- */
+ if (inl->flag & JOIN_OUTER
+ || inl->flag & JOIN_ANTI) {
+ rowl->fld_last->fld_next = emptyr;
+ record_write(rowl, F, join->out->fields);
+ rowl->fld_last->fld_next = 0;
+ } else {
+ record_prune(rowl);
+ }
+ s = record_read2(rowl, FL, inl->fields);
+ if (s)
+ break;
+ } else if (s == 0) {
+ /* x- && y- */
+ if ((inl->flag & JOIN_ANTI)
+ && (inr->flag & JOIN_ANTI)) {
+ record_prune(rowl);
+ record_prune(rowr);
+ } else if (inl->flag & JOIN_ANTI) {
+ emptyl->fld_last->fld_next = rowr;
+ record_write(emptyl, F, join->out->fields);
+ emptyl->fld_last->fld_next = 0;
+ record_prune(rowl);
+ } else if (inr->flag & JOIN_ANTI) {
+ rowl->fld_last->fld_next = emptyr;
+ record_write(rowl, F, join->out->fields);
+ rowl->fld_last->fld_next = 0;
+ record_prune(rowr);
+ } else {
+ rowl->fld_last->fld_next = rowr;
+ record_write(rowl, F, join->out->fields);
+ rowl->fld_last->fld_next = 0;
+ }
+
+ s = record_read2(rowl, FL, inl->fields);
+ if (s)
+ break;
+ s = record_read2(rowr, FR, inr->fields);
+ if (s)
+ break;
+ } else {
+ /* y+ || y- */
+ if (inr->flag & JOIN_OUTER
+ || inr->flag & JOIN_ANTI) {
+ emptyl->fld_last->fld_next = rowr;
+ record_write(emptyl, F, join->out->fields);
+ emptyl->fld_last->fld_next = 0;
+ } else {
+ record_prune(rowr);
+ }
+
+ s = record_read2(rowr, FR, inr->fields);
+ if (s)
+ break;
+ }
+ }
+
+ if (FL->size
+ && ((inl->flag & JOIN_OUTER) || inl->flag & JOIN_ANTI)) {
+ while (FL->size) {
+ rowl->fld_last->fld_next = emptyr;
+ record_write(rowl, F, join->out->fields);
+ rowl->fld_last->fld_next = 0;
+
+ s = record_read2(rowl, FL, inl->fields);
+ }
+ }
+
+ if (FR->size
+ && ((inr->flag & JOIN_OUTER) || inr->flag & JOIN_ANTI)) {
+ while (FR->size) {
+ emptyl->fld_last->fld_next = rowr;
+ record_write(emptyl, F, join->out->fields);
+ emptyl->fld_last->fld_next = 0;
+
+ s = record_read2(rowr, FR, inr->fields);
+ }
+ }
+ file_write(F);
+ s = 0;
+err:
+ record_destroy(&rowl);
+ record_destroy(&rowr);
+ file_close(&FR);
+ file_close(&FL);
+ file_close(&F);
+ record_destroy(&emptyl);
+ record_destroy(&emptyr);
+
+ /* remove temporary sort file */
+ if (inl->flag & JOIN_UNSORTED) {
+ unlink(inl->filename);
+ }
+ if (inr->flag & JOIN_UNSORTED) {
+ unlink(inr->filename);
+ }
+
+ return s;
+}
diff --git a/proc/vos_join.h b/proc/vos_join.h
new file mode 100644
index 0000000..352e488
--- /dev/null
+++ b/proc/vos_join.h
@@ -0,0 +1,9 @@
+#ifndef _VOS_JOIN_H
+#define _VOS_JOIN_H 1
+
+#include "op/vos_StmtJoin.h"
+#include "proc/vos_sort.h"
+
+int vos_process_join(struct Stmt *join);
+
+#endif
diff --git a/proc/vos_load.c b/proc/vos_load.c
new file mode 100644
index 0000000..af1ab0b
--- /dev/null
+++ b/proc/vos_load.c
@@ -0,0 +1,20 @@
+#include "vos_load.h"
+
+/**
+ * @desc:
+ * check if file to `load' is exist.
+ * @return:
+ * < 0 : success.
+ * < E_FILE_NOT_EXIST : fail.
+ */
+int vos_process_load(struct Stmt *load)
+{
+ int fd = 0;
+
+ fd = open(load->in->filename, O_RDONLY);
+ if (fd < 0)
+ return E_FILE_NOT_EXIST;
+
+ close(fd);
+ return 0;
+}
diff --git a/proc/vos_load.h b/proc/vos_load.h
new file mode 100644
index 0000000..98f08ae
--- /dev/null
+++ b/proc/vos_load.h
@@ -0,0 +1,9 @@
+#ifndef _VOS_PROCESS_LOAD_H
+#define _VOS_PROCESS_LOAD_H 1
+
+#include "type/vos_TStmt.h"
+#include "op/vos_File.h"
+
+int vos_process_load(struct Stmt *load);
+
+#endif
diff --git a/proc/vos_parser.c b/proc/vos_parser.c
new file mode 100644
index 0000000..ac57bf4
--- /dev/null
+++ b/proc/vos_parser.c
@@ -0,0 +1,1307 @@
+#include "proc/vos_parser.h"
+
+enum parsing_set_todo {
+ PSET_DONE = 0,
+ PSET_START,
+ PSET_VAR,
+ PSET_VALUE,
+ PSET_END
+};
+
+enum parsing_load_todo {
+ PLOAD_DONE = 0,
+ PLOAD_START,
+ PLOAD_NAME,
+ PLOAD_FIELD_BEGIN,
+ PLOAD_FIELD_END,
+ PLOAD_AS,
+ PLOAD_AS_NAME,
+ PLOAD_END
+};
+
+enum parsing_field_todo {
+ PFIELD_DONE = 0,
+ PFIELD_START,
+ PFIELD_LEFTQ,
+ PFIELD_PARENT_NAME,
+ PFIELD_PARENT_SEP,
+ PFIELD_NAME,
+ PFIELD_RIGHTQ,
+ PFIELD_STARTP,
+ PFIELD_ENDP,
+ PFIELD_TYPE,
+ PFIELD_DATE_FORMAT,
+ PFIELD_SEP,
+ PFIELD_END
+};
+
+enum parsing_sort_todo {
+ PSORT_DONE = 0,
+ PSORT_START,
+ PSORT_INPUT,
+ PSORT_BY,
+ PSORT_FIELD,
+ PSORT_ORDER,
+ PSORT_FIELD_SEP,
+ PSORT_INTO,
+ PSORT_AS,
+ PSORT_AS_VALUE,
+ PSORT_END
+};
+
+enum parsing_create_todo {
+ PCREATE_DONE = 0,
+ PCREATE_START,
+ PCREATE_FILENAME,
+ PCREATE_FROM,
+ PCREATE_FROM_VALUE,
+ PCREATE_FROM_SEP,
+ PCREATE_FIELD_BEGIN,
+ PCREATE_FIELD_END,
+ PCREATE_FILTER,
+ PCREATE_FILTER_BEGIN,
+ PCREATE_FILTER_END,
+ PCREATE_AS,
+ PCREATE_AS_NAME,
+ PCREATE_END
+};
+
+enum parsing_filter_todo {
+ PFLTR_DONE = 0,
+ PFLTR_START,
+ PFLTR_RULE,
+ PFLTR_PARENT_NAME,
+ PFLTR_PARENT_SEP,
+ PFLTR_FIELD_NAME,
+ PFLTR_OP,
+ PFLTR_VALUE,
+ PFLTR_END
+};
+
+enum parsing_join_todo {
+ PJOIN_DONE = 0,
+ PJOIN_START,
+ PJOIN_INPUT,
+ PJOIN_INPUT_JOIN_FLAG,
+ PJOIN_INPUT_SORT_FLAG,
+ PJOIN_INPUT_SEP,
+ PJOIN_INTO,
+ PJOIN_FIELD_BEGIN,
+ PJOIN_FIELD_START,
+ PJOIN_FIELD_L_PARENT_NAME,
+ PJOIN_FIELD_R_PARENT_NAME,
+ PJOIN_FIELD_L_PARENT_SEP,
+ PJOIN_FIELD_R_PARENT_SEP,
+ PJOIN_FIELD_L_NAME,
+ PJOIN_FIELD_R_NAME,
+ PJOIN_FIELD_OP,
+ PJOIN_FIELD_SEP,
+ PJOIN_FIELD_END,
+ PJOIN_AS,
+ PJOIN_AS_NAME,
+ PJOIN_END
+};
+
+static int stmt_get_output_from(struct StmtMeta **smeta, struct Stmt *stmt,
+ const char *name)
+{
+ int s;
+ struct Stmt *p = 0;
+
+ p = stmt_find_by_name(stmt, name);
+ if (! p)
+ return E_PARSER_INV_VALUE;
+
+ switch (p->type) {
+ case STMT_LOAD:
+ s = stmtmeta_soft_copy(p->in, smeta);
+ break;
+ case STMT_SORT:
+ s = stmtmeta_soft_copy(p->out, smeta);
+ break;
+ case STMT_CREATE:
+ s = stmtmeta_soft_copy(p->out, smeta);
+ break;
+ case STMT_JOIN:
+ s = stmtmeta_soft_copy(p->out, smeta);
+ break;
+ default:
+ s = E_PARSER_INV_STMT;
+ }
+ return s;
+}
+
+static int parsing_SET(struct Stmt **stmt, struct LL **ptok)
+{
+ int s = PSET_START;
+
+ while ((*ptok) && s != PSET_DONE) {
+ switch (s) {
+ case PSET_START:
+ s = stmtset_create(stmt);
+ if (s)
+ return s;
+ s = PSET_VAR;
+ break;
+ case PSET_VAR:
+ s = set_get_var_idx((*ptok)->str);
+ if (s < 0) {
+ s = E_PARSER_UNK_TOKEN;
+ goto err;
+ }
+
+ (*stmt)->set->var_idx = s;
+
+ if (s == SET_PROC_CMP_CASE_SENSITIVE
+ || s == SET_PROC_CMP_CASE_NOTSENSITIVE)
+ s = PSET_END;
+ else
+ s = PSET_VALUE;
+ break;
+ case PSET_VALUE:
+ (*stmt)->set->value = (*ptok)->str;
+ (*ptok)->str = 0;
+ s = PSET_END;
+ break;
+ case PSET_END:
+ if ((*ptok)->str[0] != ';') {
+ s = E_PARSER_UNX_CHAR;
+ _vos.e_nparm0 = (*ptok)->num;
+ _vos.e_nparm1 = (*ptok)->str[0];
+ goto err;
+ }
+ s = PSET_DONE;
+ break;
+ }
+ (*ptok) = (*ptok)->next;
+ }
+ if (s != PSET_DONE) {
+ s = E_PARSER_INV_STMT;
+err:
+ stmtset_destroy(stmt);
+ }
+ return s;
+}
+
+/**
+ * @desc:
+ * if mref not null, that mean we parsing field for create statement.
+ */
+static int parsing_FIELD(struct StmtMeta *mref, struct StmtMeta *mout,
+ struct LL **ptok)
+{
+ int idx = 1;
+ int s = 0;
+ int todo_next = 0;
+ struct LL *prevtok = 0;
+ struct Field *f = 0;
+ struct Field *fsearch = 0;
+ struct StmtMeta *pmeta = 0;
+ struct String *fname = 0;
+
+ if (mref) {
+ s = str_create(&fname);
+ if (s)
+ goto err;
+ }
+
+ s = PFIELD_START;
+ while ((*ptok) && s != PFIELD_DONE) {
+ switch (s) {
+ case PFIELD_START:
+ f = (struct Field *) calloc(1, sizeof(struct Field));
+ if (! f) {
+ s = E_MEM;
+ goto err;
+ }
+ s = PFIELD_LEFTQ;
+ break;
+
+ case PFIELD_LEFTQ:
+ switch ((*ptok)->str[0]) {
+ case '\'':
+ f->left_q = (*ptok)->str[1];
+ s = PFIELD_SEP;
+ todo_next = PFIELD_PARENT_NAME;
+ break;
+ case ':':
+ s = PFIELD_PARENT_NAME;
+ break;
+ default:
+ s = E_PARSER_UNX_TOKEN;
+ goto err;
+ }
+ break;
+
+ case PFIELD_SEP:
+ switch ((*ptok)->str[0]) {
+ case ':':
+ s = todo_next;
+ break;
+ case ',':
+ if (todo_next == PFIELD_TYPE) {
+ s = PFIELD_END;
+ continue;
+ }
+ /* if todo_next != PFIELD_TYPE that's mean
+ * there is an error in statement so skip it
+ * to 'default' */
+ case ')':
+ if (todo_next == PFIELD_TYPE) {
+ s = PFIELD_END;
+ continue;
+ }
+ default:
+ s = E_PARSER_UNX_TOKEN;
+ goto err;
+ }
+ break;
+
+ case PFIELD_PARENT_NAME:
+ if (mref) {
+ prevtok = (*ptok);
+ s = PFIELD_PARENT_SEP;
+ break;
+ }
+ s = PFIELD_NAME;
+ continue;
+
+ case PFIELD_PARENT_SEP:
+ if ((*ptok)->str[0] == '.') {
+ pmeta = stmtmeta_search_filename(mref,
+ prevtok->str);
+ if (! pmeta) {
+ (*ptok) = prevtok;
+ s = E_PARSER_INV_VALUE;
+ goto err;
+ }
+ s = PFIELD_NAME;
+ break;
+ }
+ /* continue to below */
+ pmeta = mref;
+ (*ptok) = prevtok;
+
+ case PFIELD_NAME:
+ if (mref) {
+ /* search field */
+ s = stmtmeta_search_field(pmeta, (*ptok)->str,
+ &fsearch);
+ if (s == E_PARSER_UNK_FIELDNAME)
+ goto err;
+
+ /* create field name "x.field" */
+ if (pmeta->alias) {
+ str_append(fname, pmeta->alias);
+ str_append(fname, ".");
+ }
+ str_append(fname, fsearch->name);
+ s = str_raw_copy(fname->buf, &f->name);
+ if (s)
+ goto err;
+ str_prune(fname);
+ } else {
+ /* check if field already declared */
+ s = stmtmeta_search_field(mout, (*ptok)->str,
+ &fsearch);
+ if (s != E_PARSER_UNK_FIELDNAME) {
+ s = E_PARSER_AMB_FIELDNAME;
+ goto err;
+ }
+
+ f->name = (*ptok)->str;
+ (*ptok)->str = 0;
+ }
+ s = PFIELD_SEP;
+ todo_next = PFIELD_RIGHTQ;
+ break;
+
+ case PFIELD_RIGHTQ:
+ switch ((*ptok)->str[0]) {
+ case '\'':
+ f->right_q = (*ptok)->str[1];
+ s = PFIELD_SEP;
+ todo_next = PFIELD_STARTP;
+ break;
+ case ':':
+ s = PFIELD_STARTP;
+ break;
+ default:
+ s = E_PARSER_UNX_TOKEN;
+ goto err;
+ }
+ break;
+
+ case PFIELD_STARTP:
+ if ((*ptok)->str[0] == ':')
+ s = PFIELD_ENDP;
+ else if (isdigit((*ptok)->str[0])) {
+ f->start_p = strtol((*ptok)->str, 0, 0);
+ s = PFIELD_SEP;
+ todo_next = PFIELD_ENDP;
+ } else {
+ s = E_PARSER_INV_VALUE;
+ goto err;
+ }
+ break;
+
+ case PFIELD_ENDP:
+ if (isdigit((*ptok)->str[0])) {
+ f->end_p = strtol((*ptok)->str, 0, 0);
+ if (f->end_p < f->start_p) {
+ s = E_PARSER_INV_POS;
+ goto err;
+ }
+ } else if ((*ptok)->str[0] == '\'') {
+ f->sep = (*ptok)->str[1];
+ } else {
+ s = PFIELD_SEP;
+ todo_next = PFIELD_TYPE;
+ continue;
+ }
+
+ s = PFIELD_SEP;
+ todo_next = PFIELD_TYPE;
+ break;
+
+ case PFIELD_TYPE:
+ s = field_get_type_idx((*ptok)->str);
+ if (s < 0) {
+ s = E_PARSER_INV_VALUE;
+ goto err;
+ }
+ f->type = s;
+ if (s == FT_DATETIME)
+ s = PFIELD_DATE_FORMAT;
+ else
+ s = PFIELD_END;
+ break;
+
+ case PFIELD_DATE_FORMAT:
+ if (isalpha((*ptok)->str[0])) {
+ f->date_format = (*ptok)->str;
+ (*ptok)->str = 0;
+ s = PFIELD_END;
+ break;
+ }
+
+ case PFIELD_END:
+ if (mref) {
+ fsearch->idx = idx++;
+ fsearch->flag |= FFLAG_CREATE;
+ pmeta = 0;
+ }
+ fsearch = 0;
+
+ switch ((*ptok)->str[0]) {
+ case ',':
+ s = PFIELD_START;
+ field_add(&mout->fields, f);
+ break;
+ case ')':
+ s = PFIELD_DONE;
+ field_add(&mout->fields, f);
+ break;
+ default:
+ s = E_PARSER_UNX_TOKEN;
+ goto err;
+ }
+ continue;
+ }
+ (*ptok) = (*ptok)->next;
+ }
+
+ if (s != PFIELD_DONE) {
+ s = E_PARSER_INV_STMT;
+err:
+ if (f)
+ field_destroy(&f);
+ if (mout->fields)
+ field_destroy(&mout->fields);
+ }
+ if (fname)
+ str_destroy(&fname);
+ return s;
+}
+
+static int parsing_LOAD(struct Stmt **load, struct LL **ptok)
+{
+ int s = PLOAD_START;
+
+ while ((*ptok) && s != PLOAD_DONE) {
+ switch (s) {
+ case PLOAD_START:
+ s = stmtload_create(load);
+ if (s)
+ return s;
+ s = PLOAD_NAME;
+ break;
+
+ case PLOAD_NAME:
+ (*load)->in->filename = (*ptok)->str;
+ (*ptok)->str = 0;
+ s = PLOAD_FIELD_BEGIN;
+ break;
+
+ case PLOAD_FIELD_BEGIN:
+ if ((*ptok)->str[0] != '(') {
+ s = E_PARSER_UNX_CHAR;
+ _vos.e_nparm0 = (*ptok)->num;
+ _vos.e_nparm1 = (*ptok)->str[0];
+ goto err;
+ }
+ s = parsing_FIELD(0, (*load)->in, ptok);
+ if (s)
+ goto err;
+
+ case PLOAD_FIELD_END:
+ if ((*ptok)->str[0] != ')') {
+ s = E_PARSER_UNX_CHAR;
+ _vos.e_nparm0 = (*ptok)->num;
+ _vos.e_nparm1 = (*ptok)->str[0];
+ goto err;
+ }
+ s = PLOAD_AS;
+ break;
+
+ case PLOAD_AS:
+ s = strcasecmp((*ptok)->str, "AS");
+ if (s == 0) {
+ s = PLOAD_AS_NAME;
+ break;
+ }
+ case PLOAD_END:
+ if ((*ptok)->str[0] != ';') {
+ s = E_PARSER_UNX_TOKEN;
+ goto err;
+ }
+ s = PLOAD_DONE;
+ break;
+
+ case PLOAD_AS_NAME:
+ (*load)->in->alias = (*ptok)->str;
+ (*ptok)->str = 0;
+ s = PLOAD_END;
+ break;
+ }
+ (*ptok) = (*ptok)->next;
+ }
+
+ if (s != PLOAD_DONE) {
+ s = E_PARSER_INV_STMT;
+err:
+ stmtload_destroy(load);
+ }
+ return s;
+}
+
+static int parsing_SORT(struct Stmt *stmt, struct Stmt **sort,
+ struct LL **ptok)
+{
+ int idx = 1;
+ int s = PSORT_START;
+ struct StmtMeta *smeta = 0;
+ struct Field *fsearch = 0;
+
+ while ((*ptok) && s != PSORT_DONE) {
+ switch (s) {
+ case PSORT_START:
+ s = stmtsort_create(sort);
+ if (s)
+ goto err;
+ s = PSORT_INPUT;
+ break;
+
+ case PSORT_INPUT:
+ s = stmt_get_output_from(&smeta, stmt, (*ptok)->str);
+ if (s)
+ goto err;
+
+ stmtmeta_add(&(*sort)->in, smeta);
+ s = PSORT_BY;
+ break;
+
+ case PSORT_BY:
+ s = strcasecmp((*ptok)->str, "BY");
+ if (s) {
+ s = E_PARSER_INV_STMT;
+ goto err;
+ }
+ s = PSORT_FIELD;
+ break;
+
+ case PSORT_FIELD:
+ s = stmtmeta_search_field(smeta, (*ptok)->str,
+ &fsearch);
+ if (s == E_PARSER_UNK_FIELDNAME)
+ goto err;
+
+ s = PSORT_ORDER;
+ break;
+
+ case PSORT_ORDER:
+ s = sort_get_idx((*ptok)->str);
+ if (s > 0) {
+ fsearch->flag = s;
+ s = PSORT_FIELD_SEP;
+ break;
+ } else
+ fsearch->flag = FFLAG_SORT_ASC;
+ /* go below */
+
+ case PSORT_FIELD_SEP:
+ fsearch->idx = idx++;
+ fsearch = 0;
+ if ((*ptok)->str[0] == ',') {
+ s = PSORT_FIELD;
+ break;
+ }
+
+ s = strcasecmp((*ptok)->str, "INTO");
+ if (s == 0) {
+ s = PSORT_INTO;
+ break;
+ }
+ /* go below */
+
+ case PSORT_AS:
+ s = strcasecmp((*ptok)->str, "AS");
+ if (s == 0) {
+ s = PSORT_AS_VALUE;
+ break;
+ }
+ /* go below */
+
+ case PSORT_END:
+ if ((*ptok)->str[0] == ';') {
+ s = PSORT_DONE;
+ } else {
+ s = E_PARSER_UNK_TOKEN;
+ goto err;
+ }
+ break;
+
+ case PSORT_INTO:
+ (*sort)->out->filename = (*ptok)->str;
+ (*ptok)->str = 0;
+ s = PSORT_AS;
+ break;
+
+ case PSORT_AS_VALUE:
+ (*sort)->out->alias = (*ptok)->str;
+ (*ptok)->str = 0;
+ s = PSORT_END;
+ break;
+ }
+ (*ptok) = (*ptok)->next;
+ }
+
+ if (s == PSORT_DONE)
+ s = stmtsort_init_output((*sort));
+ else
+ s = E_PARSER_INV_STMT;
+err:
+ if (s) {
+ stmtsort_destroy(sort);
+ }
+ return s;
+}
+
+/**
+ * @return:
+ * < 0 : success
+ * < !0 : fail
+ */
+static int parsing_FILTER(struct StmtMeta *mref, struct LL **ptok)
+{
+ int s = PFLTR_START;
+ int fltr_rule = 0;
+ int fltr_idx = 1;
+ struct LL *prevtok = 0;
+ struct StmtMeta *pmeta = 0;
+ struct Field *fsearch = 0;
+
+ while ((*ptok) && s != PFLTR_DONE) {
+ switch (s) {
+ case PFLTR_START: /* needed, so we can check next ptok */
+ s = PFLTR_RULE;
+ break;
+
+ case PFLTR_RULE:
+ fltr_rule = rule_get_idx((*ptok)->str);
+ if (fltr_rule < 0) {
+ s = E_PARSER_INV_STMT;
+ goto err;
+ }
+ s = PFLTR_PARENT_NAME;
+ break;
+
+ case PFLTR_PARENT_NAME:
+ prevtok = (*ptok);
+ s = PFLTR_PARENT_SEP;
+ break;
+
+ case PFLTR_PARENT_SEP:
+ if ((*ptok)->str[0] == '.') {
+ pmeta = stmtmeta_search_filename(mref,
+ prevtok->str);
+ if (! pmeta) {
+ s = E_PARSER_INV_VALUE;
+ goto err;
+ }
+ s = PFLTR_FIELD_NAME;
+ break;
+ } else {
+ s = stmtmeta_search_field(mref, prevtok->str,
+ &fsearch);
+ if (s == E_PARSER_UNK_FIELDNAME)
+ goto err;
+
+ s = PFLTR_OP;
+ continue;
+ }
+
+ case PFLTR_FIELD_NAME:
+ s = stmtmeta_search_field(pmeta, (*ptok)->str,
+ &fsearch);
+ if (s == E_PARSER_UNK_FIELDNAME)
+ goto err;
+ s = PFLTR_OP;
+ break;
+
+ case PFLTR_OP:
+ s = op_get_idx((*ptok)->str);
+ if (s < 0) {
+ s = E_PARSER_UNK_TOKEN;
+ goto err;
+ }
+ fsearch->fop = _filter_f[s];
+ s = PFLTR_VALUE;
+ break;
+
+ case PFLTR_VALUE:
+ fsearch->fltr_v = (*ptok)->str;
+ (*ptok)->str = 0;
+ s = PFLTR_END;
+ break;
+
+ case PFLTR_END:
+ fsearch->flag |= FFLAG_FILTER;
+ fsearch->fltr_idx = fltr_idx++;
+ fsearch->fltr_rule = fltr_rule;
+ fsearch = 0;
+ pmeta = 0;
+
+ if ((*ptok)->str[0] == ')') {
+ s = PFLTR_DONE;
+ continue;
+ }
+ if ((*ptok)->str[0] == ',') {
+ s = PFLTR_START;
+ continue;
+ }
+
+ s = E_PARSER_UNX_TOKEN;
+ goto err;
+ }
+ (*ptok) = (*ptok)->next;
+ }
+
+ if (s != PFLTR_DONE)
+ s = E_PARSER_INV_STMT;
+err:
+ return s;
+}
+
+static int parsing_CREATE(struct Stmt *stmt, struct Stmt **create,
+ struct LL **ptok)
+{
+ int s = PCREATE_START;
+ struct StmtMeta *smeta = 0;
+
+ while ((*ptok) && s != PCREATE_DONE) {
+ switch (s) {
+ case PCREATE_START:
+ s = stmtcreate_create(create);
+ if (s)
+ return s;
+ s = PCREATE_FILENAME;
+ break;
+
+ case PCREATE_FILENAME:
+ (*create)->out->filename = (*ptok)->str;
+ (*ptok)->str = 0;
+ s = PCREATE_FROM;
+ break;
+
+ case PCREATE_FROM:
+ s = strcasecmp((*ptok)->str, "FROM");
+ if (s) {
+ s = E_PARSER_INV_STMT;
+ goto err;
+ }
+ s = PCREATE_FROM_VALUE;
+ break;
+
+ case PCREATE_FROM_VALUE:
+ s = stmt_get_output_from(&smeta, stmt, (*ptok)->str);
+ if (s)
+ goto err;
+
+ stmtmeta_add(&(*create)->in, smeta);
+ smeta = 0;
+ s = PCREATE_FROM_SEP;
+ break;
+
+ case PCREATE_FROM_SEP:
+ if ((*ptok)->str[0] == ',') {
+ s = PCREATE_FROM_VALUE;
+ break;
+ }
+
+ case PCREATE_FIELD_BEGIN:
+ if ((*ptok)->str[0] != '(') {
+ s = E_PARSER_UNX_CHAR;
+ _vos.e_nparm0 = (*ptok)->num;
+ _vos.e_nparm1 = (*ptok)->str[0];
+ goto err;
+ }
+ s = parsing_FIELD((*create)->in, (*create)->out, ptok);
+ if (s)
+ goto err;
+
+ case PCREATE_FIELD_END:
+ if ((*ptok)->str[0] != ')') {
+ s = E_PARSER_UNX_CHAR;
+ _vos.e_nparm0 = (*ptok)->num;
+ _vos.e_nparm1 = (*ptok)->str[0];
+ goto err;
+ }
+ s = PCREATE_FILTER;
+ break;
+
+ case PCREATE_FILTER:
+ s = strcasecmp((*ptok)->str, "FILTER");
+ if (s == 0) {
+ s = PCREATE_FILTER_BEGIN;
+ break;
+ }
+
+ case PCREATE_AS:
+ s = strcasecmp((*ptok)->str, "AS");
+ if (s == 0) {
+ s = PCREATE_AS_NAME;
+ break;
+ }
+
+ case PCREATE_END:
+ if ((*ptok)->str[0] != ';') {
+ s = E_PARSER_UNX_TOKEN;
+ goto err;
+ }
+ s = PCREATE_DONE;
+ break;
+
+ case PCREATE_FILTER_BEGIN:
+ if ((*ptok)->str[0] != '(') {
+ s = E_PARSER_UNX_CHAR;
+ _vos.e_nparm0 = (*ptok)->num;
+ _vos.e_nparm1 = (*ptok)->str[0];
+ goto err;
+ }
+ s = parsing_FILTER((*create)->in, ptok);
+ if (s)
+ goto err;
+
+ case PCREATE_FILTER_END:
+ if ((*ptok)->str[0] != ')') {
+ s = E_PARSER_UNX_CHAR;
+ _vos.e_nparm0 = (*ptok)->num;
+ _vos.e_nparm1 = (*ptok)->str[0];
+ goto err;
+ }
+ s = PCREATE_AS;
+ break;
+
+ case PCREATE_AS_NAME:
+ (*create)->out->alias = (*ptok)->str;
+ (*ptok)->str = 0;
+ s = PCREATE_END;
+ break;
+ }
+ (*ptok) = (*ptok)->next;
+ }
+
+ if (s != PCREATE_DONE) {
+ s = E_PARSER_INV_STMT;
+err:
+ stmtcreate_destroy(create);
+ }
+ return s;
+
+}
+
+static int parsing_JOIN_where(struct StmtMeta *mref, struct LL **ptok)
+{
+ int s = 0;
+ int todo = PJOIN_FIELD_START;
+ int join_idx = 1;
+ struct LL *prevtok = 0;
+ struct StmtMeta *pmeta = 0;
+ struct Field *fsearch = 0;
+
+ while ((*ptok) && todo != PJOIN_FIELD_END) {
+ switch (todo) {
+ case PJOIN_FIELD_START:
+ todo = PJOIN_FIELD_L_PARENT_NAME;
+ break;
+
+ case PJOIN_FIELD_L_PARENT_NAME:
+ case PJOIN_FIELD_R_PARENT_NAME:
+ prevtok = (*ptok);
+ if (todo == PJOIN_FIELD_L_PARENT_NAME)
+ todo = PJOIN_FIELD_L_PARENT_SEP;
+ else
+ todo = PJOIN_FIELD_R_PARENT_SEP;
+ break;
+
+ case PJOIN_FIELD_L_PARENT_SEP:
+ case PJOIN_FIELD_R_PARENT_SEP:
+ if ((*ptok)->str[0] == '.') {
+ pmeta = stmtmeta_search_filename(mref,
+ prevtok->str);
+ if (! pmeta) {
+ s = E_PARSER_INV_VALUE;
+ goto err;
+ }
+ if (todo == PJOIN_FIELD_L_PARENT_SEP)
+ todo = PJOIN_FIELD_L_NAME;
+ else
+ todo = PJOIN_FIELD_R_NAME;
+ } else {
+ s = stmtmeta_search_field(mref, prevtok->str,
+ &fsearch);
+ if (s == E_PARSER_UNK_FIELDNAME)
+ goto err;
+
+ if (todo == PJOIN_FIELD_L_PARENT_SEP)
+ todo = PJOIN_FIELD_OP;
+ else
+ todo = PJOIN_FIELD_SEP;
+ continue;
+ }
+ break;
+
+ case PJOIN_FIELD_L_NAME:
+ case PJOIN_FIELD_R_NAME:
+ s = stmtmeta_search_field(pmeta, (*ptok)->str,
+ &fsearch);
+ if (s == E_PARSER_UNK_FIELDNAME)
+ goto err;
+ if (todo == PJOIN_FIELD_L_NAME)
+ todo = PJOIN_FIELD_OP;
+ else
+ todo = PJOIN_FIELD_SEP;
+ break;
+
+ case PJOIN_FIELD_OP:
+ s = op_get_idx((*ptok)->str);
+ if (s < OP_EQUAL || s > OP_TRUE_EQUAL) {
+ s = E_PARSER_INV_VALUE;
+ goto err;
+ }
+ fsearch->idx = join_idx;
+ fsearch->flag |= FFLAG_JOIN;
+ fsearch->fop = _filter_f[s];
+ fsearch = 0;
+ pmeta = 0;
+ todo = PJOIN_FIELD_R_PARENT_NAME;
+ break;
+
+ case PJOIN_FIELD_SEP:
+ fsearch->idx |= join_idx;
+ fsearch->flag |= FFLAG_JOIN;
+ join_idx = join_idx << 1;
+ fsearch = 0;
+ pmeta = 0;
+ if ((*ptok)->str[0] == ',') {
+ todo = PJOIN_FIELD_START;
+ continue;
+ }
+ if ((*ptok)->str[0] == ')') {
+ todo = PJOIN_FIELD_END;
+ continue;
+ }
+ s = E_PARSER_UNK_TOKEN;
+ goto err;
+ }
+ (*ptok) = (*ptok)->next;
+ }
+ return 0;
+err:
+ return s;
+}
+
+static int parsing_JOIN(struct Stmt *stmt, struct Stmt **join,
+ struct LL **ptok)
+{
+ int s = PJOIN_START;
+ int n_input = 1;
+ struct StmtMeta *smeta = 0;
+
+ while ((*ptok) && s != PJOIN_DONE) {
+ switch (s) {
+ case PJOIN_START:
+ s = stmtjoin_create(join);
+ if (s)
+ return s;
+
+ s = PJOIN_INPUT;
+ break;
+
+ case PJOIN_INPUT:
+ if (n_input > 2) {
+ s = E_PARSER_INV_STMT;
+ goto err;
+ }
+
+ s = stmt_get_output_from(&smeta, stmt, (*ptok)->str);
+ if (s)
+ goto err;
+
+ stmtmeta_add(&(*join)->in, smeta);
+ s = PJOIN_INPUT_JOIN_FLAG;
+ break;
+
+ case PJOIN_INPUT_JOIN_FLAG:
+ s = join_get_flag((*ptok)->str);
+ if (s > 0) {
+ smeta->flag |= s;
+ s = PJOIN_INPUT_SORT_FLAG;
+ break;
+ }
+
+ case PJOIN_INPUT_SORT_FLAG:
+ s = join_get_sort_flag((*ptok)->str);
+ if (s > 0) {
+ smeta->flag |= s;
+ s = PJOIN_INPUT_SEP;
+ break;
+ } else {
+ smeta->flag |= JOIN_UNSORTED;
+ }
+
+ case PJOIN_INPUT_SEP:
+ if ((*ptok)->str[0] == ',') {
+ n_input++;
+ s = PJOIN_INPUT;
+ smeta = 0;
+ break;
+ }
+
+ s = strcasecmp((*ptok)->str, "INTO");
+ if (s == 0) {
+ s = PJOIN_INTO;
+ break;
+ }
+
+ case PJOIN_FIELD_BEGIN:
+ if ((*ptok)->str[0] == '(') {
+ if (n_input != 2) {
+ s = E_PARSER_INV_STMT;
+ goto err;
+ }
+
+ s = parsing_JOIN_where((*join)->in, ptok);
+ if (s)
+ goto err;
+
+ s = PJOIN_FIELD_END;
+ continue;
+ }
+ s = E_PARSER_UNK_TOKEN;
+ goto err;
+
+ case PJOIN_FIELD_END:
+ if ((*ptok)->str[0] == ')') {
+ s = PJOIN_AS;
+ break;
+ }
+ s = E_PARSER_UNK_TOKEN;
+ goto err;
+
+ case PJOIN_AS:
+ s = strcasecmp((*ptok)->str, "AS");
+ if (s == 0) {
+ s = PJOIN_AS_NAME;
+ break;
+ }
+
+ case PJOIN_END:
+ if ((*ptok)->str[0] == ';') {
+ s = PJOIN_DONE;
+ break;
+ }
+ s = E_PARSER_UNK_TOKEN;
+ goto err;
+
+ case PJOIN_INTO:
+ (*join)->out->filename = (*ptok)->str;
+ (*ptok)->str = 0;
+ s = PJOIN_FIELD_BEGIN;
+ break;
+
+ case PJOIN_AS_NAME:
+ (*join)->out->alias = (*ptok)->str;
+ (*ptok)->str = 0;
+ s = PJOIN_END;
+ break;
+ }
+ (*ptok) = (*ptok)->next;
+ }
+ if (s == PJOIN_DONE) {
+ s = stmtjoin_init_output((*join));
+ } else
+ s = E_PARSER_INV_STMT;
+err:
+ if (s)
+ stmtjoin_destroy(join);
+
+ return s;
+}
+
+/**
+ * @return:
+ * < 0 : success
+ * < -1 : fail
+ */
+static int parsing_token(struct Stmt **stmt, struct LL **ptok)
+{
+ int s = 0;
+ int stmt_type = 0;
+ struct Stmt *new_stmt = 0;
+
+ while ((*ptok)) {
+ stmt_type = stmt_get_type_idx((*ptok)->str);
+ if (stmt_type < 0)
+ return E_PARSER_UNK_TOKEN;
+
+ switch (stmt_type) {
+ case STMT_SET:
+ s = parsing_SET(&new_stmt, ptok);
+ break;
+ case STMT_LOAD:
+ s = parsing_LOAD(&new_stmt, ptok);
+ break;
+ case STMT_SORT:
+ s = parsing_SORT((*stmt), &new_stmt, ptok);
+ break;
+ case STMT_CREATE:
+ s = parsing_CREATE((*stmt), &new_stmt, ptok);
+ break;
+ case STMT_JOIN:
+ s = parsing_JOIN((*stmt), &new_stmt, ptok);
+ break;
+ default:
+ return E_PARSER_UNX_TOKEN;
+ }
+ if (s)
+ goto err;
+ stmt_add(stmt, new_stmt);
+ }
+ s = 0;
+err:
+ return s;
+}
+
+int vos_parsing(struct Stmt **stmt, const char *script)
+{
+ int s = 0;
+ unsigned int line_no = 1;
+ struct String *str = 0;
+ struct File *F = 0;
+ struct LL *ls_tok = 0;
+ struct LL *ptok = 0;
+
+ s = file_open(&F, script, FOPEN_RO);
+ if (s)
+ goto err;
+
+ s = file_read(F);
+ if (s)
+ goto err;
+
+ s = str_create(&str);
+ if (s)
+ goto err;
+
+ while (F->idx < F->size) {
+ switch (FCURC(F)) {
+ case CH_NEWLINE:
+ line_no++;
+ case ' ': case '\b': case '\f': case '\r': case '\t':
+ case '\v':
+ break;
+
+ case '#':
+ s = file_skip_until(F, CH_NEWLINE);
+ if (s)
+ goto err;
+
+ line_no++;
+ break;
+
+ case '(': case ')': case ':': case ',': case ';': case '.':
+ case '+': case '-':
+ s = str_append_c(str, FCURC(F));
+ if (s)
+ goto err;
+
+ s = ll_add(&ls_tok, line_no, str->buf);
+ if (s)
+ goto err;
+
+ str_prune(str);
+ break;
+
+ case '!': case '=': case '<': case '>':
+ do {
+ s = str_append_c(str, FCURC(F));
+ if (s)
+ goto err;
+ F->idx++;
+ if (F->idx >= F->size) {
+ s = file_read(F);
+ if (s)
+ break;
+ }
+ } while (FCURC(F) == '=');
+
+ s = ll_add(&ls_tok, line_no, str->buf);
+ if (s)
+ goto err;
+
+ str_prune(str);
+ continue;
+
+ case '[':
+ F->idx++;
+ file_fetch_until(F, str, ']');
+ if (FCURC(F) != ']') {
+ s = E_PARSER_UNX_CHAR;
+ _vos.e_nparm0 = line_no;
+ _vos.e_nparm1 = FCURC(F);
+ goto err;
+ }
+ s = ll_add(&ls_tok, line_no, str->buf);
+ if (s)
+ goto err;
+
+ str_prune(str);
+ break;
+ case '\"':
+ F->idx++;
+ file_fetch_until(F, str, '\"');
+ if (FCURC(F) != '\"') {
+ s = E_PARSER_UNX_CHAR;
+ _vos.e_nparm0 = line_no;
+ _vos.e_nparm1 = FCURC(F);
+ goto err;
+ }
+ s = ll_add(&ls_tok, line_no, str->buf);
+ if (s)
+ goto err;
+
+ str_prune(str);
+ break;
+ case '\'':
+ s = str_append_c(str, FCURC(F));
+ if (s)
+ goto err;
+
+ F->idx++;
+ if (FCURC(F) == '\\')
+ F->idx++;
+
+ s = str_append_c(str, FCURC(F));
+ if (s)
+ goto err;
+
+ F->idx++;
+ if (FCURC(F) != '\'') {
+ s = E_PARSER_UNX_CHAR;
+ _vos.e_nparm0 = line_no;
+ _vos.e_nparm1 = FCURC(F);
+ goto err;
+ }
+
+ s = str_append_c(str, FCURC(F));
+ if (s)
+ goto err;
+
+ s = ll_add(&ls_tok, line_no, str->buf);
+ if (s)
+ goto err;
+
+ str_prune(str);
+ break;
+ default:
+ if (! isalnum(FCURC(F)) && FCURC(F) != '_') {
+ s = E_PARSER_UNX_CHAR;
+ _vos.e_nparm0 = line_no;
+ _vos.e_nparm1 = FCURC(F);
+ goto err;
+ }
+ while (isalnum(FCURC(F)) || FCURC(F) == '_') {
+ s = str_append_c(str, FCURC(F));
+ if (s)
+ goto err;
+ F->idx++;
+ }
+ s = ll_add(&ls_tok, line_no, str->buf);
+ if (s)
+ goto err;
+
+ str_prune(str);
+ continue;
+ }
+ F->idx++;
+ }
+
+ if (_vos.debug & DBG_PARSER) {
+ ll_print(ls_tok);
+ }
+
+ ptok = ls_tok;
+ s = parsing_token(stmt, &ptok);
+ if (s)
+ goto err;
+
+ goto out;
+err:
+ switch (s) {
+ case E_PARSER_UNK_TOKEN:
+ case E_PARSER_UNX_TOKEN:
+ case E_PARSER_UNK_FIELDNAME:
+ case E_PARSER_INV_FIELDNAME:
+ case E_PARSER_INV_VALUE:
+ case E_PARSER_INV_STMT:
+ case E_PARSER_AMB_FIELDNAME:
+ _vos.e_nparm0 = ptok->num;
+ _vos.e_sparm0 = ptok->str;
+ ptok->str = 0;
+ break;
+ case E_PARSER_INV_POS:
+ _vos.e_nparm0 = ptok->num;
+ break;
+ }
+out:
+ if (_vos.debug & DBG_PARSER) {
+ stmt_print((*stmt));
+ }
+ ll_destroy(&ls_tok);
+ str_destroy(&str);
+ file_close(&F);
+
+ return s;
+}
diff --git a/proc/vos_parser.h b/proc/vos_parser.h
new file mode 100644
index 0000000..0ad6c66
--- /dev/null
+++ b/proc/vos_parser.h
@@ -0,0 +1,10 @@
+#ifndef _VOS_PARSER_H
+#define _VOS_PARSER_H 1
+
+#include "op/vos_LL.h"
+#include "op/vos_File.h"
+#include "op/vos_Stmt.h"
+
+int vos_parsing(struct Stmt **stmt, const char *script);
+
+#endif
diff --git a/proc/vos_set.c b/proc/vos_set.c
new file mode 100644
index 0000000..7fc3899
--- /dev/null
+++ b/proc/vos_set.c
@@ -0,0 +1,33 @@
+#include "proc/vos_set.h"
+
+int vos_process_set(struct StmtSet *set)
+{
+ switch (set->var_idx) {
+ case SET_FILE_BUFFER_SIZE:
+ _vos.file_buf_size = strtoul(set->value, 0, 0);
+ if (! _vos.file_buf_size)
+ _vos.file_buf_size = VOS_DEF_FILE_BUF_SIZE;
+ break;
+
+ case SET_PROC_CMP_CASE_SENSITIVE:
+ _vos.proc_cmp_case = CMP_CASE_SENSITIVE;
+ break;
+
+ case SET_PROC_CMP_CASE_NOTSENSITIVE:
+ _vos.proc_cmp_case = CMP_CASE_NOTSENSITIVE;
+ break;
+
+ case SET_PROC_MAX:
+ _vos.proc_max = strtol(set->value, 0, 0);
+ if (! _vos.proc_max)
+ _vos.proc_max = VOS_DEF_PROC_MAX;
+ break;
+
+ case SET_PROC_MAX_ROW:
+ _vos.proc_max_row = strtoul(set->value, 0, 0);
+ if (! _vos.proc_max_row)
+ _vos.proc_max_row = VOS_DEF_PROC_MAX_ROW;
+ break;
+ }
+ return 0;
+}
diff --git a/proc/vos_set.h b/proc/vos_set.h
new file mode 100644
index 0000000..bf3432f
--- /dev/null
+++ b/proc/vos_set.h
@@ -0,0 +1,9 @@
+#ifndef _VOS_SET_H
+#define _VOS_SET_H 1
+
+#include "vos.h"
+#include "op/vos_StmtSet.h"
+
+int vos_process_set(struct StmtSet *set);
+
+#endif
diff --git a/proc/vos_sort.c b/proc/vos_sort.c
new file mode 100644
index 0000000..627bfd8
--- /dev/null
+++ b/proc/vos_sort.c
@@ -0,0 +1,396 @@
+#include "proc/vos_sort.h"
+
+/**
+ * sort: sort record using mergesort
+ * @desc:
+ * about mergesort. the key is in merge.
+ * merge case 1:
+ * 1 2 3
+ * 4 5 6
+ * merge case 2:
+ * 4 5 6
+ * 1 2 3
+ * merge case 3:
+ * 1 3 5
+ * 2 4 6
+ */
+static struct Record * sort(struct Record *rows, unsigned long n_row)
+{
+ int s = 0;
+ unsigned long i = 1;
+ unsigned long nl = 0;
+ unsigned long nr = 0;
+ struct Record *l = 0;
+ struct Record *r = 0;
+ struct Record *tmp = 0;
+
+ if (n_row <= 1) {
+ if (rows)
+ rows->row_last = rows;
+ return rows;
+ }
+
+ nl = n_row / 2;
+ nr = n_row - nl;
+
+ tmp = rows->row_last;
+ l = rows;
+ for (; i < nl; i++)
+ rows = rows->row_next;
+
+ l->row_last = rows;
+ r = rows->row_next;
+ r->row_last = tmp;
+ l->row_last->row_next = 0;
+
+ if (nl > 1)
+ l = sort(l, nl);
+ if (nr > 1)
+ r = sort(r, nr);
+
+ /* merge case 1 */
+ s = record_cmp(l->row_last, r);
+ if (s <= 0) {
+ l->row_last->row_next = r;
+ l->row_last = r->row_last;
+ r->row_last = 0;
+ return l;
+ }
+ /* merge case 2 : must be '>' not '>=' to keep 'stable' result */
+ s = record_cmp(l, r->row_last);
+ if (s > 0) {
+ r->row_last->row_next = l;
+ r->row_last = l->row_last;
+ l->row_last = 0;
+ return r;
+ }
+ /* merge case 3 */
+ rows = 0;
+ s = record_cmp(l, r);
+ if (s < 0) {
+ rows = l;
+ rows->row_last = rows;
+ l = l->row_next;
+ } else if (s == 0) {
+ rows = l;
+ l = l->row_next;
+ rows->row_next = r;
+ rows->row_last = r;
+ r = r->row_next;
+ } else {
+ rows = r;
+ rows->row_last = rows;
+ r = r->row_next;
+ }
+
+ while (l && r) {
+ s = record_cmp(l, r);
+ if (s < 0) {
+ rows->row_last->row_next = l;
+ rows->row_last = l;
+ l = l->row_next;
+ } else if (s == 0) {
+ rows->row_last->row_next = l;
+ l = l->row_next;
+ rows->row_last->row_next->row_next = r;
+ rows->row_last = r;
+ r = r->row_next;
+ } else {
+ rows->row_last->row_next = r;
+ rows->row_last = r;
+ r = r->row_next;
+ }
+ }
+
+ if (l) {
+ rows->row_last->row_next = l;
+ while (l->row_next)
+ l = l->row_next;
+ rows->row_last = l;
+ }
+ if (r) {
+ rows->row_last->row_next = r;
+ while (r->row_next)
+ r = r->row_next;
+ rows->row_last = r;
+ }
+
+ return rows;
+}
+
+static int sort_write(struct ProcSort *psort, struct Record *rows)
+{
+ int s = 0;
+ char *tmp = 0;
+ struct File *Fout = 0;
+
+ do {
+ s = str_raw_randomize(VOS_SORT_TMP_FORMAT, &tmp);
+ if (s)
+ return s;
+
+ s = file_open(&Fout, tmp, FOPEN_WO);
+ if (s == 0)
+ ll_add(&psort->lsout, psort->tid, tmp);
+ free(tmp);
+ } while (s == E_FILE_EXIST);
+
+ s = record_write(rows, Fout, psort->sort->out->fields);
+
+ file_write(Fout);
+ file_close(&Fout);
+
+ return s;
+}
+
+/**
+ * @desc:
+ * for each thread, sort input file from pos_start to pos_end
+ */
+static void *sort_process(void *parm)
+{
+ int s = 0;
+ unsigned long n_row = 0;
+ struct File *F = 0;
+ struct Record *R = 0;
+ struct ProcSort *psort = 0;
+ struct Record *rows = 0;
+
+ psort = (struct ProcSort *) parm;
+
+ if (_vos.debug & DBG_SORT) {
+ printf("(%lu) sort pos: %ld to %ld\n", psort->tid,
+ psort->pos_start, psort->pos_end);
+ }
+
+ s = file_open(&F, psort->sort->in->filename, FOPEN_RO);
+ if (s)
+ goto err;
+
+ F->pos = psort->pos_start;
+ if (psort->pos_start != 0) {
+ s = lseek(F->d, psort->pos_start, SEEK_SET);
+ if (s < 0) {
+ s = E_FILE_SEEK;
+ str_raw_copy(F->name, &_vos.e_sparm0);
+ goto err;
+ }
+
+ s = file_read(F);
+ if (s)
+ goto err;
+
+ /* skip one row */
+ s = file_skip_until(F, CH_NEWLINE);
+ if (s)
+ goto err;
+ F->idx++;
+ } else {
+ s = file_read(F);
+ if (s)
+ goto err;
+ }
+
+ /* phase 1: create & file rows */
+ while (FCURP(F) < psort->pos_end) {
+ s = record_read(&R, F, psort->sort->in->fields);
+ if (! R)
+ break;
+
+ record_add_row(&psort->rows, R);
+ psort->n_row++;
+ if (psort->n_row >= _vos.proc_max_row)
+ break;
+ }
+
+ /* check if error, but not end of file */
+ if (s && s != E_FILE_END)
+ goto err;
+
+ /* sort rows */
+ psort->rows = sort(psort->rows, psort->n_row);
+
+ /* dump rows */
+ s = sort_write(psort, psort->rows);
+ if (s)
+ goto err;
+
+ if (psort->n_row < _vos.proc_max_row || s == E_FILE_END)
+ goto out;
+
+ /* phase 2: only use already-created-rows */
+ R = psort->rows;
+ psort->rows = R->row_next;
+ psort->rows->row_last = R->row_last;
+ R->row_next = 0;
+ R->row_last = 0;
+ n_row = 0;
+ while (FCURP(F) < psort->pos_end) {
+ s = record_read2(R, F, psort->sort->in->fields);
+ if (s) {
+ if (s == E_FILE_END)
+ break;
+ goto err;
+ }
+
+ record_add_row(&rows, R);
+ n_row++;
+ if (n_row >= _vos.proc_max_row) {
+ rows = sort(rows, n_row);
+
+ s = sort_write(psort, rows);
+ if (s)
+ goto err;
+
+ psort->rows = rows;
+ rows = 0;
+ n_row = 0;
+ }
+
+ R = psort->rows;
+ psort->rows = R->row_next;
+ if (psort->rows) {
+ psort->rows->row_last = R->row_last;
+ R->row_next = 0;
+ R->row_last = 0;
+ }
+ }
+
+ if (n_row) {
+ if (_vos.debug & DBG_SORT) {
+ printf(" (%lu) : F->pos %lu, F->idx %lu, "\
+ "F->size %lu\n", psort->tid, F->pos, F->idx,
+ F->size);
+ printf(" (%lu) : %lu\n", psort->tid, n_row);
+ printf(" (%lu) : last row : ", psort->tid);
+ record_print(rows->row_last);
+ }
+
+ rows = sort(rows, n_row);
+
+ s = sort_write(psort, rows);
+ if (s)
+ goto err;
+
+ R->row_next = rows;
+ psort->rows->row_last->row_next = R;
+ psort->rows->row_last = rows->row_last;
+ psort->rows->row_last->row_next = 0;
+ rows->row_last = 0;
+ }
+
+ if (_vos.debug & DBG_SORT) {
+ printf(" (%lu) psort first row : %p\n", psort->tid, psort->rows);
+ printf(" (%lu) psort last row : %p\n", psort->tid, psort->rows->row_last);
+ printf(" (%lu) counting rows ...\n", psort->tid);
+ n_row = 0;
+ rows = psort->rows;
+ while (rows->row_next) {
+ n_row++;
+ rows = rows->row_next;
+ }
+ n_row++;
+ printf(" (%lu) number of rows : %lu\n", psort->tid, n_row);
+ printf(" (%lu) last row : %p\n", psort->tid, rows);
+ }
+out:
+ if (_vos.debug & DBG_SORT)
+ ll_print(psort->lsout);
+ s = 0;
+err:
+ file_close(&F);
+ psort->retval = s;
+
+ return (void *) s;
+}
+
+int vos_process_sort(struct Stmt *sort)
+{
+ int i = 0;
+ int s = 0;
+ unsigned long fsize = 0;
+ unsigned long esize = 0;
+ unsigned long all_n_row = 0;
+ struct ProcSort *sort_proc = 0;
+ struct LL *lsout = 0;
+ struct LL *ll = 0;
+ struct Record *all_rows = 0;
+ struct Record *cnt_rows = 0;
+
+ s = file_raw_get_size(sort->in->filename, &fsize);
+ if (s)
+ goto err;
+
+ esize = fsize / _vos.proc_max;
+
+ sort_proc = (struct ProcSort *) calloc(_vos.proc_max,
+ sizeof(struct ProcSort));
+ if (! sort_proc) {
+ s = E_MEM;
+ goto err;
+ }
+
+ /* create thread for sort */
+ for (i = 0; i < _vos.proc_max; i++) {
+ sort_proc[i].pos_start = i * esize;
+
+ if ((i + 1) == _vos.proc_max)
+ sort_proc[i].pos_end = fsize;
+ else
+ sort_proc[i].pos_end = sort_proc[i].pos_start + esize;
+
+ sort_proc[i].n_row = 0;
+ sort_proc[i].rows = 0;
+ sort_proc[i].sort = sort;
+
+ pthread_create(&sort_proc[i].tid, 0, sort_process,
+ (void *) &sort_proc[i]);
+ }
+
+ for (i = 0; i < _vos.proc_max; i++) {
+ pthread_join(sort_proc[i].tid, 0);
+
+ if (sort_proc[i].retval && !s)
+ s = sort_proc[i].retval;
+ else {
+ ll_link(&lsout, sort_proc[i].lsout);
+ if (! all_rows)
+ all_rows = sort_proc[i].rows;
+ else {
+ all_rows->row_last->row_next =
+ sort_proc[i].rows;
+ all_rows->row_last = sort_proc[i].rows->row_last;
+ }
+ all_n_row += sort_proc[i].n_row;
+ }
+ }
+
+ if (! s) {
+ if (_vos.debug & DBG_SORT) {
+ esize = 0;
+ cnt_rows = all_rows;
+ printf(" all-rows first row : %p\n", all_rows);
+ printf(" all-rows last row : %p\n", all_rows->row_last);
+ while (cnt_rows) {
+ esize++;
+ cnt_rows = cnt_rows->row_next;
+ if (cnt_rows == all_rows->row_last)
+ printf(" last row found in : %lu\n", esize);
+ }
+ printf(" count all rows : %lu\n", esize);
+ }
+ /* use already created rows for merge */
+ s = vos_sort_merge(sort, lsout, &all_rows, all_n_row);
+ }
+err:
+ /* remove all temporary file */
+ ll = lsout;
+ while (ll) {
+ unlink(ll->str);
+ ll = ll->next;
+ }
+ ll_destroy(&lsout);
+ record_destroy(&all_rows);
+ free(sort_proc);
+ return s;
+}
diff --git a/proc/vos_sort.h b/proc/vos_sort.h
new file mode 100644
index 0000000..ca871c9
--- /dev/null
+++ b/proc/vos_sort.h
@@ -0,0 +1,10 @@
+#ifndef _VOS_SORT_H
+#define _VOS_SORT_H 1
+
+#include <pthread.h>
+#include "type/vos_TProcSort.h"
+#include "proc/vos_sort_merge.h"
+
+int vos_process_sort(struct Stmt *sort);
+
+#endif
diff --git a/proc/vos_sort_merge.c b/proc/vos_sort_merge.c
new file mode 100644
index 0000000..30bddf2
--- /dev/null
+++ b/proc/vos_sort_merge.c
@@ -0,0 +1,241 @@
+#include "proc/vos_sort_merge.h"
+
+static int mnode_new(struct MNode **node, const int level, const char *file)
+{
+ int s = 0;
+
+ (*node) = (struct MNode *) calloc(1, sizeof(struct MNode));
+ if (! (*node))
+ return E_MEM;
+
+ s = file_open(&(*node)->file, file, FOPEN_RO);
+ if (s)
+ goto err;
+
+ s = file_read((*node)->file);
+ if (s)
+ goto err;
+
+ (*node)->level = level;
+ s = 0;
+err:
+ if (s && (*node)) {
+ if ((*node)->file)
+ file_close(&(*node)->file);
+ free((*node));
+ }
+ return s;
+}
+
+static void mnode_destroy(struct MNode **node)
+{
+ if (! (*node))
+ return;
+ if ((*node)->file)
+ file_close(&(*node)->file);
+ if ((*node)->row)
+ record_destroy(&(*node)->row);
+ mnode_destroy(&(*node)->left);
+ mnode_destroy(&(*node)->right);
+ free((*node));
+ (*node) = 0;
+}
+
+static void mnode_print(struct MNode *root)
+{
+ if (root->left)
+ mnode_print(root->left);
+ record_print(root->row);
+ if (root->right)
+ mnode_print(root->right);
+}
+
+static struct MNode * mnode_insert(struct MNode *root, struct MNode *node)
+{
+ int s = 0;
+
+ if (! root)
+ return node;
+
+ s = record_cmp(root->row, node->row);
+ if (s < 0) {
+ root->right = mnode_insert(root->right, node);
+ } else if (s == 0) {
+ if (root->level < node->level)
+ root->right = mnode_insert(root->right, node);
+ else
+ root->left = mnode_insert(root->left, node);
+ } else {
+ root->left = mnode_insert(root->left, node);
+ }
+
+ return root;
+}
+
+static int merge_init(struct MNode **root, struct LL *lsfile,
+ struct Field *fld)
+{
+ int s = 0;
+ int level = 1;
+ struct MNode *node = 0;
+
+ while (lsfile) {
+ s = mnode_new(&node, level, lsfile->str);
+ if (s)
+ return s;
+
+ s = record_read(&node->row, node->file, fld);
+ if (! node->row)
+ return s;
+
+ (*root) = mnode_insert((*root), node);
+
+ level++;
+ lsfile = lsfile->next;
+ }
+
+ return 0;
+}
+
+static struct MNode * mnode_get_loser(struct MNode **root,
+ struct MNode **loser2)
+{
+ struct MNode *loser = (*root);
+
+ while (loser->left) {
+ (*loser2) = loser;
+ loser = loser->left;
+ }
+
+ if (loser == (*root)) {
+ (*root) = (*root)->right;
+ (*loser2) = (*root);
+ } else {
+ (*loser2)->left = loser->right;
+ }
+
+ if ((*loser2)) {
+ while ((*loser2)->left)
+ (*loser2) = (*loser2)->left;
+ }
+
+ loser->right = 0;
+ return loser;
+}
+
+int vos_sort_merge(struct Stmt *sort, struct LL *lsfile,
+ struct Record **_all_rows, unsigned long all_n_row)
+{
+ int s = 0;
+ unsigned long n_row = 0;
+ struct File *F = 0;
+ struct MNode *root = 0;
+ struct MNode *loser = 0;
+ struct MNode *loser2 = 0;
+ struct Record *rows = 0;
+ struct Record *R = 0;
+ struct Record *all_rows = (*_all_rows);
+
+ /* in case of only one file to merge */
+ if (! lsfile->next) {
+ s = rename(lsfile->str, sort->out->filename);
+ return s;
+ }
+
+ s = file_open(&F, sort->out->filename, FOPEN_WO);
+ if (s)
+ goto err;
+
+ s = merge_init(&root, lsfile, sort->out->fields);
+ if (s)
+ goto err;
+
+ R = all_rows;
+ all_rows = R->row_next;
+ R->row_next = 0;
+ R->row_last = 0;
+ while (root) {
+ loser2 = 0;
+ loser = mnode_get_loser(&root, &loser2);
+
+ if (loser2) {
+ do {
+ record_add_row(&rows, loser->row);
+ n_row++;
+ if (n_row >= all_n_row || ! all_rows) {
+ s = record_write(rows, F,
+ sort->out->fields);
+ if (s)
+ goto err;
+
+ all_rows = rows;
+ all_rows->row_last = 0;
+ rows = 0;
+ n_row = 0;
+ }
+
+ loser->row = R;
+ R = all_rows;
+ all_rows = R->row_next;
+ R->row_next = 0;
+ R->row_last = 0;
+
+ s = record_read2(loser->row, loser->file,
+ sort->out->fields);
+ if (s)
+ break;
+
+ s = record_cmp(loser2->row, loser->row);
+ } while (s > 0
+ || (s == 0 && loser2->level > loser->level));
+ } else {
+ do {
+ record_add_row(&rows, loser->row);
+ n_row++;
+ if (n_row >= all_n_row || ! all_rows) {
+ s = record_write(rows, F,
+ sort->out->fields);
+ if (s)
+ goto err;
+
+ all_rows = rows;
+ all_rows->row_last = 0;
+ rows = 0;
+ n_row = 0;
+ }
+
+ loser->row = R;
+ R = all_rows;
+ all_rows = R->row_next;
+ R->row_next = 0;
+ R->row_last = 0;
+
+ s = record_read2(loser->row, loser->file,
+ sort->out->fields);
+ } while (s == 0);
+ }
+ if (s == E_FILE_END)
+ mnode_destroy(&loser);
+ else
+ root = mnode_insert(root, loser);
+ }
+
+ R->row_next = all_rows;
+ if (n_row) {
+ s = record_write(rows, F, sort->out->fields);
+ if (s)
+ goto err;
+
+ rows->row_last->row_next = R;
+ (*_all_rows) = rows;
+ } else {
+ (*_all_rows) = R;
+ }
+
+ file_write(F);
+ s = 0;
+err:
+ mnode_destroy(&root);
+ file_close(&F);
+ return s;
+}
diff --git a/proc/vos_sort_merge.h b/proc/vos_sort_merge.h
new file mode 100644
index 0000000..1a0e29e
--- /dev/null
+++ b/proc/vos_sort_merge.h
@@ -0,0 +1,12 @@
+#ifndef _VOS_MERGE_H
+#define _VOS_MERGE_H 1
+
+#include "type/vos_TMNode.h"
+#include "op/vos_StmtSort.h"
+#include "op/vos_LL.h"
+#include "op/vos_Record.h"
+
+int vos_sort_merge(struct Stmt *sort, struct LL *lsfile,
+ struct Record **_all_rows, unsigned long all_n_row);
+
+#endif
diff --git a/type/vos_TBucket.h b/type/vos_TBucket.h
new file mode 100644
index 0000000..2ea8d0d
--- /dev/null
+++ b/type/vos_TBucket.h
@@ -0,0 +1,12 @@
+#ifndef _VOS_TYPE_BUCKET_H
+#define _VOS_TYPE_BUCKET_H 1
+
+#include "type/vos_TRecord.h"
+
+struct Bucket {
+ int stat;
+ struct Record *cnt;
+ struct Record *p;
+};
+
+#endif
diff --git a/type/vos_TField.h b/type/vos_TField.h
new file mode 100644
index 0000000..b39b8c8
--- /dev/null
+++ b/type/vos_TField.h
@@ -0,0 +1,42 @@
+#ifndef _VOS_TYPE_FIELD_H
+#define _VOS_TYPE_FIELD_H 1
+
+enum _field_type_idx {
+ FT_STRING = 0,
+ FT_NUMBER,
+ FT_DATETIME,
+ N_FIELD_TYPE
+};
+
+enum _fflag_sort_idx {
+ FFLAG_SORT_ASC = 1,
+ FFLAG_SORT_DESC = 2,
+ N_FFLAG_SORT
+};
+
+enum _fflag_idx {
+ FFLAG_CREATE = 4,
+ FFLAG_FILTER = 8,
+ FFLAG_JOIN = 16,
+ N_FFLAG
+};
+
+struct Field {
+ int idx;
+ int flag;
+ int type;
+ int left_q;
+ int right_q;
+ int start_p;
+ int end_p;
+ int sep;
+ int fltr_idx;
+ int fltr_rule;
+ int (*fop)(const int, const void *, const void *);
+ char *name;
+ char *date_format;
+ char *fltr_v;
+ struct Field *next;
+};
+
+#endif
diff --git a/type/vos_TFile.h b/type/vos_TFile.h
new file mode 100644
index 0000000..cfadda6
--- /dev/null
+++ b/type/vos_TFile.h
@@ -0,0 +1,27 @@
+#ifndef _VOS_TYPE_FILE_H
+#define _VOS_TYPE_FILE_H 1
+
+enum _file_open_flag {
+ FOPEN_RO = 1,
+ FOPEN_WO = 2
+};
+
+/**
+ * @desc:
+ * d - descriptor
+ * idx - index of buffer
+ * buf - content of file
+ * size - size of buf
+ * pos - pointer to last file position from last read/write.
+ * to get the current file position: pos + idx
+ */
+struct File {
+ int d;
+ long int idx;
+ long int size;
+ unsigned long pos;
+ const char *name;
+ char *buf;
+};
+
+#endif
diff --git a/type/vos_TFilter.h b/type/vos_TFilter.h
new file mode 100644
index 0000000..618eb0d
--- /dev/null
+++ b/type/vos_TFilter.h
@@ -0,0 +1,22 @@
+#ifndef _VOS_TYPE_FILTER_H
+#define _VOS_TYPE_FILTER_H 1
+
+enum _filter_op_idx {
+ OP_EQUAL = 0, /* not case sensitive */
+ OP_TRUE_EQUAL, /* case sensitive */
+ OP_NOT_EQUAL,
+ OP_NOT_TRUE_EQUAL,
+ OP_MORE,
+ OP_LESS,
+ OP_MORE_EQUAL,
+ OP_LESS_EQUAL,
+ N_FLTR_OP
+};
+
+enum _filter_rule_idx {
+ FLTR_REJECT = 0,
+ FLTR_ACCEPT = 1,
+ N_FLTR_RULE
+};
+
+#endif
diff --git a/type/vos_TLL.h b/type/vos_TLL.h
new file mode 100644
index 0000000..5220d79
--- /dev/null
+++ b/type/vos_TLL.h
@@ -0,0 +1,11 @@
+#ifndef _VOS_TYPE_LL_H
+#define _VOS_TYPE_LL_H 1
+
+struct LL {
+ unsigned long num;
+ char *str;
+ struct LL *next;
+ struct LL *last;
+};
+
+#endif
diff --git a/type/vos_TMNode.h b/type/vos_TMNode.h
new file mode 100644
index 0000000..bf46cb2
--- /dev/null
+++ b/type/vos_TMNode.h
@@ -0,0 +1,15 @@
+#ifndef _VOS_TYPE_MERGE_NODE_H
+#define _VOS_TYPE_MERGE_NODE_H 1
+
+#include "type/vos_TFile.h"
+#include "type/vos_TRecord.h"
+
+struct MNode {
+ int level;
+ struct Record *row;
+ struct File *file;
+ struct MNode *left;
+ struct MNode *right;
+};
+
+#endif
diff --git a/type/vos_TProcCreate.h b/type/vos_TProcCreate.h
new file mode 100644
index 0000000..70f9242
--- /dev/null
+++ b/type/vos_TProcCreate.h
@@ -0,0 +1,23 @@
+#ifndef _VOS_TYPE_PROCESS_CREATE_H
+#define _VOS_TYPE_PROCESS_CREATE_H 1
+
+#include "type/vos_TStmtMeta.h"
+#include "type/vos_TBucket.h"
+#include "type/vos_TStmt.h"
+
+enum _cproc_status {
+ CPROC_START = 1,
+ CPROC_BUCKETS_FULL,
+ CPROC_DONE,
+ CPROC_END
+};
+
+struct ProcCreate {
+ pthread_t tid;
+ int retval;
+ int status;
+ struct StmtMeta *in;
+ struct Bucket *buckets;
+};
+
+#endif
diff --git a/type/vos_TProcSort.h b/type/vos_TProcSort.h
new file mode 100644
index 0000000..1539a62
--- /dev/null
+++ b/type/vos_TProcSort.h
@@ -0,0 +1,18 @@
+#ifndef _VOS_TYPE_PROCESS_SORT_H
+#define _VOS_TYPE_PROCESS_SORT_H 1
+
+#include "type/vos_TLL.h"
+#include "type/vos_TStmt.h"
+
+struct ProcSort {
+ pthread_t tid;
+ int retval;
+ unsigned long pos_start;
+ unsigned long pos_end;
+ unsigned long n_row;
+ struct Record *rows;
+ const struct Stmt *sort;
+ struct LL *lsout;
+};
+
+#endif
diff --git a/type/vos_TRecord.h b/type/vos_TRecord.h
new file mode 100644
index 0000000..1bd0d97
--- /dev/null
+++ b/type/vos_TRecord.h
@@ -0,0 +1,16 @@
+#ifndef _VOS_TYPE_RECORD_H
+#define _VOS_TYPE_RECORD_H 1
+
+#include "type/vos_TString.h"
+
+struct Record {
+ int idx;
+ int flag;
+ struct String *v;
+ struct Record *fld_next;
+ struct Record *fld_last;
+ struct Record *row_next;
+ struct Record *row_last;
+};
+
+#endif
diff --git a/type/vos_TStmt.h b/type/vos_TStmt.h
new file mode 100644
index 0000000..a6e79ef
--- /dev/null
+++ b/type/vos_TStmt.h
@@ -0,0 +1,26 @@
+#ifndef _VOS_TYPE_STMT_H
+#define _VOS_TYPE_STMT_H 1
+
+#include "type/vos_TStmtSet.h"
+#include "type/vos_TStmtMeta.h"
+
+enum _stmt_type_idx {
+ STMT_SET = 0,
+ STMT_LOAD,
+ STMT_CREATE,
+ STMT_SORT,
+ STMT_JOIN,
+ N_STMT_TYPE
+};
+
+struct Stmt {
+ unsigned short type;
+ struct StmtSet *set;
+ struct StmtMeta *in;
+ struct StmtMeta *out;
+ struct Stmt *next;
+ struct Stmt *prev;
+ struct Stmt *last;
+};
+
+#endif
diff --git a/type/vos_TStmtJoin.h b/type/vos_TStmtJoin.h
new file mode 100644
index 0000000..aae8fc3
--- /dev/null
+++ b/type/vos_TStmtJoin.h
@@ -0,0 +1,17 @@
+#ifndef _VOS_TYPE_STMTJOIN_H
+#define _VOS_TYPE_STMTJOIN_H 1
+
+enum _stmt_join_flag {
+ JOIN_NORMAL = 0,
+ JOIN_OUTER = 1,
+ JOIN_ANTI = 2,
+ N_JOIN_FLAG
+};
+
+enum _stmt_join_sort_flag {
+ JOIN_UNSORTED = 4,
+ JOIN_SORTED = 8,
+ N_JOIN_SORT_FLAG
+};
+
+#endif
diff --git a/type/vos_TStmtMeta.h b/type/vos_TStmtMeta.h
new file mode 100644
index 0000000..5e37c3b
--- /dev/null
+++ b/type/vos_TStmtMeta.h
@@ -0,0 +1,14 @@
+#ifndef _VOS_TYPE_STMTMETA_H
+#define _VOS_TYPE_STMTMETA_H 1
+
+#include "type/vos_TField.h"
+
+struct StmtMeta {
+ int flag;
+ char *filename;
+ char *alias;
+ struct Field *fields;
+ struct StmtMeta *next;
+};
+
+#endif
diff --git a/type/vos_TStmtSet.h b/type/vos_TStmtSet.h
new file mode 100644
index 0000000..849a370
--- /dev/null
+++ b/type/vos_TStmtSet.h
@@ -0,0 +1,18 @@
+#ifndef _VOS_TYPE_STMTSET_H
+#define _VOS_TYPE_STMTSET_H 1
+
+enum _set_idx {
+ SET_FILE_BUFFER_SIZE = 0,
+ SET_PROC_CMP_CASE_SENSITIVE,
+ SET_PROC_CMP_CASE_NOTSENSITIVE,
+ SET_PROC_MAX,
+ SET_PROC_MAX_ROW,
+ N_SET
+};
+
+struct StmtSet {
+ unsigned short var_idx;
+ char *value;
+};
+
+#endif
diff --git a/type/vos_TString.h b/type/vos_TString.h
new file mode 100644
index 0000000..ee231fa
--- /dev/null
+++ b/type/vos_TString.h
@@ -0,0 +1,10 @@
+#ifndef _VOS_TYPE_STRING_H
+#define _VOS_TYPE_STRING_H 1
+
+struct String {
+ int idx;
+ int len;
+ char *buf;
+};
+
+#endif
diff --git a/type/vos_TVos.h b/type/vos_TVos.h
new file mode 100644
index 0000000..a22ff65
--- /dev/null
+++ b/type/vos_TVos.h
@@ -0,0 +1,42 @@
+#ifndef _VOS_T_H
+#define _VOS_T_H
+
+/**
+ * @desc:
+ * - DBG_SCRIPT : don't process the script
+ * use to check if script is valid or not
+ * - DBG_PARSER : debug parsing process and execute statement in
+ * the script
+ * - DBG_SORT : debug sort process
+ * - DBG_CREATE : debug create process
+ * - DBG_JOIN : debug join process
+ * - DBG_ALL : debug all process
+ */
+enum _vos_debug {
+ DBG_SCRIPT = 1,
+ DBG_PARSER = 2,
+ DBG_SORT = 4,
+ DBG_CREATE = 8,
+ DBG_JOIN = 16,
+ DBG_ALL = 30
+};
+
+enum _vos_cmp_case {
+ CMP_CASE_SENSITIVE = 0,
+ CMP_CASE_NOTSENSITIVE
+};
+
+struct Vos {
+ int debug; /* debug parameter */
+ int e_nparm0; /* first error parameter for number */
+ int e_nparm1; /* second error parameter for number */
+ int proc_cmp_case; /* use compare case sensitive ? */
+ unsigned long file_buf_size; /* size of buffer for file */
+ unsigned long proc_max; /* maximum process for sort */
+ unsigned long proc_max_row; /* maximum row for each process */
+ char *script; /* vos script */
+ char *e_sparm0; /* first error parameter (string) */
+ char *e_sparm1; /* second error parameter (string) */
+};
+
+#endif
diff --git a/vos.c b/vos.c
new file mode 100644
index 0000000..a2d6fee
--- /dev/null
+++ b/vos.c
@@ -0,0 +1,156 @@
+#include "proc/vos_parser.h"
+#include "proc/vos_set.h"
+#include "proc/vos_load.h"
+#include "proc/vos_sort.h"
+#include "proc/vos_create.h"
+#include "proc/vos_join.h"
+
+/**
+ * @return:
+ * < 0..(n-1) : success
+ * < -1 : fail
+ */
+int get_token_idx(const char **ls, const unsigned int n, const char *tok)
+{
+ int i = n - 1;
+ int s = 0;
+
+ if (! (*ls) || ! tok)
+ return -1;
+
+ for (; i >= 0; i--) {
+ s = strcasecmp(ls[i], tok);
+ if (s == 0)
+ return i;
+ }
+
+ return i;
+}
+
+static int vos_init(int argc, char **argv)
+{
+ /* very lazy parsing argument */
+ if (argc < 1 || argc == 2 || argc > 3)
+ return E_VOS_PARAM;
+
+ _vos.debug = 0;
+
+ if (argc == 3) {
+ if (argv[1][0] != '-')
+ return E_VOS_PARAM;
+ if (argv[1][1] != 'd')
+ return E_VOS_PARAM;
+ _vos.debug = strtol(argv[2], 0, 0);
+ }
+
+ _vos.file_buf_size = VOS_DEF_FILE_BUF_SIZE;
+ _vos.proc_cmp_case = VOS_DEF_PROC_CMP_CASE;
+ _vos.proc_max = VOS_DEF_PROC_MAX;
+ _vos.proc_max_row = VOS_DEF_PROC_MAX_ROW;
+ _vos.script = argv[argc];
+
+ srand(time((void *) 0));
+
+ return 0;
+}
+
+static int vos_process(struct Stmt *stmt)
+{
+ int s;
+
+ while (stmt) {
+ switch (stmt->type) {
+ case STMT_SET:
+ vos_process_set(stmt->set);
+ break;
+ case STMT_LOAD:
+ s = vos_process_load(stmt);
+ if (s)
+ return s;
+ break;
+ case STMT_SORT:
+ s = vos_process_sort(stmt);
+ if (s)
+ return s;
+ break;
+ case STMT_CREATE:
+ s = vos_process_create(stmt);
+ if (s)
+ return s;
+ break;
+ case STMT_JOIN:
+ s = vos_process_join(stmt);
+ if (s)
+ return s;
+ break;
+ }
+ stmt = stmt->next;
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int s;
+ struct Stmt *stmt = 0;
+
+ s = vos_init(argc - 1, argv);
+ if (s)
+ return s;
+
+ s = vos_parsing(&stmt, _vos.script);
+ if (s)
+ goto err;
+
+ if (! (_vos.debug & DBG_SCRIPT))
+ s = vos_process(stmt);
+
+ if (! s)
+ goto out;
+
+err:
+ switch (s) {
+ case E_VOS_PARAM:
+ case E_FILE_NOT_OPEN:
+ case E_MEM:
+ vos_error0(s);
+ break;
+ case E_FILE_OPEN:
+ case E_FILE_EXIST:
+ case E_FILE_NOT_EXIST:
+ case E_FILE_SEEK:
+ case E_FILE_READ:
+ case E_FILE_WRITE:
+ vos_error1(s, _vos.e_sparm0);
+ break;
+ case E_PARSER_INV_POS:
+ vos_error1(s, _vos.e_nparm0);
+ break;
+ case E_PARSER_UNX_CHAR:
+ vos_error2(s, _vos.e_nparm0, _vos.e_nparm1);
+ break;
+ case E_PARSER_UNX_TOKEN:
+ case E_PARSER_UNK_TOKEN:
+ case E_PARSER_UNK_FIELDNAME:
+ case E_PARSER_INV_FIELDNAME:
+ case E_PARSER_INV_VALUE:
+ case E_PARSER_INV_STMT:
+ case E_PARSER_AMB_FIELDNAME:
+ vos_error2(s, _vos.e_nparm0, _vos.e_sparm0);
+ break;
+ case E_FILE_END:
+ break;
+ default:
+ fprintf(stderr, "vos error number : %d\n", s);
+ }
+
+ if (_vos.e_sparm0)
+ free(_vos.e_sparm0);
+ if (_vos.e_sparm1)
+ free(_vos.e_sparm1);
+out:
+ stmt_destroy(&stmt);
+
+ return s;
+}
diff --git a/vos.h b/vos.h
new file mode 100644
index 0000000..cc1e3dc
--- /dev/null
+++ b/vos.h
@@ -0,0 +1,19 @@
+#ifndef _VOS_H
+#define _VOS_H 1
+
+#include "type/vos_TVos.h"
+
+#define VOS_DEF_DATE_FORMAT "YYYY/MM/DD"
+#define VOS_DEF_FILE_BUF_SIZE 8192
+#define VOS_DEF_PROC_CMP_CASE CMP_CASE_SENSITIVE
+#define VOS_DEF_PROC_MAX 2
+#define VOS_DEF_PROC_MAX_ROW 100000
+#define VOS_SORT_OUT_FORMAT "sort.XXXXXXXX"
+#define VOS_SORT_TMP_FORMAT "tmp.sort.XXXXXXXX"
+#define VOS_JOIN_OUT_FORMAT "join.XXXXXXXX"
+
+struct Vos _vos;
+
+int get_token_idx(const char **ls, const unsigned int n, const char *tok);
+
+#endif
diff --git a/vos_errno.c b/vos_errno.c
new file mode 100644
index 0000000..5f340e1
--- /dev/null
+++ b/vos_errno.c
@@ -0,0 +1,27 @@
+#include "vos_errno.h"
+
+const char *vos_errmsg[N_VOS_ERRNO] = {
+ "\0",
+ "Usage: vos [-d {1,2,4,8,16}] <vos script>\n\0",
+
+ "line %d: unexpected character '%c'.\n\0",
+ "line %d: unexpected token '%s'.\n\0",
+ "line %d: unknown token '%s'.\n\0",
+ "line %d: unknown field name '%s'.\n\0", /* 5 */
+ "line %d: invalid field name '%s'.\n\0",
+ "line %d: invalid position value.\n\0",
+ "line %d: invalid format or value '%s'.\n\0",
+ "line %d: invalid statement '%s'.\n\0",
+ "line %d: duplicate/ambigous field name '%s'.\n\0", /* 10 */
+
+ "error: cannot open file '%s'.\n\0",
+ "error: file '%s' exist.\n\0",
+ "error: file '%s' is not exist.\n\0",
+ "error: file not open\n\0",
+ "error: cannot seek file '%s'.\n\0", /* 15 */
+ "error: cannot read file.\n\0",
+ "error: errot at writing to file.\n\0",
+ "error: end of file.\n\0",
+ "error: converting string to number.\n\0",
+ "error: out of memory.\n\0" /* 20 */
+};
diff --git a/vos_errno.h b/vos_errno.h
new file mode 100644
index 0000000..a3b7c75
--- /dev/null
+++ b/vos_errno.h
@@ -0,0 +1,37 @@
+#ifndef _VOS_ERRNO_H
+#define _VOS_ERRNO_H 1
+
+#include <errno.h>
+
+enum vos_errno {
+ E_VOS_PARAM = 1,
+/* parser module error number */
+ E_PARSER_UNX_CHAR,
+ E_PARSER_UNX_TOKEN,
+ E_PARSER_UNK_TOKEN,
+ E_PARSER_UNK_FIELDNAME,
+ E_PARSER_INV_FIELDNAME,
+ E_PARSER_INV_POS,
+ E_PARSER_INV_VALUE,
+ E_PARSER_INV_STMT,
+ E_PARSER_AMB_FIELDNAME, /* 10 */
+/* error number from system */
+ E_FILE_OPEN,
+ E_FILE_EXIST,
+ E_FILE_NOT_EXIST,
+ E_FILE_NOT_OPEN,
+ E_FILE_SEEK, /* 15 */
+ E_FILE_READ,
+ E_FILE_WRITE,
+ E_FILE_END,
+ E_STRTONUM,
+ E_MEM,
+ N_VOS_ERRNO
+};
+extern const char *vos_errmsg[N_VOS_ERRNO];
+
+#define vos_error0(N) fprintf(stderr,vos_errmsg[N])
+#define vos_error1(N,V) fprintf(stderr,vos_errmsg[N],V)
+#define vos_error2(N,V,W) fprintf(stderr,vos_errmsg[N],V,W)
+
+#endif