Initial checkin of YAML substances.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3772 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
why 2003-05-09 21:25:50 +00:00
Родитель 605adb86e2
Коммит 55f4dc4c9a
25 изменённых файлов: 7962 добавлений и 0 удалений

5
ext/syck/extconf.rb Normal file
Просмотреть файл

@ -0,0 +1,5 @@
require 'mkmf'
have_header( "st.h" )
create_makefile( "syck" )

1494
ext/syck/gram.c Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

79
ext/syck/gram.h Normal file
Просмотреть файл

@ -0,0 +1,79 @@
/* A Bison parser, made from gram.y, by GNU bison 1.75. */
/* Skeleton parser for Yacc-like parsing with Bison,
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, when this file is copied by Bison into a
Bison output file, you may use that output file without restriction.
This special exception was added by the Free Software Foundation
in version 1.24 of Bison. */
#ifndef BISON_Y_TAB_H
# define BISON_Y_TAB_H
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
/* Put the tokens into the symbol table, so that GDB and other debuggers
know about them. */
enum yytokentype {
ANCHOR = 258,
ALIAS = 259,
TRANSFER = 260,
ITRANSFER = 261,
WORD = 262,
PLAIN = 263,
BLOCK = 264,
DOCSEP = 265,
IOPEN = 266,
INDENT = 267,
IEND = 268
};
#endif
#define ANCHOR 258
#define ALIAS 259
#define TRANSFER 260
#define ITRANSFER 261
#define WORD 262
#define PLAIN 263
#define BLOCK 264
#define DOCSEP 265
#define IOPEN 266
#define INDENT 267
#define IEND 268
#ifndef YYSTYPE
#line 23 "gram.y"
typedef union {
SYMID nodeId;
SyckNode *nodeData;
char *name;
} yystype;
/* Line 1281 of /usr/local/share/bison/yacc.c. */
#line 72 "y.tab.h"
# define YYSTYPE yystype
#endif
#endif /* not BISON_Y_TAB_H */

231
ext/syck/handler.c Normal file
Просмотреть файл

@ -0,0 +1,231 @@
//
// handler.h
//
// $Author$
// $Date$
//
// Copyright (C) 2003 why the lucky stiff
//
#include "syck.h"
SYMID
syck_hdlr_add_node( SyckParser *p, SyckNode *n )
{
SYMID id;
if ( ! n->id )
{
n->id = (p->handler)( p, n );
}
id = n->id;
if ( n->anchor == NULL )
{
syck_free_node( n );
}
return id;
}
SyckNode *
syck_hdlr_add_anchor( SyckParser *p, char *a, SyckNode *n )
{
n->anchor = a;
st_insert( p->anchors, (st_data_t)a, (st_data_t)n );
return n;
}
SyckNode *
syck_hdlr_add_alias( SyckParser *p, char *a )
{
SyckNode *n;
if ( st_lookup( p->anchors, (st_data_t)a, (st_data_t *)&n ) )
{
return n;
}
return syck_new_str( "..." );
}
void
syck_add_transfer( char *uri, SyckNode *n, int taguri )
{
char *comma = NULL;
char *slash = uri;
char *domain = NULL;
if ( taguri == 0 )
{
n->type_id = uri;
return;
}
if ( uri[0] == '!' )
{
syck_xprivate( n, uri + 1, strlen( uri ) - 1 );
S_FREE( uri );
return;
}
while ( *(++slash) != '\0' )
{
if ( *slash == '/' )
break;
if ( *slash == ',' )
comma = slash;
}
if ( *slash == '\0' )
{
syck_taguri( n, "yaml.org,2002", uri, strlen( uri ) );
}
else if ( comma == NULL )
{
domain = S_ALLOC_N( char, ( slash - uri ) + 15 );
domain[0] = '\0';
strncat( domain, uri, slash - uri );
strcat( domain, ".yaml.org,2002" );
syck_taguri( n, domain, slash + 1, strlen( uri ) - ( slash - uri + 1 ) );
S_FREE( domain );
}
else
{
domain = S_ALLOC_N( char, slash - uri );
domain[0] = '\0';
strncat( domain, uri, slash - uri );
syck_taguri( n, domain, slash + 1, strlen( uri ) - ( slash - uri + 1 ) );
S_FREE( domain );
}
S_FREE( uri );
}
void
syck_xprivate( SyckNode *n, char *type_id, int type_len )
{
if ( n->type_id != NULL )
S_FREE( n->type_id );
n->type_id = S_ALLOC_N( char, type_len + 14 );
n->type_id[0] = '\0';
strcat( n->type_id, "x-private:" );
strncat( n->type_id, type_id, type_len );
}
void
syck_taguri( SyckNode *n, char *domain, char *type_id, int type_len )
{
if ( n->type_id != NULL )
S_FREE( n->type_id );
n->type_id = S_ALLOC_N( char, strlen( domain ) + type_len + 14 );
n->type_id[0] = '\0';
strcat( n->type_id, "taguri:" );
strcat( n->type_id, domain );
strcat( n->type_id, ":" );
strncat( n->type_id, type_id, type_len );
}
int
syck_try_implicit( SyckNode *n )
{
return 1;
}
void
syck_fold_format( struct SyckStr *n, int blockType, int indt_len, int nlDisp )
{
char *spc;
char *eol = NULL;
char *first_nl = NULL;
char *fc = n->ptr;
int keep_nl = 0;
int nl_count = 0;
//
// Scan the sucker for newlines and strip indent
//
while ( fc < n->ptr + n->len )
{
if ( *fc == '\n' )
{
spc = fc;
while ( *(++spc) == ' ' )
{
if ( blockType != BLOCK_PLAIN && spc - fc > indt_len )
break;
}
if ( blockType != BLOCK_LIT && *spc != ' ' )
{
if ( eol != NULL ) fc = eol;
if ( first_nl == NULL && keep_nl == 1 )
{
first_nl = fc;
*first_nl = ' ';
}
if ( nl_count == 1 )
{
*first_nl = '\n';
keep_nl = 0;
}
}
fc += keep_nl;
if ( fc != spc && ( n->len - ( spc - n->ptr ) ) > 0 )
{
S_MEMMOVE( fc, spc, char, n->len - ( spc - n->ptr ) );
}
n->len -= spc - fc;
keep_nl = 1;
eol = NULL;
nl_count++;
}
else
{
//
// eol tracks the last space on a line
//
if ( *fc == ' ' )
{
if ( eol == NULL ) eol = fc;
}
else
{
eol = NULL;
}
first_nl = NULL;
nl_count = 0;
fc++;
}
}
n->ptr[n->len] = '\n';
//
// Chomp or keep?
//
if ( nlDisp != NL_KEEP )
{
fc = n->ptr + n->len - 1;
while ( *fc == '\n' )
fc--;
if ( nlDisp != NL_CHOMP )
fc += 1;
n->len = fc - n->ptr + 1;
}
else
{
//
// Force last line break which I gave back
// to the tokenizer.
//
n->len++;
n->ptr[n->len] = '\n';
}
n->ptr[ n->len ] = '\0';
}

860
ext/syck/implicit.c Normal file
Просмотреть файл

