1/*
2 * yaml2byte.c
3 *
4 * $Author: kojima1 $
5 * $Date: 2007/03/09 23:41:58 $
6 *
7 * Copyright (C) 2003 why the lucky stiff, clark evans
8 *
9 *   WARNING WARNING WARNING  --- THIS IS *NOT JUST* PLAYING
10 *   ANYMORE! -- WHY HAS EMBRACED THIS AS THE REAL THING!
11 */
12#include <syck.h>
13#include <assert.h>
14#define YAMLBYTE_UTF8
15#include "yamlbyte.h"
16
17#include <stdio.h>
18#define TRACE0(a)  \
19    do { printf(a); printf("\n"); fflush(stdout); } while(0)
20#define TRACE1(a,b) \
21    do { printf(a,b); printf("\n"); fflush(stdout); } while(0)
22#define TRACE2(a,b,c) \
23    do { printf(a,b,c); printf("\n"); fflush(stdout); } while(0)
24#define TRACE3(a,b,c,d) \
25    do { printf(a,b,c,d); printf("\n"); fflush(stdout); } while(0)
26
27/* Reinvent the wheel... */
28#define CHUNKSIZE 64
29#define HASH ((long)0xCAFECAFE)
30typedef struct {
31   long hash;
32   char *buffer;
33   long length;
34   long remaining;
35   int  printed;
36} bytestring_t;
37bytestring_t *bytestring_alloc() {
38    bytestring_t *ret;
39    /*TRACE0("bytestring_alloc()");*/
40    ret = S_ALLOC(bytestring_t);
41    ret->hash   = HASH;
42    ret->length = CHUNKSIZE;
43    ret->remaining = ret->length;
44    ret->buffer = S_ALLOC_N(char, ret->length + 1 );
45    ret->buffer[0] = 0;
46    ret->printed = 0;
47    return ret;
48}
49void bytestring_append(bytestring_t *str, char code,
50                       char *start, char *finish)
51{
52    long grow;
53    long length = 2;   /* CODE + LF */
54    char *curr;
55    assert(str && HASH == str->hash);
56    /*TRACE0("bytestring_append()");*/
57    if(start) {
58        if(!finish)
59            finish = start + strlen(start);
60        length += (finish-start);
61    }
62    if(length > str->remaining) {
63        grow = (length - str->remaining) + CHUNKSIZE;
64        str->remaining += grow;
65        str->length    += grow;
66        str->buffer = S_REALLOC_N( str->buffer, char, str->length + 1 );
67        assert(str->buffer);
68    }
69    curr = str->buffer + (str->length - str->remaining);
70    *curr = code;
71    curr += 1;
72    if(start)
73        while(start < finish)
74            *curr ++ = *start ++;
75    *curr = '\n';
76    curr += 1;
77    *curr = 0;
78    str->remaining = str->remaining - length;
79    assert( (str->buffer + str->length) - str->remaining );
80}
81void bytestring_extend(bytestring_t *str, bytestring_t *ext)
82{
83    char *from;
84    char *curr;
85    char *stop;
86    long grow;
87    long length;
88    assert(str && HASH == str->hash);
89    assert(ext && HASH == ext->hash);
90    if(ext->printed) {
91        assert(ext->buffer[0] ==YAMLBYTE_ANCHOR);
92        curr = ext->buffer;
93        while( '\n' != *curr)
94            curr++;
95        bytestring_append(str, YAMLBYTE_ALIAS, ext->buffer + 1, curr);
96    } else {
97        ext->printed = 1;
98        length  = (ext->length - ext->remaining);
99        if(length > str->remaining) {
100            grow = (length - str->remaining) + CHUNKSIZE;
101            str->remaining += grow;
102            str->length    += grow;
103            str->buffer = S_REALLOC_N( str->buffer, char, str->length + 1 );
104        }
105        curr = str->buffer + (str->length - str->remaining);
106        from = ext->buffer;
107        stop = ext->buffer + length;
108        while( from < stop )
109            *curr ++ = *from ++;
110        *curr = 0;
111        str->remaining = str->remaining - length;
112        assert( (str->buffer + str->length) - str->remaining );
113    }
114}
115
116/* convert SyckNode into yamlbyte_buffer_t objects */
117SYMID
118syck_yaml2byte_handler(p, n)
119    SyckParser *p;
120    SyckNode *n;
121{
122    SYMID oid;
123    long i;
124    char ch;
125    char nextcode;
126    char *start;
127    char *current;
128    char *finish;
129    bytestring_t *val = NULL;
130    bytestring_t *sav = NULL;
131    /*TRACE0("syck_yaml2byte_handler()");*/
132    val = bytestring_alloc();
133    if(n->anchor) bytestring_append(val,YAMLBYTE_ANCHOR, n->anchor, NULL);
134    if ( n->type_id )
135    {
136        if ( p->taguri_expansion )
137        {
138            bytestring_append(val,YAMLBYTE_TRANSFER, n->type_id, NULL);
139        }
140        else
141        {
142            char *type_tag = S_ALLOC_N( char, strlen( n->type_id ) + 1 );
143            type_tag[0] = '\0';
144            strcat( type_tag, "!" );
145            strcat( type_tag, n->type_id );
146            bytestring_append( val, YAMLBYTE_TRANSFER, type_tag, NULL);
147        }
148    }
149    switch (n->kind)
150    {
151        case syck_str_kind:
152            nextcode = YAMLBYTE_SCALAR;
153            start  = n->data.str->ptr;
154            finish = start + n->data.str->len - 1;
155            current = start;
156            /*TRACE2("SCALAR: %s %d", start, n->data.str->len); */
157            while(1) {
158                ch = *current;
159                if('\n' == ch || 0 == ch || current > finish) {
160                    if(current >= start) {
161                        bytestring_append(val, nextcode, start, current);
162                        nextcode = YAMLBYTE_CONTINUE;
163                    }
164                    start = current + 1;
165                    if(current > finish)
166                    {
167                        break;
168                    }
169                    else if('\n' == ch )
170                    {
171                        bytestring_append(val,YAMLBYTE_NEWLINE,NULL,NULL);
172                    }
173                    else if(0 == ch)
174                    {
175                        bytestring_append(val,YAMLBYTE_NULLCHAR,NULL,NULL);
176                    }
177                    else
178                    {
179                        assert("oops");
180                    }
181                }
182                current += 1;
183            }
184        break;
185        case syck_seq_kind:
186            bytestring_append(val,YAMLBYTE_SEQUENCE,NULL,NULL);
187            for ( i = 0; i < n->data.list->idx; i++ )
188            {
189                oid = syck_seq_read( n, i );
190                syck_lookup_sym( p, oid, (char **)&sav );
191                bytestring_extend(val, sav);
192            }
193            bytestring_append(val,YAMLBYTE_END_BRANCH,NULL,NULL);
194        break;
195        case syck_map_kind:
196            bytestring_append(val,YAMLBYTE_MAPPING,NULL,NULL);
197            for ( i = 0; i < n->data.pairs->idx; i++ )
198            {
199                oid = syck_map_read( n, map_key, i );
200                syck_lookup_sym( p, oid, (char **)&sav );
201                bytestring_extend(val, sav);
202                oid = syck_map_read( n, map_value, i );
203                syck_lookup_sym( p, oid, (char **)&sav );
204                bytestring_extend(val, sav);
205            }
206            bytestring_append(val,YAMLBYTE_END_BRANCH,NULL,NULL);
207        break;
208    }
209    oid = syck_add_sym( p, (char *) val );
210    /*TRACE1("Saving: %s", val->buffer );*/
211    return oid;
212}
213
214char *
215syck_yaml2byte(char *yamlstr)
216{
217    SYMID oid;
218    char *ret;
219    bytestring_t *sav;
220
221    SyckParser *parser = syck_new_parser();
222    syck_parser_str_auto( parser, yamlstr, NULL );
223    syck_parser_handler( parser, syck_yaml2byte_handler );
224    syck_parser_error_handler( parser, NULL );
225    syck_parser_implicit_typing( parser, 1 );
226    syck_parser_taguri_expansion( parser, 1 );
227    oid = syck_parse( parser );
228
229    if ( syck_lookup_sym( parser, oid, (char **)&sav ) == 1 ) {
230        ret = S_ALLOC_N( char, strlen( sav->buffer ) + 3 );
231        ret[0] = '\0';
232        strcat( ret, "D\n" );
233        strcat( ret, sav->buffer );
234    }
235    else
236    {
237        ret = NULL;
238    }
239
240    syck_free_parser( parser );
241    return ret;
242}
243
244#ifdef TEST_YBEXT
245#include <stdio.h>
246int main() {
247   char *yaml = "test: 1\nand: \"with new\\nline\\n\"\nalso: &3 three\nmore: *3";
248   printf("--- # YAML \n");
249   printf(yaml);
250   printf("\n...\n");
251   printf(syck_yaml2byte(yaml));
252   return 0;
253}
254#endif
255
256