@ -0,0 +1,860 @@
/* Generated by re2c 0.5 on Mon Apr 21 23:42:24 2003 */
#line 1 "lib/implicit.re"
//
// implicit.re
//
// $Author$
// $Date$
//
// Copyright (C) 2003 why the lucky stiff
//
#include "syck.h"
#define YYCTYPE char
#define YYCURSOR cursor
#define YYMARKER marker
#define YYLIMIT limit
#define YYFILL(n)
#define TAG_IMPLICIT( tid ) \
if ( taguri == 1 ) \
{ \
syck_taguri( n, "yaml.org,2002", tid, strlen( tid ) ); \
} else { \
n->type_id = syck_strndup( tid, strlen( tid ) ); \
} \
return;
void
try_tag_implicit( SyckNode *n, int taguri )
{
char *cursor, *limit, *marker;
if ( n->kind != syck_str_kind )
return;
cursor = n->data.str->ptr;
limit = cursor + n->data.str->len;
{
YYCTYPE yych;
unsigned int yyaccept;
static unsigned char yybm[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 8, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
8, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 193, 0, 4, 0,
215, 231, 231, 231, 231, 231, 231, 231,
167, 167, 0, 0, 0, 0, 0, 0,
0, 128, 128, 128, 128, 128, 128, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 128, 128, 128, 128, 128, 128, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
};
goto yy0;
yy1: ++YYCURSOR;
yy0:
if((YYLIMIT - YYCURSOR) < 26) YYFILL(26);
yych = *YYCURSOR;
if(yych <= 'S'){
if(yych <= '/'){
if(yych <= '+'){
if(yych <= '\000') goto yy2;
if(yych <= '*') goto yy20;
goto yy15;
} else {
if(yych <= ',') goto yy20;
if(yych <= '-') goto yy16;
if(yych <= '.') goto yy19;
goto yy20;
}
} else {
if(yych <= 'F'){
if(yych <= '0') goto yy17;
if(yych <= '9') goto yy18;
if(yych <= 'E') goto yy20;
goto yy14;
} else {
if(yych <= 'M') goto yy20;
if(yych <= 'N') goto yy6;
if(yych <= 'O') goto yy12;
goto yy20;
}
}
} else {
if(yych <= 'n'){
if(yych <= 'Y'){
if(yych <= 'T') goto yy8;
if(yych <= 'X') goto yy20;
goto yy10;
} else {
if(yych == 'f') goto yy13;
if(yych <= 'm') goto yy20;
goto yy5;
}
} else {
if(yych <= 'x'){
if(yych <= 'o') goto yy11;
if(yych == 't') goto yy7;
goto yy20;
} else {
if(yych <= 'y') goto yy9;
if(yych == '~') goto yy3;
goto yy20;
}
}
}
yy2: YYCURSOR = YYMARKER;
switch(yyaccept){
case 0: goto yy4;
}
yy3: yych = *++YYCURSOR;
if(yych <= '\000') goto yy185;
yy4:
#line 99
{ TAG_IMPLICIT( "str" ); }
yy5: yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
if(yych == 'o') goto yy158;
if(yych == 'u') goto yy188;
goto yy4;
yy6: yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
if(yych <= 'U'){
if(yych == 'O') goto yy158;
if(yych <= 'T') goto yy4;
goto yy181;
} else {
if(yych <= 'o'){
if(yych <= 'n') goto yy4;
goto yy158;
} else {
if(yych == 'u') goto yy182;
goto yy4;
}
}
yy7: yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
if(yych == 'r') goto yy179;
goto yy4;
yy8: yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
if(yych == 'R') goto yy175;
if(yych == 'r') goto yy176;
goto yy4;
yy9: yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
if(yych == 'e') goto yy174;
goto yy4;
yy10: yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
if(yych == 'E') goto yy172;
if(yych == 'e') goto yy173;
goto yy4;
yy11: yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
if(yych == 'f') goto yy171;
if(yych == 'n') goto yy168;
goto yy4;
yy12: yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
if(yych <= 'N'){
if(yych == 'F') goto yy166;
if(yych <= 'M') goto yy4;
goto yy168;
} else {
if(yych <= 'f'){
if(yych <= 'e') goto yy4;
goto yy167;
} else {
if(yych == 'n') goto yy168;
goto yy4;
}
}
yy13: yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
if(yych == 'a') goto yy163;
goto yy4;
yy14: yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
if(yych == 'A') goto yy154;
if(yych == 'a') goto yy155;
goto yy4;
yy15: yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
if(yych <= '/'){
if(yych == '.') goto yy153;
goto yy4;
} else {
if(yych <= '0') goto yy144;
if(yych <= '9') goto yy38;
goto yy4;
}
yy16: yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
if(yych <= '/'){
if(yych == '.') goto yy143;
goto yy4;
} else {
if(yych <= '0') goto yy144;
if(yych <= '9') goto yy38;
goto yy4;
}
yy17: yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
if(yych <= '.'){
if(yych <= '+'){
if(yych <= '\000') goto yy42;
goto yy4;
} else {
if(yych <= ',') goto yy128;
if(yych <= '-') goto yy4;
goto yy40;
}
} else {
if(yych <= '9'){
if(yych <= '/') goto yy4;
if(yych <= '7') goto yy126;
goto yy127;
} else {
if(yych == 'x') goto yy130;
goto yy4;
}
}
yy18: yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
if(yych <= '-'){
if(yych <= '\000') goto yy42;
if(yych == ',') goto yy38;
goto yy4;
} else {
if(yych <= '.') goto yy40;
if(yych <= '/') goto yy4;
if(yych <= '9') goto yy37;
goto yy4;
}
yy19: yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
if(yych <= 'N'){
if(yych == 'I') goto yy24;
if(yych <= 'M') goto yy4;
goto yy22;
} else {
if(yych <= 'i'){
if(yych <= 'h') goto yy4;
goto yy23;
} else {
if(yych == 'n') goto yy21;
goto yy4;
}
}
yy20: yych = *++YYCURSOR;
goto yy4;
yy21: yych = *++YYCURSOR;
if(yych == 'a') goto yy36;
goto yy2;
yy22: yych = *++YYCURSOR;
if(yych == 'A') goto yy31;
if(yych == 'a') goto yy32;
goto yy2;
yy23: yych = *++YYCURSOR;
if(yych == 'n') goto yy30;
goto yy2;
yy24: yych = *++YYCURSOR;
if(yych == 'N') goto yy25;
if(yych == 'n') goto yy26;
goto yy2;
yy25: yych = *++YYCURSOR;
if(yych == 'F') goto yy27;
goto yy2;
yy26: yych = *++YYCURSOR;
if(yych != 'f') goto yy2;
yy27: yych = *++YYCURSOR;
if(yych >= '\001') goto yy2;
yy28: yych = *++YYCURSOR;
yy29:
#line 85
{ TAG_IMPLICIT( "float#inf" ); }
yy30: yych = *++YYCURSOR;
if(yych == 'f') goto yy27;
goto yy2;
yy31: yych = *++YYCURSOR;
if(yych == 'N') goto yy33;
goto yy2;
yy32: yych = *++YYCURSOR;
if(yych != 'N') goto yy2;
yy33: yych = *++YYCURSOR;
if(yych >= '\001') goto yy2;
yy34: yych = *++YYCURSOR;
yy35:
#line 89
{ TAG_IMPLICIT( "float#nan" ); }
yy36: yych = *++YYCURSOR;
if(yych == 'n') goto yy33;
goto yy2;
yy37: yych = *++YYCURSOR;
if(yych <= '/') goto yy39;
if(yych <= '9') goto yy56;
goto yy39;
yy38: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
yy39: if(yybm[0+yych] & 1) goto yy38;
if(yych <= '\000') goto yy42;
if(yych != '.') goto yy2;
yy40: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
yy41: if(yybm[0+yych] & 2) goto yy40;
if(yych <= '.'){
if(yych <= '+'){
if(yych <= '\000') goto yy46;
goto yy2;
} else {
if(yych <= ',') goto yy44;
if(yych <= '-') goto yy2;
goto yy48;
}
} else {
if(yych <= 'E'){
if(yych <= 'D') goto yy2;
goto yy50;
} else {
if(yych == 'e') goto yy50;
goto yy2;
}
}
yy42: yych = *++YYCURSOR;
yy43:
#line 79
{ TAG_IMPLICIT( "int" ); }
yy44: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
yy45: if(yych <= ','){
if(yych <= '\000') goto yy46;
if(yych <= '+') goto yy2;
goto yy44;
} else {
if(yych <= '/') goto yy2;
if(yych <= '9') goto yy44;
goto yy2;
}
yy46: yych = *++YYCURSOR;
yy47:
#line 81
{ TAG_IMPLICIT( "float#fix" ); }
yy48: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
yy49: if(yybm[0+yych] & 4) goto yy48;
if(yych == 'E') goto yy50;
if(yych != 'e') goto yy2;
yy50: yych = *++YYCURSOR;
if(yych == '+') goto yy51;
if(yych != '-') goto yy2;
yy51: yych = *++YYCURSOR;
if(yych <= '\000') goto yy2;
goto yy53;
yy52: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
yy53: if(yych <= '\000') goto yy54;
if(yych <= '/') goto yy2;
if(yych <= '9') goto yy52;
goto yy2;
yy54: yych = *++YYCURSOR;
yy55:
#line 83
{ TAG_IMPLICIT( "float#exp" ); }
yy56: yych = *++YYCURSOR;
if(yych <= '/') goto yy39;
if(yych >= ':') goto yy39;
yy57: yych = *++YYCURSOR;
if(yych != '-') goto yy39;
yy58: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy59: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy60: yych = *++YYCURSOR;
if(yych != '-') goto yy2;
yy61: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy62: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy63: yych = *++YYCURSOR;
if(yych <= 'S'){
if(yych <= '\000') goto yy64;
if(yych <= '/') goto yy69;
if(yych <= '9') goto yy2;
goto yy69;
} else {
if(yych <= 'T') goto yy66;
if(yych == 't') goto yy67;
goto yy69;
}
yy64: yych = *++YYCURSOR;
yy65:
#line 91
{ TAG_IMPLICIT( "timestamp#ymd" ); }
yy66: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych <= '9') goto yy112;
goto yy2;
yy67: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych <= '9') goto yy92;
goto yy2;
yy68: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
yy69: if(yybm[0+yych] & 8) goto yy68;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy70: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy71: yych = *++YYCURSOR;
if(yych != ':') goto yy2;
yy72: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy73: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy74: yych = *++YYCURSOR;
if(yych != ':') goto yy2;
yy75: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy76: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy77: yych = *++YYCURSOR;
if(yych <= '\037'){
if(yych == '\t') goto yy80;
goto yy2;
} else {
if(yych <= ' ') goto yy80;
if(yych != '.') goto yy2;
}
yy78: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
yy79: if(yybm[0+yych] & 16) goto yy78;
if(yych <= '0') goto yy2;
if(yych <= '9') goto yy90;
goto yy2;
yy80: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
yy81: if(yych <= '*'){
if(yych <= '\t'){
if(yych <= '\b') goto yy2;
goto yy80;
} else {
if(yych == ' ') goto yy80;
goto yy2;
}
} else {
if(yych <= '-'){
if(yych == ',') goto yy2;
goto yy83;
} else {
if(yych != 'Z') goto yy2;
}
}
yy82: yych = *++YYCURSOR;
if(yych <= '\000') goto yy87;
goto yy2;
yy83: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy84: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy85: yych = *++YYCURSOR;
if(yych <= '\000') goto yy87;
if(yych != ':') goto yy2;
yy86: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych <= '9') goto yy89;
goto yy2;
yy87: yych = *++YYCURSOR;
yy88:
#line 95
{ TAG_IMPLICIT( "timestamp#spaced" ); }
yy89: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych <= '9') goto yy82;
goto yy2;
yy90: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
yy91: if(yybm[0+yych] & 16) goto yy78;
if(yych <= '\037'){
if(yych == '\t') goto yy80;
goto yy2;
} else {
if(yych <= ' ') goto yy80;
if(yych <= '0') goto yy2;
if(yych <= '9') goto yy90;
goto yy2;
}
yy92: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy93: yych = *++YYCURSOR;
if(yych != ':') goto yy2;
yy94: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy95: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy96: yych = *++YYCURSOR;
if(yych != ':') goto yy2;
yy97: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy98: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy99: yych = *++YYCURSOR;
if(yych <= '-'){
if(yych == '+') goto yy103;
if(yych <= ',') goto yy2;
goto yy103;
} else {
if(yych <= '.') goto yy100;
if(yych == 'Z') goto yy102;
goto yy2;
}
yy100: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
yy101: if(yych <= '/') goto yy2;
if(yych <= '0') goto yy100;
if(yych <= '9') goto yy110;
goto yy2;
yy102: yych = *++YYCURSOR;
if(yych <= '\000') goto yy107;
goto yy2;
yy103: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy104: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy105: yych = *++YYCURSOR;
if(yych <= '\000') goto yy107;
if(yych != ':') goto yy2;
yy106: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych <= '9') goto yy109;
goto yy2;
yy107: yych = *++YYCURSOR;
yy108:
#line 93
{ TAG_IMPLICIT( "timestamp#iso8601" ); }
yy109: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych <= '9') goto yy102;
goto yy2;
yy110: ++YYCURSOR;
if((YYLIMIT - YYCURSOR) < 7) YYFILL(7);
yych = *YYCURSOR;
yy111: if(yych <= '/'){
if(yych <= '+'){
if(yych <= '*') goto yy2;
goto yy103;
} else {
if(yych == '-') goto yy103;
goto yy2;
}
} else {
if(yych <= '9'){
if(yych <= '0') goto yy100;
goto yy110;
} else {
if(yych == 'Z') goto yy102;
goto yy2;
}
}
yy112: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy113: yych = *++YYCURSOR;
if(yych != ':') goto yy2;
yy114: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy115: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy116: yych = *++YYCURSOR;
if(yych != ':') goto yy2;
yy117: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy118: yych = *++YYCURSOR;
if(yych <= '/') goto yy2;
if(yych >= ':') goto yy2;
yy119: yych = *++YYCURSOR;
if(yych <= '-'){
if(yych == '+') goto yy103;
if(yych <= ',') goto yy2;
goto yy103;
} else {
if(yych <= '.') goto yy120;
if(yych == 'Z') goto yy122;
goto yy2;
}
yy120: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
yy121: if(yych <= '/') goto yy2;
if(yych <= '0') goto yy120;
if(yych <= '9') goto yy124;
goto yy2;
yy122: yych = *++YYCURSOR;
if(yych >= '\001') goto yy2;
yy123: yych = *++YYCURSOR;
goto yy108;
yy124: ++YYCURSOR;
if((YYLIMIT - YYCURSOR) < 7) YYFILL(7);
yych = *YYCURSOR;
yy125: if(yych <= '/'){
if(yych <= '+'){
if(yych <= '*') goto yy2;
goto yy103;
} else {
if(yych == '-') goto yy103;
goto yy2;
}
} else {
if(yych <= '9'){
if(yych <= '0') goto yy120;
goto yy124;
} else {
if(yych == 'Z') goto yy122;
goto yy2;
}
}
yy126: yych = *++YYCURSOR;
if(yych <= '/') goto yy129;
if(yych <= '7') goto yy141;
if(yych <= '9') goto yy139;
goto yy129;
yy127: yych = *++YYCURSOR;
if(yych <= '/') goto yy138;
if(yych <= '9') goto yy139;
goto yy138;
yy128: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
yy129: if(yybm[0+yych] & 64) goto yy128;
if(yych <= '.'){
if(yych <= '\000') goto yy135;
if(yych <= '-') goto yy2;
goto yy40;
} else {
if(yych <= '/') goto yy2;
if(yych <= '9') goto yy137;
goto yy2;
}
yy130: yych = *++YYCURSOR;
if(yych <= '\000') goto yy2;
goto yy132;
yy131: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
yy132: if(yybm[0+yych] & 128) goto yy131;
if(yych >= '\001') goto yy2;
yy133: yych = *++YYCURSOR;
yy134:
#line 75
{ TAG_IMPLICIT( "int#hex" ); }
yy135: yych = *++YYCURSOR;
yy136:
#line 77
{ TAG_IMPLICIT( "int#oct" ); }
yy137: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
yy138: if(yych <= '-'){
if(yych == ',') goto yy137;
goto yy2;
} else {
if(yych <= '.') goto yy40;
if(yych <= '/') goto yy2;
if(yych <= '9') goto yy137;
goto yy2;
}
yy139: yych = *++YYCURSOR;
if(yych <= '/') goto yy138;
if(yych >= ':') goto yy138;
yy140: yych = *++YYCURSOR;
if(yych == '-') goto yy58;
goto yy138;
yy141: yych = *++YYCURSOR;
if(yych <= '/') goto yy129;
if(yych <= '7') goto yy142;
if(yych <= '9') goto yy140;
goto yy129;
yy142: yych = *++YYCURSOR;
if(yych == '-') goto yy58;
goto yy129;
yy143: yych = *++YYCURSOR;
if(yych == 'I') goto yy146;
if(yych == 'i') goto yy145;
goto yy2;
yy144: yych = *++YYCURSOR;
if(yych <= '\000') goto yy42;
if(yych == 'x') goto yy130;
goto yy129;
yy145: yych = *++YYCURSOR;
if(yych == 'n') goto yy152;
goto yy2;
yy146: yych = *++YYCURSOR;
if(yych == 'N') goto yy147;
if(yych == 'n') goto yy148;
goto yy2;
yy147: yych = *++YYCURSOR;
if(yych == 'F') goto yy149;
goto yy2;
yy148: yych = *++YYCURSOR;
if(yych != 'f') goto yy2;
yy149: yych = *++YYCURSOR;
if(yych >= '\001') goto yy2;
yy150: yych = *++YYCURSOR;
yy151:
#line 87
{ TAG_IMPLICIT( "float#neginf" ); }
yy152: yych = *++YYCURSOR;
if(yych == 'f') goto yy149;
goto yy2;
yy153: yych = *++YYCURSOR;
if(yych == 'I') goto yy24;
if(yych == 'i') goto yy23;
goto yy2;
yy154: yych = *++YYCURSOR;
if(yych == 'L') goto yy161;
goto yy2;
yy155: yych = *++YYCURSOR;
if(yych != 'l') goto yy2;
yy156: yych = *++YYCURSOR;
if(yych != 's') goto yy2;
yy157: yych = *++YYCURSOR;
if(yych != 'e') goto yy2;
yy158: yych = *++YYCURSOR;
if(yych >= '\001') goto yy2;
yy159: yych = *++YYCURSOR;
yy160:
#line 73
{ TAG_IMPLICIT( "bool#no" ); }
yy161: yych = *++YYCURSOR;
if(yych != 'S') goto yy2;
yy162: yych = *++YYCURSOR;
if(yych == 'E') goto yy158;
goto yy2;
yy163: yych = *++YYCURSOR;
if(yych != 'l') goto yy2;
yy164: yych = *++YYCURSOR;
if(yych != 's') goto yy2;
yy165: yych = *++YYCURSOR;
if(yych == 'e') goto yy158;
goto yy2;
yy166: yych = *++YYCURSOR;
if(yych == 'F') goto yy158;
goto yy2;
yy167: yych = *++YYCURSOR;
if(yych == 'f') goto yy158;
goto yy2;
yy168: yych = *++YYCURSOR;
if(yych >= '\001') goto yy2;
yy169: yych = *++YYCURSOR;
yy170:
#line 71
{ TAG_IMPLICIT( "bool#yes" ); }
yy171: yych = *++YYCURSOR;
if(yych == 'f') goto yy158;
goto yy2;
yy172: yych = *++YYCURSOR;
if(yych == 'S') goto yy168;
goto yy2;
yy173: yych = *++YYCURSOR;
if(yych == 's') goto yy168;
goto yy2;
yy174: yych = *++YYCURSOR;
if(yych == 's') goto yy168;
goto yy2;
yy175: yych = *++YYCURSOR;
if(yych == 'U') goto yy178;
goto yy2;
yy176: yych = *++YYCURSOR;
if(yych != 'u') goto yy2;
yy177: yych = *++YYCURSOR;
if(yych == 'e') goto yy168;
goto yy2;
yy178: yych = *++YYCURSOR;
if(yych == 'E') goto yy168;
goto yy2;
yy179: yych = *++YYCURSOR;
if(yych != 'u') goto yy2;
yy180: yych = *++YYCURSOR;
if(yych == 'e') goto yy168;
goto yy2;
yy181: yych = *++YYCURSOR;
if(yych == 'L') goto yy187;
goto yy2;
yy182: yych = *++YYCURSOR;
if(yych != 'l') goto yy2;
yy183: yych = *++YYCURSOR;
if(yych != 'l') goto yy2;
yy184: yych = *++YYCURSOR;
if(yych >= '\001') goto yy2;
yy185: yych = *++YYCURSOR;
yy186:
#line 69
{ TAG_IMPLICIT( "null" ); }
yy187: yych = *++YYCURSOR;
if(yych == 'L') goto yy184;
goto yy2;
yy188: yych = *++YYCURSOR;
if(yych != 'l') goto yy2;
yy189: yych = *++YYCURSOR;
if(yych == 'l') goto yy184;
goto yy2;
}
#line 101
}

306
ext/syck/node.c Normal file
Просмотреть файл

@ -0,0 +1,306 @@
//
// node.c
//
// $Author$
// $Date$
//
// Copyright (C) 2003 why the lucky stiff
//
#include "syck.h"
//
// Node allocation functions
//
SyckNode *
syck_alloc_node( enum syck_kind_tag type )
{
SyckNode *s;
s = S_ALLOC( SyckNode );
s->kind = type;
s->id = NULL;
s->type_id = NULL;
s->anchor = NULL;
return s;
}
void
syck_free_node( SyckNode *n )
{
syck_free_members( n );
if ( n->type_id != NULL )
S_FREE( n->type_id );
if ( n->anchor != NULL )
S_FREE( n->anchor );
S_FREE( n );
}
SyckNode *
syck_alloc_map()
{
SyckNode *n;
struct SyckMap *m;
m = S_ALLOC( struct SyckMap );
m->idx = 0;
m->capa = ALLOC_CT;
m->keys = S_ALLOC_N( SYMID, m->capa );
m->values = S_ALLOC_N( SYMID, m->capa );
n = syck_alloc_node( syck_map_kind );
n->data.pairs = m;
return n;
}
SyckNode *
syck_alloc_seq()
{
SyckNode *n;
struct SyckSeq *s;
s = S_ALLOC( struct SyckSeq );
s->idx = 0;
s->capa = ALLOC_CT;
s->items = S_ALLOC_N( SYMID, s->capa );
n = syck_alloc_node( syck_seq_kind );
n->data.list = s;
return n;
}
SyckNode *
syck_alloc_str()
{
SyckNode *n;
struct SyckStr *s;
s = S_ALLOC( struct SyckStr );
s->len = 0;
s->ptr = NULL;
n = syck_alloc_node( syck_str_kind );
n->data.str = s;
return n;
}
SyckNode *
syck_new_str( char *str )
{
return syck_new_str2( str, strlen( str ) );
}
SyckNode *
syck_new_str2( char *str, long len )
{
SyckNode *n;
n = syck_alloc_str();
n->data.str->ptr = S_ALLOC_N( char, len + 1 );
n->data.str->len = len;
memcpy( n->data.str->ptr, str, len );
n->data.str->ptr[len] = '\0';
return n;
}
void
syck_str_blow_away_commas( SyckNode *n )
{
char *go, *end;
go = n->data.str->ptr;
end = go + n->data.str->len;
while ( *(++go) != '\0' )
{
if ( *go == ',' )
{
n->data.str->len -= 1;
memmove( go, go + 1, end - go );
end -= 1;
}
}
}
char *
syck_str_read( SyckNode *n )
{
ASSERT( n != NULL );
return n->data.str->ptr;
}
SyckNode *
syck_new_map( SYMID key, SYMID value )
{
SyckNode *n;
n = syck_alloc_map();
syck_map_add( n, key, value );
return n;
}
void
syck_map_add( SyckNode *map, SYMID key, SYMID value )
{
struct SyckMap *m;
long idx;
ASSERT( map != NULL );
ASSERT( map->data.pairs != NULL );
m = map->data.pairs;
idx = m->idx;
m->idx += 1;
if ( m->idx > m->capa )
{
m->capa += ALLOC_CT;
S_REALLOC_N( m->keys, SYMID, m->capa );
S_REALLOC_N( m->values, SYMID, m->capa );
}
m->keys[idx] = key;
m->values[idx] = value;
}
void
syck_map_update( SyckNode *map1, SyckNode *map2 )
{
struct SyckMap *m1, *m2;
long new_idx, new_capa;
ASSERT( map1 != NULL );
ASSERT( map2 != NULL );
m1 = map1->data.pairs;
m2 = map2->data.pairs;
if ( m2->idx < 1 ) return;
new_idx = m1->idx;
new_idx += m2->idx;
new_capa = m1->capa;
while ( new_idx > new_capa )
{
new_capa += ALLOC_CT;
}
if ( new_capa > m1->capa )
{
m1->capa = new_capa;
S_REALLOC_N( m1->keys, SYMID, m1->capa );
S_REALLOC_N( m1->values, SYMID, m1->capa );
}
new_idx = 0;
for ( new_idx = 0; new_idx < m2->idx; m1->idx++, new_idx++ )
{
m1->keys[m1->idx] = m2->keys[new_idx];
m1->values[m1->idx] = m2->values[new_idx];
}
}
long
syck_map_count( SyckNode *map )
{
ASSERT( map != NULL );
ASSERT( map->data.pairs != NULL );
return map->data.pairs->idx;
}
SYMID
syck_map_read( SyckNode *map, enum map_part p, long idx )
{
struct SyckMap *m;
ASSERT( map != NULL );
m = map->data.pairs;
ASSERT( m != NULL );
if ( p == map_key )
{
return m->keys[idx];
}
else
{
return m->values[idx];
}
}
SyckNode *
syck_new_seq( SYMID value )
{
SyckNode *n;
n = syck_alloc_seq();
syck_seq_add( n, value );
return n;
}
void
syck_seq_add( SyckNode *arr, SYMID value )
{
struct SyckSeq *s;
long idx;
ASSERT( arr != NULL );
ASSERT( arr->data.list != NULL );
s = arr->data.list;
idx = s->idx;
s->idx += 1;
if ( s->idx > s->capa )
{
s->capa += ALLOC_CT;
S_REALLOC_N( s->items, SYMID, s->capa );
}
s->items[idx] = value;
}
long
syck_seq_count( SyckNode *seq )
{
ASSERT( seq != NULL );
ASSERT( seq->data.list != NULL );
return seq->data.list->idx;
}
SYMID
syck_seq_read( SyckNode *seq, long idx )
{
struct SyckSeq *s;
ASSERT( seq != NULL );
s = seq->data.list;
ASSERT( s != NULL );
return s->items[idx];
}
void
syck_free_members( SyckNode *n )
{
int i;
switch ( n->kind )
{
case syck_str_kind:
if ( n->data.str->ptr != NULL )
{
S_FREE( n->data.str->ptr );
n->data.str->ptr = NULL;
n->data.str->len = 0;
S_FREE( n->data.str );
}
break;
case syck_seq_kind:
S_FREE( n->data.list->items );
S_FREE( n->data.list );
break;
case syck_map_kind:
S_FREE( n->data.pairs->keys );
S_FREE( n->data.pairs->values );
S_FREE( n->data.pairs );
break;
}
}

569
ext/syck/rubyext.c Normal file
Просмотреть файл

@ -0,0 +1,569 @@
//
// rubyext.c
//
// $Author$
// $Date$
//
// Copyright (C) 2003 why the lucky stiff
//
#include "ruby.h"
#include "syck.h"
#include <sys/types.h>
#include <time.h>
static ID s_utc, s_read, s_binmode;
static VALUE sym_model, sym_generic;
static VALUE sym_scalar, sym_seq, sym_map;
VALUE cNode;
//
// my private collection of numerical oddities.
//
static double S_zero() { return 0.0; }
static double S_one() { return 1.0; }
static double S_inf() { return S_one() / S_zero(); }
static double S_nan() { return S_zero() / S_zero(); }
static VALUE syck_node_transform( VALUE );
//
// read from io.
//
long
rb_syck_io_str_read( char *buf, SyckIoStr *str, long max_size, long skip )
{
long len = 0;
ASSERT( str != NULL );
max_size -= skip;
if ( max_size < 0 ) max_size = 0;
if ( max_size > 0 )
{
//
// call io#read.
//
VALUE src = (VALUE)str->ptr;
VALUE n = LONG2NUM(max_size);
VALUE str = rb_funcall2(src, s_read, 1, &n);
if (!NIL_P(str))
{
len = RSTRING(str)->len;
memcpy( buf + skip, RSTRING(str)->ptr, len );
}
}
len += skip;
buf[len] = '\0';
return len;
}
//
// determine: are we reading from a string or io?
//
void
syck_parser_assign_io(parser, port)
SyckParser *parser;
VALUE port;
{
if (rb_respond_to(port, rb_intern("to_str"))) {
//arg.taint = OBJ_TAINTED(port); /* original taintedness */
//StringValue(port); /* possible conversion */
syck_parser_str( parser, RSTRING(port)->ptr, RSTRING(port)->len, NULL );
}
else if (rb_respond_to(port, s_read)) {
if (rb_respond_to(port, s_binmode)) {
rb_funcall2(port, s_binmode, 0, 0);
}
//arg.taint = Qfalse;
syck_parser_str( parser, (char *)port, 0, rb_syck_io_str_read );
}
else {
rb_raise(rb_eTypeError, "instance of IO needed");
}
}
//
// creating timestamps
//
SYMID
rb_syck_mktime(str)
char *str;
{
VALUE time;
char *ptr = str;
VALUE year, mon, day, hour, min, sec;
// Year
ptr[4] = '\0';
year = INT2FIX(strtol(ptr, NULL, 10));
// Month
ptr += 4;
while ( !isdigit( *ptr ) ) ptr++;
mon = INT2FIX(strtol(ptr, NULL, 10));
// Day
ptr += 2;
while ( !isdigit( *ptr ) ) ptr++;
day = INT2FIX(strtol(ptr, NULL, 10));
// Hour
ptr += 2;
while ( !isdigit( *ptr ) ) ptr++;
hour = INT2FIX(strtol(ptr, NULL, 10));
// Minute
ptr += 2;
while ( !isdigit( *ptr ) ) ptr++;
min = INT2FIX(strtol(ptr, NULL, 10));
// Second
ptr += 2;
while ( !isdigit( *ptr ) ) ptr++;
sec = INT2FIX(strtol(ptr, NULL, 10));
time = rb_funcall(rb_cTime, s_utc, 6, year, mon, day, hour, min, sec );
return time;
}
//
// {generic mode} node handler
// - Loads data into Node classes
//
SYMID
rb_syck_parse_handler(p, n)
SyckParser *p;
SyckNode *n;
{
VALUE t, v, obj;
int i;
obj = rb_obj_alloc(cNode);
if ( n->type_id != NULL )
{
t = rb_str_new2(n->type_id);
rb_iv_set(obj, "@type_id", t);
}
switch (n->kind)
{
case syck_str_kind:
rb_iv_set(obj, "@kind", sym_scalar);
v = rb_str_new( n->data.str->ptr, n->data.str->len );
break;
case syck_seq_kind:
rb_iv_set(obj, "@kind", sym_seq);
v = rb_ary_new2( n->data.list->idx );
for ( i = 0; i < n->data.list->idx; i++ )
{
rb_ary_store( v, i, syck_seq_read( n, i ) );
}
break;
case syck_map_kind:
rb_iv_set(obj, "@kind", sym_map);
v = rb_hash_new();
for ( i = 0; i < n->data.pairs->idx; i++ )
{
VALUE key = syck_node_transform( syck_map_read( n, map_key, i ) );
VALUE val = rb_ary_new();
rb_ary_push(val, syck_map_read( n, map_key, i ));
rb_ary_push(val, syck_map_read( n, map_value, i ));
rb_hash_aset( v, key, val );
}
break;
}
if ( p->bonus != 0 )
{
VALUE proc = (VALUE)p->bonus;
rb_funcall(proc, rb_intern("call"), 1, v);
}
rb_iv_set(obj, "@value", v);
return obj;
}
//
// {native mode} node handler
// - Converts data into native Ruby types
//
SYMID
rb_syck_load_handler(p, n)
SyckParser *p;
SyckNode *n;
{
VALUE obj;
long i;
int str = 0;
switch (n->kind)
{
case syck_str_kind:
if ( n->type_id == NULL || strcmp( n->type_id, "str" ) == 0 )
{
obj = rb_str_new( n->data.str->ptr, n->data.str->len );
}
else if ( strcmp( n->type_id, "null" ) == 0 )
{
obj = Qnil;
}
else if ( strcmp( n->type_id, "bool#yes" ) == 0 )
{
obj = Qtrue;
}
else if ( strcmp( n->type_id, "bool#no" ) == 0 )
{
obj = Qfalse;
}
else if ( strcmp( n->type_id, "int#hex" ) == 0 )
{
obj = rb_cstr2inum( n->data.str->ptr, 16 );
}
else if ( strcmp( n->type_id, "int#oct" ) == 0 )
{
obj = rb_cstr2inum( n->data.str->ptr, 8 );
}
else if ( strncmp( n->type_id, "int", 3 ) == 0 )
{
syck_str_blow_away_commas( n );
obj = rb_cstr2inum( n->data.str->ptr, 10 );
}
else if ( strcmp( n->type_id, "float#nan" ) == 0 )
{
obj = rb_float_new( S_nan() );
}
else if ( strcmp( n->type_id, "float#inf" ) == 0 )
{
obj = rb_float_new( S_inf() );
}
else if ( strcmp( n->type_id, "float#neginf" ) == 0 )
{
obj = rb_float_new( -S_inf() );
}
else if ( strncmp( n->type_id, "float", 5 ) == 0 )
{
double f;
syck_str_blow_away_commas( n );
f = strtod( n->data.str->ptr, NULL );
obj = rb_float_new( f );
}
else if ( strcmp( n->type_id, "timestamp#iso8601" ) == 0 )
{
obj = rb_syck_mktime( n->data.str->ptr );
}
else if ( strcmp( n->type_id, "timestamp#spaced" ) == 0 )
{
obj = rb_syck_mktime( n->data.str->ptr );
}
else if ( strcmp( n->type_id, "timestamp#ymd" ) == 0 )
{
S_REALLOC_N( n->data.str->ptr, char, 22 );
strcat( n->data.str->ptr, "t12:00:00Z" );
obj = rb_syck_mktime( n->data.str->ptr );
}
else if ( strncmp( n->type_id, "timestamp", 9 ) == 0 )
{
obj = rb_syck_mktime( n->data.str->ptr );
}
else
{
obj = rb_str_new( n->data.str->ptr, n->data.str->len );
}
break;
case syck_seq_kind:
obj = rb_ary_new2( n->data.list->idx );
for ( i = 0; i < n->data.list->idx; i++ )
{
rb_ary_store( obj, i, syck_seq_read( n, i ) );
}
break;
case syck_map_kind:
obj = rb_hash_new();
for ( i = 0; i < n->data.pairs->idx; i++ )
{
rb_hash_aset( obj, syck_map_read( n, map_key, i ), syck_map_read( n, map_value, i ) );
}
break;
}
if ( p->bonus != 0 )
{
VALUE proc = (VALUE)p->bonus;
rb_funcall(proc, rb_intern("call"), 1, obj);
}
return obj;
}
//
// friendly errors.
//
void
rb_syck_err_handler(p, msg)
SyckParser *p;
char *msg;
{
char *endl = p->cursor;
while ( *endl != '\0' && *endl != '\n' )
endl++;
endl[0] = '\0';
rb_raise(rb_eLoadError, "%s on line %d, col %d: `%s'",
msg,
p->linect,
p->cursor - p->lineptr,
p->lineptr);
}
//
// data loaded based on the model requested.
//
void
syck_set_model( parser, model )
SyckParser *parser;
VALUE model;
{
if ( model == sym_generic )
{
syck_parser_handler( parser, rb_syck_parse_handler );
syck_parser_error_handler( parser, rb_syck_err_handler );
syck_parser_implicit_typing( parser, 1 );
syck_parser_taguri_expansion( parser, 1 );
}
else
{
syck_parser_handler( parser, rb_syck_load_handler );
syck_parser_error_handler( parser, rb_syck_err_handler );
syck_parser_implicit_typing( parser, 1 );
syck_parser_taguri_expansion( parser, 0 );
}
}
//
// wrap syck_parse().
//
static VALUE
rb_run_syck_parse(parser)
SyckParser *parser;
{
return syck_parse(parser);
}
//
// free parser.
//
static VALUE
rb_syck_ensure(parser)
SyckParser *parser;
{
syck_free_parser( parser );
return 0;
}
//
// YAML::Syck::Parser.new
//
VALUE
syck_parser_new(argc, argv, class)
int argc;
VALUE *argv;
VALUE class;
{
VALUE pobj, options, init_argv[1];
SyckParser *parser = syck_new_parser();
rb_scan_args(argc, argv, "01", &options);
pobj = Data_Wrap_Struct( class, 0, syck_free_parser, parser );
if ( ! rb_obj_is_instance_of( options, rb_cHash ) )
{
options = rb_hash_new();
}
init_argv[0] = options;
rb_obj_call_init(pobj, 1, init_argv);
return pobj;
}
//
// YAML::Syck::Parser.initialize( options )
//
static VALUE
syck_parser_initialize( self, options )
VALUE self, options;
{
rb_iv_set(self, "@options", options);
return self;
}
//
// YAML::Syck::Parser.load( IO or String )
//
VALUE
syck_parser_load(argc, argv, self)
int argc;
VALUE *argv;
VALUE self;
{
VALUE port, proc, v, model;
SyckParser *parser;
rb_scan_args(argc, argv, "11", &port, &proc);
Data_Get_Struct(self, SyckParser, parser);
syck_parser_assign_io(parser, port);
model = rb_hash_aref( rb_iv_get( self, "@options" ), sym_model );
syck_set_model( parser, model );
parser->bonus = 0;
if ( !NIL_P( proc ) )
{
parser->bonus = (void *)proc;
}
v = syck_parse( parser );
if ( v == NULL )
{
return Qnil;
}
//v = rb_ensure(rb_run_syck_parse, (VALUE)&parser, rb_syck_ensure, (VALUE)&parser);
return v;
}
//
// YAML::Syck::Parser.load_documents( IO or String ) { |doc| }
//
VALUE
syck_parser_load_documents(argc, argv, self)
int argc;
VALUE *argv;
VALUE self;
{
VALUE port, proc, v, model;
SyckParser *parser;
rb_scan_args(argc, argv, "1&", &port, &proc);
Data_Get_Struct(self, SyckParser, parser);
syck_parser_assign_io(parser, port);
model = rb_hash_aref( rb_iv_get( self, "@options" ), sym_model );
syck_set_model( parser, model );
parser->bonus = 0;
while ( 1 )
{
v = syck_parse( parser );
if ( parser->eof == 1 )
{
break;
}
rb_funcall( proc, rb_intern("call"), 1, v );
}
return Qnil;
}
//
// YAML::Syck::Node.initialize
//
static VALUE
syck_node_initialize( self, type_id, val )
VALUE self, type_id, val;
{
rb_iv_set( self, "@type_id", type_id );
rb_iv_set( self, "@value", val );
}
static VALUE
syck_node_thash( entry, t )
VALUE entry, t;
{
VALUE key, val;
key = rb_ary_entry( entry, 0 );
val = syck_node_transform( rb_ary_entry( rb_ary_entry( entry, 1 ), 1 ) );
rb_hash_aset( t, key, val );
}
static VALUE
syck_node_ahash( entry, t )
VALUE entry, t;
{
VALUE val = syck_node_transform( entry );
rb_ary_push( t, val );
}
//
// YAML::Syck::Node.transform
//
static VALUE
syck_node_transform( self )
VALUE self;
{
VALUE t = Qnil;
VALUE val = rb_iv_get( self, "@value" );
if ( rb_obj_is_instance_of( val, rb_cHash ) )
{
t = rb_hash_new();
rb_iterate( rb_each, val, syck_node_thash, t );
}
else if ( rb_obj_is_instance_of( val, rb_cArray ) )
{
t = rb_ary_new();
rb_iterate( rb_each, val, syck_node_ahash, t );
}
else
{
t = val;
}
return t;
}
//
// Initialize Syck extension
//
void
Init_syck()
{
VALUE rb_yaml = rb_define_module( "YAML" );
VALUE rb_syck = rb_define_module_under( rb_yaml, "Syck" );
VALUE cParser = rb_define_class_under( rb_syck, "Parser", rb_cObject );
rb_define_const( rb_syck, "VERSION", rb_str_new2( SYCK_VERSION ) );
//
// Global symbols
//
s_utc = rb_intern("utc");
s_read = rb_intern("read");
s_binmode = rb_intern("binmode");
sym_model = ID2SYM(rb_intern("Model"));
sym_generic = ID2SYM(rb_intern("Generic"));
sym_map = ID2SYM(rb_intern("map"));
sym_scalar = ID2SYM(rb_intern("scalar"));
sym_seq = ID2SYM(rb_intern("seq"));
//
// Define YAML::Syck::Parser class
//
rb_define_attr( cParser, "options", 1, 1 );
rb_define_singleton_method(cParser, "new", syck_parser_new, -1);
rb_define_method(cParser, "initialize", syck_parser_initialize, 1);
rb_define_method(cParser, "load", syck_parser_load, -1);
rb_define_method(cParser, "load_documents", syck_parser_load_documents, -1);
//
// Define YAML::Syck::Node class
//
cNode = rb_define_class_under( rb_syck, "Node", rb_cObject );
rb_define_attr( cNode, "kind", 1, 1 );
rb_define_attr( cNode, "type_id", 1, 1 );
rb_define_attr( cNode, "value", 1, 1 );
rb_define_attr( cNode, "anchor", 1, 1 );
rb_define_method( cNode, "initialize", syck_node_initialize, 2);
rb_define_method( cNode, "transform", syck_node_transform, 0);
}

460
ext/syck/syck.c Normal file
Просмотреть файл

@ -0,0 +1,460 @@
//
// syck.c
//
// $Author$
// $Date$
//
// Copyright (C) 2003 why the lucky stiff
//
#include <stdio.h>
#include <string.h>
#include "syck.h"
#define SYCK_YAML_MAJOR 1
#define SYCK_YAML_MINOR 0
#define SYCK_BUFFERSIZE 262144
//
// Custom assert
//
void
syck_assert( char *file_name, unsigned line_num )
{
fflush( NULL );
fprintf( stderr, "\nAssertion failed: %s, line %u\n",
file_name, line_num );
fflush( stderr );
abort();
}
char *
syck_strndup( char *buf, long len )
{
char *new = S_ALLOC_N( char, len + 1 );
S_MEMZERO( new, char, len + 1 );
S_MEMCPY( new, buf, char, len );
}
//
// Default IO functions
//
long
syck_io_file_read( char *buf, SyckIoFile *file, long max_size, long skip )
{
char *beg;
long len = 0;
ASSERT( file != NULL );
max_size -= skip;
len = fread( buf + skip, max_size, sizeof( char ), file->ptr );
#if REDEBUG
printf( "LEN: %d\n", len );
#endif
len += skip;
buf[len] = '\0';
#if REDEBUG
printf( "POS: %d\n", len );
printf( "BUFFER: %s\n", buf );
#endif
return len;
}
long
syck_io_str_read( char *buf, SyckIoStr *str, long max_size, long skip )
{
char *beg;
long len = 0;
ASSERT( str != NULL );
beg = str->ptr;
if ( max_size >= 0 )
{
max_size -= skip;
if ( max_size < 0 ) max_size = 0;
str->ptr += max_size;
if ( str->ptr > str->end )
{
str->ptr = str->end;
}
}
else
{
// Use exact string length
while ( str->ptr < str->end ) {
if (*(str->ptr++) == '\n') break;
}
}
if ( beg < str->ptr )
{
len = str->ptr - beg;
S_MEMCPY( buf + skip, beg, char, len );
}
#if REDEBUG
printf( "LEN: %d\n", len );
#endif
len += skip;
buf[len] = '\0';
#if REDEBUG
printf( "POS: %d\n", len );
printf( "BUFFER: %s\n", buf );
#endif
return len;
}
void
syck_parser_reset_levels( SyckParser *p )
{
p->lvl_idx = 1;
p->levels[0].spaces = -1;
p->levels[0].domain = "yaml.org,2002/";
p->levels[0].status = syck_lvl_header;
}
void
syck_parser_reset_cursor( SyckParser *p )
{
if ( p->buffer == NULL )
{
p->buffer = S_ALLOC_N( char, p->bufsize );
}
p->buffer[0] = '\0';
p->cursor = NULL;
p->lineptr = NULL;
p->token = NULL;
p->toktmp = NULL;
p->marker = NULL;
p->limit = NULL;
p->linect = 0;
p->eof = 0;
p->last_token = 0;
p->force_token = 0;
}
//
// Allocate the parser
//
SyckParser *
syck_new_parser()
{
SyckParser *p;
p = S_ALLOC( SyckParser );
p->lvl_capa = ALLOC_CT;
p->levels = S_ALLOC_N( SyckLevel, p->lvl_capa );
p->io_type = syck_io_str;
p->io.str = NULL;
p->syms = NULL;
p->anchors = st_init_strtable();
p->implicit_typing = 1;
p->taguri_expansion = 0;
p->bufsize = SYCK_BUFFERSIZE;
p->buffer = NULL;
syck_parser_reset_levels( p );
return p;
}
int
syck_add_sym( SyckParser *p, char *data )
{
SYMID id = 0;
if ( p->syms == NULL )
{
p->syms = st_init_numtable();
}
id = p->syms->num_entries;
st_insert( p->syms, id, (st_data_t)data );
return id;
}
int
syck_lookup_sym( SyckParser *p, SYMID id, char **data )
{
if ( p->syms == NULL ) return 0;
return st_lookup( p->syms, id, (st_data_t *)data );
}
int
syck_st_free_nodes( char *key, SyckNode *n, char *arg )
{
syck_free_node( n );
return ST_CONTINUE;
}
void
syck_free_parser( SyckParser *p )
{
char *key;
SyckNode *node;
//
// Free the adhoc symbol table
//
if ( p->syms != NULL )
{
st_free_table( p->syms );
}
//
// Free the anchor table
//
st_foreach( p->anchors, syck_st_free_nodes, (st_data_t)NULL );
st_free_table( p->anchors );
//
// Free all else
//
S_FREE( p->levels );
if ( p->buffer != NULL )
{
S_FREE( p->buffer );
}
free_any_io( p );
S_FREE( p );
}
void
syck_parser_handler( SyckParser *p, SyckNodeHandler hdlr )
{
ASSERT( p != NULL );
p->handler = hdlr;
}
void
syck_parser_implicit_typing( SyckParser *p, int flag )
{
p->implicit_typing = ( flag == 0 ? 0 : 1 );
}
void
syck_parser_taguri_expansion( SyckParser *p, int flag )
{
p->taguri_expansion = ( flag == 0 ? 0 : 1 );
}
void
syck_parser_error_handler( SyckParser *p, SyckErrorHandler hdlr )
{
ASSERT( p != NULL );
p->error_handler = hdlr;
}
void
syck_parser_file( SyckParser *p, FILE *fp, SyckIoFileRead read )
{
ASSERT( p != NULL );
free_any_io( p );
syck_parser_reset_cursor( p );
p->io_type = syck_io_file;
p->io.file = S_ALLOC( SyckIoFile );
p->io.file->ptr = fp;
if ( read != NULL )
{
p->io.file->read = read;
}
else
{
p->io.file->read = syck_io_file_read;
}
}
void
syck_parser_str( SyckParser *p, char *ptr, long len, SyckIoStrRead read )
{
ASSERT( p != NULL );
free_any_io( p );
syck_parser_reset_cursor( p );
p->io_type = syck_io_str;
p->io.str = S_ALLOC( SyckIoStr );
p->io.str->beg = ptr;
p->io.str->ptr = ptr;
p->io.str->end = ptr + len;
if ( read != NULL )
{
p->io.str->read = read;
}
else
{
p->io.str->read = syck_io_str_read;
}
}
void
syck_parser_str_auto( SyckParser *p, char *ptr, SyckIoStrRead read )
{
syck_parser_str( p, ptr, strlen( ptr ), read );
}
SyckLevel *
syck_parser_current_level( SyckParser *p )
{
return &p->levels[p->lvl_idx-1];
}
void
syck_parser_pop_level( SyckParser *p )
{
ASSERT( p != NULL );
// The root level should never be popped
if ( p->lvl_idx <= 1 ) return;
p->lvl_idx -= 1;
if ( p->levels[p->lvl_idx - 1].domain != p->levels[p->lvl_idx].domain )
{
free( p->levels[p->lvl_idx].domain );
}
}
void
syck_parser_add_level( SyckParser *p, int len, enum syck_level_status status )
{
ASSERT( p != NULL );
if ( p->lvl_idx + 1 > p->lvl_capa )
{
p->lvl_capa += ALLOC_CT;
S_REALLOC_N( p->levels, SyckLevel, p->lvl_capa );
}
ASSERT( len > p->levels[p->lvl_idx-1].spaces );
p->levels[p->lvl_idx].spaces = len;
p->levels[p->lvl_idx].domain = p->levels[p->lvl_idx-1].domain;
p->levels[p->lvl_idx].status = status;
p->lvl_idx += 1;
}
void
free_any_io( SyckParser *p )
{
ASSERT( p != NULL );
switch ( p->io_type )
{
case syck_io_str:
if ( p->io.str != NULL )
{
S_FREE( p->io.str );
p->io.str = NULL;
}
break;
case syck_io_file:
if ( p->io.file != NULL )
{
S_FREE( p->io.file );
p->io.file = NULL;
}
break;
}
}
long
syck_move_tokens( SyckParser *p )
{
long count, skip;
ASSERT( p->buffer != NULL );
if ( p->token == NULL )
return 0;
skip = p->limit - p->token;
if ( skip < 1 )
return 0;
#if REDEBUG
printf( "DIFF: %d\n", skip );
#endif
if ( ( count = p->token - p->buffer ) )
{
S_MEMMOVE( p->buffer, p->token, char, skip );
p->token = p->buffer;
p->marker -= count;
p->cursor -= count;
p->toktmp -= count;
p->limit -= count;
p->lineptr -= count;
}
return skip;
}
void
syck_check_limit( SyckParser *p, long len )
{
if ( p->cursor == NULL )
{
p->cursor = p->buffer;
p->lineptr = p->buffer;
p->marker = p->buffer;
}
p->limit = p->buffer + len;
}
long
syck_parser_read( SyckParser *p )
{
long len = 0;
long skip = 0;
ASSERT( p != NULL );
switch ( p->io_type )
{
case syck_io_str:
skip = syck_move_tokens( p );
len = (p->io.str->read)( p->buffer, p->io.str, SYCK_BUFFERSIZE - 1, skip );
break;
case syck_io_file:
skip = syck_move_tokens( p );
len = (p->io.file->read)( p->buffer, p->io.file, SYCK_BUFFERSIZE - 1, skip );
break;
}
syck_check_limit( p, len );
return len;
}
long
syck_parser_readlen( SyckParser *p, long max_size )
{
long len = 0;
long skip = 0;
ASSERT( p != NULL );
switch ( p->io_type )
{
case syck_io_str:
skip = syck_move_tokens( p );
len = (p->io.str->read)( p->buffer, p->io.str, max_size, skip );
break;
case syck_io_file:
skip = syck_move_tokens( p );
len = (p->io.file->read)( p->buffer, p->io.file, max_size, skip );
break;
}
syck_check_limit( p, len );
return len;
}
SYMID
syck_parse( SyckParser *p )
{
char *line;
ASSERT( p != NULL );
p->root = NULL;
syck_parser_reset_levels( p );
yyparse( p );
return p->root;
}
void
syck_default_error_handler( SyckParser *p, char *msg )
{
printf( "Error at [Line %d, Col %d]: %s\n",
p->linect,
p->cursor - p->lineptr,
msg );
}

257
ext/syck/syck.h Normal file
Просмотреть файл

@ -0,0 +1,257 @@
//
// syck.h
//
// $Author$
// $Date$
//
// Copyright (C) 2003 why the lucky stiff
//
#ifndef SYCK_H
#define SYCK_H
#define SYCK_VERSION "0.25"
#include <stdio.h>
#ifdef HAVE_ST_H
#include <st.h>
#else
#include "syck_st.h"
#endif
#if defined(__cplusplus)
extern "C" {
#endif
//
// Memory Allocation
//
#if defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
#include <alloca.h>
#endif
#if DEBUG
void syck_assert( char *, unsigned );
# define ASSERT(f) \
if ( f ) \
{} \
else \
syck_assert( __FILE__, __LINE__ )
#else
# define ASSERT(f)
#endif
#ifndef NULL
# define NULL (void *)0
#endif
#define ALLOC_CT 8
#define S_ALLOC_N(type,n) (type*)malloc(sizeof(type)*(n))
#define S_ALLOC(type) (type*)malloc(sizeof(type))
#define S_REALLOC_N(var,type,n) (var)=(type*)realloc((char*)(var),sizeof(type)*(n))
#define S_FREE(n) free(n); n = NULL;
#define S_ALLOCA_N(type,n) (type*)alloca(sizeof(type)*(n))
#define S_MEMZERO(p,type,n) memset((p), 0, sizeof(type)*(n))
#define S_MEMCPY(p1,p2,type,n) memcpy((p1), (p2), sizeof(type)*(n))
#define S_MEMMOVE(p1,p2,type,n) memmove((p1), (p2), sizeof(type)*(n))
#define S_MEMCMP(p1,p2,type,n) memcmp((p1), (p2), sizeof(type)*(n))
#define BLOCK_FOLD 10
#define BLOCK_LIT 20
#define BLOCK_PLAIN 30
#define NL_CHOMP 130
#define NL_KEEP 140
//
// Node definitions
//
#define SYMID unsigned long
typedef struct _syck_parser SyckParser;
typedef struct _syck_file SyckIoFile;
typedef struct _syck_str SyckIoStr;
typedef struct _syck_node SyckNode;
typedef struct _syck_level SyckLevel;
enum syck_kind_tag {
syck_map_kind,
syck_seq_kind,
syck_str_kind
};
enum map_part {
map_key,
map_value
};
struct _syck_node {
// Symbol table ID
SYMID id;
// Underlying kind
enum syck_kind_tag kind;
// Fully qualified tag-uri for type
char *type_id;
// Anchor name
char *anchor;
union {
// Storage for map data
struct SyckMap {
SYMID *keys;
SYMID *values;
long capa;
long idx;
} *pairs;
// Storage for sequence data
struct SyckSeq {
SYMID *items;
long capa;
long idx;
} *list;
// Storage for string data
struct SyckStr {
char *ptr;
long len;
} *str;
} data;
};
//
// Parser definitions
//
typedef SYMID (*SyckNodeHandler)(SyckParser *, SyckNode *);
typedef void (*SyckErrorHandler)(SyckParser *, char *);
typedef long (*SyckIoFileRead)(char *, SyckIoFile *, long, long);
typedef long (*SyckIoStrRead)(char *, SyckIoStr *, long, long);
enum syck_io_type {
syck_io_str,
syck_io_file
};
enum syck_level_status {
syck_lvl_header,
syck_lvl_doc,
syck_lvl_seq,
syck_lvl_block,
syck_lvl_str,
syck_lvl_inline,
syck_lvl_end,
syck_lvl_pause
};
struct _syck_parser {
// Root node
SYMID root;
// Implicit typing flag
int implicit_typing, taguri_expansion;
// Scripting language function to handle nodes
SyckNodeHandler handler;
// Error handler
SyckErrorHandler error_handler;
// IO type
enum syck_io_type io_type;
// Custom buffer size
size_t bufsize;
// Buffer pointers
char *buffer, *lineptr, *toktmp, *token, *cursor, *marker, *limit;
// Line counter
int linect;
// Last token from yylex()
int last_token;
// Force a token upon next call to yylex()
int force_token;
// EOF flag
int eof;
union {
struct _syck_file {
FILE *ptr;
SyckIoFileRead read;
} *file;
struct _syck_str {
char *beg, *ptr, *end;
SyckIoStrRead read;
} *str;
} io;
// Symbol table
st_table *anchors;
// Optional symbol table for SYMIDs
st_table *syms;
// Levels of indentation
struct _syck_level {
int spaces;
char *domain;
enum syck_level_status status;
} *levels;
int lvl_idx;
int lvl_capa;
void *bonus;
};
//
// Handler prototypes
//
SYMID syck_hdlr_add_node( SyckParser *, SyckNode * );
SyckNode *syck_hdlr_add_anchor( SyckParser *, char *, SyckNode * );
SyckNode *syck_hdlr_add_alias( SyckParser *, char * );
void syck_add_transfer( char *, SyckNode *, int );
void syck_xprivate( SyckNode *, char *, int );
void syck_taguri( SyckNode *, char *, char *, int );
int syck_add_sym( SyckParser *, char * );
int syck_lookup_sym( SyckParser *, SYMID, char ** );
int syck_try_implicit( SyckNode * );
void syck_fold_format( struct SyckStr *, int, int, int );
void try_tag_implicit( SyckNode *, int );
//
// API prototypes
//
char *syck_strndup( char *, long );
long syck_io_file_read( char *, SyckIoFile *, long, long );
long syck_io_str_read( char *, SyckIoStr *, long, long );
SyckParser *syck_new_parser();
void syck_free_parser( SyckParser * );
void syck_parser_implicit_typing( SyckParser *, int );
void syck_parser_taguri_expansion( SyckParser *, int );
void syck_parser_handler( SyckParser *, SyckNodeHandler );
void syck_parser_error_handler( SyckParser *, SyckErrorHandler );
void syck_parser_file( SyckParser *, FILE *, SyckIoFileRead );
void syck_parser_str( SyckParser *, char *, long, SyckIoStrRead );
void syck_parser_str_auto( SyckParser *, char *, SyckIoStrRead );
SyckLevel *syck_parser_current_level( SyckParser * );
void syck_parser_add_level( SyckParser *, int, enum syck_level_status );
void free_any_io( SyckParser * );
long syck_parser_read( SyckParser * );
long syck_parser_readlen( SyckParser *, long );
void syck_parser_init( SyckParser *, int );
SYMID syck_parse( SyckParser * );
void syck_default_error_handler( SyckParser *, char * );
//
// Allocation prototypes
//
SyckNode *syck_alloc_map();
SyckNode *syck_alloc_seq();
SyckNode *syck_alloc_str();
void syck_free_node( SyckNode * );
void syck_free_members( SyckNode * );
SyckNode *syck_new_str( char * );
SyckNode *syck_new_str2( char *, long );
void syck_str_blow_away_commas( SyckNode * );
char *syck_str_read( SyckNode * );
SyckNode *syck_new_map( SYMID, SYMID );
void syck_map_add( SyckNode *, SYMID, SYMID );
SYMID syck_map_read( SyckNode *, enum map_part, long );
long syck_map_count( SyckNode * );
void syck_map_update( SyckNode *, SyckNode * );
SyckNode *syck_new_seq( SYMID );
void syck_seq_add( SyckNode *, SYMID );
SYMID syck_seq_read( SyckNode *, long );
long syck_seq_count( SyckNode * );
#if defined(__cplusplus)
} /* extern "C" { */
#endif
#endif /* ifndef SYCK_H */

1638
ext/syck/token.c Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

119
lib/yaml.rb Normal file
Просмотреть файл

@ -0,0 +1,119 @@
# vim:sw=4:ts=4
# $Id$
#
# YAML.rb
#
# Loads the parser/loader and emitter/writer.
#
module YAML
begin
require 'syck'
Parser = YAML::Syck::Parser
rescue LoadError
require 'yaml/parser'
Parser = YAML::Parser
end
require 'yaml/emitter'
require 'yaml/rubytypes'
#
# Allocate blank object
#
def YAML.object_maker( obj_class, val )
if Hash === val
name = obj_class.name
o = ::Marshal.load( sprintf( "\004\006o:%c%s\000", name.length + 5, name ))
val.each_pair { |k,v|
o.instance_eval "@#{k} = v"
}
o
else
raise YAML::Error, "Invalid object explicitly tagged !ruby/Object: " + val.inspect
end
end
#
# Input methods
#
#
# Load a single document from the current stream
#
def YAML.load( io )
yp = YAML::Parser.new.parse( io )
end
#
# Parse a single document from the current stream
#
def YAML.parse( io )
yp = YAML::Parser.new( :Model => :Generic ).parse( io )
end
#
# Load all documents from the current stream
#
def YAML.each_document( io, &doc_proc )
yp = YAML::Parser.new.parse_documents( io, &doc_proc )
end
#
# Identical to each_document
#
def YAML.load_documents( io, &doc_proc )
YAML.each_document( io, &doc_proc )
end
#
# Parse all documents from the current stream
#
def YAML.each_node( io, &doc_proc )
yp = YAML::Parser.new( :Model => :Generic ).parse_documents( io, &doc_proc )
end
#
# Parse all documents from the current stream
#
def YAML.parse_documents( io, &doc_proc )
YAML.each_node( io, &doc_proc )
end
#
# Load all documents from the current stream
#
def YAML.load_stream( io )
yp = YAML::Parser.new
d = nil
yp.parse_documents( io ) { |doc|
d = YAML::Stream.new( yp.options ) if not d
d.add( doc )
}
return d
end
end
#
# ryan: You know how Kernel.p is a really convenient way to dump ruby
# structures? The only downside is that it's not as legible as
# YAML.
#
# _why: (listening)
#
# ryan: I know you don't want to urinate all over your users' namespaces.
# But, on the other hand, convenience of dumping for debugging is,
# IMO, a big YAML use case.
#
# _why: Go nuts! Have a pony parade!
#
# ryan: Either way, I certainly will have a pony parade.
#
module Kernel
def y( x )
puts x.to_yaml
end
end

216
lib/yaml/basenode.rb Normal file
Просмотреть файл

@ -0,0 +1,216 @@
#
# YAML::BaseNode class
#
require 'yaml/ypath'
module YAML
#
# YAML Generic Model container
#
module BaseNode
#
# Search for YPath entry and return
# qualified nodes.
#
def select( ypath_str )
matches = match_path( ypath_str )
#
# Create a new generic view of the elements selected
#
if matches
result = []
matches.each { |m|
result.push m.last
}
YamlNode.new( 'seq', result )
end
end
#
# Search for YPath entry and return
# transformed nodes.
#
def select!( ypath_str )
matches = match_path( ypath_str )
#
# Create a new generic view of the elements selected
#
if matches
result = []
matches.each { |m|
result.push m.last.transform
}
result
end
end
#
# Search for YPath entry and return a list of
# qualified paths.
#
def search( ypath_str )
matches = match_path( ypath_str )
if matches
matches.collect { |m|
path = []
m.each_index { |i|
path.push m[i] if ( i % 2 ).zero?
}
"/" + path.compact.join( "/" )
}
end
end
def at( seg )
if Hash === @value and @value.has_key?( seg )
@value[seg][1]
elsif Array === @value and seg =~ /\A\d+\Z/ and @value[seg.to_i]
@value[seg.to_i]
end
end
#
# YPath search returning a complete depth array
#
def match_path( ypath_str )
depth = 0
matches = []
YPath.each_path( ypath_str ) do |ypath|
seg = match_segment( ypath, 0 )
matches += seg if seg
end
matches.uniq
end
#
# Search a node for a single YPath segment
#
def match_segment( ypath, depth )
deep_nodes = []
seg = ypath.segments[ depth ]
if seg == "/"
unless String === @value
idx = -1
@value.collect { |v|
idx += 1
if Hash === @value
match_init = [v[0], v[1][1]]
match_deep = v[1][1].match_segment( ypath, depth )
else
match_init = [idx, v]
match_deep = v.match_segment( ypath, depth )
end
if match_deep
match_deep.each { |m|
deep_nodes.push( match_init + m )
}
end
}
end
depth += 1
seg = ypath.segments[ depth ]
end
match_nodes =
case seg
when "."
[[nil, self]]
when ".."
[["..", nil]]
when "*"
if @value.is_a? Enumerable
idx = -1
@value.collect { |h|
idx += 1
if Hash === @value
[h[0], h[1][1]]
else
[idx, h]
end
}
end
else
if seg =~ /^"(.*)"$/
seg = $1
elsif seg =~ /^'(.*)'$/
seg = $1
end
if ( v = at( seg ) )
[[ seg, v ]]
end
end
return deep_nodes unless match_nodes
pred = ypath.predicates[ depth ]
if pred
case pred
when /^\.=/
pred = $'
match_nodes.reject! { |n|
n.last.value != pred
}
else
match_nodes.reject! { |n|
n.last.at( pred ).nil?
}
end
end
return match_nodes + deep_nodes unless ypath.segments.length > depth + 1
#puts "DEPTH: #{depth + 1}"
deep_nodes = []
match_nodes.each { |n|
if n[1].is_a? YamlNode
match_deep = n[1].match_segment( ypath, depth + 1 )
if match_deep
match_deep.each { |m|
deep_nodes.push( n + m )
}
end
else
deep_nodes = []
end
}
deep_nodes = nil if deep_nodes.length == 0
deep_nodes
end
#
# We want the node to act like as Hash
# if it is.
#
def []( *k )
if Hash === @value
v = @value.[]( *k )
v[1] if v
elsif Array === @value
@value.[]( *k )
end
end
def children
if Hash === @value
@value.values.collect { |c| c[1] }
elsif Array === @value
@value
end
end
def children_with_index
if Hash === @value
@value.keys.collect { |i| [self[i], i] }
elsif Array === @value
i = -1; @value.collect { |v| i += 1; [v, i] }
end
end
def emit
transform.to_yaml
end
end
end

51
lib/yaml/constants.rb Normal file
Просмотреть файл

@ -0,0 +1,51 @@
#
# Constants used throughout the library
#
module YAML
#
# Constants
#
VERSION = '0.60'
SUPPORTED_YAML_VERSIONS = ['1.0']
#
# Parser tokens
#
WORD_CHAR = 'A-Za-z0-9'
PRINTABLE_CHAR = '-_A-Za-z0-9!?/()$\'". '
NOT_PLAIN_CHAR = '\x7f\x0-\x1f\x80-\x9f'
ESCAPE_CHAR = '[\\x00-\\x08\\x0b-\\x0d\\x0e-\\x1f]'
INDICATOR_CHAR = '*&!|\\\\^@%{}[]='
SPACE_INDICATORS = '-#:,?'
RESTRICTED_INDICATORS = '#:,}]'
DNS_COMP_RE = "\\w(?:[-\\w]*\\w)?"
DNS_NAME_RE = "(?:(?:#{DNS_COMP_RE}\\.)+#{DNS_COMP_RE}|#{DNS_COMP_RE})"
ESCAPES = %w{\z \x01 \x02 \x03 \x04 \x05 \x06 \a
\x08 \t \n \v \f \r \x0e \x0f
\x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17
\x18 \x19 \x1a \e \x1c \x1d \x1e \x1f
}
UNESCAPES = {
'z' => "\x00", 'a' => "\x07", 'b' => "\x08", 't' => "\x09",
'n' => "\x0a", 'v' => "\x0b", 'f' => "\x0c",
'r' => "\x0d", 'e' => "\x1b", '\\' => '\\',
}
#
# Default settings
#
DEFAULTS = {
:Indent => 2, :UseHeader => false, :UseVersion => false, :Version => '1.0',
:SortKeys => false, :AnchorFormat => 'id%03d', :ExplicitTypes => false,
:WidthType => 'absolute', :BestWidth => 80,
:UseBlock => false, :UseFold => false, :Encoding => :None
}
TRANSFER_DOMAINS = {
'yaml.org,2002' => {},
'ruby.yaml.org,2002' => {}
}
PRIVATE_TYPES = {}
IMPLICIT_TYPES = [ 'null', 'bool', 'time', 'int', 'float' ]
end

111
lib/yaml/dbm.rb Normal file
Просмотреть файл

@ -0,0 +1,111 @@
require 'yaml'
require 'dbm'
#
# YAML + DBM = YDBM
# - Same interface as DBM class
#
module YAML
class DBM < ::DBM
VERSION = "0.1"
def []( key )
fetch( key )
end
def []=( key, val )
store( key, val )
end
def fetch( keystr, ifnone = nil )
begin
val = super( keystr )
return YAML::load( val ) if String === val
rescue IndexError
end
if block_given?
yield keystr
else
ifnone
end
end
def index( keystr )
super( keystr.to_yaml )
end
def indexes( *keys )
keys.collect { |k| fetch( k ) }
end
def delete( key )
v = super( key )
if String === v
v = YAML::load( v )
end
v
end
def delete_if
del_keys = keys.dup
del_keys.delete_if { |k| yield( k, fetch( k ) ) == false }
del_keys.each { |k| delete( k ) }
self
end
def reject
hsh = self.to_hash
hsh.reject { |k,v| yield k, v }
end
def each_pair
keys.each { |k| yield k, fetch( k ) }
self
end
def each_value
super { |v| yield YAML::load( v ) }
self
end
def values
super.collect { |v| YAML::load( v ) }
end
def has_value?( val )
each_value { |v| return true if v == val }
return false
end
def invert
h = {}
keys.each { |k| h[ self.fetch( k ) ] = k }
h
end
def replace( hsh )
clear
update( hsh )
end
def shift
a = super
a[1] = YAML::load( a[1] ) if a
a
end
def select( *keys )
if block_given?
self.keys.collect { |k| v = self[k]; [k, v] if yield k, v }.compact
else
indexes( *keys )
end
end
def store( key, val )
super( key, val.to_yaml )
val
end
def update( hsh )
hsh.keys.each do |k|
self.store( k, hsh.fetch( k ) )
end
self
end
def to_a
a = []
keys.each { |k| a.push [ k, self.fetch( k ) ] }
a
end
def to_hash
h = {}
keys.each { |k| h[ k ] = self.fetch( k ) }
h
end
alias :each :each_pair
end
end

330
lib/yaml/emitter.rb Normal file
Просмотреть файл

@ -0,0 +1,330 @@
#
# Output classes and methods
#
require 'yaml/constants'
require 'yaml/encoding'
require 'yaml/error'
module YAML
#
# Emit a set of values
#
class Emitter
attr_accessor :options
def initialize( opts )
opts = {} if opts.class != Hash
@options = YAML::DEFAULTS.dup.update( opts )
@headless = 0
@seq_map = false
@anchors = {}
@anchor_extras = {}
@active_anchors = []
@level = -1
self.clear
end
def clear
@buffer = []
end
#
# Version string
#
def version_s
" %YAML:#{@options[:Version]}" if @options[:UseVersion]
end
#
# Header
#
def header
if @headless.nonzero?
""
else
"---#{version_s} "
end
end
#
# Emit binary data
#
def binary_base64( value )
self << "!binary "
self.node_text( [value].pack("m"), '|' )
end
#
# Emit plain, normal flowing text
#
def node_text( value, block = '>' )
valx = value.dup
if @options[:UseBlock]
block = '|'
elsif not @options[:UseFold] and valx =~ /\n[ \t]/ and not valx =~ /#{YAML::ESCAPE_CHAR}/
block = '|'
end
str = block.dup
if valx =~ /\n\Z\n/
str << "+"
elsif valx =~ /\Z\n/
else
str << "-"
end
if valx =~ /#{YAML::ESCAPE_CHAR}/
valx = YAML::escape( valx )
end
if valx =~ /\A[ \t#]/
str << @options[:Indent].to_s
end
if block == '>'
valx = fold( valx )
end
self << str + indent_text( valx ) + "\n"
end
#
# Emit a simple, unqouted string
#
def simple( value )
self << value.to_s
end
#
# Emit double-quoted string
#
def double( value )
"\"#{YAML.escape( value )}\""
end
#
# Emit single-quoted string
#
def single( value )
"'#{value}'"
end
#
# Write a text block with the current indent
#
def indent_text( text )
return "" if text.to_s.empty?
spacing = " " * ( @level * @options[:Indent] )
return "\n" + text.gsub( /^([^\n])/, "#{spacing}\\1" )
end
#
# Write a current indent
#
def indent
#p [ self.id, @level, :INDENT ]
return " " * ( @level * @options[:Indent] )
end
#
# Add indent to the buffer
#
def indent!
self << indent
end
#
# Folding paragraphs within a column
#
def fold( value )
value.gsub!( /\A\n+/, '' )
folded = $&.to_s
width = (0..@options[:BestWidth])
while not value.empty?
last = value.index( /(\n+)/ )
chop_s = false
if width.include?( last )
last += $1.length - 1
elsif width.include?( value.length )
last = value.length
else
last = value.rindex( /[ \t]/, @options[:BestWidth] )
chop_s = true
end
folded += value.slice!( 0, width.include?( last ) ? last + 1 : @options[:BestWidth] )
folded.chop! if chop_s
folded += "\n" unless value.empty?
end
folded
end
#
# Quick mapping
#
def map( type, &e )
val = Mapping.new
e.call( val )
self << "#{type} " if type.length.nonzero?
#
# Empty hashes
#
if val.length.zero?
self << "{}"
else
if @buffer.length == 1 and @options[:UseHeader] == false and type.length.zero?
@headless = 1
end
defkey = @options.delete( :DefaultKey )
if defkey
seq_map_shortcut
self << "= : "
defkey.to_yaml( :Emitter => self )
end
#
# Emit the key and value
#
val.each { |v|
seq_map_shortcut
if v[0].is_complex_yaml?
self << "? "
end
v[0].to_yaml( :Emitter => self )
if v[0].is_complex_yaml?
self << "\n"
indent!
end
self << ": "
v[1].to_yaml( :Emitter => self )
}
end
end
def seq_map_shortcut
if @seq_map
@anchor_extras[@buffer.length - 1] = "\n" + indent
@seq_map = false
else
self << "\n"
indent!
end
end
#
# Quick sequence
#
def seq( type, &e )
val = Sequence.new
e.call( val )
self << "#{type} " if type.length.nonzero?
#
# Empty arrays
#
if val.length.zero?
self << "[]"
else
if @buffer.length == 1 and @options[:UseHeader] == false and type.length.zero?
@headless = 1
end
#
# Emit the key and value
#
val.each { |v|
self << "\n"
indent!
self << "- "
@seq_map = true if v.class == Hash
v.to_yaml( :Emitter => self )
}
end
end
#
# Concatenate to the buffer
#
def <<( str )
#p [ self.id, @level, str ]
@buffer.last << str
end
#
# Monitor objects and allow references
#
def start_object( oid )
@level += 1
@buffer.push( "" )
#p [ self.id, @level, :OPEN ]
idx = nil
if oid
if @anchors.has_key?( oid )
idx = @active_anchors.index( oid )
unless idx
idx = @active_anchors.length
af_str = "&#{@options[:AnchorFormat]} " % [ idx + 1 ]
af_str += @anchor_extras[ @anchors[ oid ] ].to_s
@buffer[ @anchors[ oid ] ][0,0] = af_str
@headless = 0 if @anchors[ oid ].zero?
end
idx += 1
@active_anchors.push( oid )
else
@anchors[ oid ] = @buffer.length - 1
end
end
return idx
end
#
# Output method
#
def end_object
@level -= 1
@buffer.push( "" )
#p [ self.id, @level, :END ]
if @level < 0
YAML.internal_to_utf( header + @buffer.to_s[@headless..-1], @options[:Encoding] )
end
end
end
#
# Emitter helper classes
#
class Mapping < Array
def add( k, v )
push [k, v]
end
end
class Sequence < Array
def add( v )
push v
end
end
#
# Allocate an Emitter if needed
#
def YAML.quick_emit( oid, opts = {}, &e )
old_opt = nil
if opts[:Emitter].is_a? YAML::Emitter
out = opts.delete( :Emitter )
old_opt = out.options.dup
out.options.update( opts )
else
out = YAML::Emitter.new( opts )
end
aidx = out.start_object( oid )
if aidx
out.simple( "*#{out.options[:AnchorFormat]} " % [ aidx ] )
else
e.call( out )
end
if old_opt.is_a? Hash
out.options = old_opt
end
out.end_object
end
end

123
lib/yaml/encoding.rb Normal file
Просмотреть файл

@ -0,0 +1,123 @@
#
# Handle Unicode-to-Internal conversion
#
module YAML
#
# Encodings ( $-K to ICONV )
#
CHARSETS = {
'NONE' => 'LATIN1',
'ASCII' => 'US-ASCII',
'UTF-8' => 'UTF-8',
'EUC' => 'EUC-JP',
'SJIS' => 'SHIFT-JIS'
}
#
# YAML documents can be in UTF-8, UTF-16 or UTF-32
# So let's read and write in Unicode
#
@@unicode = false
begin
require 'iconv'
DEFAULTS[:Encoding] = :Utf8
rescue LoadError
end
def YAML.unicode; @@unicode; end
def YAML.unicode=( bool ); @@unicode = bool; end
#
# Unicode conversion
#
def YAML.utf_to_internal( str, from_enc )
return unless str
to_enc = CHARSETS[$-K]
case from_enc
when :Utf32
Iconv.iconv( to_enc, 'UTF-32', str )[0]
when :Utf16
Iconv.iconv( to_enc, 'UTF-16', str )[0]
when :Utf8
Iconv.iconv( to_enc, 'UTF-8', str )[0]
when :None
str
else
raise YAML::Error, ERROR_UNSUPPORTED_ENCODING % from_enc.inspect
end
end
def YAML.internal_to_utf( str, to_enc )
return unless str
from_enc = CHARSETS[$-K]
case to_enc
when :Utf32
Iconv.iconv( 'UTF-32', from_enc, str )[0]
when :Utf16
Iconv.iconv( 'UTF-16', from_enc, str )[0]
when :Utf8
Iconv.iconv( 'UTF-8', from_enc, str )[0]
when :None
str
else
raise YAML::Error, ERROR_UNSUPPORTED_ENCODING % to_enc.inspect
end
end
def YAML.sniff_encoding( str )
unless YAML::unicode
:None
else
case str
when /^\x00\x00\xFE\xFF/ # UTF-32
:Utf32
when /^\xFE\xFF/ # UTF-32BE
:Utf16
else
:Utf8
end
end
end
def YAML.enc_separator( enc )
case enc
when :Utf32
"\000\000\000\n"
when :Utf16
"\000\n"
when :Utf8
"\n"
when :None
"\n"
else
raise YAML::Error, ERROR_UNSUPPORTED_ENCODING % enc.inspect
end
end
#
# Escape the string, condensing common escapes
#
def YAML.escape( value )
value.gsub( /\\/, "\\\\\\" ).gsub( /"/, "\\\"" ).gsub( /([\x00-\x1f])/ ) { |x| ESCAPES[ x.unpack("C")[0] ] }
end
#
# Unescape the condenses escapes
#
def YAML.unescape( value )
value.gsub( /\\(?:([nevbr\\fartz])|0?x([0-9a-fA-F]{2})|u([0-9a-fA-F]{4}))/ ) { |x|
if $3
["#$3".hex ].pack('U*')
elsif $2
[$2].pack( "H2" )
else
UNESCAPES[$1]
end
}
end
end

33
lib/yaml/error.rb Normal file
Просмотреть файл

@ -0,0 +1,33 @@
#
# Error messages and exception class
#
module YAML
#
# Error messages
#
ERROR_NO_HEADER_NODE = "With UseHeader=false, the node Array or Hash must have elements"
ERROR_NEED_HEADER = "With UseHeader=false, the node must be an Array or Hash"
ERROR_BAD_EXPLICIT = "Unsupported explicit transfer: '%s'"
ERROR_MANY_EXPLICIT = "More than one explicit transfer"
ERROR_MANY_IMPLICIT = "More than one implicit request"
ERROR_NO_ANCHOR = "No anchor for alias '%s'"
ERROR_BAD_ANCHOR = "Invalid anchor: %s"
ERROR_MANY_ANCHOR = "More than one anchor"
ERROR_ANCHOR_ALIAS = "Can't define both an anchor and an alias"
ERROR_BAD_ALIAS = "Invalid alias: %s"
ERROR_MANY_ALIAS = "More than one alias"
ERROR_ZERO_INDENT = "Can't use zero as an indentation width"
ERROR_UNSUPPORTED_VERSION = "This release of YAML.rb does not support YAML version %s"
ERROR_UNSUPPORTED_ENCODING = "Attempt to use unsupported encoding: %s"
#
# YAML Error classes
#
class Error < StandardError; end
class ParseError < Error; end
end

558
lib/yaml/rubytypes.rb Normal file
Просмотреть файл

@ -0,0 +1,558 @@
require 'date'
#
# Type conversions
#
class Object
def is_complex_yaml?
true
end
def to_yaml_type
"!ruby/object:#{self.class}"
end
def to_yaml_properties
instance_variables.sort
end
def to_yaml( opts = {} )
YAML::quick_emit( self.id, opts ) { |out|
out.map( self.to_yaml_type ) { |map|
to_yaml_properties.each { |m|
map.add( m[1..-1], instance_eval( m ) )
}
}
}
end
end
YAML.add_ruby_type( Object ) { |type, val|
type, obj_class = YAML.read_type_class( type, Object )
YAML.object_maker( obj_class, val )
}
#
# Maps: Hash#to_yaml
#
class Hash
def is_complex_yaml?
true
end
def to_yaml_type
if self.class == Hash or self.class == YAML::SpecialHash
"!map"
else
"!ruby/hash:#{self.class}"
end
end
def to_yaml( opts = {} )
opts[:DocType] = self.class if Hash === opts
YAML::quick_emit( self.id, opts ) { |out|
hash_type = to_yaml_type
if not out.options[:ExplicitTypes] and hash_type == "!map"
hash_type = ""
end
out.map( hash_type ) { |map|
#
# Sort the hash
#
if out.options[:SortKeys]
map.concat( self.sort )
else
map.concat( self.to_a )
end
}
}
end
end
hash_proc = Proc.new { |type, val|
if Array === val
val = Hash.[]( *val ) # Convert the map to a sequence
elsif Hash === val
type, obj_class = YAML.read_type_class( type, Hash )
if obj_class != Hash
o = obj_class.new
o.update( val )
val = o
end
else
raise YAML::Error, "Invalid map explicitly tagged !map: " + val.inspect
end
val
}
YAML.add_builtin_type( /^map/, &hash_proc )
YAML.add_ruby_type( Hash, &hash_proc )
module YAML
#
# Ruby-specific collection: !ruby/flexhash
#
class FlexHash < Array
def []( k )
self.assoc( k ).to_a[1]
end
def []=( k, *rest )
val, set = rest.reverse
if ( tmp = self.assoc( k ) ) and not set
tmp[1] = val
else
self << [ k, val ]
end
val
end
def has_key?( k )
self.assoc( k ) ? true : false
end
def is_complex_yaml?
true
end
def to_yaml( opts = {} )
YAML::quick_emit( self.id, opts ) { |out|
out.seq( "!ruby/flexhash" ) { |seq|
self.each { |v|
if v[1]
seq.add( Hash.[]( *v ) )
else
seq.add( v[0] )
end
}
}
}
end
end
YAML.add_ruby_type( :flexhash ) { |type, val|
if Array === val
p = FlexHash.new
val.each { |v|
if Hash === v
p.concat( v.to_a ) # Convert the map to a sequence
else
p << [ v, nil ]
end
}
p
else
raise YAML::Error, "Invalid !ruby/flexhash: " + val.inspect
end
}
end
#
# Structs: export as a !map
#
class Struct
def is_complex_yaml?
true
end
def to_yaml( opts = {} )
YAML::quick_emit( self.id, opts ) { |out|
#
# Basic struct is passed as a YAML map
#
struct_name = self.class.name.gsub( "Struct:", "" )
out.map( "!ruby/struct#{struct_name}" ) { |map|
self.members.each { |m|
map.add( m, self[m] )
}
}
}
end
end
YAML.add_ruby_type( Struct ) { |type, val|
type =~ /^struct:(\w+)/
if Hash === val
type = $1
struct_type = nil
struct_def = []
struct_name = ""
if $1.to_s.length > 1
struct_name = $1[0..$1.length]
struct_def << struct_name
end
#
# Use existing Struct if it exists
#
begin
struct_type = Struct.const_get( struct_name )
rescue NameError
end
if not struct_type
struct_type = Struct.new( *struct_def.concat( val.keys.collect { |k| k.intern } ) )
end
#
# Set the Struct properties
#
st = struct_type.new
st.members.each { |m|
st.send( "#{m}=", val[m] )
}
st
else
raise YAML::Error, "Invalid Ruby Struct: " + val.inspect
end
}
#
# Sequences: Array#to_yaml
#
class Array
def is_complex_yaml?
true
end
def to_yaml_type
if self.class == Array
"!seq"
else
"!ruby/array:#{self.class}"
end
end
def to_yaml( opts = {} )
opts[:DocType] = self.class if Hash === opts
YAML::quick_emit( self.id, opts ) { |out|
array_type = to_yaml_type
if not out.options[:ExplicitTypes] and array_type == "!seq"
array_type = ""
end
out.seq( array_type ) { |seq|
seq.concat( self )
}
}
end
end
array_proc = Proc.new { |type, val|
if Array === val
type, obj_class = YAML.read_type_class( type, Array )
if obj_class != Array
o = obj_class.new
o.concat( val )
val = o
end
val
else
val.to_a
end
}
YAML.add_builtin_type( /^seq/, &array_proc )
YAML.add_ruby_type( Array, &array_proc )
#
# String#to_yaml
#
class String
def is_complex_yaml?
( self =~ /\n.+/ ? true : false )
end
def is_binary_data?
( self.count( "^ -~", "^\r\n" ) / self.size > 0.3 || self.count( "\x00" ) > 0 )
end
def to_yaml( opts = {} )
complex = false
if self.is_complex_yaml?
complex = true
elsif opts[:BestWidth].to_i > 0
if self.length > opts[:BestWidth] and opts[:UseFold]
complex = true
end
end
YAML::quick_emit( complex ? self.id : nil, opts ) { |out|
if complex
if self.is_binary_data?
out.binary_base64( self )
else
out.node_text( self )
end
else
ostr = if out.options[:KeepValue]
self
elsif empty?
"''"
elsif YAML.detect_implicit( self ) != 'str'
"\"#{YAML.escape( self )}\""
elsif self =~ /#{YAML::ESCAPE_CHAR}|[#{YAML::SPACE_INDICATORS}] |\n|\'/
"\"#{YAML.escape( self )}\""
elsif self =~ /^[^#{YAML::WORD_CHAR}]/
"\"#{YAML.escape( self )}\""
else
self
end
out.simple( ostr )
end
}
end
end
YAML.add_builtin_type( 'str' ) { |type,val| val.to_s }
YAML.add_builtin_type( 'binary' ) { |type,val|
enctype = "m"
if String === val
val.gsub( /\s+/, '' ).unpack( enctype )[0]
else
raise YAML::Error, "Binary data must be represented by a string: " + val.inspect
end
}
#
# Symbol#to_yaml
#
class Symbol
def is_complex_yaml?
false
end
def to_yaml( opts = {} )
YAML::quick_emit( nil, opts ) { |out|
out << "!ruby/sym "
self.id2name.to_yaml( :Emitter => out )
}
end
end
symbol_proc = Proc.new { |type, val|
if String === val
val.intern
else
raise YAML::Error, "Invalid Symbol: " + val.inspect
end
}
YAML.add_ruby_type( Symbol, &symbol_proc )
YAML.add_ruby_type( :sym, &symbol_proc )
#
# Range#to_yaml
#
class Range
def is_complex_yaml?
false
end
def to_yaml( opts = {} )
YAML::quick_emit( nil, opts ) { |out|
out << "!ruby/range "
self.inspect.to_yaml( :Emitter => out )
}
end
end
YAML.add_ruby_type( Range ) { |type, val|
if String === val and val =~ /^(.*[^.])(\.{2,3})([^.].*)$/
r1, rdots, r2 = $1, $2, $3
Range.new( YAML.try_implicit( r1 ), YAML.try_implicit( r2 ), rdots.length == 3 )
elsif Hash === val
Range.new( val['begin'], val['end'], val['exclude_end?'] )
else
raise YAML::Error, "Invalid Range: " + val.inspect
end
}
#
# Make an RegExp
#
class Regexp
def is_complex_yaml?
false
end
def to_yaml( opts = {} )
YAML::quick_emit( nil, opts ) { |out|
out << "!ruby/regexp "
self.inspect.to_yaml( :Emitter => out )
}
end
end
regexp_proc = Proc.new { |type, val|
if String === val and val =~ /^\/(.*)\/([mix]*)$/
val = { 'REGEXP' => $1, 'MODIFIERS' => $2 }
end
if Hash === val
mods = nil
unless val['MODIFIERS'].to_s.empty?
mods = 0x00
if val['MODIFIERS'].include?( 'x' )
mods |= Regexp::EXTENDED
elsif val['MODIFIERS'].include?( 'i' )
mods |= Regexp::IGNORECASE
elsif val['MODIFIERS'].include?( 'm' )
mods |= Regexp::POSIXLINE
end
end
Regexp::compile( val['REGEXP'], mods )
else
raise YAML::Error, "Invalid Regular expression: " + val.inspect
end
}
YAML.add_domain_type( "perl.yaml.org,2002", /^regexp/, &regexp_proc )
YAML.add_ruby_type( Regexp, &regexp_proc )
#
# Emit a Time object as an ISO 8601 timestamp
#
class Time
def is_complex_yaml?
false
end
def to_yaml( opts = {} )
YAML::quick_emit( nil, opts ) { |out|
tz = "Z"
# from the tidy Tobias Peters <t-peters@gmx.de> Thanks!
unless self.utc?
utc_same_instant = self.dup.utc
utc_same_writing = Time.utc(year,month,day,hour,min,sec,usec)
difference_to_utc = utc_same_writing - utc_same_instant
if (difference_to_utc < 0)
difference_sign = '-'
absolute_difference = -difference_to_utc
else
difference_sign = '+'
absolute_difference = difference_to_utc
end
difference_minutes = (absolute_difference/60).round
tz = "%s%02d:%02d" % [ difference_sign, difference_minutes / 60, difference_minutes % 60]
end
( self.strftime( "%Y-%m-%d %H:%M:%S." ) +
"%06d %s" % [usec, tz] ).
to_yaml( :Emitter => out, :KeepValue => true )
}
end
end
YAML.add_builtin_type( 'time' ) { |type, val|
if val =~ /\A(\d{4})\-(\d{1,2})\-(\d{1,2})[Tt](\d{2})\:(\d{2})\:(\d{2})(\.\d{1,2})?(Z|[-+][0-9][0-9](?:\:[0-9][0-9])?)\Z/
YAML.mktime( *$~.to_a[1,8] )
elsif val =~ /\A(\d{4})\-(\d{1,2})\-(\d{1,2})[ \t]+(\d{2})\:(\d{2})\:(\d{2})(\.\d+)?[ \t]+(Z|[-+][0-9][0-9](?:\:[0-9][0-9])?)\Z/
YAML.mktime( *$~.to_a[1,8] )
elsif val =~ /\A(\d{4})\-(\d{1,2})\-(\d{1,2})[ \t]+(\d{2})\:(\d{2})\:(\d{2})(\.\d{1,2})?\Z/
YAML.mktime( *$~.to_a[1,7] )
elsif val =~ /\A(\d{4})\-(\d{1,2})\-(\d{1,2})\Z/
Date.new($1.to_i, $2.to_i, $3.to_i)
elsif type == :Implicit
:InvalidType
else
raise YAML::TypeError, "Invalid !time string: " + val.inspect
end
}
#
# Emit a Date object as a simple implicit
#
class Date
def is_complex_yaml?
false
end
def to_yaml( opts = {} )
opts[:KeepValue] = true
self.to_s.to_yaml( opts )
end
end
#
# Send Integer, Booleans, NilClass to String
#
class Numeric
def is_complex_yaml?
false
end
def to_yaml( opts = {} )
str = self.to_s
if str == "Infinity"
str = ".Inf"
elsif str == "-Infinity"
str = "-.Inf"
elsif str == "NaN"
str = ".NaN"
end
opts[:KeepValue] = true
str.to_yaml( opts )
end
end
YAML.add_builtin_type( 'float' ) { |type, val|
if val =~ /\A[-+]?[\d][\d,]*\.[\d,]*[eE][-+][0-9]+\Z/ # Float (exponential)
$&.tr( ',', '' ).to_f
elsif val =~ /\A[-+]?[\d][\d,]*\.[\d,]*\Z/ # Float (fixed)
$&.tr( ',', '' ).to_f
elsif val =~ /\A([-+]?)\.(inf|Inf|INF)\Z/ # Float (english)
( $1 == "-" ? -1.0/0.0 : 1.0/0.0 )
elsif val =~ /\A\.(nan|NaN|NAN)\Z/
0.0/0.0
elsif type == :Implicit
:InvalidType
else
val.to_f
end
}
YAML.add_builtin_type( 'int' ) { |type, val|
if val =~ /\A[-+]?0[0-7,]+\Z/ # Integer (octal)
$&.oct
elsif val =~ /\A[-+]?0x[0-9a-fA-F,]+\Z/ # Integer (hex)
$&.hex
elsif val =~ /\A[-+]?\d[\d,]*\Z/ # Integer (canonical)
$&.tr( ',', '' ).to_i
elsif val =~ /\A([-+]?)(\d[\d,]*(?::[0-5]?[0-9])+)\Z/
sign = ( $1 == '-' ? -1 : 1 )
digits = $2.split( /:/ ).collect { |x| x.to_i }
val = 0; digits.each { |x| val = ( val * 60 ) + x }; val *= sign
elsif type == :Implicit
:InvalidType
else
val.to_i
end
}
class TrueClass
def is_complex_yaml?
false
end
def to_yaml( opts = {} )
opts[:KeepValue] = true
"true".to_yaml( opts )
end
end
class FalseClass
def is_complex_yaml?
false
end
def to_yaml( opts = {} )
opts[:KeepValue] = true
"false".to_yaml( opts )
end
end
YAML.add_builtin_type( 'bool' ) { |type, val|
if val =~ /\A(\+|true|True|TRUE|yes|Yes|YES|on|On|ON)\Z/
true
elsif val =~ /\A(\-|false|False|FALSE|no|No|NO|off|Off|OFF)\Z/
false
elsif type == :Implicit
:InvalidType
else
raise YAML::TypeError, "Invalid !bool string: " + val.inspect
end
}
class NilClass
def is_complex_yaml?
false
end
def to_yaml( opts = {} )
opts[:KeepValue] = true
"".to_yaml( opts )
end
end
YAML.add_builtin_type( 'null' ) { |type, val|
if val =~ /\A(\~|null|Null|NULL)\Z/
nil
elsif val.empty?
nil
elsif type == :Implicit
:InvalidType
else
raise YAML::TypeError, "Invalid !null string: " + val.inspect
end
}

75
lib/yaml/store.rb Normal file
Просмотреть файл

@ -0,0 +1,75 @@
#
# YAML::Store
#
require 'yaml'
require 'pstore'
module YAML
class Store < PStore
#
# Constructor
#
def initialize( *o )
@opt = YAML::DEFAULTS.dup
if String === o.first
super(o.pop)
end
if o.last.is_a? Hash
@opt.update(o.pop)
end
end
#
# Override Pstore#transaction
#
def transaction
raise YAML::Error, "nested transaction" if @transaction
raise YAML::Error, "no filename for transaction" unless @filename
begin
@transaction = true
value = nil
backup = @filename+"~"
if File::exist?(@filename)
file = File::open(@filename, "rb+")
orig = true
else
@table = {}
file = File::open(@filename, "wb+")
file.write( @table.to_yaml( @opt ) )
end
file.flock(File::LOCK_EX)
if orig
File::copy @filename, backup
@table = YAML::load( file )
end
begin
catch(:pstore_abort_transaction) do
value = yield(self)
end
rescue Exception
@abort = true
raise
ensure
unless @abort
begin
file.rewind
file.write( @table.to_yaml( @opt ) )
file.truncate(file.pos)
rescue
File::rename backup, @filename if File::exist?(backup)
raise
end
end
@abort = false
end
ensure
@table = nil
@transaction = false
file.close if file
end
value
end
end
end

44
lib/yaml/stream.rb Normal file
Просмотреть файл

@ -0,0 +1,44 @@
module YAML
#
# YAML::Stream -- for emitting many documents
#
class Stream
attr_accessor :documents, :options
def initialize( opts = {} )
@options = opts
@documents = []
end
def []( i )
@documents[ i ]
end
def add( doc )
@documents << doc
end
def edit( doc_num, doc )
@documents[ doc_num ] = doc
end
def emit
opts = @options.dup
opts[:UseHeader] = true if @documents.length > 1
ct = 0
out = Emitter.new( opts )
@documents.each { |v|
if ct > 0
out << "\n--- "
end
v.to_yaml( :Emitter => out )
ct += 1
}
out.end_object
end
end
end

83
lib/yaml/stringio.rb Normal file
Просмотреть файл

@ -0,0 +1,83 @@
#
# Limited StringIO if no core lib is available
#
begin
require 'stringio'
rescue LoadError
# StringIO based on code by MoonWolf
class StringIO
def initialize(string="")
@string=string
@pos=0
@eof=(string.size==0)
end
def pos
@pos
end
def eof
@eof
end
alias eof? eof
def readline(rs=$/)
if @eof
raise EOFError
else
if p = @string[@pos..-1]=~rs
line = @string[@pos,p+1]
else
line = @string[@pos..-1]
end
@pos+=line.size
@eof =true if @pos==@string.size
$_ = line
end
end
def rewind
seek(0,0)
end
def seek(offset,whence)
case whence
when 0
@pos=offset
when 1
@pos+=offset
when 2
@pos=@string.size+offset
end
@eof=(@pos>=@string.size)
0
end
end
#
# Class method for creating streams
#
def YAML.make_stream( io )
if String === io
io = StringIO.new( io )
elsif not IO === io
raise YAML::Error, "YAML stream must be an IO or String object."
end
if YAML::unicode
def io.readline
YAML.utf_to_internal( readline( @ln_sep ), @utf_encoding )
end
def io.check_unicode
@utf_encoding = YAML.sniff_encoding( read( 4 ) )
@ln_sep = YAML.enc_separator( @utf_encoding )
seek( -4, IO::SEEK_CUR )
end
def io.utf_encoding
@utf_encoding
end
io.check_unicode
else
def io.utf_encoding
:None
end
end
io
end
end

19
lib/yaml/syck.rb Normal file
Просмотреть файл

@ -0,0 +1,19 @@
#
# YAML::Syck module
# .. glues syck and yaml.rb together ..
#
require 'syck'
require 'yaml/basenode'
module YAML
module Syck
#
# Mixin BaseNode functionality
#
class Node
include YAML::BaseNode
end
end
end

195
lib/yaml/types.rb Normal file
Просмотреть файл

@ -0,0 +1,195 @@
#
# Classes required by the full core typeset
#
module YAML
#
# Default private type
#
class PrivateType
attr_accessor :type_id, :value
def initialize( type, val )
@type_id = type; @value = val
end
def to_yaml( opts = {} )
YAML::quick_emit( self.id, opts ) { |out|
out << " !!#{@type_id}"
value.to_yaml( :Emitter => out )
}
end
end
#
# Default domain type
#
class DomainType
attr_accessor :domain, :type_id, :value
def initialize( domain, type, val )
@domain = domain; @type_id = type; @value = val
end
def to_yaml_type
dom = @domain.dup
if dom =~ /\.yaml\.org,2002$/
dom = $`
end
"#{dom}/#{@type_id}"
end
def to_yaml( opts = {} )
YAML::quick_emit( self.id, opts ) { |out|
out << " !#{to_yaml_type} "
value.to_yaml( :Emitter => out )
}
end
end
#
# YAML Hash class to support comments and defaults
#
class SpecialHash < Kernel::Hash
attr_accessor :default
def inspect
self.default.to_s
end
def to_s
self.default.to_s
end
def update( h )
if YAML::SpecialHash === h
@default = h.default if h.default
end
super( h )
end
def to_yaml( opts = {} )
opts[:DefaultKey] = self.default
super( opts )
end
end
#
# Builtin collection: !omap
#
class Omap < Array
def self.[]( *vals )
o = Omap.new
0.step( vals.length - 1, 2 ) { |i|
o[vals[i]] = vals[i+1]
}
o
end
def []( k )
self.assoc( k ).to_a[1]
end
def []=( k, *rest )
val, set = rest.reverse
if ( tmp = self.assoc( k ) ) and not set
tmp[1] = val
else
self << [ k, val ]
end
val
end
def has_key?( k )
self.assoc( k ) ? true : false
end
def is_complex_yaml?
true
end
def to_yaml( opts = {} )
YAML::quick_emit( self.id, opts ) { |out|
out.seq( "!omap" ) { |seq|
self.each { |v|
seq.add( Hash[ *v ] )
}
}
}
end
end
YAML.add_builtin_type( "omap" ) { |type, val|
if Array === val
p = Omap.new
val.each { |v|
if Hash === v
p.concat( v.to_a ) # Convert the map to a sequence
else
raise YAML::Error, "Invalid !omap entry: " + val.inspect
end
}
else
raise YAML::Error, "Invalid !omap: " + val.inspect
end
p
}
#
# Builtin collection: !pairs
#
class Pairs < Array
def self.[]( *vals )
p = Pairs.new
0.step( vals.length - 1, 2 ) { |i|
p[vals[i]] = vals[i+1]
}
p
end
def []( k )
self.assoc( k ).to_a
end
def []=( k, val )
self << [ k, val ]
val
end
def has_key?( k )
self.assoc( k ) ? true : false
end
def is_complex_yaml?
true
end
def to_yaml( opts = {} )
YAML::quick_emit( self.id, opts ) { |out|
out.seq( "!pairs" ) { |seq|
self.each { |v|
seq.add( Hash[ *v ] )
}
}
}
end
end
YAML.add_builtin_type( "pairs" ) { |type, val|
if Array === val
p = Pairs.new
val.each { |v|
if Hash === v
p.concat( v.to_a ) # Convert the map to a sequence
else
raise YAML::Error, "Invalid !pairs entry: " + val.inspect
end
}
else
raise YAML::Error, "Invalid !pairs: " + val.inspect
end
p
}
#
# Builtin collection: !set
#
class Set < Hash
def to_yaml_type
"!set"
end
end
YAML.add_builtin_type( 'set' ) { |type, val|
if Array === val
val = Set[ *val ]
elsif Hash === val
Set[ val ]
else
raise YAML::Error, "Invalid map explicitly tagged !map: " + val.inspect
end
val
}
end

54
lib/yaml/yamlnode.rb Normal file
Просмотреть файл

@ -0,0 +1,54 @@
#
# YAML::YamlNode class
#
require 'yaml/basenode'
module YAML
#
# YAML Generic Model container
#
class YamlNode
include BaseNode
attr_accessor :kind, :type_id, :value, :anchor
def initialize( t, v )
@type_id = t
if Hash === v
@kind = 'map'
@value = {}
v.each { |k,v|
@value[ k.transform ] = [ k, v ]
}
elsif Array === v
@kind = 'seq'
@value = v
elsif String === v
@kind = 'scalar'
@value = v
end
end
#
# Transform this node fully into a native type
#
def transform
t = nil
if @value.is_a? Hash
t = {}
@value.each { |k,v|
t[ k ] = v[1].transform
}
elsif @value.is_a? Array
t = []
@value.each { |v|
t.push v.transform
}
else
t = @value
end
YAML.transfer_method( @type_id, t )
end
end
end

52
lib/yaml/ypath.rb Normal file
Просмотреть файл

@ -0,0 +1,52 @@
#
# YAML::YPath
#
module YAML
class YPath
attr_accessor :segments, :predicates, :flags
def initialize( str )
@segments = []
@predicates = []
@flags = nil
while str =~ /^\/?(\/|[^\/[]+)(?:\[([^\]]+)\])?/
@segments.push $1
@predicates.push $2
str = $'
end
unless str.to_s.empty?
@segments += str.split( "/" )
end
if @segments.length == 0
@segments.push "."
end
end
def YPath.each_path( str )
#
# Find choices
#
paths = []
str = "(#{ str })"
while str.sub!( /\(([^()]+)\)/, "\n#{ paths.length }\n" )
paths.push $1.split( '|' )
end
#
# Construct all possible paths
#
all = [ str ]
( paths.length - 1 ).downto( 0 ) do |i|
all = all.collect do |a|
paths[i].collect do |p|
a.gsub( /\n#{ i }\n/, p )
end
end.flatten.uniq
end
all.collect do |path|
yield YPath.new( path )
end
end
end
end