on 4e3075b help sign in
75 files changed+14710−3851
since splitsnapshots
unifiedsplit
.github/workflows/tests.yml−44 .gitignore−5 .gitmodules−3 .travis.yml+175 ChangeLog.md+92 Data/Yaml.hs+186 yaml/src/Data/Yaml/Aeson.hs → Data/Yaml/Aeson.hs Data/Yaml/Builder.hs+113 yaml/src/Data/Yaml/Config.hs → Data/Yaml/Config.hs+16−38 yaml/src/Data/Yaml/Include.hs → Data/Yaml/Include.hs+9−41 Data/Yaml/Internal.hs+281 yaml/src/Data/Yaml/Parser.hs → Data/Yaml/Parser.hs+19−24 yaml/src/Data/Yaml/Pretty.hs → Data/Yaml/Pretty.hs+11−47 Data/Yaml/TH.hs+44 yaml/LICENSE → LICENSE Makefile+4 README.md+10−16 yaml/Setup.lhs → Setup.lhs libyaml/src/Text/Libyaml.hs → Text/Libyaml.hs+138−318 appveyor.yml+20 yaml/builder-test.hs → builder-test.hs libyaml/c/helper.c → c/helper.c+17−51 libyaml/include/helper.h → c/helper.h+1−4 yaml/examples/Config.hs → examples/Config.hs+2−3 yaml/examples/Main.hs → examples/Main.hs yaml/examples/Simple.hs → examples/Simple.hs+1−2 exe/json2yaml.hs+22 exe/yaml2json.hs+28 libyaml/ChangeLog.md−27 libyaml/LICENSE+16−22 libyaml/Makefile+9−4 libyaml/README.md−3 libyaml/Setup.hs−2 libyaml/api.c+1403 libyaml/dumper.c+394 libyaml/emitter.c+2329 libyaml/libyaml.cabal−68 libyaml/loader.c+444 libyaml/package.yaml−53 libyaml/parser.c+1374 libyaml/reader.c+469 libyaml/scanner.c+3580 libyaml/writer.c+141 libyaml/yaml.h+1973 libyaml/yaml_private.h+661 yaml/parser-test.hs → parser-test.hs stack.yaml+1−8 test/Data/Yaml/IncludeSpec.hs+44 test/Data/YamlSpec.hs+517 yaml/test/Spec.hs → test/Spec.hs yaml/test/json.yaml → test/json.yaml yaml/test/largest-string.yaml → test/largest-string.yaml yaml/test/resources/accent/foo.yaml → test/resources/accent/foo.yaml yaml/test/resources/bar.yaml → test/resources/bar.yaml yaml/test/resources/baz.yaml → test/resources/baz.yaml yaml/test/resources/foo.yaml → test/resources/foo.yaml yaml/test/resources/loop/bar.yaml → test/resources/loop/bar.yaml yaml/test/resources/loop/foo.yaml → test/resources/loop/foo.yaml yaml.cabal+166 yaml/ChangeLog.md−303 yaml/README.md−26 yaml/exe/Common.hs−68 yaml/exe/json2yaml.hs−106 yaml/exe/yaml2json.hs−87 yaml/package.yaml−113 yaml/src/Data/Yaml.hs−292 yaml/src/Data/Yaml/Builder.hs−240 yaml/src/Data/Yaml/Internal.hs−469 yaml/src/Data/Yaml/TH.hs−80 yaml/test/Data/Yaml/IncludeSpec.hs−139 yaml/test/Data/Yaml/THSpec.hs−17 yaml/test/Data/YamlSpec.hs−899 yaml/test/resources/empty.yaml yaml/test/resources/empty2.yaml−1 yaml/yaml.cabal−228
.github/workflows/tests.ymldeleted−44
@@ -1,44 +0,0 @@
1−name: Tests
2−
3−on:
4− pull_request:
5− push:
6− branches:
7− - master
8−
9−jobs:
10− build:
11− name: CI
12− runs-on: ${{ matrix.os }}
13− strategy:
14− fail-fast: false
15− matrix:
16− os: [ubuntu-latest, macos-latest, windows-latest]
17− resolver: [nightly, lts-22, lts-20, lts-17]
18− exclude:
19− - os: windows-latest
20− resolver: lts-15
21− - os: windows-latest
22− resolver: nightly
23−
24− steps:
25− - name: Clone project
26− uses: actions/checkout@v3
27−
28− - name: Cache dependencies
29− if: ${{ runner.os != 'Windows' }}
30− # Andreas Abel, 2023-06-10, switching off caching on Windows since ~/.stack is not the correct path here.
31− uses: actions/cache@v3
32− with:
33− path: ~/.stack
34− #NB: This path is not valid on Windows
35− key: ${{ runner.os }}-${{ matrix.resolver }}-${{ hashFiles('stack.yaml') }}
36− restore-keys: |
37− ${{ runner.os }}-${{ matrix.resolver }}-
38−
39− - name: Build and run tests
40− shell: bash
41− run: |
42− set -ex
43− stack upgrade || curl -sSL https://get.haskellstack.org/ | sh -s - -f
44− stack test --bench --no-run-benchmarks --haddock --no-haddock-deps --no-terminal --resolver=${{ matrix.resolver }}
.gitignore−5
@@ -4,8 +4,3 @@ cabal-dev/
44.cabal-sandbox/
55cabal.sandbox.config
66.stack-work/
7−*~
8−tarballs/
9−.dir-locals.el
10−*#
11−stack.yaml.lock
.gitmodulesdeleted−3
@@ -1,3 +0,0 @@
1−[submodule "vendor/libyaml"]
2− path = libyaml/vendor/libyaml
3− url = https://github.com/snoyberg/libyaml
.travis.ymlnew file+175
@@ -0,0 +1,175 @@
1+# Copy these contents into the root directory of your Github project in a file
2+# named .travis.yml
3+
4+# Use new container infrastructure to enable caching
5+sudo: false
6+
7+# Choose a lightweight base image; we provide our own build tools.
8+language: c
9+
10+# Caching so the next build will be fast too.
11+cache:
12+ directories:
13+ - $HOME/.ghc
14+ - $HOME/.cabal
15+ - $HOME/.stack
16+
17+# The different configurations we want to test. We have BUILD=cabal which uses
18+# cabal-install, and BUILD=stack which uses Stack. More documentation on each
19+# of those below.
20+#
21+# We set the compiler values here to tell Travis to use a different
22+# cache file per set of arguments.
23+#
24+# If you need to have different apt packages for each combination in the
25+# matrix, you can use a line such as:
26+# addons: {apt: {packages: [libfcgi-dev,libgmp-dev]}}
27+matrix:
28+ include:
29+ # We grab the appropriate GHC and cabal-install versions from hvr's PPA. See:
30+ # https://github.com/hvr/multi-ghc-travis
31+ #- env: BUILD=cabal GHCVER=7.0.4 CABALVER=1.16 HAPPYVER=1.19.5 ALEXVER=3.1.7
32+ # compiler: ": #GHC 7.0.4"
33+ # addons: {apt: {packages: [cabal-install-1.16,ghc-7.0.4,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
34+ #- env: BUILD=cabal GHCVER=7.2.2 CABALVER=1.16 HAPPYVER=1.19.5 ALEXVER=3.1.7
35+ # compiler: ": #GHC 7.2.2"
36+ # addons: {apt: {packages: [cabal-install-1.16,ghc-7.2.2,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
37+ #- env: BUILD=cabal GHCVER=7.4.2 CABALVER=1.16 HAPPYVER=1.19.5 ALEXVER=3.1.7
38+ # compiler: ": #GHC 7.4.2"
39+ # addons: {apt: {packages: [cabal-install-1.16,ghc-7.4.2,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
40+ - env: BUILD=cabal GHCVER=7.6.3 CABALVER=1.16 HAPPYVER=1.19.5 ALEXVER=3.1.7
41+ compiler: ": #GHC 7.6.3"
42+ addons: {apt: {packages: [cabal-install-1.16,ghc-7.6.3,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
43+ - env: BUILD=cabal GHCVER=7.8.4 CABALVER=1.18 HAPPYVER=1.19.5 ALEXVER=3.1.7
44+ compiler: ": #GHC 7.8.4"
45+ addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
46+ - env: BUILD=cabal GHCVER=7.10.3 CABALVER=1.22 HAPPYVER=1.19.5 ALEXVER=3.1.7
47+ compiler: ": #GHC 7.10.3"
48+ addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
49+
50+ # Build with the newest GHC and cabal-install. This is an accepted failure,
51+ # see below.
52+ - env: BUILD=cabal GHCVER=head CABALVER=head HAPPYVER=1.19.5 ALEXVER=3.1.7
53+ compiler: ": #GHC HEAD"
54+ addons: {apt: {packages: [cabal-install-head,ghc-head,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
55+
56+ # The Stack builds. We can pass in arbitrary Stack arguments via the ARGS
57+ # variable, such as using --stack-yaml to point to a different file.
58+ - env: BUILD=stack ARGS=""
59+ compiler: ": #stack default"
60+ addons: {apt: {packages: [ghc-7.10.3], sources: [hvr-ghc]}}
61+
62+ - env: BUILD=stack ARGS="--resolver lts-2"
63+ compiler: ": #stack 7.8.4"
64+ addons: {apt: {packages: [ghc-7.8.4], sources: [hvr-ghc]}}
65+
66+ - env: BUILD=stack ARGS="--resolver lts-3"
67+ compiler: ": #stack 7.10.2"
68+ addons: {apt: {packages: [ghc-7.10.2], sources: [hvr-ghc]}}
69+
70+ - env: BUILD=stack ARGS="--resolver lts-5"
71+ compiler: ": #stack 7.10.3"
72+ addons: {apt: {packages: [ghc-7.10.3], sources: [hvr-ghc]}}
73+
74+ # Nightly builds are allowed to fail
75+ - env: BUILD=stack ARGS="--resolver nightly"
76+ compiler: ": #stack nightly"
77+ addons: {apt: {packages: [libgmp,libgmp-dev]}}
78+
79+ # Build on OS X in addition to Linux
80+ - env: BUILD=stack ARGS=""
81+ compiler: ": #stack default osx"
82+ os: osx
83+
84+ - env: BUILD=stack ARGS="--resolver lts-2"
85+ compiler: ": #stack 7.8.4 osx"
86+ os: osx
87+
88+ - env: BUILD=stack ARGS="--resolver lts-3"
89+ compiler: ": #stack 7.10.2 osx"
90+ os: osx
91+
92+ - env: BUILD=stack ARGS="--resolver lts-5"
93+ compiler: ": #stack 7.10.3 osx"
94+ os: osx
95+
96+ - env: BUILD=stack ARGS="--resolver nightly"
97+ compiler: ": #stack nightly osx"
98+ os: osx
99+
100+ allow_failures:
101+ - env: BUILD=cabal GHCVER=head CABALVER=head HAPPYVER=1.19.5 ALEXVER=3.1.7
102+ - env: BUILD=stack ARGS="--resolver nightly"
103+
104+before_install:
105+# Using compiler above sets CC to an invalid value, so unset it
106+- unset CC
107+
108+# We want to always allow newer versions of packages when building on GHC HEAD
109+- CABALARGS=""
110+- if [ "x$GHCVER" = "xhead" ]; then CABALARGS=--allow-newer; fi
111+
112+# Download and unpack the stack executable
113+- export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$HOME/.local/bin:/opt/alex/$ALEXVER/bin:/opt/happy/$HAPPYVER/bin:$HOME/.cabal/bin:$PATH
114+- mkdir -p ~/.local/bin
115+- |
116+ if [ `uname` = "Darwin" ]
117+ then
118+ travis_retry curl --insecure -L https://www.stackage.org/stack/osx-x86_64 | tar xz --strip-components=1 --include '*/stack' -C ~/.local/bin
119+ else
120+ travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'
121+ fi
122+
123+ # Use the more reliable S3 mirror of Hackage
124+ mkdir -p $HOME/.cabal
125+ echo 'remote-repo: hackage.haskell.org:http://hackage.fpcomplete.com/' > $HOME/.cabal/config
126+ echo 'remote-repo-cache: $HOME/.cabal/packages' >> $HOME/.cabal/config
127+
128+ if [ "$CABALVER" != "1.16" ]
129+ then
130+ echo 'jobs: $ncpus' >> $HOME/.cabal/config
131+ fi
132+
133+# Get the list of packages from the stack.yaml file
134+- PACKAGES=$(stack --install-ghc query locals | grep '^ *path' | sed 's@^ *path:@@')
135+
136+install:
137+- echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
138+- if [ -f configure.ac ]; then autoreconf -i; fi
139+- |
140+ set -ex
141+ case "$BUILD" in
142+ stack)
143+ stack --no-terminal --install-ghc $ARGS test --only-dependencies
144+ ;;
145+ cabal)
146+ cabal --version
147+ travis_retry cabal update
148+ cabal install --only-dependencies --enable-tests --enable-benchmarks --force-reinstalls --ghc-options=-O0 --reorder-goals --max-backjumps=-1 $CABALARGS $PACKAGES
149+ ;;
150+ esac
151+ set +ex
152+
153+script:
154+- |
155+ set -ex
156+ case "$BUILD" in
157+ stack)
158+ stack --no-terminal $ARGS test --haddock --no-haddock-deps
159+ ;;
160+ cabal)
161+ cabal install --enable-tests --enable-benchmarks --force-reinstalls --ghc-options=-O0 --reorder-goals --max-backjumps=-1 $CABALARGS $PACKAGES
162+
163+ ORIGDIR=$(pwd)
164+ for dir in $PACKAGES
165+ do
166+ cd $dir
167+ cabal check || [ "$CABALVER" == "1.16" ]
168+ cabal sdist
169+ SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz && \
170+ (cd dist && cabal install --force-reinstalls "$SRC_TGZ")
171+ cd $ORIGDIR
172+ done
173+ ;;
174+ esac
175+ set +ex
ChangeLog.mdnew file+92
@@ -0,0 +1,92 @@
1+## 0.8.19.0
2+
3+* Add `Data.Yaml.TH` module
4+
5+## 0.8.18.7
6+
7+* Add `O_TRUNC` when opening files
8+
9+## 0.8.18.6
10+
11+* s/fdopen/_fdopen on Windows [#96](https://github.com/snoyberg/yaml/issues/96)
12+
13+## 0.8.18.5
14+
15+* Properly fix previous bug (fixes #94)
16+
17+## 0.8.18.4
18+
19+* Remove file with non-ASCII name due to Stack/cabal-install/Hackage
20+ restrictions (see [#92](https://github.com/snoyberg/yaml/issues/92))
21+
22+## 0.8.18.2
23+
24+* Handle non-ASCII filenames correctly on Windows [#91](https://github.com/snoyberg/yaml/pull/91)
25+
26+## 0.8.18.1
27+
28+* Improve prettyPrintParseException when context is empty [#89](https://github.com/snoyberg/yaml/pull/89)
29+
30+## 0.8.18
31+
32+* Switched yaml decode function for config file readers in `Data.Yaml.Config` to
33+ the one from `Data.Yaml.Include` that supports `!include` syntax.
34+
35+## 0.8.17.2
36+
37+* Fix pretty-printing order of UnexpectedEvent's fields (fixes [#84](https://github.com/snoyberg/yaml/issues/84)) [#85](https://github.com/snoyberg/yaml/pull/85)
38+
39+## 0.8.17.1
40+
41+* Avoid bug in Cabal [#83](https://github.com/snoyberg/yaml/pull/83)
42+
43+## 0.8.17
44+
45+* `loadYamlSettingsArgs`
46+
47+## 0.8.16.1
48+
49+* Slight doc improvement
50+
51+## 0.8.16
52+
53+Add env variable parsing. `loadYamlSettings` can read config values from the environment with Yaml that specifies an env var.
54+The syntax is
55+
56+`var: _env:ENV_VAR:default`
57+
58+## 0.8.15.3
59+
60+* Give a warning when compiling with GHCJS
61+
62+## 0.8.15.2
63+
64+* Canonicalise Monad instances [#76](https://github.com/snoyberg/yaml/pull/76)
65+
66+## 0.8.15.1
67+
68+* Compile with aeson below 0.7 [#70](https://github.com/snoyberg/yaml/pull/70)
69+
70+## 0.8.15
71+
72+* Parse `Scientific` directly, avoiding loss in precision. [#68](https://github.com/snoyberg/yaml/pull/68)
73+
74+## 0.8.14
75+
76+* Pretty print improvements for exceptions [#67](https://github.com/snoyberg/yaml/pull/67)
77+
78+## 0.8.13
79+
80+* Pretty module [#66](https://github.com/snoyberg/yaml/pull/66)
81+
82+## 0.8.12
83+
84+* Proper handling of `String "+123"` [#64](https://github.com/snoyberg/yaml/issues/64)
85+
86+## 0.8.11
87+
88+* Function to print prettier parse exceptions [#59](https://github.com/snoyberg/yaml/pull/59)
89+
90+## 0.8.10
91+
92+Add the Data.Yaml.Include module
Data/Yaml.hsnew file+186
@@ -0,0 +1,186 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+
5+-- | Provides a high-level interface for processing YAML files.
6+--
7+-- This module reuses most of the infrastructure from the @aeson@ package.
8+-- This means that you can use all of the existing tools for JSON
9+-- processing for processing YAML files. As a result, much of the
10+-- documentation below mentions JSON; do not let that confuse you, it's
11+-- intentional.
12+--
13+-- For the most part, YAML content translates directly into JSON, and
14+-- therefore there is very little data loss. If you need to deal with YAML
15+-- more directly (e.g., directly deal with aliases), you should use the
16+-- "Text.Libyaml" module instead.
17+--
18+-- For documentation on the @aeson@ types, functions, classes, and
19+-- operators, please see the @Data.Aeson@ module of the @aeson@ package.
20+--
21+-- Look in the examples directory of the source repository for some initial
22+-- pointers on how to use this library.
23+
24+#if (defined (ghcjs_HOST_OS))
25+module Data.Yaml {-# WARNING "GHCJS is not supported yet (will break at runtime once called)." #-}
26+#else
27+module Data.Yaml
28+#endif
29+ ( -- * Types
30+ Value (..)
31+ , Parser
32+ , Object
33+ , Array
34+ , ParseException(..)
35+ , prettyPrintParseException
36+ , YamlException (..)
37+ , YamlMark (..)
38+ -- * Constructors and accessors
39+ , object
40+ , array
41+ , (.=)
42+ , (.:)
43+ , (.:?)
44+ , (.!=)
45+ -- * Parsing
46+ , parseMonad
47+ , parseEither
48+ , parseMaybe
49+ -- * Classes
50+ , ToJSON (..)
51+ , FromJSON (..)
52+ -- * Encoding/decoding
53+ , encode
54+ , encodeFile
55+ , decode
56+ , decodeFile
57+ -- ** Better error information
58+ , decodeEither
59+ , decodeEither'
60+ , decodeFileEither
61+ -- ** More control over decoding
62+ , decodeHelper
63+ ) where
64+#if !MIN_VERSION_base(4,8,0)
65+import Control.Applicative((<$>))
66+#endif
67+import Control.Exception
68+import Control.Monad.Trans.Resource (runResourceT)
69+import Data.Aeson
70+ ( Value (..), ToJSON (..), FromJSON (..), object
71+ , (.=) , (.:) , (.:?) , (.!=)
72+ , Object, Array
73+ )
74+import Data.Aeson.Encode (encodeToTextBuilder)
75+import Data.Aeson.Types (Pair, parseMaybe, parseEither, Parser)
76+import Data.ByteString (ByteString)
77+import qualified Data.Conduit as C
78+import qualified Data.Conduit.List as CL
79+import qualified Data.HashMap.Strict as M
80+import qualified Data.HashSet as HashSet
81+import Data.Text.Encoding (encodeUtf8)
82+import qualified Data.Text.Encoding as TE
83+import qualified Data.Text.Lazy as TL
84+import Data.Text.Lazy.Builder (toLazyText)
85+import qualified Data.Vector as V
86+import System.IO.Unsafe (unsafePerformIO)
87+
88+import Data.Yaml.Internal
89+import Text.Libyaml hiding (encode, decode, encodeFile, decodeFile)
90+import qualified Text.Libyaml as Y
91+
92+encode :: ToJSON a => a -> ByteString
93+encode obj = unsafePerformIO $
94+ runResourceT $ CL.sourceList (objToEvents $ toJSON obj)
95+ C.$$ Y.encode
96+
97+encodeFile :: ToJSON a => FilePath -> a -> IO ()
98+encodeFile fp obj = runResourceT
99+ $ CL.sourceList (objToEvents $ toJSON obj)
100+ C.$$ Y.encodeFile fp
101+
102+objToEvents :: Value -> [Y.Event]
103+objToEvents o = (:) EventStreamStart
104+ . (:) EventDocumentStart
105+ $ objToEvents' o
106+ [ EventDocumentEnd
107+ , EventStreamEnd
108+ ]
109+
110+{- FIXME
111+scalarToEvent :: YamlScalar -> Event
112+scalarToEvent (YamlScalar v t s) = EventScalar v t s Nothing
113+-}
114+
115+objToEvents' :: Value -> [Y.Event] -> [Y.Event]
116+--objToEvents' (Scalar s) rest = scalarToEvent s : rest
117+objToEvents' (Array list) rest =
118+ EventSequenceStart Nothing
119+ : foldr objToEvents' (EventSequenceEnd : rest) (V.toList list)
120+objToEvents' (Object pairs) rest =
121+ EventMappingStart Nothing
122+ : foldr pairToEvents (EventMappingEnd : rest) (M.toList pairs)
123+
124+-- Empty strings need special handling to ensure they get quoted. This avoids:
125+-- https://github.com/snoyberg/yaml/issues/24
126+objToEvents' (String "") rest = EventScalar "" NoTag SingleQuoted Nothing : rest
127+
128+objToEvents' (String s) rest =
129+ event : rest
130+ where
131+ event
132+ -- Make sure that special strings are encoded as strings properly.
133+ -- See: https://github.com/snoyberg/yaml/issues/31
134+ | s `HashSet.member` specialStrings || isNumeric s = EventScalar (encodeUtf8 s) NoTag SingleQuoted Nothing
135+ | otherwise = EventScalar (encodeUtf8 s) StrTag PlainNoTag Nothing
136+objToEvents' Null rest = EventScalar "null" NullTag PlainNoTag Nothing : rest
137+objToEvents' (Bool True) rest = EventScalar "true" BoolTag PlainNoTag Nothing : rest
138+objToEvents' (Bool False) rest = EventScalar "false" BoolTag PlainNoTag Nothing : rest
139+-- Use aeson's implementation which gets rid of annoying decimal points
140+objToEvents' n@Number{} rest = EventScalar (TE.encodeUtf8 $ TL.toStrict $ toLazyText $ encodeToTextBuilder n) IntTag PlainNoTag Nothing : rest
141+
142+pairToEvents :: Pair -> [Y.Event] -> [Y.Event]
143+pairToEvents (k, v) rest =
144+ EventScalar (encodeUtf8 k) StrTag PlainNoTag Nothing
145+ : objToEvents' v rest
146+
147+decode :: FromJSON a
148+ => ByteString
149+ -> Maybe a
150+decode bs = unsafePerformIO
151+ $ either (const Nothing) id
152+ <$> decodeHelper_ (Y.decode bs)
153+
154+decodeFile :: FromJSON a
155+ => FilePath
156+ -> IO (Maybe a)
157+decodeFile fp = decodeHelper (Y.decodeFile fp) >>= either throwIO (return . either (const Nothing) id)
158+
159+-- | A version of 'decodeFile' which should not throw runtime exceptions.
160+--
161+-- Since 0.8.4
162+decodeFileEither
163+ :: FromJSON a
164+ => FilePath
165+ -> IO (Either ParseException a)
166+decodeFileEither = decodeHelper_ . Y.decodeFile
167+
168+decodeEither :: FromJSON a => ByteString -> Either String a
169+decodeEither bs = unsafePerformIO
170+ $ either (Left . prettyPrintParseException) id
171+ <$> decodeHelper (Y.decode bs)
172+
173+-- | More helpful version of 'decodeEither' which returns the 'YamlException'.
174+--
175+-- Since 0.8.3
176+decodeEither' :: FromJSON a => ByteString -> Either ParseException a
177+decodeEither' = either Left (either (Left . AesonException) Right)
178+ . unsafePerformIO
179+ . decodeHelper
180+ . Y.decode
181+
182+array :: [Value] -> Value
183+array = Array . V.fromList
184+
185+parseMonad :: Monad m => (a -> Parser b) -> a -> m b
186+parseMonad p = either fail return . parseEither p
yaml/src/Data/Yaml/Aeson.hs → Data/Yaml/Aeson.hsrenamed

The content is the same.

Data/Yaml/Builder.hsnew file+113
@@ -0,0 +1,113 @@
1+{-# LANGUAGE FlexibleInstances #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE CPP #-}
4+-- | NOTE: This module is a highly experimental preview release. It may change
5+-- drastically, or be entirely removed, in a future release.
6+module Data.Yaml.Builder
7+ ( YamlBuilder (..)
8+ , ToYaml (..)
9+ , mapping
10+ , array
11+ , string
12+ , bool
13+ , null
14+ , scientific
15+ , number
16+ , toByteString
17+ , writeYamlFile
18+ , (.=)
19+ ) where
20+
21+import Prelude hiding (null)
22+
23+import Control.Arrow (second)
24+import Control.Monad.Trans.Resource (runResourceT)
25+import Data.Aeson.Encode (encodeToTextBuilder)
26+import Data.Aeson.Types (Value(..))
27+import Data.ByteString (ByteString)
28+import qualified Data.ByteString.Char8 as S8
29+import Data.Conduit
30+import qualified Data.HashSet as HashSet
31+import Data.Scientific (Scientific)
32+import Data.Text (Text)
33+import Data.Text.Encoding (encodeUtf8)
34+import qualified Data.Text.Encoding as TE
35+import qualified Data.Text.Lazy as TL
36+import Data.Text.Lazy.Builder (toLazyText)
37+import System.IO.Unsafe (unsafePerformIO)
38+
39+import Data.Yaml.Internal
40+import Text.Libyaml
41+
42+(.=) :: ToYaml a => Text -> a -> (Text, YamlBuilder)
43+k .= v = (k, toYaml v)
44+
45+newtype YamlBuilder = YamlBuilder { unYamlBuilder :: [Event] -> [Event] }
46+
47+class ToYaml a where
48+ toYaml :: a -> YamlBuilder
49+instance ToYaml YamlBuilder where
50+ toYaml = id
51+instance ToYaml a => ToYaml [(Text, a)] where
52+ toYaml = mapping . map (second toYaml)
53+instance ToYaml a => ToYaml [a] where
54+ toYaml = array . map toYaml
55+instance ToYaml Text where
56+ toYaml = string
57+instance ToYaml Int where
58+ toYaml i = YamlBuilder (EventScalar (S8.pack $ show i) IntTag PlainNoTag Nothing:)
59+
60+mapping :: [(Text, YamlBuilder)] -> YamlBuilder
61+mapping pairs = YamlBuilder $ \rest ->
62+ EventMappingStart Nothing : foldr addPair (EventMappingEnd : rest) pairs
63+ where
64+ addPair (key, YamlBuilder value) after
65+ = EventScalar (encodeUtf8 key) StrTag PlainNoTag Nothing
66+ : value after
67+
68+array :: [YamlBuilder] -> YamlBuilder
69+array bs =
70+ YamlBuilder $ (EventSequenceStart Nothing:) . flip (foldr go) bs . (EventSequenceEnd:)
71+ where
72+ go (YamlBuilder b) = b
73+
74+string :: Text -> YamlBuilder
75+-- Empty strings need special handling to ensure they get quoted. This avoids:
76+-- https://github.com/snoyberg/yaml/issues/24
77+string "" = YamlBuilder (EventScalar "" NoTag SingleQuoted Nothing :)
78+string s =
79+ YamlBuilder (event :)
80+ where
81+ event
82+ -- Make sure that special strings are encoded as strings properly.
83+ -- See: https://github.com/snoyberg/yaml/issues/31
84+ | s `HashSet.member` specialStrings || isNumeric s = EventScalar (encodeUtf8 s) NoTag SingleQuoted Nothing
85+ | otherwise = EventScalar (encodeUtf8 s) StrTag PlainNoTag Nothing
86+
87+-- Use aeson's implementation which gets rid of annoying decimal points
88+scientific :: Scientific -> YamlBuilder
89+scientific n = YamlBuilder (EventScalar (TE.encodeUtf8 $ TL.toStrict $ toLazyText $ encodeToTextBuilder (Number n)) IntTag PlainNoTag Nothing :)
90+
91+{-# DEPRECATED number "Use scientific" #-}
92+number :: Scientific -> YamlBuilder
93+number = scientific
94+
95+bool :: Bool -> YamlBuilder
96+bool True = YamlBuilder (EventScalar "true" BoolTag PlainNoTag Nothing :)
97+bool False = YamlBuilder (EventScalar "false" BoolTag PlainNoTag Nothing :)
98+
99+null :: YamlBuilder
100+null = YamlBuilder (EventScalar "null" NullTag PlainNoTag Nothing :)
101+
102+toEvents :: YamlBuilder -> [Event]
103+toEvents (YamlBuilder front) =
104+ EventStreamStart : EventDocumentStart : front [EventDocumentEnd, EventStreamEnd]
105+
106+toSource :: (Monad m, ToYaml a) => a -> Source m Event
107+toSource = mapM_ yield . toEvents . toYaml
108+
109+toByteString :: ToYaml a => a -> ByteString
110+toByteString yb = unsafePerformIO $ runResourceT $ toSource yb $$ encode
111+
112+writeYamlFile :: ToYaml a => FilePath -> a -> IO ()
113+writeYamlFile fp yb = runResourceT $ toSource yb $$ encodeFile fp
yaml/src/Data/Yaml/Config.hs → Data/Yaml/Config.hsrenamed+16−38
@@ -5,7 +5,7 @@
55-- In particular, merging environment variables with yaml values
66--
77-- 'loadYamlSettings' is a high-level API for loading YAML and merging environment variables.
8−-- A yaml value of @_env:ENV_VAR:default@ or just @_env:ENV_VAR@ will lookup the environment variable @ENV_VAR@.
8+-- A yaml value of @_env:ENV_VAR:default@ will lookup the environment variable @ENV_VAR@.
99--
1010-- On a historical note, this code was taken directly from the yesod web framework's configuration module.
1111module Data.Yaml.Config
@@ -33,13 +33,7 @@ import Data.Monoid
3333import Data.Semigroup
3434import Data.List.NonEmpty (nonEmpty)
3535import Data.Aeson
36−#if MIN_VERSION_aeson(2,0,0)
37−import qualified Data.Aeson.Key as K
38−import qualified Data.Aeson.KeyMap as H
39−import Data.Aeson.KeyMap (KeyMap)
40−#else
4136import qualified Data.HashMap.Strict as H
42−#endif
4337import Data.Text (Text, pack)
4438import System.Environment (getArgs, getEnvironment)
4539import Control.Arrow ((***))
@@ -51,16 +45,6 @@ import qualified Data.Yaml.Include as YI
5145import Data.Maybe (fromMaybe)
5246import qualified Data.Text as T
5347
54−#if MIN_VERSION_aeson(2,0,0)
55−fromText :: T.Text -> Key
56−fromText = K.fromText
57−#else
58−fromText :: T.Text -> T.Text
59−fromText = id
60−
61−type KeyMap a = H.HashMap T.Text a
62−#endif
63−
6448newtype MergedValue = MergedValue { getMergedValue :: Value }
6549
6650instance Semigroup MergedValue where
@@ -80,7 +64,7 @@ mergeValues x _ = x
8064--
8165-- @since 0.8.16
8266applyEnvValue :: Bool -- ^ require an environment variable to be present?
83− -> KeyMap Text -> Value -> Value
67+ -> H.HashMap Text Text -> Value -> Value
8468applyEnvValue requireEnv' env =
8569 goV
8670 where
@@ -90,7 +74,7 @@ applyEnvValue requireEnv' env =
9074 t2 <- T.stripPrefix "_env:" t1
9175 let (name, t3) = T.break (== ':') t2
9276 mdef = fmap parseValue $ T.stripPrefix ":" t3
93− Just $ case H.lookup (fromText name) env of
77+ Just $ case H.lookup name env of
9478 Just val ->
9579 -- If the default value parses as a String, we treat the
9680 -- environment variable as a raw value and do not parse it.
@@ -109,16 +93,13 @@ applyEnvValue requireEnv' env =
10993 _ -> Null
11094 goV v = v
11195
112− parseValue val = either
113− (const (String val))
114− id
115− (Y.decodeThrow $ encodeUtf8 val)
96+ parseValue val = fromMaybe (String val) $ Y.decode $ encodeUtf8 val
11697
11798-- | Get the actual environment as a @HashMap@ from @Text@ to @Text@.
11899--
119100-- @since 0.8.16
120−getCurrentEnv :: IO (KeyMap Text)
121−getCurrentEnv = fmap (H.fromList . map (fromText . pack *** pack)) getEnvironment
101+getCurrentEnv :: IO (H.HashMap Text Text)
102+getCurrentEnv = fmap (H.fromList . map (pack *** pack)) getEnvironment
122103
123104-- | A convenience wrapper around 'applyEnvValue' and 'getCurrentEnv'
124105--
@@ -134,8 +115,8 @@ applyCurrentEnv requireEnv' orig = flip (applyEnvValue requireEnv') orig <$> get
134115data EnvUsage = IgnoreEnv
135116 | UseEnv
136117 | RequireEnv
137− | UseCustomEnv (KeyMap Text)
138− | RequireCustomEnv (KeyMap Text)
118+ | UseCustomEnv (H.HashMap Text Text)
119+ | RequireCustomEnv (H.HashMap Text Text)
139120
140121-- | Do not use any environment variables, instead relying on defaults values
141122-- in the config file.
@@ -162,14 +143,14 @@ requireEnv = RequireEnv
162143-- @HashMap@ as the environment.
163144--
164145-- @since 0.8.16
165−useCustomEnv :: KeyMap Text -> EnvUsage
146+useCustomEnv :: H.HashMap Text Text -> EnvUsage
166147useCustomEnv = UseCustomEnv
167148
168149-- | Same as 'requireEnv', but instead of the actual environment, use the
169150-- provided @HashMap@ as the environment.
170151--
171152-- @since 0.8.16
172−requireCustomEnv :: KeyMap Text -> EnvUsage
153+requireCustomEnv :: H.HashMap Text Text -> EnvUsage
173154requireCustomEnv = RequireCustomEnv
174155
175156-- | Load the settings from the following three sources:
@@ -185,11 +166,6 @@ requireCustomEnv = RequireCustomEnv
185166--
186167-- > loadYamlSettings ["config/foo.yaml"] [] useEnv
187168--
188−-- Alternatively you can configure settings through the Yaml @Value@ directly in Haskell.
189−-- For example, to load up settings from only from environment variables, you can use:
190−--
191−-- > loadYamlSettings [] [object ["connectionString" .= ("_env:DATABASE_URL" :: String)]] requireEnv
192−--
193169-- @since 0.8.16
194170loadYamlSettings
195171 :: FromJSON settings
@@ -201,7 +177,9 @@ loadYamlSettings runTimeFiles compileValues envUsage = do
201177 runValues <- forM runTimeFiles $ \fp -> do
202178 eres <- YI.decodeFileEither fp
203179 case eres of
204− Left e -> throwIO (Y.LoadSettingsException fp e)
180+ Left e -> do
181+ putStrLn $ "loadYamlSettings: Could not parse file as YAML: " ++ fp
182+ throwIO e
205183 Right value -> return value
206184
207185 value' <-
@@ -216,9 +194,9 @@ loadYamlSettings runTimeFiles compileValues envUsage = do
216194 UseCustomEnv env -> return $ applyEnvValue False env value'
217195 RequireCustomEnv env -> return $ applyEnvValue True env value'
218196
219− case Y.parseEither parseJSON value of
220− Left s -> error $ "Could not convert to expected type: " ++ s
221− Right settings -> return settings
197+ case fromJSON value of
198+ Error s -> error $ "Could not convert to AppSettings: " ++ s
199+ Success settings -> return settings
222200
223201-- | Same as @loadYamlSettings@, but get the list of runtime config files from
224202-- the command line arguments.
yaml/src/Data/Yaml/Include.hs → Data/Yaml/Include.hsrenamed+9−41
@@ -1,16 +1,5 @@
1−{-# LANGUAGE CPP #-}
21{-# LANGUAGE RankNTypes #-}
3−module Data.Yaml.Include (
4− decodeFile
5−, decodeFileEither
6−, decodeFileWithWarnings
7−) where
8−
9−#if !MIN_VERSION_directory(1, 2, 3)
10−import Control.Exception (handleJust)
11−import Control.Monad (guard)
12−import System.IO.Error (ioeGetFileName, ioeGetLocation, isDoesNotExistError)
13−#endif
2+module Data.Yaml.Include (decodeFile, decodeFileEither) where
143
154import Control.Exception (throwIO)
165import Control.Monad (when)
@@ -24,41 +13,30 @@ import Data.Text.Encoding (decodeUtf8)
2413import System.Directory
2514import System.FilePath
2615
27−import Data.Yaml.Internal (ParseException(..), Warning(..), decodeHelper_, decodeHelper)
16+import Data.Yaml.Internal (ParseException(..), decodeHelper_, decodeHelper)
2817import Text.Libyaml hiding (decodeFile)
2918import qualified Text.Libyaml as Y
3019
3120eventsFromFile
3221 :: MonadResource m
3322 => FilePath
34− -> ConduitM i Event m ()
23+ -> Producer m Event
3524eventsFromFile = go []
3625 where
37− go :: MonadResource m => [FilePath] -> FilePath -> ConduitM i Event m ()
26+ go :: MonadResource m => [FilePath] -> FilePath -> Producer m Event
3827 go seen fp = do
39− cfp <- liftIO $ handleNotFound $ canonicalizePath fp
28+ cfp <- liftIO $ canonicalizePath fp
4029 when (cfp `elem` seen) $ do
4130 liftIO $ throwIO CyclicIncludes
42− Y.decodeFile cfp .| do
31+ Y.decodeFile cfp $= do
4332 awaitForever $ \event -> case event of
4433 EventScalar f (UriTag "!include") _ _ -> do
4534 let includeFile = takeDirectory cfp </> unpack (decodeUtf8 f)
46− go (cfp : seen) includeFile .| CL.filter (`notElem` irrelevantEvents)
35+ go (cfp : seen) includeFile $= CL.filter (`notElem` irrelevantEvents)
4736 _ -> yield event
4837
4938 irrelevantEvents = [EventStreamStart, EventDocumentStart, EventDocumentEnd, EventStreamEnd]
5039
51−#if !MIN_VERSION_directory(1, 2, 3)
52− handleNotFound = handleJust
53− (\e -> do
54− guard (isDoesNotExistError e)
55− guard (ioeGetLocation e == "canonicalizePath")
56− ioeGetFileName e)
57− (throwIO . YamlException . ("Yaml file not found: " ++))
58−#else
59− handleNotFound = id
60−#endif
61−
6240-- | Like `Data.Yaml.decodeFile` but with support for relative and absolute
6341-- includes.
6442--
@@ -69,7 +47,7 @@ decodeFile
6947 :: FromJSON a
7048 => FilePath
7149 -> IO (Maybe a)
72−decodeFile fp = (fmap snd <$> decodeHelper (eventsFromFile fp)) >>= either throwIO (return . either (const Nothing) id)
50+decodeFile fp = decodeHelper (eventsFromFile fp) >>= either throwIO (return . either (const Nothing) id)
7351
7452-- | Like `Data.Yaml.decodeFileEither` but with support for relative and
7553-- absolute includes.
@@ -81,14 +59,4 @@ decodeFileEither
8159 :: FromJSON a
8260 => FilePath
8361 -> IO (Either ParseException a)
84−decodeFileEither = fmap (fmap snd) . decodeFileWithWarnings
85−
86−-- | A version of `decodeFileEither` that returns warnings along with the parse
87−-- result.
88−--
89−-- @since 0.10.0
90−decodeFileWithWarnings
91− :: FromJSON a
92− => FilePath
93− -> IO (Either ParseException ([Warning], a))
94−decodeFileWithWarnings = decodeHelper_ . eventsFromFile
62+decodeFileEither = decodeHelper_ . eventsFromFile
Data/Yaml/Internal.hsnew file+281
@@ -0,0 +1,281 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE DeriveDataTypeable #-}
3+{-# LANGUAGE PatternGuards #-}
4+{-# LANGUAGE OverloadedStrings #-}
5+module Data.Yaml.Internal
6+ (
7+ ParseException(..)
8+ , prettyPrintParseException
9+ , parse
10+ , decodeHelper
11+ , decodeHelper_
12+ , specialStrings
13+ , isNumeric
14+ ) where
15+
16+#if !MIN_VERSION_base(4,8,0)
17+import Control.Applicative ((<$>), Applicative(..))
18+#endif
19+import Control.Exception
20+import Control.Exception.Enclosed
21+import Control.Monad (liftM, ap, unless)
22+import Control.Monad.IO.Class (MonadIO, liftIO)
23+import Control.Monad.Trans.Class (MonadTrans, lift)
24+import Control.Monad.Trans.Resource (ResourceT, runResourceT)
25+import Control.Monad.Trans.State
26+import Data.Aeson
27+import Data.Aeson.Types hiding (parse)
28+import qualified Data.Attoparsec.Text as Atto
29+import Data.ByteString (ByteString)
30+import Data.Char (toUpper)
31+import qualified Data.Conduit as C
32+import qualified Data.Conduit.List as CL
33+import qualified Data.HashMap.Strict as M
34+import qualified Data.HashSet as HashSet
35+import qualified Data.Map as Map
36+import Data.Scientific (Scientific)
37+import Data.Text (Text, pack)
38+import qualified Data.Text as T
39+import Data.Text.Encoding (decodeUtf8With)
40+import Data.Text.Encoding.Error (lenientDecode)
41+import Data.Typeable
42+import qualified Data.Vector as V
43+
44+import qualified Text.Libyaml as Y
45+import Text.Libyaml hiding (encode, decode, encodeFile, decodeFile)
46+
47+data ParseException = NonScalarKey
48+ | UnknownAlias { _anchorName :: Y.AnchorName }
49+ | UnexpectedEvent { _received :: Maybe Event
50+ , _expected :: Maybe Event
51+ }
52+ | InvalidYaml (Maybe YamlException)
53+ | AesonException String
54+ | OtherParseException SomeException
55+ | NonStringKeyAlias Y.AnchorName Value
56+ | CyclicIncludes
57+ deriving (Show, Typeable)
58+
59+instance Exception ParseException where
60+#if MIN_VERSION_base(4, 8, 0)
61+ displayException = prettyPrintParseException
62+#endif
63+
64+-- | Alternative to 'show' to display a 'ParseException' on the screen.
65+-- Instead of displaying the data constructors applied to their arguments,
66+-- a more textual output is returned. For example, instead of printing:
67+--
68+-- > InvalidYaml (Just (YamlParseException {yamlProblem = "did not find expected ',' or '}'", yamlContext = "while parsing a flow mapping", yamlProblemMark = YamlMark {yamlIndex = 42, yamlLine = 2, yamlColumn = 12}})))
69+--
70+-- It looks more pleasant to print:
71+--
72+-- > YAML parse exception at line 2, column 12,
73+-- > while parsing a flow mapping:
74+-- > did not find expected ',' or '}'
75+--
76+-- Since 0.8.11
77+prettyPrintParseException :: ParseException -> String
78+prettyPrintParseException pe = case pe of
79+ NonScalarKey -> "Non scalar key"
80+ UnknownAlias anchor -> "Unknown alias `" ++ anchor ++ "`"
81+ UnexpectedEvent { _expected = mbExpected, _received = mbUnexpected } -> unlines
82+ [ "Unexpected event: expected"
83+ , " " ++ show mbExpected
84+ , "but received"
85+ , " " ++ show mbUnexpected
86+ ]
87+ InvalidYaml mbYamlError -> case mbYamlError of
88+ Nothing -> "Unspecified YAML error"
89+ Just yamlError -> case yamlError of
90+ YamlException s -> "YAML exception:\n" ++ s
91+ YamlParseException problem context mark -> concat
92+ [ "YAML parse exception at line " ++ show (yamlLine mark) ++
93+ ", column " ++ show (yamlColumn mark)
94+ , case context of
95+ "" -> ":\n"
96+ -- The context seems to include a leading "while" or similar.
97+ _ -> ",\n" ++ context ++ ":\n"
98+ , problem
99+ ]
100+ AesonException s -> "Aeson exception:\n" ++ s
101+ OtherParseException exc -> "Generic parse exception:\n" ++ show exc
102+ NonStringKeyAlias anchor value -> unlines
103+ [ "Non-string key alias:"
104+ , " Anchor name: " ++ anchor
105+ , " Value: " ++ show value
106+ ]
107+ CyclicIncludes -> "Cyclic includes"
108+
109+newtype PErrorT m a = PErrorT { runPErrorT :: m (Either ParseException a) }
110+instance Monad m => Functor (PErrorT m) where
111+ fmap = liftM
112+instance Monad m => Applicative (PErrorT m) where
113+ pure = PErrorT . return . Right
114+ (<*>) = ap
115+instance Monad m => Monad (PErrorT m) where
116+ return = pure
117+ (PErrorT m) >>= f = PErrorT $ do
118+ e <- m
119+ case e of
120+ Left e' -> return $ Left e'
121+ Right a -> runPErrorT $ f a
122+instance MonadTrans PErrorT where
123+ lift = PErrorT . liftM Right
124+instance MonadIO m => MonadIO (PErrorT m) where
125+ liftIO = lift . liftIO
126+
127+type Parse = StateT (Map.Map String Value) (ResourceT IO)
128+
129+requireEvent :: Event -> C.Sink Event Parse ()
130+requireEvent e = do
131+ f <- CL.head
132+ unless (f == Just e) $ liftIO $ throwIO $ UnexpectedEvent f $ Just e
133+
134+parse :: C.Sink Event Parse Value
135+parse = do
136+ requireEvent EventStreamStart
137+ requireEvent EventDocumentStart
138+ res <- parseO
139+ requireEvent EventDocumentEnd
140+ requireEvent EventStreamEnd
141+ return res
142+
143+parseScalar :: ByteString -> Anchor -> Style -> Tag
144+ -> C.Sink Event Parse Text
145+parseScalar v a style tag = do
146+ let res = decodeUtf8With lenientDecode v
147+ case a of
148+ Nothing -> return res
149+ Just an -> do
150+ lift $ modify (Map.insert an $ textToValue style tag res)
151+ return res
152+
153+textToValue :: Style -> Tag -> Text -> Value
154+textToValue SingleQuoted _ t = String t
155+textToValue DoubleQuoted _ t = String t
156+textToValue _ StrTag t = String t
157+textToValue Folded _ t = String t
158+textToValue _ _ t
159+ | t `elem` ["null", "Null", "NULL", "~", ""] = Null
160+ | any (t `isLike`) ["y", "yes", "on", "true"] = Bool True
161+ | any (t `isLike`) ["n", "no", "off", "false"] = Bool False
162+ | Right x <- textToScientific t = Number x
163+ | otherwise = String t
164+ where x `isLike` ref = x `elem` [ref, T.toUpper ref, titleCased]
165+ where titleCased = toUpper (T.head ref) `T.cons` T.tail ref
166+
167+textToScientific :: Text -> Either String Scientific
168+textToScientific = Atto.parseOnly (Atto.scientific <* Atto.endOfInput)
169+
170+parseO :: C.Sink Event Parse Value
171+parseO = do
172+ me <- CL.head
173+ case me of
174+ Just (EventScalar v tag style a) -> textToValue style tag <$> parseScalar v a style tag
175+ Just (EventSequenceStart a) -> parseS a id
176+ Just (EventMappingStart a) -> parseM a M.empty
177+ Just (EventAlias an) -> do
178+ m <- lift get
179+ case Map.lookup an m of
180+ Nothing -> liftIO $ throwIO $ UnknownAlias an
181+ Just v -> return v
182+ _ -> liftIO $ throwIO $ UnexpectedEvent me Nothing
183+
184+parseS :: Y.Anchor
185+ -> ([Value] -> [Value])
186+ -> C.Sink Event Parse Value
187+parseS a front = do
188+ me <- CL.peek
189+ case me of
190+ Just EventSequenceEnd -> do
191+ CL.drop 1
192+ let res = Array $ V.fromList $ front []
193+ case a of
194+ Nothing -> return res
195+ Just an -> do
196+ lift $ modify $ Map.insert an res
197+ return res
198+ _ -> do
199+ o <- parseO
200+ parseS a $ front . (:) o
201+
202+parseM :: Y.Anchor
203+ -> M.HashMap Text Value
204+ -> C.Sink Event Parse Value
205+parseM a front = do
206+ me <- CL.peek
207+ case me of
208+ Just EventMappingEnd -> do
209+ CL.drop 1
210+ let res = Object front
211+ case a of
212+ Nothing -> return res
213+ Just an -> do
214+ lift $ modify $ Map.insert an res
215+ return res
216+ _ -> do
217+ CL.drop 1
218+ s <- case me of
219+ Just (EventScalar v tag style a') -> parseScalar v a' style tag
220+ Just (EventAlias an) -> do
221+ m <- lift get
222+ case Map.lookup an m of
223+ Nothing -> liftIO $ throwIO $ UnknownAlias an
224+ Just (String t) -> return t
225+ Just v -> liftIO $ throwIO $ NonStringKeyAlias an v
226+ _ -> liftIO $ throwIO $ UnexpectedEvent me Nothing
227+ o <- parseO
228+
229+ let al = M.insert s o front
230+ al' = if s == pack "<<"
231+ then case o of
232+ Object l -> M.union front l
233+ Array l -> M.union front $ foldl merge' M.empty $ V.toList l
234+ _ -> al
235+ else al
236+ parseM a al'
237+ where merge' al (Object om) = M.union al om
238+ merge' al _ = al
239+
240+decodeHelper :: FromJSON a
241+ => C.Source Parse Y.Event
242+ -> IO (Either ParseException (Either String a))
243+decodeHelper src = do
244+ x <- tryAny $ runResourceT $ flip evalStateT Map.empty $ src C.$$ parse
245+ case x of
246+ Left e
247+ | Just pe <- fromException e -> return $ Left pe
248+ | Just ye <- fromException e -> return $ Left $ InvalidYaml $ Just (ye :: YamlException)
249+ | otherwise -> throwIO e
250+ Right y -> return $ Right $ parseEither parseJSON y
251+
252+decodeHelper_ :: FromJSON a
253+ => C.Source Parse Event
254+ -> IO (Either ParseException a)
255+decodeHelper_ src = do
256+ x <- tryAny $ runResourceT $ flip evalStateT Map.empty $ src C.$$ parse
257+ return $ case x of
258+ Left e
259+ | Just pe <- fromException e -> Left pe
260+ | Just ye <- fromException e -> Left $ InvalidYaml $ Just (ye :: YamlException)
261+ | otherwise -> Left $ OtherParseException e
262+ Right y -> either
263+ (Left . AesonException)
264+ Right
265+ (parseEither parseJSON y)
266+
267+-- | Strings which must be escaped so as not to be treated as non-string scalars.
268+specialStrings :: HashSet.HashSet Text
269+specialStrings = HashSet.fromList $ T.words
270+ "y Y yes Yes YES n N no No NO true True TRUE false False FALSE on On ON off Off OFF null Null NULL ~"
271+
272+isNumeric :: Text -> Bool
273+isNumeric =
274+ T.all isNumeric'
275+ where
276+ isNumeric' c = ('0' <= c && c <= '9')
277+ || c == 'e'
278+ || c == 'E'
279+ || c == '.'
280+ || c == '-'
281+ || c == '+'
yaml/src/Data/Yaml/Parser.hs → Data/Yaml/Parser.hsrenamed+19−24
@@ -9,18 +9,20 @@ import Control.Applicative
99import Control.Exception (Exception)
1010import Control.Monad (MonadPlus (..), liftM, ap)
1111import Control.Monad.Trans.Class (lift)
12−import Control.Monad.Trans.Resource (MonadThrow, throwM)
12+import Control.Monad.Trans.Resource (MonadThrow, monadThrow, runResourceT)
1313import Control.Monad.Trans.Writer.Strict (tell, WriterT)
1414import Data.ByteString (ByteString)
1515import Data.Conduit
16+#if MIN_VERSION_conduit(1,1,0)
1617import Data.Conduit.Lift (runWriterC)
18+#define runWriterSC runWriterC
19+#else
20+import Data.Conduit.Lift (runWriterSC)
21+#endif
1722import qualified Data.Map as Map
1823#if !MIN_VERSION_base(4,8,0)
1924import Data.Monoid (Monoid (..))
2025#endif
21−#if !MIN_VERSION_base(4,11,0)
22−import Data.Semigroup (Semigroup(..))
23−#endif
2426import Data.Text (Text, pack, unpack)
2527import Data.Text.Encoding (decodeUtf8)
2628import Data.Text.Read (signed, decimal)
@@ -39,22 +41,15 @@ instance Applicative YamlParser where
3941instance Alternative YamlParser where
4042 empty = fail "empty"
4143 (<|>) = mplus
42−instance Semigroup (YamlParser a) where
43− (<>) = mplus
4444instance Monoid (YamlParser a) where
4545 mempty = fail "mempty"
46−#if !MIN_VERSION_base(4,11,0)
47− mappend = (<>)
48−#endif
46+ mappend = mplus
4947instance Monad YamlParser where
5048 return = pure
5149 YamlParser f >>= g = YamlParser $ \am ->
5250 case f am of
5351 Left t -> Left t
5452 Right x -> unYamlParser (g x) am
55−#if MIN_VERSION_base(4,13,0)
56−instance MonadFail YamlParser where
57−#endif
5853 fail = YamlParser . const . Left . pack
5954instance MonadPlus YamlParser where
6055 mzero = fail "mzero"
@@ -134,7 +129,7 @@ data RawDoc = RawDoc YamlValue AnchorMap
134129parseRawDoc :: (FromYaml a, MonadThrow m) => RawDoc -> m a
135130parseRawDoc (RawDoc val am) =
136131 case unYamlParser (fromYaml val) am of
137− Left t -> throwM $ FromYamlException t
132+ Left t -> monadThrow $ FromYamlException t
138133 Right x -> return x
139134
140135(.:) :: FromYaml a => [(Text, YamlValue)] -> Text -> YamlParser a
@@ -150,11 +145,11 @@ data YamlParseException
150145 deriving (Show, Typeable)
151146instance Exception YamlParseException
152147
153−sinkValue :: MonadThrow m => ConduitM Event o (WriterT AnchorMap m) YamlValue
148+sinkValue :: MonadThrow m => Consumer Event (WriterT AnchorMap m) YamlValue
154149sinkValue =
155150 start
156151 where
157− start = await >>= maybe (throwM UnexpectedEndOfEvents) go
152+ start = await >>= maybe (monadThrow UnexpectedEndOfEvents) go
158153
159154 tell' Nothing val = return val
160155 tell' (Just name) val = do
@@ -165,21 +160,21 @@ sinkValue =
165160 go EventDocumentStart = start
166161 go (EventAlias a) = return $ Alias a
167162 go (EventScalar a b c d) = tell' d $ Scalar a b c d
168− go (EventSequenceStart _tag _style mname) = do
163+ go (EventSequenceStart mname) = do
169164 vals <- goS id
170165 let val = Sequence vals mname
171166 tell' mname val
172− go (EventMappingStart _tag _style mname) = do
167+ go (EventMappingStart mname) = do
173168 pairs <- goM id
174169 let val = Mapping pairs mname
175170 tell' mname val
176171
177− go e = throwM $ UnexpectedEvent e
172+ go e = monadThrow $ UnexpectedEvent e
178173
179174 goS front = do
180175 me <- await
181176 case me of
182− Nothing -> throwM UnexpectedEndOfEvents
177+ Nothing -> monadThrow UnexpectedEndOfEvents
183178 Just EventSequenceEnd -> return $ front []
184179 Just e -> do
185180 val <- go e
@@ -188,17 +183,17 @@ sinkValue =
188183 goM front = do
189184 mk <- await
190185 case mk of
191− Nothing -> throwM UnexpectedEndOfEvents
186+ Nothing -> monadThrow UnexpectedEndOfEvents
192187 Just EventMappingEnd -> return $ front []
193188 Just (EventScalar a b c d) -> do
194189 _ <- tell' d $ Scalar a b c d
195190 let k = decodeUtf8 a
196191 v <- start
197192 goM (front . ((k, v):))
198− Just e -> throwM $ UnexpectedEvent e
193+ Just e -> monadThrow $ UnexpectedEvent e
199194
200−sinkRawDoc :: MonadThrow m => ConduitM Event o m RawDoc
201−sinkRawDoc = uncurry RawDoc <$> runWriterC sinkValue
195+sinkRawDoc :: MonadThrow m => Consumer Event m RawDoc
196+sinkRawDoc = uncurry RawDoc <$> runWriterSC sinkValue
202197
203198readYamlFile :: FromYaml a => FilePath -> IO a
204−readYamlFile fp = runConduitRes (decodeFile fp .| sinkRawDoc) >>= parseRawDoc
199+readYamlFile fp = runResourceT (decodeFile fp $$ sinkRawDoc) >>= parseRawDoc
yaml/src/Data/Yaml/Pretty.hs → Data/Yaml/Pretty.hsrenamed+11−47
@@ -1,16 +1,13 @@
11{-# LANGUAGE CPP #-}
22-- | Prettier YAML encoding.
33--
4−-- @since 0.8.13
4+-- Since 0.8.13
55module Data.Yaml.Pretty
66 ( encodePretty
77 , Config
88 , getConfCompare
99 , setConfCompare
10− , getConfDropNull
11− , setConfDropNull
1210 , defConfig
13− , pretty
1411 ) where
1512
1613import Prelude hiding (null)
@@ -18,16 +15,10 @@ import Prelude hiding (null)
1815#if !MIN_VERSION_base(4,8,0)
1916import Control.Applicative ((<$>))
2017#endif
21−import Data.Bifunctor (first)
22−#if MIN_VERSION_aeson(2,0,0)
23−import qualified Data.Aeson.Key as K
24−import qualified Data.Aeson.KeyMap as HM
25−#else
26−import qualified Data.HashMap.Strict as HM
27−#endif
2818import Data.Aeson.Types
2919import Data.ByteString (ByteString)
3020import Data.Function (on)
21+import qualified Data.HashMap.Strict as HM
3122import Data.List (sortBy)
3223#if !MIN_VERSION_base(4,8,0)
3324import Data.Monoid
@@ -37,58 +28,31 @@ import qualified Data.Vector as V
3728
3829import Data.Yaml.Builder
3930
40−#if MIN_VERSION_aeson(2,0,0)
41−toText :: Key -> Text
42−toText = K.toText
43−#else
44−toText :: Key -> Text
45−toText = id
46−
47−type Key = Text
48−#endif
49−
5031-- |
51−-- @since 0.8.13
32+-- Since 0.8.13
5233data Config = Config
5334 { confCompare :: Text -> Text -> Ordering -- ^ Function used to sort keys in objects
54− , confDropNull :: Bool -- ^ Drop null values from objects
5535 }
5636
57−-- | The default configuration: do not sort objects or drop keys
37+-- | The default configuration: do not sort objects.
5838--
59−-- @since 0.8.13
39+-- Since 0.8.13
6040defConfig :: Config
61−defConfig = Config mempty False
41+defConfig = Config mempty
6242
6343-- |
64−-- @since 0.8.13
44+-- Since 0.8.13
6545getConfCompare :: Config -> Text -> Text -> Ordering
6646getConfCompare = confCompare
6747
68−-- | Sets ordering for object keys
69−--
70−-- @since 0.8.13
48+-- |
49+-- Since 0.8.13
7150setConfCompare :: (Text -> Text -> Ordering) -> Config -> Config
7251setConfCompare cmp c = c { confCompare = cmp }
7352
74−-- |
75−-- @since 0.8.24
76−getConfDropNull :: Config -> Bool
77−getConfDropNull = confDropNull
78−
79−-- | Drop entries with `Null` value from objects, if set to `True`
80−--
81−-- @since 0.8.24
82−setConfDropNull :: Bool -> Config -> Config
83−setConfDropNull m c = c { confDropNull = m }
84−
8553pretty :: Config -> Value -> YamlBuilder
8654pretty cfg = go
87− where go (Object o) = let sort = sortBy (confCompare cfg `on` fst)
88− select
89− | confDropNull cfg = HM.filter (/= Null)
90− | otherwise = id
91− in mapping (sort $ fmap (first toText) $ HM.toList $ HM.map go $ select o)
55+ where go (Object o) = mapping (sortBy (confCompare cfg `on` fst) $ HM.toList $ HM.map go o)
9256 go (Array a) = array (go <$> V.toList a)
9357 go Null = null
9458 go (String s) = string s
@@ -97,6 +61,6 @@ pretty cfg = go
9761
9862-- | Configurable 'encode'.
9963--
100−-- @since 0.8.13
64+-- Since 0.8.13
10165encodePretty :: ToJSON a => Config -> a -> ByteString
10266encodePretty cfg = toByteString . pretty cfg . toJSON
Data/Yaml/TH.hsnew file+44
@@ -0,0 +1,44 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+{-# LANGUAGE TemplateHaskell #-}
4+
5+module Data.Yaml.TH
6+ ( -- * Decoding
7+ decodeFile
8+ -- * Re-exports from "Data.Yaml"
9+ , Value (..)
10+ , Parser
11+ , Object
12+ , Array
13+ , object
14+ , array
15+ , (.=)
16+ , (.:)
17+ , (.:?)
18+ , (.!=)
19+ , FromJSON (..)
20+ ) where
21+
22+import Data.Yaml hiding (decodeFile)
23+import Language.Haskell.TH
24+import Language.Haskell.TH.Syntax
25+
26+-- | Decode a @yaml@ file at compile time. Only available on GHC version @7.8.1@
27+-- or higher.
28+--
29+-- @since 0.8.19.0
30+--
31+-- ==== __Examples__
32+--
33+-- @
34+-- {-\# LANGUAGE TemplateHaskell \#-}
35+--
36+-- config :: Config
37+-- config = $$('decodeFile' "config.yaml")
38+-- @
39+decodeFile :: forall a. (Lift a, FromJSON a) => FilePath -> Q (TExp a)
40+decodeFile path = do
41+ addDependentFile path
42+ runIO (decodeFileEither path) >>= \case
43+ Left err -> fail (prettyPrintParseException err)
44+ Right x -> fmap TExp (lift (x :: a))
yaml/LICENSE → LICENSErenamed

The content is the same.

Makefilenew file+4
@@ -0,0 +1,4 @@
1+libhelper.so : helper.o
2+ gcc -shared -Wl,-soname,libhelper.so -o libhelper.so helper.o
3+helper.o : c/helper.c
4+ gcc -c -fPIC c/helper.c -o helper.o
README.md+10−16
@@ -1,23 +1,17 @@
1−# YAML Haskell Library
1+## yaml
22
3−[![Build Status](https://dev.azure.com/snoyberg/yaml/_apis/build/status/snoyberg.yaml?branchName=master)](https://dev.azure.com/snoyberg/yaml/_build/latest?definitionId=7&branchName=master)
3+Provides support for parsing and emitting Yaml documents.
44
5−This project contains two haskell packages: `yaml` for higher-level parsing and writing of yaml documents, and `libyaml`
6−for lower-level event-based streaming.
5+This package includes the [full libyaml C library version 0.1.5 by Kirill Simonov](http://pyyaml.org/wiki/LibYAML) in the package so you don't need to worry about any non-Haskell dependencies.
76
8−## `yaml` Package
7+The package is broken down into two primary modules. `Data.Yaml` provides a high-level interface based around the JSON datatypes provided by the `aeson` package. `Text.Libyaml` provides a lower-level, streaming interface. For most users, `Data.Yaml` is recommended.
98
10−`yaml` provides a high-level interface based around the JSON datatypes provided by the `aeson` package. This allows
11−using JSON and YAML interchangeably in your code with the `aeson` typeclasses. See the
12−[yaml README](https://github.com/snoyberg/yaml/tree/master/yaml/README.md) for more details.
9+### Examples
1310
14−## `libyaml` Package
11+Usage examples can be found in the `Data.Yaml` documentation or in the [examples](./examples) directory.
1512
16−`libyaml` is a wrapper over the libyaml C library (and includes the source so no external library is needed). It is an
17−event-based streaming API. See the [libyaml README](https://github.com/snoyberg/yaml/tree/master/libyaml/README.md) for
18−more details.
13+### Additional modules
1914
20−## License
21−
22−This project is licensed with the BSD 3-Clause license. Copies of the license can be found in both the `yaml` and
23−`libyaml` subdirectories
15+* `Data.Yaml.Include` supports adding `!include` directives to your YAML files.
16+* `Data.Yaml.Builder` and `Data.Yaml.Parser` allow more fine-grained control of parsing an rendering, as opposed to just using the aeson typeclass and datatype system for parsing and rendering.
17+* `Data.Yaml.Aeson` is currently a re-export of `Data.Yaml` to explicitly choose to use the aeson-compatible API.
yaml/Setup.lhs → Setup.lhsrenamed

The content is the same.

libyaml/src/Text/Libyaml.hs → Text/Libyaml.hsrenamed+138−318
@@ -7,37 +7,21 @@
77{-# LANGUAGE RankNTypes #-}
88{-# LANGUAGE CPP #-}
99{-# LANGUAGE TypeFamilies #-}
10−{-# LANGUAGE ScopedTypeVariables #-}
1110
1211-- | Low-level, streaming YAML interface. For a higher-level interface, see
1312-- "Data.Yaml".
1413module Text.Libyaml
1514 ( -- * The event stream
16− MarkedEvent(..)
17− , Event (..)
15+ Event (..)
1816 , Style (..)
19− , SequenceStyle (..)
20− , MappingStyle (..)
2117 , Tag (..)
2218 , AnchorName
2319 , Anchor
2420 -- * Encoding and decoding
2521 , encode
26− , encodeWith
2722 , decode
28− , decodeMarked
2923 , encodeFile
3024 , decodeFile
31− , decodeFileMarked
32− , encodeFileWith
33− , FormatOptions
34− , defaultFormatOptions
35− , setWidth
36− , setTagRendering
37− , renderScalarTags
38− , renderAllTags
39− , renderNoTags
40− , renderUriTags
4125 -- * Error handling
4226 , YamlException (..)
4327 , YamlMark (..)
@@ -65,16 +49,12 @@ import Control.Monad.Trans.Resource
6549import Data.Conduit hiding (Source, Sink, Conduit)
6650import Data.Data
6751
68−import Data.ByteString (ByteString, packCString, packCStringLen)
52+import Data.ByteString (ByteString, packCStringLen)
53+import qualified Data.ByteString
6954import qualified Data.ByteString.Char8 as B8
7055import qualified Data.ByteString.Internal as B
7156import qualified Data.ByteString.Unsafe as BU
7257
73−#if WINDOWS && __GLASGOW_HASKELL__ >= 806
74−import System.Directory (removeFile)
75−import qualified Control.Exception
76−#endif
77−
7858data Event =
7959 EventStreamStart
8060 | EventStreamEnd
@@ -82,23 +62,12 @@ data Event =
8262 | EventDocumentEnd
8363 | EventAlias !AnchorName
8464 | EventScalar !ByteString !Tag !Style !Anchor
85− | EventSequenceStart !Tag !SequenceStyle !Anchor
65+ | EventSequenceStart !Anchor
8666 | EventSequenceEnd
87− | EventMappingStart !Tag !MappingStyle !Anchor
67+ | EventMappingStart !Anchor
8868 | EventMappingEnd
8969 deriving (Show, Eq)
9070
91−-- | Event with start and end marks.
92−--
93−-- @since 0.10.4.0
94−data MarkedEvent = MarkedEvent
95− { yamlEvent :: Event
96− , yamlStartMark :: YamlMark
97− , yamlEndMark :: YamlMark
98− }
99−
100−-- | Style for scalars - e.g. quoted / folded
101−--
10271data Style = Any
10372 | Plain
10473 | SingleQuoted
@@ -108,18 +77,6 @@ data Style = Any
10877 | PlainNoTag
10978 deriving (Show, Read, Eq, Enum, Bounded, Ord, Data, Typeable)
11079
111−-- | Style for sequences - e.g. block or flow
112−--
113−-- @since 0.9.0
114−data SequenceStyle = AnySequence | BlockSequence | FlowSequence
115− deriving (Show, Eq, Enum, Bounded, Ord, Data, Typeable)
116−
117−-- | Style for mappings - e.g. block or flow
118−--
119−-- @since 0.9.0
120−data MappingStyle = AnyMapping | BlockMapping | FlowMapping
121− deriving (Show, Eq, Enum, Bounded, Ord, Data, Typeable)
122−
12380data Tag = StrTag
12481 | FloatTag
12582 | NullTag
@@ -132,11 +89,6 @@ data Tag = StrTag
13289 | NoTag
13390 deriving (Show, Eq, Read, Data, Typeable)
13491
135−tagSuppressed :: Tag -> Bool
136−tagSuppressed (NoTag) = True
137−tagSuppressed (UriTag "") = True
138−tagSuppressed _ = False
139−
14092type AnchorName = String
14193type Anchor = Maybe AnchorName
14294
@@ -194,24 +146,6 @@ foreign import ccall unsafe "yaml_parser_set_input_file"
194146 -> File
195147 -> IO ()
196148
197−data MarkRawStruct
198−type MarkRaw = Ptr MarkRawStruct
199−
200−foreign import ccall unsafe "get_mark_index"
201− c_get_mark_index :: MarkRaw -> IO CULong
202−
203−foreign import ccall unsafe "get_mark_line"
204− c_get_mark_line :: MarkRaw -> IO CULong
205−
206−foreign import ccall unsafe "get_mark_column"
207− c_get_mark_column :: MarkRaw -> IO CULong
208−
209−getMark :: MarkRaw -> IO YamlMark
210−getMark m = YamlMark
211− <$> (fromIntegral <$> c_get_mark_index m)
212− <*> (fromIntegral <$> c_get_mark_line m)
213− <*> (fromIntegral <$> c_get_mark_column m)
214−
215149data FileStruct
216150type File = Ptr FileStruct
217151
@@ -225,10 +159,10 @@ foreign import ccall unsafe "fdopen"
225159 -> IO File
226160foreign import ccall unsafe "fclose"
227161 c_fclose :: File
228− -> IO CInt
162+ -> IO ()
229163
230164foreign import ccall unsafe "fclose_helper"
231− c_fclose_helper :: File -> IO CInt
165+ c_fclose_helper :: File -> IO ()
232166
233167foreign import ccall unsafe "yaml_parser_parse"
234168 c_yaml_parser_parse :: Parser -> EventRaw -> IO CInt
@@ -242,8 +176,14 @@ foreign import ccall "get_parser_error_problem"
242176foreign import ccall "get_parser_error_context"
243177 c_get_parser_error_context :: Parser -> IO (Ptr CUChar)
244178
245−foreign import ccall unsafe "get_parser_error_mark"
246− c_get_parser_error_mark :: Parser -> IO MarkRaw
179+foreign import ccall unsafe "get_parser_error_index"
180+ c_get_parser_error_index :: Parser -> IO CULong
181+
182+foreign import ccall unsafe "get_parser_error_line"
183+ c_get_parser_error_line :: Parser -> IO CULong
184+
185+foreign import ccall unsafe "get_parser_error_column"
186+ c_get_parser_error_column :: Parser -> IO CULong
247187
248188makeString :: MonadIO m => (a -> m (Ptr CUChar)) -> a -> m String
249189makeString f a = do
@@ -268,12 +208,6 @@ data EventType = YamlNoEvent
268208foreign import ccall unsafe "get_event_type"
269209 c_get_event_type :: EventRaw -> IO CInt
270210
271−foreign import ccall unsafe "get_start_mark"
272− c_get_start_mark :: EventRaw -> IO MarkRaw
273−
274−foreign import ccall unsafe "get_end_mark"
275− c_get_end_mark :: EventRaw -> IO MarkRaw
276−
277211foreign import ccall unsafe "get_scalar_value"
278212 c_get_scalar_value :: EventRaw -> IO (Ptr CUChar)
279213
@@ -283,6 +217,9 @@ foreign import ccall unsafe "get_scalar_length"
283217foreign import ccall unsafe "get_scalar_tag"
284218 c_get_scalar_tag :: EventRaw -> IO (Ptr CUChar)
285219
220+foreign import ccall unsafe "get_scalar_tag_len"
221+ c_get_scalar_tag_len :: EventRaw -> IO CULong
222+
286223foreign import ccall unsafe "get_scalar_style"
287224 c_get_scalar_style :: EventRaw -> IO CInt
288225
@@ -292,43 +229,16 @@ foreign import ccall unsafe "get_scalar_anchor"
292229foreign import ccall unsafe "get_sequence_start_anchor"
293230 c_get_sequence_start_anchor :: EventRaw -> IO CString
294231
295−foreign import ccall unsafe "get_sequence_start_style"
296− c_get_sequence_start_style :: EventRaw -> IO CInt
297−
298−foreign import ccall unsafe "get_sequence_start_tag"
299− c_get_sequence_start_tag :: EventRaw -> IO (Ptr CUChar)
300−
301232foreign import ccall unsafe "get_mapping_start_anchor"
302233 c_get_mapping_start_anchor :: EventRaw -> IO CString
303234
304−foreign import ccall unsafe "get_mapping_start_style"
305− c_get_mapping_start_style :: EventRaw -> IO CInt
306−
307−foreign import ccall unsafe "get_mapping_start_tag"
308− c_get_mapping_start_tag :: EventRaw -> IO (Ptr CUChar)
309−
310235foreign import ccall unsafe "get_alias_anchor"
311236 c_get_alias_anchor :: EventRaw -> IO CString
312237
313−readAnchor :: (EventRaw -> IO CString) -> EventRaw -> IO Anchor
314−readAnchor getAnchor er = do
315− yanchor <- getAnchor er
316− if yanchor == nullPtr
317− then return Nothing
318− else Just <$> peekCString yanchor
319−
320−readStyle :: (Enum a) => (EventRaw -> IO CInt) -> EventRaw -> IO a
321−readStyle getStyle er = toEnum . fromEnum <$> getStyle er
322−
323−readTag :: (EventRaw -> IO (Ptr CUChar)) -> EventRaw -> IO Tag
324−readTag getTag er = bsToTag <$> (getTag er >>= packCString . castPtr)
325−
326−getEvent :: EventRaw -> IO (Maybe MarkedEvent)
238+getEvent :: EventRaw -> IO (Maybe Event)
327239getEvent er = do
328240 et <- c_get_event_type er
329− startMark <- c_get_start_mark er >>= getMark
330− endMark <- c_get_end_mark er >>= getMark
331− event <- case toEnum $ fromEnum et of
241+ case toEnum $ fromEnum et of
332242 YamlNoEvent -> return Nothing
333243 YamlStreamStartEvent -> return $ Just EventStreamStart
334244 YamlStreamEndEvent -> return $ Just EventStreamEnd
@@ -343,26 +253,38 @@ getEvent er = do
343253 YamlScalarEvent -> do
344254 yvalue <- c_get_scalar_value er
345255 ylen <- c_get_scalar_length er
256+ ytag <- c_get_scalar_tag er
257+ ytag_len <- c_get_scalar_tag_len er
258+ ystyle <- c_get_scalar_style er
259+ let ytag_len' = fromEnum ytag_len
346260 let yvalue' = castPtr yvalue
261+ let ytag' = castPtr ytag
347262 let ylen' = fromEnum ylen
348263 bs <- packCStringLen (yvalue', ylen')
349− tag <- readTag c_get_scalar_tag er
350− style <- readStyle c_get_scalar_style er
351− anchor <- readAnchor c_get_scalar_anchor er
352− return $ Just $ EventScalar bs tag style anchor
264+ tagbs <-
265+ if ytag_len' == 0
266+ then return Data.ByteString.empty
267+ else packCStringLen (ytag', ytag_len')
268+ let style = toEnum $ fromEnum ystyle
269+ yanchor <- c_get_scalar_anchor er
270+ anchor <- if yanchor == nullPtr
271+ then return Nothing
272+ else Just <$> peekCString yanchor
273+ return $ Just $ EventScalar bs (bsToTag tagbs) style anchor
353274 YamlSequenceStartEvent -> do
354− tag <- readTag c_get_sequence_start_tag er
355− style <- readStyle c_get_sequence_start_style er
356− anchor <- readAnchor c_get_sequence_start_anchor er
357− return $ Just $ EventSequenceStart tag style anchor
275+ yanchor <- c_get_sequence_start_anchor er
276+ anchor <- if yanchor == nullPtr
277+ then return Nothing
278+ else Just <$> peekCString yanchor
279+ return $ Just $ EventSequenceStart anchor
358280 YamlSequenceEndEvent -> return $ Just EventSequenceEnd
359281 YamlMappingStartEvent -> do
360− tag <- readTag c_get_mapping_start_tag er
361− style <- readStyle c_get_mapping_start_style er
362− anchor <- readAnchor c_get_mapping_start_anchor er
363− return $ Just $ EventMappingStart tag style anchor
282+ yanchor <- c_get_mapping_start_anchor er
283+ anchor <- if yanchor == nullPtr
284+ then return Nothing
285+ else Just <$> peekCString yanchor
286+ return $ Just $ EventMappingStart anchor
364287 YamlMappingEndEvent -> return $ Just EventMappingEnd
365− return $ (\e -> MarkedEvent e startMark endMark) <$> event
366288
367289-- Emitter
368290
@@ -402,9 +324,6 @@ foreign import ccall unsafe "yaml_emitter_set_unicode"
402324foreign import ccall unsafe "yaml_emitter_set_output_file"
403325 c_yaml_emitter_set_output_file :: Emitter -> File -> IO ()
404326
405−foreign import ccall unsafe "yaml_emitter_set_width"
406− c_yaml_emitter_set_width :: Emitter -> CInt -> IO ()
407−
408327foreign import ccall unsafe "yaml_emitter_emit"
409328 c_yaml_emitter_emit :: Emitter -> EventRaw -> IO CInt
410329
@@ -462,8 +381,8 @@ foreign import ccall unsafe "yaml_alias_event_initialize"
462381 -> Ptr CUChar
463382 -> IO CInt
464383
465−toEventRaw :: FormatOptions -> Event -> (EventRaw -> IO a) -> IO a
466−toEventRaw opts e f = allocaBytes eventSize $ \er -> do
384+toEventRaw :: Event -> (EventRaw -> IO a) -> IO a
385+toEventRaw e f = allocaBytes eventSize $ \er -> do
467386 ret <- case e of
468387 EventStreamStart ->
469388 c_yaml_stream_start_event_initialize
@@ -481,13 +400,13 @@ toEventRaw opts e f = allocaBytes eventSize $ \er -> do
481400 len' = fromIntegral len :: CInt
482401 let thetag' = tagToString thetag
483402 withCString thetag' $ \tag' -> do
484− let pi0 = tagsImplicit e
485− (pi, style) =
486− case style0 of
487− PlainNoTag -> (1, Plain)
488− x -> (pi0, x)
403+ let (pi, style) =
404+ case style0 of
405+ PlainNoTag -> (1, Plain)
406+ x -> (0, x)
489407 style' = toEnum $ fromEnum style
490408 tagP = castPtr tag'
409+ qi = if null thetag' then 1 else 0
491410 case anchor of
492411 Nothing ->
493412 c_yaml_scalar_event_initialize
@@ -497,7 +416,7 @@ toEventRaw opts e f = allocaBytes eventSize $ \er -> do
497416 value' -- value
498417 len' -- length
499418 pi -- plain_implicit
500− pi -- quoted_implicit
419+ qi -- quoted_implicit
501420 style' -- style
502421 Just anchor' ->
503422 withCString anchor' $ \anchorP' -> do
@@ -509,50 +428,42 @@ toEventRaw opts e f = allocaBytes eventSize $ \er -> do
509428 value' -- value
510429 len' -- length
511430 0 -- plain_implicit
512− pi -- quoted_implicit
431+ qi -- quoted_implicit
513432 style' -- style
514− EventSequenceStart tag style Nothing ->
515− withCString (tagToString tag) $ \tag' -> do
516− let tagP = castPtr tag'
433+ EventSequenceStart Nothing ->
434+ c_yaml_sequence_start_event_initialize
435+ er
436+ nullPtr
437+ nullPtr
438+ 1
439+ 0 -- YAML_ANY_SEQUENCE_STYLE
440+ EventSequenceStart (Just anchor) ->
441+ withCString anchor $ \anchor' -> do
442+ let anchorP = castPtr anchor'
517443 c_yaml_sequence_start_event_initialize
518− er
519− nullPtr
520− tagP
521− (tagsImplicit e)
522− (toEnum $ fromEnum style)
523− EventSequenceStart tag style (Just anchor) ->
524− withCString (tagToString tag) $ \tag' -> do
525− let tagP = castPtr tag'
526− withCString anchor $ \anchor' -> do
527− let anchorP = castPtr anchor'
528− c_yaml_sequence_start_event_initialize
529− er
530− anchorP
531− tagP
532− (tagsImplicit e)
533− (toEnum $ fromEnum style)
444+ er
445+ anchorP
446+ nullPtr
447+ 1
448+ 0 -- YAML_ANY_SEQUENCE_STYLE
534449 EventSequenceEnd ->
535450 c_yaml_sequence_end_event_initialize er
536− EventMappingStart tag style Nothing ->
537− withCString (tagToString tag) $ \tag' -> do
538− let tagP = castPtr tag'
451+ EventMappingStart Nothing ->
452+ c_yaml_mapping_start_event_initialize
453+ er
454+ nullPtr
455+ nullPtr
456+ 1
457+ 0 -- YAML_ANY_SEQUENCE_STYLE
458+ EventMappingStart (Just anchor) ->
459+ withCString anchor $ \anchor' -> do
460+ let anchorP = castPtr anchor'
539461 c_yaml_mapping_start_event_initialize
540462 er
463+ anchorP
541464 nullPtr
542− tagP
543− (tagsImplicit e)
544− (toEnum $ fromEnum style)
545− EventMappingStart tag style (Just anchor) ->
546− withCString (tagToString tag) $ \tag' -> do
547− withCString anchor $ \anchor' -> do
548− let tagP = castPtr tag'
549− let anchorP = castPtr anchor'
550− c_yaml_mapping_start_event_initialize
551− er
552− anchorP
553− tagP
554− (tagsImplicit e)
555− (toEnum $ fromEnum style)
465+ 1
466+ 0 -- YAML_ANY_SEQUENCE_STYLE
556467 EventMappingEnd ->
557468 c_yaml_mapping_end_event_initialize er
558469 EventAlias anchor ->
@@ -563,29 +474,19 @@ toEventRaw opts e f = allocaBytes eventSize $ \er -> do
563474 anchorP
564475 unless (ret == 1) $ throwIO $ ToEventRawException ret
565476 f er
566− where
567− tagsImplicit (EventScalar _ t _ _) | tagSuppressed t = 1
568− tagsImplicit (EventMappingStart t _ _) | tagSuppressed t = 1
569− tagsImplicit (EventSequenceStart t _ _) | tagSuppressed t = 1
570− tagsImplicit evt = toImplicitParam $ formatOptionsRenderTags opts evt
571477
572478newtype ToEventRawException = ToEventRawException CInt
573479 deriving (Show, Typeable)
574480instance Exception ToEventRawException
575481
576−-- | Create a conduit that yields events from a bytestring.
577−decode :: MonadResource m => B.ByteString -> ConduitM i Event m ()
578−decode = mapOutput yamlEvent . decodeMarked
579−
580−-- | Create a conduit that yields marked events from a bytestring.
581−--
582−-- This conduit will yield identical events to that of "decode", but also
583−-- includes start and end marks for each event.
584−--
585−-- @since 0.10.4.0
586−decodeMarked :: MonadResource m => B.ByteString -> ConduitM i MarkedEvent m ()
587−decodeMarked bs | B8.null bs = return ()
588−decodeMarked bs =
482+decode :: MonadResource m => B.ByteString
483+#if MIN_VERSION_conduit(1, 0, 0)
484+ -> Producer m Event
485+#else
486+ -> GSource m Event
487+#endif
488+decode bs | B8.null bs = return ()
489+decode bs =
589490 bracketP alloc cleanup (runParser . fst)
590491 where
591492 alloc = mask_ $ do
@@ -625,18 +526,13 @@ openFile file rawOpenFlags openMode = do
625526 then withCString openMode $ \openMode' -> c_fdopen fd openMode'
626527 else return nullPtr
627528
628−-- | Creata a conduit that yields events from a file.
629−decodeFile :: MonadResource m => FilePath -> ConduitM i Event m ()
630−decodeFile = mapOutput yamlEvent . decodeFileMarked
631−
632−-- | Create a conduit that yields marked events from a file.
633−--
634−-- This conduit will yield identical events to that of "decodeFile", but also
635−-- includes start and end marks for each event.
636−--
637−-- @since 0.10.4.0
638−decodeFileMarked :: MonadResource m => FilePath -> ConduitM i MarkedEvent m ()
639−decodeFileMarked file =
529+decodeFile :: MonadResource m => FilePath
530+#if MIN_VERSION_conduit(1, 0, 0)
531+ -> Producer m Event
532+#else
533+ -> GSource m Event
534+#endif
535+decodeFile file =
640536 bracketP alloc cleanup (runParser . fst)
641537 where
642538 alloc = mask_ $ do
@@ -659,12 +555,16 @@ decodeFileMarked file =
659555 c_yaml_parser_set_input_file ptr file'
660556 return (ptr, file')
661557 cleanup (ptr, file') = do
662− res <- c_fclose_helper file'
663− when (res /= 0) $ throwIO $ YamlException $ "could not close file: " ++ file
558+ c_fclose_helper file'
664559 c_yaml_parser_delete ptr
665560 free ptr
666561
667−runParser :: MonadResource m => Parser -> ConduitM i MarkedEvent m ()
562+runParser :: MonadResource m => Parser
563+#if MIN_VERSION_conduit(1, 0, 0)
564+ -> Producer m Event
565+#else
566+ -> GSource m Event
567+#endif
668568runParser parser = do
669569 e <- liftIO $ parserParseOne' parser
670570 case e of
@@ -673,7 +573,7 @@ runParser parser = do
673573 Right (Just ev) -> yield ev >> runParser parser
674574
675575parserParseOne' :: Parser
676− -> IO (Either YamlException (Maybe MarkedEvent))
576+ -> IO (Either YamlException (Maybe Event))
677577parserParseOne' parser = allocaBytes eventSize $ \er -> do
678578 res <- liftIO $ c_yaml_parser_parse parser er
679579 flip finally (c_yaml_event_delete er) $
@@ -681,92 +581,21 @@ parserParseOne' parser = allocaBytes eventSize $ \er -> do
681581 then do
682582 problem <- makeString c_get_parser_error_problem parser
683583 context <- makeString c_get_parser_error_context parser
684− problemMark <- c_get_parser_error_mark parser >>= getMark
584+ index <- c_get_parser_error_index parser
585+ line <- c_get_parser_error_line parser
586+ column <- c_get_parser_error_column parser
587+ let problemMark = YamlMark (fromIntegral index) (fromIntegral line) (fromIntegral column)
685588 return $ Left $ YamlParseException problem context problemMark
686589 else Right <$> getEvent er
687590
688−-- | Whether a tag should be rendered explicitly in the output or left
689−-- implicit.
690−--
691−-- @since 0.1.1.0
692−data TagRender = Explicit | Implicit
693− deriving (Enum)
694−
695−toImplicitParam :: TagRender -> CInt
696−toImplicitParam Explicit = 0
697−toImplicitParam Implicit = 1
698−
699−-- | A value for 'formatOptionsRenderTags' that renders no
700−-- collection tags but all scalar tags (unless suppressed with styles
701−-- 'NoTag or 'PlainNoTag').
702−--
703−-- @since 0.1.1.0
704−renderScalarTags :: Event -> TagRender
705−renderScalarTags (EventScalar _ _ _ _) = Explicit
706−renderScalarTags (EventSequenceStart _ _ _) = Implicit
707−renderScalarTags (EventMappingStart _ _ _) = Implicit
708−renderScalarTags _ = Implicit
709−
710−-- | A value for 'formatOptionsRenderTags' that renders all
711−-- tags (except 'NoTag' tag and 'PlainNoTag' style).
712−--
713−-- @since 0.1.1.0
714−renderAllTags :: Event -> TagRender
715−renderAllTags _ = Explicit
716−
717−-- | A value for 'formatOptionsRenderTags' that renders no
718−-- tags.
719−--
720−-- @since 0.1.1.0
721−renderNoTags :: Event -> TagRender
722−renderNoTags _ = Implicit
723−
724−-- | A value for 'formatOptionsRenderCollectionTags' that renders tags
725−-- which are instances of 'UriTag'
726−--
727−-- @since 0.1.1.0
728−renderUriTags :: Event -> TagRender
729−renderUriTags (EventScalar _ UriTag{} _ _) = Explicit
730−renderUriTags (EventSequenceStart UriTag{} _ _) = Explicit
731−renderUriTags (EventMappingStart UriTag{} _ _) = Explicit
732−renderUriTags _ = Implicit
733−
734−-- | Contains options relating to the formatting (indendation, width) of the YAML output.
735−--
736−-- @since 0.10.2.0
737−data FormatOptions = FormatOptions
738− { formatOptionsWidth :: Maybe Int
739− , formatOptionsRenderTags :: Event -> TagRender
740− }
741−
742−-- |
743−-- @since 0.10.2.0
744−defaultFormatOptions :: FormatOptions
745−defaultFormatOptions = FormatOptions
746− { formatOptionsWidth = Just 80 -- by default the width is set to 0 in the C code, which gets turned into 80 in yaml_emitter_emit_stream_start
747− , formatOptionsRenderTags = renderScalarTags
748− }
749−
750−-- | Set the maximum number of columns in the YAML output, or 'Nothing' for infinite. By default, the limit is 80 characters.
751−--
752−-- @since 0.10.2.0
753−setWidth :: Maybe Int -> FormatOptions -> FormatOptions
754−setWidth w opts = opts { formatOptionsWidth = w }
755−
756−-- | Control when and whether tags are rendered to output.
757−--
758−-- @since 0.1.1.0
759−setTagRendering :: (Event -> TagRender) -> FormatOptions -> FormatOptions
760−setTagRendering f opts = opts { formatOptionsRenderTags = f }
761−
762−encode :: MonadResource m => ConduitM Event o m ByteString
763−encode = encodeWith defaultFormatOptions
764−
765−-- |
766−-- @since 0.10.2.0
767−encodeWith :: MonadResource m => FormatOptions -> ConduitM Event o m ByteString
768−encodeWith opts =
769− runEmitter opts alloc close
591+encode :: MonadResource m
592+#if MIN_VERSION_conduit(1, 0, 0)
593+ => Consumer Event m ByteString
594+#else
595+ => GSink Event m ByteString
596+#endif
597+encode =
598+ runEmitter alloc close
770599 where
771600 alloc emitter = do
772601 fbuf <- mallocForeignPtrBytes bufferSize
@@ -776,34 +605,20 @@ encodeWith opts =
776605 close _ fbuf = withForeignPtr fbuf $ \b -> do
777606 ptr' <- c_get_buffer_buff b
778607 len <- c_get_buffer_used b
779− fptr <- newForeignPtr finalizerFree $ castPtr ptr'
608+ fptr <- newForeignPtr_ $ castPtr ptr'
780609 return $ B.fromForeignPtr fptr 0 $ fromIntegral len
781610
782−
783611encodeFile :: MonadResource m
784612 => FilePath
785− -> ConduitM Event o m ()
786−encodeFile = encodeFileWith defaultFormatOptions
787−
788−-- |
789−-- @since 0.10.2.0
790−encodeFileWith :: MonadResource m
791− => FormatOptions
792− -> FilePath
793− -> ConduitM Event o m ()
794−encodeFileWith opts filePath =
795− bracketP getFile cleanup $ \file -> runEmitter opts (alloc file) (\u _ -> return u)
613+#if MIN_VERSION_conduit(1, 0, 0)
614+ -> Consumer Event m ()
615+#else
616+ -> GInfSink Event m
617+#endif
618+encodeFile filePath =
619+ bracketP getFile c_fclose $ \file -> runEmitter (alloc file) (\u _ -> return u)
796620 where
797− cleanup file = do
798− res <- c_fclose file
799− when (res /= 0) $ throwIO $ YamlException $ "could not close file: " ++ filePath
800−
801621 getFile = do
802−#if WINDOWS && __GLASGOW_HASKELL__ >= 806
803− -- See: https://github.com/snoyberg/yaml/issues/178#issuecomment-550180027
804− removeFile filePath `Control.Exception.catch`
805− (\(_ :: Control.Exception.IOException) -> pure ())
806−#endif
807622 file <- openFile filePath write_flags "w"
808623 if file == nullPtr
809624 then throwIO $ YamlException $ "could not open file for write: " ++ filePath
@@ -812,11 +627,15 @@ encodeFileWith opts filePath =
812627 alloc file emitter = c_yaml_emitter_set_output_file emitter file
813628
814629runEmitter :: MonadResource m
815− => FormatOptions
816− -> (Emitter -> IO a) -- ^ alloc
630+ => (Emitter -> IO a) -- ^ alloc
631+#if MIN_VERSION_conduit(1, 0, 0)
817632 -> (() -> a -> IO b) -- ^ close
818− -> ConduitM Event o m b
819−runEmitter opts allocI closeI =
633+ -> Consumer Event m b
634+#else
635+ -> (u -> a -> IO b) -- ^ close
636+ -> Pipe l Event o u m b
637+#endif
638+runEmitter allocI closeI =
820639 bracketP alloc cleanup go
821640 where
822641 alloc = mask_ $ do
@@ -826,9 +645,6 @@ runEmitter opts allocI closeI =
826645#ifndef __NO_UNICODE__
827646 c_yaml_emitter_set_unicode emitter 1
828647#endif
829− c_yaml_emitter_set_width emitter $ case formatOptionsWidth opts of
830− Nothing -> -1 --infinite
831− Just width -> fromIntegral width
832648 a <- allocI emitter
833649 return (emitter, a)
834650 cleanup (emitter, _) = do
@@ -838,10 +654,14 @@ runEmitter opts allocI closeI =
838654 go (emitter, a) =
839655 loop
840656 where
657+#if MIN_VERSION_conduit(1, 0, 0)
841658 loop = await >>= maybe (close ()) push
659+#else
660+ loop = awaitE >>= either close push
661+#endif
842662
843663 push e = do
844− _ <- liftIO $ toEventRaw opts e $ c_yaml_emitter_emit emitter
664+ _ <- liftIO $ toEventRaw e $ c_yaml_emitter_emit emitter
845665 loop
846666 close u = liftIO $ closeI u a
847667
appveyor.ymlnew file+20
@@ -0,0 +1,20 @@
1+# Disabled cache in hope of improving reliability of AppVeyor builds
2+#cache:
3+#- "c:\\sr" # stack root, short paths == fewer problems
4+
5+build: off
6+
7+before_test:
8+- curl -sS -ostack.zip -L --insecure http://www.stackage.org/stack/windows-i386
9+- 7z x stack.zip stack.exe
10+
11+clone_folder: "c:\\stack"
12+environment:
13+ global:
14+ STACK_ROOT: "c:\\sr"
15+
16+test_script:
17+- stack setup > nul
18+# The ugly echo "" hack is to avoid complaints about 0 being an invalid file
19+# descriptor
20+- echo "" | stack --no-terminal test
yaml/builder-test.hs → builder-test.hsrenamed

The content is the same.

libyaml/c/helper.c → c/helper.crenamed+17−51
@@ -56,9 +56,19 @@ char const * get_parser_error_context(yaml_parser_t *p)
5656 return p->context;
5757}
5858
59−const yaml_mark_t * get_parser_error_mark(yaml_parser_t *p)
59+unsigned int get_parser_error_index(yaml_parser_t *p)
6060{
61− return &p->problem_mark;
61+ return p->problem_mark.index;
62+}
63+
64+unsigned int get_parser_error_line(yaml_parser_t *p)
65+{
66+ return p->problem_mark.line;
67+}
68+
69+unsigned int get_parser_error_column(yaml_parser_t *p)
70+{
71+ return p->problem_mark.column;
6272}
6373
6474char const * get_emitter_error(yaml_emitter_t *e)
@@ -98,6 +108,11 @@ unsigned char * get_scalar_tag(yaml_event_t *e)
98108 return s;
99109}
100110
111+unsigned long get_scalar_tag_len(yaml_event_t *e)
112+{
113+ return strlen((char *) get_scalar_tag(e));
114+}
115+
101116int get_scalar_style(yaml_event_t *e)
102117{
103118 return e->data.scalar.style;
@@ -113,65 +128,16 @@ unsigned char * get_sequence_start_anchor(yaml_event_t *e)
113128 return e->data.sequence_start.anchor;
114129}
115130
116−int get_sequence_start_style(yaml_event_t *e)
117−{
118− return e->data.sequence_start.style;
119−}
120−
121−unsigned char * get_sequence_start_tag(yaml_event_t *e)
122−{
123− unsigned char *s = e->data.sequence_start.tag;
124− if (!s) s = (unsigned char *) "";
125− return s;
126−}
127−
128131unsigned char * get_mapping_start_anchor(yaml_event_t *e)
129132{
130133 return e->data.mapping_start.anchor;
131134}
132135
133−int get_mapping_start_style(yaml_event_t *e)
134−{
135− return e->data.mapping_start.style;
136−}
137−
138−unsigned char * get_mapping_start_tag(yaml_event_t *e)
139−{
140− unsigned char *s = e->data.mapping_start.tag;
141− if (!s) s = (unsigned char *) "";
142− return s;
143−}
144−
145136unsigned char * get_alias_anchor(yaml_event_t *e)
146137{
147138 return e->data.alias.anchor;
148139}
149140
150−const yaml_mark_t * get_start_mark(yaml_event_t *e)
151−{
152− return &e->start_mark;
153−}
154−
155−const yaml_mark_t * get_end_mark(yaml_event_t *e)
156−{
157− return &e->end_mark;
158−}
159−
160−unsigned int get_mark_index(yaml_mark_t *m)
161−{
162− return m->index;
163−}
164−
165−unsigned int get_mark_line(yaml_mark_t *m)
166−{
167− return m->line;
168−}
169−
170−unsigned int get_mark_column(yaml_mark_t *m)
171−{
172− return m->column;
173−}
174−
175141int yaml_parser_set_input_filename(yaml_parser_t *parser, const char *filename)
176142{
177143 FILE *in = fopen(filename, "r");
libyaml/include/helper.h → c/helper.hrenamed+1−4
@@ -28,12 +28,9 @@ unsigned char * get_scalar_value(yaml_event_t *e);
2828unsigned long get_scalar_length(yaml_event_t *e);
2929
3030unsigned char * get_scalar_tag(yaml_event_t *e);
31−unsigned char * get_sequence_start_tag(yaml_event_t *e);
32−unsigned char * get_mapping_start_tag(yaml_event_t *e);
31+unsigned long get_scalar_tag_len(yaml_event_t *e);
3332
3433int get_scalar_style(yaml_event_t *e);
35−int get_sequence_start_style(yaml_event_t *e);
36−int get_mapping_start_style(yaml_event_t *e);
3734
3835unsigned char * get_scalar_anchor(yaml_event_t *e);
3936unsigned char * get_sequence_start_anchor(yaml_event_t *e);
yaml/examples/Config.hs → examples/Config.hsrenamed+2−3
@@ -50,6 +50,5 @@ instance FromJSON Config where
5050 parseJSON _ = fail "Expected Object for Config value"
5151
5252main :: IO ()
53−main = do
54− config <- Y.decodeThrow configYaml
55− print (config :: Config)
53+main =
54+ print $ (Y.decode configYaml :: Maybe Config)
yaml/examples/Main.hs → examples/Main.hsrenamed

The content is the same.

yaml/examples/Simple.hs → examples/Simple.hsrenamed+1−2
@@ -6,8 +6,7 @@ import qualified Data.Yaml as Y
66
77main :: IO ()
88main = do
9− res <- Y.decodeThrow "[1,2,3]"
10− print (res :: [Integer])
9+ print $ (Y.decode "[1,2,3]" :: Maybe [Integer])
1110
1211-- You can go one step further and decode into a custom type by implementing
1312-- 'FromJSON' for that type. This is also appropriate where extra
exe/json2yaml.hsnew file+22
@@ -0,0 +1,22 @@
1+import Control.Monad (when)
2+import qualified Data.Aeson as J
3+import qualified Data.ByteString as S
4+import qualified Data.ByteString.Lazy as L
5+import System.Environment (getArgs)
6+
7+import qualified Data.Yaml as Y
8+
9+main :: IO ()
10+main = do
11+ args <- getArgs
12+ when (length args > 2) $ error "Usage: json2yaml [in] [out]"
13+ let (input:output:_) = args ++ repeat "-"
14+ mval <- fmap J.decode $
15+ case input of
16+ "-" -> L.getContents
17+ _ -> L.readFile input
18+ case mval of
19+ Nothing -> error "Invalid input JSON"
20+ Just val -> case output of
21+ "-" -> S.putStr $ Y.encode (val :: Y.Value)
22+ _ -> Y.encodeFile output val
exe/yaml2json.hsnew file+28
@@ -0,0 +1,28 @@
1+import Prelude hiding (putStr, getContents)
2+
3+import Data.Aeson (encode, Value)
4+import Data.ByteString (getContents)
5+import Data.ByteString.Lazy (putStr)
6+import System.Environment (getArgs)
7+import System.Exit
8+
9+import Data.Yaml (decodeFileEither, decodeEither')
10+
11+helpMessage :: IO ()
12+helpMessage = putStrLn "yaml2json FILE\n use - as FILE to indicate stdin" >> exitFailure
13+
14+showJSON :: Show a => Either a Value -> IO b
15+showJSON ejson =
16+ case ejson of
17+ Left err -> print err >> exitFailure
18+ Right res -> putStr (encode (res :: Value)) >> exitSuccess
19+
20+main :: IO ()
21+main = do
22+ args <- getArgs
23+ case args of
24+ -- strict getContents will read in all of stdin at once
25+ (["-"]) -> getContents >>= showJSON . decodeEither'
26+ ([f]) -> decodeFileEither f >>= showJSON
27+ _ -> helpMessage
28+
libyaml/ChangeLog.mddeleted−27
@@ -1,27 +0,0 @@
1−# Changelog for libyaml
2−
3−## 0.1.4
4−
5−* Use libyaml-clib for the cbits
6−* Use pkg-config to link to system yaml
7−
8−## 0.1.3
9−
10−* Correct signature for `fclose`
11−
12−## 0.1.2
13−
14−* Upgrade `libyaml` to 0.2.2
15−
16−## 0.1.1.1
17−
18−* Work around GHC 8.6.5 issue on Windows preventing truncated files. [#178](https://github.com/snoyberg/yaml/issues/178)
19−
20−## 0.1.1.0
21−
22−* Add options to `FormatOptions` to govern when tags rendered explicitly and when they are left implicit. [#165](https://github.com/snoyberg/yaml/issues/165)
23−
24−## 0.1.0.0
25−
26−* Split `libyaml` into a separate package from `yaml`. This split occurred at
27− `yaml` version 0.10.4.0.
libyaml/LICENSE+16−22
@@ -1,25 +1,19 @@
1−The following license covers this documentation, and the source code, except
2−where otherwise indicated.
1+Copyright (c) 2006 Kirill Simonov
32
4−Copyright 2008, Michael Snoyman. All rights reserved.
3+Permission is hereby granted, free of charge, to any person obtaining a copy of
4+this software and associated documentation files (the "Software"), to deal in
5+the Software without restriction, including without limitation the rights to
6+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7+of the Software, and to permit persons to whom the Software is furnished to do
8+so, subject to the following conditions:
59
6−Redistribution and use in source and binary forms, with or without
7−modification, are permitted provided that the following conditions are met:
10+The above copyright notice and this permission notice shall be included in all
11+copies or substantial portions of the Software.
812
9−* Redistributions of source code must retain the above copyright notice, this
10− list of conditions and the following disclaimer.
11−
12−* Redistributions in binary form must reproduce the above copyright notice,
13− this list of conditions and the following disclaimer in the documentation
14− and/or other materials provided with the distribution.
15−
16−THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY EXPRESS OR
17−IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18−MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19−EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
20−INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21−NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
22−OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23−LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
24−OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25−ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19+SOFTWARE.
libyaml/Makefile+9−4
@@ -1,4 +1,9 @@
1−libhelper.so : helper.o
2− gcc -shared -Wl,-soname,libhelper.so -o libhelper.so helper.o
3−helper.o : c/helper.c
4− gcc -c -fPIC c/helper.c -o helper.o
1+CC = gcc
2+CFLAGS = -shared
3+OBJECTS = api.o dumper.o emitter.o loader.o parser.o reader.o scanner.o writer.o
4+LIB = libyaml.so
5+LFLAGS = -shared -Wl,-soname,libyaml.so
6+%.o: %.c
7+ $(CC) $(CFLAGS) -c -fPIC $<
8+yaml: $(OBJECTS)
9+ $(CC) $(LFLAGS) -o $(LIB) $(OBJECTS)
libyaml/README.mddeleted−3
@@ -1,3 +0,0 @@
1−# libyaml
2−
3−This package provides a haskell wrapper over the [libyaml C library version 0.2.2 by Kirill Simonov](https://github.com/yaml/libyaml). It contains the C source so you don't need to worry about any non-Haskell dependencies.
libyaml/Setup.hsdeleted−2
@@ -1,2 +0,0 @@
1−import Distribution.Simple
2−main = defaultMain
libyaml/api.cnew file+1403
@@ -0,0 +1,1403 @@
1+
2+#include "yaml_private.h"
3+
4+/*
5+ * Get the library version.
6+ */
7+
8+/*
9+ * added to support _WIN64
10+ */
11+#if _WIN64
12+#define STRDUP _strdup
13+#else
14+#define STRDUP strdup
15+#endif
16+
17+YAML_DECLARE(const char *)
18+yaml_get_version_string(void)
19+{
20+ return YAML_VERSION_STRING;
21+}
22+
23+/*
24+ * Get the library version numbers.
25+ */
26+
27+YAML_DECLARE(void)
28+yaml_get_version(int *major, int *minor, int *patch)
29+{
30+ *major = YAML_VERSION_MAJOR;
31+ *minor = YAML_VERSION_MINOR;
32+ *patch = YAML_VERSION_PATCH;
33+}
34+
35+/*
36+ * Allocate a dynamic memory block.
37+ */
38+
39+YAML_DECLARE(void *)
40+yaml_malloc(size_t size)
41+{
42+ return malloc(size ? size : 1);
43+}
44+
45+/*
46+ * Reallocate a dynamic memory block.
47+ */
48+
49+YAML_DECLARE(void *)
50+yaml_realloc(void *ptr, size_t size)
51+{
52+ return ptr ? realloc(ptr, size ? size : 1) : malloc(size ? size : 1);
53+}
54+
55+/*
56+ * Free a dynamic memory block.
57+ */
58+
59+YAML_DECLARE(void)
60+yaml_free(void *ptr)
61+{
62+ if (ptr) free(ptr);
63+}
64+
65+/*
66+ * Duplicate a string.
67+ */
68+
69+YAML_DECLARE(yaml_char_t *)
70+yaml_strdup(const yaml_char_t *str)
71+{
72+ if (!str)
73+ return NULL;
74+
75+ return (yaml_char_t *) STRDUP((char *)str);
76+}
77+
78+/*
79+ * Extend a string.
80+ */
81+
82+YAML_DECLARE(int)
83+yaml_string_extend(yaml_char_t **start,
84+ yaml_char_t **pointer, yaml_char_t **end)
85+{
86+ yaml_char_t *new_start = yaml_realloc(*start, (*end - *start)*2);
87+
88+ if (!new_start) return 0;
89+
90+ memset(new_start + (*end - *start), 0, *end - *start);
91+
92+ *pointer = new_start + (*pointer - *start);
93+ *end = new_start + (*end - *start)*2;
94+ *start = new_start;
95+
96+ return 1;
97+}
98+
99+/*
100+ * Append a string B to a string A.
101+ */
102+
103+YAML_DECLARE(int)
104+yaml_string_join(
105+ yaml_char_t **a_start, yaml_char_t **a_pointer, yaml_char_t **a_end,
106+ yaml_char_t **b_start, yaml_char_t **b_pointer, yaml_char_t **b_end)
107+{
108+ if (*b_start == *b_pointer)
109+ return 1;
110+
111+ while (*a_end - *a_pointer <= *b_pointer - *b_start) {
112+ if (!yaml_string_extend(a_start, a_pointer, a_end))
113+ return 0;
114+ }
115+
116+ memcpy(*a_pointer, *b_start, *b_pointer - *b_start);
117+ *a_pointer += *b_pointer - *b_start;
118+
119+ return 1;
120+}
121+
122+/*
123+ * Extend a stack.
124+ */
125+
126+YAML_DECLARE(int)
127+yaml_stack_extend(void **start, void **top, void **end)
128+{
129+ void *new_start = yaml_realloc(*start, ((char *)*end - (char *)*start)*2);
130+
131+ if (!new_start) return 0;
132+
133+ *top = (char *)new_start + ((char *)*top - (char *)*start);
134+ *end = (char *)new_start + ((char *)*end - (char *)*start)*2;
135+ *start = new_start;
136+
137+ return 1;
138+}
139+
140+/*
141+ * Extend or move a queue.
142+ */
143+
144+YAML_DECLARE(int)
145+yaml_queue_extend(void **start, void **head, void **tail, void **end)
146+{
147+ /* Check if we need to resize the queue. */
148+
149+ if (*start == *head && *tail == *end) {
150+ void *new_start = yaml_realloc(*start,
151+ ((char *)*end - (char *)*start)*2);
152+
153+ if (!new_start) return 0;
154+
155+ *head = (char *)new_start + ((char *)*head - (char *)*start);
156+ *tail = (char *)new_start + ((char *)*tail - (char *)*start);
157+ *end = (char *)new_start + ((char *)*end - (char *)*start)*2;
158+ *start = new_start;
159+ }
160+
161+ /* Check if we need to move the queue at the beginning of the buffer. */
162+
163+ if (*tail == *end) {
164+ if (*head != *tail) {
165+ memmove(*start, *head, (char *)*tail - (char *)*head);
166+ }
167+ *tail = (char *)*tail - (char *)*head + (char *)*start;
168+ *head = *start;
169+ }
170+
171+ return 1;
172+}
173+
174+
175+/*
176+ * Create a new parser object.
177+ */
178+
179+YAML_DECLARE(int)
180+yaml_parser_initialize(yaml_parser_t *parser)
181+{
182+ assert(parser); /* Non-NULL parser object expected. */
183+
184+ memset(parser, 0, sizeof(yaml_parser_t));
185+ if (!BUFFER_INIT(parser, parser->raw_buffer, INPUT_RAW_BUFFER_SIZE))
186+ goto error;
187+ if (!BUFFER_INIT(parser, parser->buffer, INPUT_BUFFER_SIZE))
188+ goto error;
189+ if (!QUEUE_INIT(parser, parser->tokens, INITIAL_QUEUE_SIZE))
190+ goto error;
191+ if (!STACK_INIT(parser, parser->indents, INITIAL_STACK_SIZE))
192+ goto error;
193+ if (!STACK_INIT(parser, parser->simple_keys, INITIAL_STACK_SIZE))
194+ goto error;
195+ if (!STACK_INIT(parser, parser->states, INITIAL_STACK_SIZE))
196+ goto error;
197+ if (!STACK_INIT(parser, parser->marks, INITIAL_STACK_SIZE))
198+ goto error;
199+ if (!STACK_INIT(parser, parser->tag_directives, INITIAL_STACK_SIZE))
200+ goto error;
201+
202+ return 1;
203+
204+error:
205+
206+ BUFFER_DEL(parser, parser->raw_buffer);
207+ BUFFER_DEL(parser, parser->buffer);
208+ QUEUE_DEL(parser, parser->tokens);
209+ STACK_DEL(parser, parser->indents);
210+ STACK_DEL(parser, parser->simple_keys);
211+ STACK_DEL(parser, parser->states);
212+ STACK_DEL(parser, parser->marks);
213+ STACK_DEL(parser, parser->tag_directives);
214+
215+ return 0;
216+}
217+
218+/*
219+ * Destroy a parser object.
220+ */
221+
222+YAML_DECLARE(void)
223+yaml_parser_delete(yaml_parser_t *parser)
224+{
225+ assert(parser); /* Non-NULL parser object expected. */
226+
227+ BUFFER_DEL(parser, parser->raw_buffer);
228+ BUFFER_DEL(parser, parser->buffer);
229+ while (!QUEUE_EMPTY(parser, parser->tokens)) {
230+ yaml_token_delete(&DEQUEUE(parser, parser->tokens));
231+ }
232+ QUEUE_DEL(parser, parser->tokens);
233+ STACK_DEL(parser, parser->indents);
234+ STACK_DEL(parser, parser->simple_keys);
235+ STACK_DEL(parser, parser->states);
236+ STACK_DEL(parser, parser->marks);
237+ while (!STACK_EMPTY(parser, parser->tag_directives)) {
238+ yaml_tag_directive_t tag_directive = POP(parser, parser->tag_directives);
239+ yaml_free(tag_directive.handle);
240+ yaml_free(tag_directive.prefix);
241+ }
242+ STACK_DEL(parser, parser->tag_directives);
243+
244+ memset(parser, 0, sizeof(yaml_parser_t));
245+}
246+
247+/*
248+ * String read handler.
249+ */
250+
251+static int
252+yaml_string_read_handler(void *data, unsigned char *buffer, size_t size,
253+ size_t *size_read)
254+{
255+ yaml_parser_t *parser = data;
256+
257+ if (parser->input.string.current == parser->input.string.end) {
258+ *size_read = 0;
259+ return 1;
260+ }
261+
262+ if (size > (size_t)(parser->input.string.end
263+ - parser->input.string.current)) {
264+ size = parser->input.string.end - parser->input.string.current;
265+ }
266+
267+ memcpy(buffer, parser->input.string.current, size);
268+ parser->input.string.current += size;
269+ *size_read = size;
270+ return 1;
271+}
272+
273+/*
274+ * File read handler.
275+ */
276+
277+static int
278+yaml_file_read_handler(void *data, unsigned char *buffer, size_t size,
279+ size_t *size_read)
280+{
281+ yaml_parser_t *parser = data;
282+
283+ *size_read = fread(buffer, 1, size, parser->input.file);
284+ return !ferror(parser->input.file);
285+}
286+
287+/*
288+ * Set a string input.
289+ */
290+
291+YAML_DECLARE(void)
292+yaml_parser_set_input_string(yaml_parser_t *parser,
293+ const unsigned char *input, size_t size)
294+{
295+ assert(parser); /* Non-NULL parser object expected. */
296+ assert(!parser->read_handler); /* You can set the source only once. */
297+ assert(input); /* Non-NULL input string expected. */
298+
299+ parser->read_handler = yaml_string_read_handler;
300+ parser->read_handler_data = parser;
301+
302+ parser->input.string.start = input;
303+ parser->input.string.current = input;
304+ parser->input.string.end = input+size;
305+}
306+
307+/*
308+ * Set a file input.
309+ */
310+
311+YAML_DECLARE(void)
312+yaml_parser_set_input_file(yaml_parser_t *parser, FILE *file)
313+{
314+ assert(parser); /* Non-NULL parser object expected. */
315+ assert(!parser->read_handler); /* You can set the source only once. */
316+ assert(file); /* Non-NULL file object expected. */
317+
318+ parser->read_handler = yaml_file_read_handler;
319+ parser->read_handler_data = parser;
320+
321+ parser->input.file = file;
322+}
323+
324+/*
325+ * Set a generic input.
326+ */
327+
328+YAML_DECLARE(void)
329+yaml_parser_set_input(yaml_parser_t *parser,
330+ yaml_read_handler_t *handler, void *data)
331+{
332+ assert(parser); /* Non-NULL parser object expected. */
333+ assert(!parser->read_handler); /* You can set the source only once. */
334+ assert(handler); /* Non-NULL read handler expected. */
335+
336+ parser->read_handler = handler;
337+ parser->read_handler_data = data;
338+}
339+
340+/*
341+ * Set the source encoding.
342+ */
343+
344+YAML_DECLARE(void)
345+yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding)
346+{
347+ assert(parser); /* Non-NULL parser object expected. */
348+ assert(!parser->encoding); /* Encoding is already set or detected. */
349+
350+ parser->encoding = encoding;
351+}
352+
353+/*
354+ * Create a new emitter object.
355+ */
356+
357+YAML_DECLARE(int)
358+yaml_emitter_initialize(yaml_emitter_t *emitter)
359+{
360+ assert(emitter); /* Non-NULL emitter object expected. */
361+
362+ memset(emitter, 0, sizeof(yaml_emitter_t));
363+ if (!BUFFER_INIT(emitter, emitter->buffer, OUTPUT_BUFFER_SIZE))
364+ goto error;
365+ if (!BUFFER_INIT(emitter, emitter->raw_buffer, OUTPUT_RAW_BUFFER_SIZE))
366+ goto error;
367+ if (!STACK_INIT(emitter, emitter->states, INITIAL_STACK_SIZE))
368+ goto error;
369+ if (!QUEUE_INIT(emitter, emitter->events, INITIAL_QUEUE_SIZE))
370+ goto error;
371+ if (!STACK_INIT(emitter, emitter->indents, INITIAL_STACK_SIZE))
372+ goto error;
373+ if (!STACK_INIT(emitter, emitter->tag_directives, INITIAL_STACK_SIZE))
374+ goto error;
375+
376+ return 1;
377+
378+error:
379+
380+ BUFFER_DEL(emitter, emitter->buffer);
381+ BUFFER_DEL(emitter, emitter->raw_buffer);
382+ STACK_DEL(emitter, emitter->states);
383+ QUEUE_DEL(emitter, emitter->events);
384+ STACK_DEL(emitter, emitter->indents);
385+ STACK_DEL(emitter, emitter->tag_directives);
386+
387+ return 0;
388+}
389+
390+/*
391+ * Destroy an emitter object.
392+ */
393+
394+YAML_DECLARE(void)
395+yaml_emitter_delete(yaml_emitter_t *emitter)
396+{
397+ assert(emitter); /* Non-NULL emitter object expected. */
398+
399+ BUFFER_DEL(emitter, emitter->buffer);
400+ BUFFER_DEL(emitter, emitter->raw_buffer);
401+ STACK_DEL(emitter, emitter->states);
402+ while (!QUEUE_EMPTY(emitter, emitter->events)) {
403+ yaml_event_delete(&DEQUEUE(emitter, emitter->events));
404+ }
405+ QUEUE_DEL(emitter, emitter->events);
406+ STACK_DEL(emitter, emitter->indents);
407+ while (!STACK_EMPTY(empty, emitter->tag_directives)) {
408+ yaml_tag_directive_t tag_directive = POP(emitter, emitter->tag_directives);
409+ yaml_free(tag_directive.handle);
410+ yaml_free(tag_directive.prefix);
411+ }
412+ STACK_DEL(emitter, emitter->tag_directives);
413+ yaml_free(emitter->anchors);
414+
415+ memset(emitter, 0, sizeof(yaml_emitter_t));
416+}
417+
418+/*
419+ * String write handler.
420+ */
421+
422+static int
423+yaml_string_write_handler(void *data, unsigned char *buffer, size_t size)
424+{
425+ yaml_emitter_t *emitter = data;
426+
427+ if (emitter->output.string.size + *emitter->output.string.size_written
428+ < size) {
429+ memcpy(emitter->output.string.buffer
430+ + *emitter->output.string.size_written,
431+ buffer,
432+ emitter->output.string.size
433+ - *emitter->output.string.size_written);
434+ *emitter->output.string.size_written = emitter->output.string.size;
435+ return 0;
436+ }
437+
438+ memcpy(emitter->output.string.buffer
439+ + *emitter->output.string.size_written, buffer, size);
440+ *emitter->output.string.size_written += size;
441+ return 1;
442+}
443+
444+/*
445+ * File write handler.
446+ */
447+
448+static int
449+yaml_file_write_handler(void *data, unsigned char *buffer, size_t size)
450+{
451+ yaml_emitter_t *emitter = data;
452+
453+ return (fwrite(buffer, 1, size, emitter->output.file) == size);
454+}
455+/*
456+ * Set a string output.
457+ */
458+
459+YAML_DECLARE(void)
460+yaml_emitter_set_output_string(yaml_emitter_t *emitter,
461+ unsigned char *output, size_t size, size_t *size_written)
462+{
463+ assert(emitter); /* Non-NULL emitter object expected. */
464+ assert(!emitter->write_handler); /* You can set the output only once. */
465+ assert(output); /* Non-NULL output string expected. */
466+
467+ emitter->write_handler = yaml_string_write_handler;
468+ emitter->write_handler_data = emitter;
469+
470+ emitter->output.string.buffer = output;
471+ emitter->output.string.size = size;
472+ emitter->output.string.size_written = size_written;
473+ *size_written = 0;
474+}
475+
476+/*
477+ * Set a file output.
478+ */
479+
480+YAML_DECLARE(void)
481+yaml_emitter_set_output_file(yaml_emitter_t *emitter, FILE *file)
482+{
483+ assert(emitter); /* Non-NULL emitter object expected. */
484+ assert(!emitter->write_handler); /* You can set the output only once. */
485+ assert(file); /* Non-NULL file object expected. */
486+
487+ emitter->write_handler = yaml_file_write_handler;
488+ emitter->write_handler_data = emitter;
489+
490+ emitter->output.file = file;
491+}
492+
493+/*
494+ * Set a generic output handler.
495+ */
496+
497+YAML_DECLARE(void)
498+yaml_emitter_set_output(yaml_emitter_t *emitter,
499+ yaml_write_handler_t *handler, void *data)
500+{
501+ assert(emitter); /* Non-NULL emitter object expected. */
502+ assert(!emitter->write_handler); /* You can set the output only once. */
503+ assert(handler); /* Non-NULL handler object expected. */
504+
505+ emitter->write_handler = handler;
506+ emitter->write_handler_data = data;
507+}
508+
509+/*
510+ * Set the output encoding.
511+ */
512+
513+YAML_DECLARE(void)
514+yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding)
515+{
516+ assert(emitter); /* Non-NULL emitter object expected. */
517+ assert(!emitter->encoding); /* You can set encoding only once. */
518+
519+ emitter->encoding = encoding;
520+}
521+
522+/*
523+ * Set the canonical output style.
524+ */
525+
526+YAML_DECLARE(void)
527+yaml_emitter_set_canonical(yaml_emitter_t *emitter, int canonical)
528+{
529+ assert(emitter); /* Non-NULL emitter object expected. */
530+
531+ emitter->canonical = (canonical != 0);
532+}
533+
534+/*
535+ * Set the indentation increment.
536+ */
537+
538+YAML_DECLARE(void)
539+yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent)
540+{
541+ assert(emitter); /* Non-NULL emitter object expected. */
542+
543+ emitter->best_indent = (1 < indent && indent < 10) ? indent : 2;
544+}
545+
546+/*
547+ * Set the preferred line width.
548+ */
549+
550+YAML_DECLARE(void)
551+yaml_emitter_set_width(yaml_emitter_t *emitter, int width)
552+{
553+ assert(emitter); /* Non-NULL emitter object expected. */
554+
555+ emitter->best_width = (width >= 0) ? width : -1;
556+}
557+
558+/*
559+ * Set if unescaped non-ASCII characters are allowed.
560+ */
561+
562+YAML_DECLARE(void)
563+yaml_emitter_set_unicode(yaml_emitter_t *emitter, int unicode)
564+{
565+ assert(emitter); /* Non-NULL emitter object expected. */
566+
567+ emitter->unicode = (unicode != 0);
568+}
569+
570+/*
571+ * Set the preferred line break character.
572+ */
573+
574+YAML_DECLARE(void)
575+yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break)
576+{
577+ assert(emitter); /* Non-NULL emitter object expected. */
578+
579+ emitter->line_break = line_break;
580+}
581+
582+/*
583+ * Destroy a token object.
584+ */
585+
586+YAML_DECLARE(void)
587+yaml_token_delete(yaml_token_t *token)
588+{
589+ assert(token); /* Non-NULL token object expected. */
590+
591+ switch (token->type)
592+ {
593+ case YAML_TAG_DIRECTIVE_TOKEN:
594+ yaml_free(token->data.tag_directive.handle);
595+ yaml_free(token->data.tag_directive.prefix);
596+ break;
597+
598+ case YAML_ALIAS_TOKEN:
599+ yaml_free(token->data.alias.value);
600+ break;
601+
602+ case YAML_ANCHOR_TOKEN:
603+ yaml_free(token->data.anchor.value);
604+ break;
605+
606+ case YAML_TAG_TOKEN:
607+ yaml_free(token->data.tag.handle);
608+ yaml_free(token->data.tag.suffix);
609+ break;
610+
611+ case YAML_SCALAR_TOKEN:
612+ yaml_free(token->data.scalar.value);
613+ break;
614+
615+ default:
616+ break;
617+ }
618+
619+ memset(token, 0, sizeof(yaml_token_t));
620+}
621+
622+/*
623+ * Check if a string is a valid UTF-8 sequence.
624+ *
625+ * Check 'reader.c' for more details on UTF-8 encoding.
626+ */
627+
628+static int
629+yaml_check_utf8(yaml_char_t *start, size_t length)
630+{
631+ yaml_char_t *end = start+length;
632+ yaml_char_t *pointer = start;
633+
634+ while (pointer < end) {
635+ unsigned char octet;
636+ unsigned int width;
637+ unsigned int value;
638+ size_t k;
639+
640+ octet = pointer[0];
641+ width = (octet & 0x80) == 0x00 ? 1 :
642+ (octet & 0xE0) == 0xC0 ? 2 :
643+ (octet & 0xF0) == 0xE0 ? 3 :
644+ (octet & 0xF8) == 0xF0 ? 4 : 0;
645+ value = (octet & 0x80) == 0x00 ? octet & 0x7F :
646+ (octet & 0xE0) == 0xC0 ? octet & 0x1F :
647+ (octet & 0xF0) == 0xE0 ? octet & 0x0F :
648+ (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
649+ if (!width) return 0;
650+ if (pointer+width > end) return 0;
651+ for (k = 1; k < width; k ++) {
652+ octet = pointer[k];
653+ if ((octet & 0xC0) != 0x80) return 0;
654+ value = (value << 6) + (octet & 0x3F);
655+ }
656+ if (!((width == 1) ||
657+ (width == 2 && value >= 0x80) ||
658+ (width == 3 && value >= 0x800) ||
659+ (width == 4 && value >= 0x10000))) return 0;
660+
661+ pointer += width;
662+ }
663+
664+ return 1;
665+}
666+
667+/*
668+ * Create STREAM-START.
669+ */
670+
671+YAML_DECLARE(int)
672+yaml_stream_start_event_initialize(yaml_event_t *event,
673+ yaml_encoding_t encoding)
674+{
675+ yaml_mark_t mark = { 0, 0, 0 };
676+
677+ assert(event); /* Non-NULL event object is expected. */
678+
679+ STREAM_START_EVENT_INIT(*event, encoding, mark, mark);
680+
681+ return 1;
682+}
683+
684+/*
685+ * Create STREAM-END.
686+ */
687+
688+YAML_DECLARE(int)
689+yaml_stream_end_event_initialize(yaml_event_t *event)
690+{
691+ yaml_mark_t mark = { 0, 0, 0 };
692+
693+ assert(event); /* Non-NULL event object is expected. */
694+
695+ STREAM_END_EVENT_INIT(*event, mark, mark);
696+
697+ return 1;
698+}
699+
700+/*
701+ * Create DOCUMENT-START.
702+ */
703+
704+YAML_DECLARE(int)
705+yaml_document_start_event_initialize(yaml_event_t *event,
706+ yaml_version_directive_t *version_directive,
707+ yaml_tag_directive_t *tag_directives_start,
708+ yaml_tag_directive_t *tag_directives_end,
709+ int implicit)
710+{
711+ struct {
712+ yaml_error_type_t error;
713+ } context;
714+ yaml_mark_t mark = { 0, 0, 0 };
715+ yaml_version_directive_t *version_directive_copy = NULL;
716+ struct {
717+ yaml_tag_directive_t *start;
718+ yaml_tag_directive_t *end;
719+ yaml_tag_directive_t *top;
720+ } tag_directives_copy = { NULL, NULL, NULL };
721+ yaml_tag_directive_t value = { NULL, NULL };
722+
723+ assert(event); /* Non-NULL event object is expected. */
724+ assert((tag_directives_start && tag_directives_end) ||
725+ (tag_directives_start == tag_directives_end));
726+ /* Valid tag directives are expected. */
727+
728+ if (version_directive) {
729+ version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t));
730+ if (!version_directive_copy) goto error;
731+ version_directive_copy->major = version_directive->major;
732+ version_directive_copy->minor = version_directive->minor;
733+ }
734+
735+ if (tag_directives_start != tag_directives_end) {
736+ yaml_tag_directive_t *tag_directive;
737+ if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
738+ goto error;
739+ for (tag_directive = tag_directives_start;
740+ tag_directive != tag_directives_end; tag_directive ++) {
741+ assert(tag_directive->handle);
742+ assert(tag_directive->prefix);
743+ if (!yaml_check_utf8(tag_directive->handle,
744+ strlen((char *)tag_directive->handle)))
745+ goto error;
746+ if (!yaml_check_utf8(tag_directive->prefix,
747+ strlen((char *)tag_directive->prefix)))
748+ goto error;
749+ value.handle = yaml_strdup(tag_directive->handle);
750+ value.prefix = yaml_strdup(tag_directive->prefix);
751+ if (!value.handle || !value.prefix) goto error;
752+ if (!PUSH(&context, tag_directives_copy, value))
753+ goto error;
754+ value.handle = NULL;
755+ value.prefix = NULL;
756+ }
757+ }
758+
759+ DOCUMENT_START_EVENT_INIT(*event, version_directive_copy,
760+ tag_directives_copy.start, tag_directives_copy.top,
761+ implicit, mark, mark);
762+
763+ return 1;
764+
765+error:
766+ yaml_free(version_directive_copy);
767+ while (!STACK_EMPTY(context, tag_directives_copy)) {
768+ yaml_tag_directive_t value = POP(context, tag_directives_copy);
769+ yaml_free(value.handle);
770+ yaml_free(value.prefix);
771+ }
772+ STACK_DEL(context, tag_directives_copy);
773+ yaml_free(value.handle);
774+ yaml_free(value.prefix);
775+
776+ return 0;
777+}
778+
779+/*
780+ * Create DOCUMENT-END.
781+ */
782+
783+YAML_DECLARE(int)
784+yaml_document_end_event_initialize(yaml_event_t *event, int implicit)
785+{
786+ yaml_mark_t mark = { 0, 0, 0 };
787+
788+ assert(event); /* Non-NULL emitter object is expected. */
789+
790+ DOCUMENT_END_EVENT_INIT(*event, implicit, mark, mark);
791+
792+ return 1;
793+}
794+
795+/*
796+ * Create ALIAS.
797+ */
798+
799+YAML_DECLARE(int)
800+yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor)
801+{
802+ yaml_mark_t mark = { 0, 0, 0 };
803+ yaml_char_t *anchor_copy = NULL;
804+
805+ assert(event); /* Non-NULL event object is expected. */
806+ assert(anchor); /* Non-NULL anchor is expected. */
807+
808+ if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0;
809+
810+ anchor_copy = yaml_strdup(anchor);
811+ if (!anchor_copy)
812+ return 0;
813+
814+ ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark);
815+
816+ return 1;
817+}
818+
819+/*
820+ * Create SCALAR.
821+ */
822+
823+YAML_DECLARE(int)
824+yaml_scalar_event_initialize(yaml_event_t *event,
825+ yaml_char_t *anchor, yaml_char_t *tag,
826+ yaml_char_t *value, int length,
827+ int plain_implicit, int quoted_implicit,
828+ yaml_scalar_style_t style)
829+{
830+ yaml_mark_t mark = { 0, 0, 0 };
831+ yaml_char_t *anchor_copy = NULL;
832+ yaml_char_t *tag_copy = NULL;
833+ yaml_char_t *value_copy = NULL;
834+
835+ assert(event); /* Non-NULL event object is expected. */
836+ /* following line added for Haskell yaml library */
837+ if (!value && !length) value = "";
838+ assert(value); /* Non-NULL anchor is expected. */
839+
840+ if (anchor) {
841+ if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error;
842+ anchor_copy = yaml_strdup(anchor);
843+ if (!anchor_copy) goto error;
844+ }
845+
846+ if (tag) {
847+ if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
848+ tag_copy = yaml_strdup(tag);
849+ if (!tag_copy) goto error;
850+ }
851+
852+ if (length < 0) {
853+ length = strlen((char *)value);
854+ }
855+
856+ if (!yaml_check_utf8(value, length)) goto error;
857+ value_copy = yaml_malloc(length+1);
858+ if (!value_copy) goto error;
859+ memcpy(value_copy, value, length);
860+ value_copy[length] = '\0';
861+
862+ SCALAR_EVENT_INIT(*event, anchor_copy, tag_copy, value_copy, length,
863+ plain_implicit, quoted_implicit, style, mark, mark);
864+
865+ return 1;
866+
867+error:
868+ yaml_free(anchor_copy);
869+ yaml_free(tag_copy);
870+ yaml_free(value_copy);
871+
872+ return 0;
873+}
874+
875+/*
876+ * Create SEQUENCE-START.
877+ */
878+
879+YAML_DECLARE(int)
880+yaml_sequence_start_event_initialize(yaml_event_t *event,
881+ yaml_char_t *anchor, yaml_char_t *tag, int implicit,
882+ yaml_sequence_style_t style)
883+{
884+ yaml_mark_t mark = { 0, 0, 0 };
885+ yaml_char_t *anchor_copy = NULL;
886+ yaml_char_t *tag_copy = NULL;
887+
888+ assert(event); /* Non-NULL event object is expected. */
889+
890+ if (anchor) {
891+ if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error;
892+ anchor_copy = yaml_strdup(anchor);
893+ if (!anchor_copy) goto error;
894+ }
895+
896+ if (tag) {
897+ if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
898+ tag_copy = yaml_strdup(tag);
899+ if (!tag_copy) goto error;
900+ }
901+
902+ SEQUENCE_START_EVENT_INIT(*event, anchor_copy, tag_copy,
903+ implicit, style, mark, mark);
904+
905+ return 1;
906+
907+error:
908+ yaml_free(anchor_copy);
909+ yaml_free(tag_copy);
910+
911+ return 0;
912+}
913+
914+/*
915+ * Create SEQUENCE-END.
916+ */
917+
918+YAML_DECLARE(int)
919+yaml_sequence_end_event_initialize(yaml_event_t *event)
920+{
921+ yaml_mark_t mark = { 0, 0, 0 };
922+
923+ assert(event); /* Non-NULL event object is expected. */
924+
925+ SEQUENCE_END_EVENT_INIT(*event, mark, mark);
926+
927+ return 1;
928+}
929+
930+/*
931+ * Create MAPPING-START.
932+ */
933+
934+YAML_DECLARE(int)
935+yaml_mapping_start_event_initialize(yaml_event_t *event,
936+ yaml_char_t *anchor, yaml_char_t *tag, int implicit,
937+ yaml_mapping_style_t style)
938+{
939+ yaml_mark_t mark = { 0, 0, 0 };
940+ yaml_char_t *anchor_copy = NULL;
941+ yaml_char_t *tag_copy = NULL;
942+
943+ assert(event); /* Non-NULL event object is expected. */
944+
945+ if (anchor) {
946+ if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error;
947+ anchor_copy = yaml_strdup(anchor);
948+ if (!anchor_copy) goto error;
949+ }
950+
951+ if (tag) {
952+ if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
953+ tag_copy = yaml_strdup(tag);
954+ if (!tag_copy) goto error;
955+ }
956+
957+ MAPPING_START_EVENT_INIT(*event, anchor_copy, tag_copy,
958+ implicit, style, mark, mark);
959+
960+ return 1;
961+
962+error:
963+ yaml_free(anchor_copy);
964+ yaml_free(tag_copy);
965+
966+ return 0;
967+}
968+
969+/*
970+ * Create MAPPING-END.
971+ */
972+
973+YAML_DECLARE(int)
974+yaml_mapping_end_event_initialize(yaml_event_t *event)
975+{
976+ yaml_mark_t mark = { 0, 0, 0 };
977+
978+ assert(event); /* Non-NULL event object is expected. */
979+
980+ MAPPING_END_EVENT_INIT(*event, mark, mark);
981+
982+ return 1;
983+}
984+
985+/*
986+ * Destroy an event object.
987+ */
988+
989+YAML_DECLARE(void)
990+yaml_event_delete(yaml_event_t *event)
991+{
992+ yaml_tag_directive_t *tag_directive;
993+
994+ assert(event); /* Non-NULL event object expected. */
995+
996+ switch (event->type)
997+ {
998+ case YAML_DOCUMENT_START_EVENT:
999+ yaml_free(event->data.document_start.version_directive);
1000+ for (tag_directive = event->data.document_start.tag_directives.start;
1001+ tag_directive != event->data.document_start.tag_directives.end;
1002+ tag_directive++) {
1003+ yaml_free(tag_directive->handle);
1004+ yaml_free(tag_directive->prefix);
1005+ }
1006+ yaml_free(event->data.document_start.tag_directives.start);
1007+ break;
1008+
1009+ case YAML_ALIAS_EVENT:
1010+ yaml_free(event->data.alias.anchor);
1011+ break;
1012+
1013+ case YAML_SCALAR_EVENT:
1014+ yaml_free(event->data.scalar.anchor);
1015+ yaml_free(event->data.scalar.tag);
1016+ yaml_free(event->data.scalar.value);
1017+ break;
1018+
1019+ case YAML_SEQUENCE_START_EVENT:
1020+ yaml_free(event->data.sequence_start.anchor);
1021+ yaml_free(event->data.sequence_start.tag);
1022+ break;
1023+
1024+ case YAML_MAPPING_START_EVENT:
1025+ yaml_free(event->data.mapping_start.anchor);
1026+ yaml_free(event->data.mapping_start.tag);
1027+ break;
1028+
1029+ default:
1030+ break;
1031+ }
1032+
1033+ memset(event, 0, sizeof(yaml_event_t));
1034+}
1035+
1036+/*
1037+ * Create a document object.
1038+ */
1039+
1040+YAML_DECLARE(int)
1041+yaml_document_initialize(yaml_document_t *document,
1042+ yaml_version_directive_t *version_directive,
1043+ yaml_tag_directive_t *tag_directives_start,
1044+ yaml_tag_directive_t *tag_directives_end,
1045+ int start_implicit, int end_implicit)
1046+{
1047+ struct {
1048+ yaml_error_type_t error;
1049+ } context;
1050+ struct {
1051+ yaml_node_t *start;
1052+ yaml_node_t *end;
1053+ yaml_node_t *top;
1054+ } nodes = { NULL, NULL, NULL };
1055+ yaml_version_directive_t *version_directive_copy = NULL;
1056+ struct {
1057+ yaml_tag_directive_t *start;
1058+ yaml_tag_directive_t *end;
1059+ yaml_tag_directive_t *top;
1060+ } tag_directives_copy = { NULL, NULL, NULL };
1061+ yaml_tag_directive_t value = { NULL, NULL };
1062+ yaml_mark_t mark = { 0, 0, 0 };
1063+
1064+ assert(document); /* Non-NULL document object is expected. */
1065+ assert((tag_directives_start && tag_directives_end) ||
1066+ (tag_directives_start == tag_directives_end));
1067+ /* Valid tag directives are expected. */
1068+
1069+ if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error;
1070+
1071+ if (version_directive) {
1072+ version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t));
1073+ if (!version_directive_copy) goto error;
1074+ version_directive_copy->major = version_directive->major;
1075+ version_directive_copy->minor = version_directive->minor;
1076+ }
1077+
1078+ if (tag_directives_start != tag_directives_end) {
1079+ yaml_tag_directive_t *tag_directive;
1080+ if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
1081+ goto error;
1082+ for (tag_directive = tag_directives_start;
1083+ tag_directive != tag_directives_end; tag_directive ++) {
1084+ assert(tag_directive->handle);
1085+ assert(tag_directive->prefix);
1086+ if (!yaml_check_utf8(tag_directive->handle,
1087+ strlen((char *)tag_directive->handle)))
1088+ goto error;
1089+ if (!yaml_check_utf8(tag_directive->prefix,
1090+ strlen((char *)tag_directive->prefix)))
1091+ goto error;
1092+ value.handle = yaml_strdup(tag_directive->handle);
1093+ value.prefix = yaml_strdup(tag_directive->prefix);
1094+ if (!value.handle || !value.prefix) goto error;
1095+ if (!PUSH(&context, tag_directives_copy, value))
1096+ goto error;
1097+ value.handle = NULL;
1098+ value.prefix = NULL;
1099+ }
1100+ }
1101+
1102+ DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy,
1103+ tag_directives_copy.start, tag_directives_copy.top,
1104+ start_implicit, end_implicit, mark, mark);
1105+
1106+ return 1;
1107+
1108+error:
1109+ STACK_DEL(&context, nodes);
1110+ yaml_free(version_directive_copy);
1111+ while (!STACK_EMPTY(&context, tag_directives_copy)) {
1112+ yaml_tag_directive_t value = POP(&context, tag_directives_copy);
1113+ yaml_free(value.handle);
1114+ yaml_free(value.prefix);
1115+ }
1116+ STACK_DEL(&context, tag_directives_copy);
1117+ yaml_free(value.handle);
1118+ yaml_free(value.prefix);
1119+
1120+ return 0;
1121+}
1122+
1123+/*
1124+ * Destroy a document object.
1125+ */
1126+
1127+YAML_DECLARE(void)
1128+yaml_document_delete(yaml_document_t *document)
1129+{
1130+ struct {
1131+ yaml_error_type_t error;
1132+ } context;
1133+ yaml_tag_directive_t *tag_directive;
1134+
1135+ context.error = YAML_NO_ERROR; /* Eliminate a compliler warning. */
1136+
1137+ assert(document); /* Non-NULL document object is expected. */
1138+
1139+ while (!STACK_EMPTY(&context, document->nodes)) {
1140+ yaml_node_t node = POP(&context, document->nodes);
1141+ yaml_free(node.tag);
1142+ switch (node.type) {
1143+ case YAML_SCALAR_NODE:
1144+ yaml_free(node.data.scalar.value);
1145+ break;
1146+ case YAML_SEQUENCE_NODE:
1147+ STACK_DEL(&context, node.data.sequence.items);
1148+ break;
1149+ case YAML_MAPPING_NODE:
1150+ STACK_DEL(&context, node.data.mapping.pairs);
1151+ break;
1152+ default:
1153+ assert(0); /* Should not happen. */
1154+ }
1155+ }
1156+ STACK_DEL(&context, document->nodes);
1157+
1158+ yaml_free(document->version_directive);
1159+ for (tag_directive = document->tag_directives.start;
1160+ tag_directive != document->tag_directives.end;
1161+ tag_directive++) {
1162+ yaml_free(tag_directive->handle);
1163+ yaml_free(tag_directive->prefix);
1164+ }
1165+ yaml_free(document->tag_directives.start);
1166+
1167+ memset(document, 0, sizeof(yaml_document_t));
1168+}
1169+
1170+/**
1171+ * Get a document node.
1172+ */
1173+
1174+YAML_DECLARE(yaml_node_t *)
1175+yaml_document_get_node(yaml_document_t *document, int index)
1176+{
1177+ assert(document); /* Non-NULL document object is expected. */
1178+
1179+ if (index > 0 && document->nodes.start + index <= document->nodes.top) {
1180+ return document->nodes.start + index - 1;
1181+ }
1182+ return NULL;
1183+}
1184+
1185+/**
1186+ * Get the root object.
1187+ */
1188+
1189+YAML_DECLARE(yaml_node_t *)
1190+yaml_document_get_root_node(yaml_document_t *document)
1191+{
1192+ assert(document); /* Non-NULL document object is expected. */
1193+
1194+ if (document->nodes.top != document->nodes.start) {
1195+ return document->nodes.start;
1196+ }
1197+ return NULL;
1198+}
1199+
1200+/*
1201+ * Add a scalar node to a document.
1202+ */
1203+
1204+YAML_DECLARE(int)
1205+yaml_document_add_scalar(yaml_document_t *document,
1206+ yaml_char_t *tag, yaml_char_t *value, int length,
1207+ yaml_scalar_style_t style)
1208+{
1209+ struct {
1210+ yaml_error_type_t error;
1211+ } context;
1212+ yaml_mark_t mark = { 0, 0, 0 };
1213+ yaml_char_t *tag_copy = NULL;
1214+ yaml_char_t *value_copy = NULL;
1215+ yaml_node_t node;
1216+
1217+ assert(document); /* Non-NULL document object is expected. */
1218+ assert(value); /* Non-NULL value is expected. */
1219+
1220+ if (!tag) {
1221+ tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG;
1222+ }
1223+
1224+ if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
1225+ tag_copy = yaml_strdup(tag);
1226+ if (!tag_copy) goto error;
1227+
1228+ if (length < 0) {
1229+ length = strlen((char *)value);
1230+ }
1231+
1232+ if (!yaml_check_utf8(value, length)) goto error;
1233+ value_copy = yaml_malloc(length+1);
1234+ if (!value_copy) goto error;
1235+ memcpy(value_copy, value, length);
1236+ value_copy[length] = '\0';
1237+
1238+ SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark);
1239+ if (!PUSH(&context, document->nodes, node)) goto error;
1240+
1241+ return document->nodes.top - document->nodes.start;
1242+
1243+error:
1244+ yaml_free(tag_copy);
1245+ yaml_free(value_copy);
1246+
1247+ return 0;
1248+}
1249+
1250+/*
1251+ * Add a sequence node to a document.
1252+ */
1253+
1254+YAML_DECLARE(int)
1255+yaml_document_add_sequence(yaml_document_t *document,
1256+ yaml_char_t *tag, yaml_sequence_style_t style)
1257+{
1258+ struct {
1259+ yaml_error_type_t error;
1260+ } context;
1261+ yaml_mark_t mark = { 0, 0, 0 };
1262+ yaml_char_t *tag_copy = NULL;
1263+ struct {
1264+ yaml_node_item_t *start;
1265+ yaml_node_item_t *end;
1266+ yaml_node_item_t *top;
1267+ } items = { NULL, NULL, NULL };
1268+ yaml_node_t node;
1269+
1270+ assert(document); /* Non-NULL document object is expected. */
1271+
1272+ if (!tag) {
1273+ tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG;
1274+ }
1275+
1276+ if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
1277+ tag_copy = yaml_strdup(tag);
1278+ if (!tag_copy) goto error;
1279+
1280+ if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error;
1281+
1282+ SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end,
1283+ style, mark, mark);
1284+ if (!PUSH(&context, document->nodes, node)) goto error;
1285+
1286+ return document->nodes.top - document->nodes.start;
1287+
1288+error:
1289+ STACK_DEL(&context, items);
1290+ yaml_free(tag_copy);
1291+
1292+ return 0;
1293+}
1294+
1295+/*
1296+ * Add a mapping node to a document.
1297+ */
1298+
1299+YAML_DECLARE(int)
1300+yaml_document_add_mapping(yaml_document_t *document,
1301+ yaml_char_t *tag, yaml_mapping_style_t style)
1302+{
1303+ struct {
1304+ yaml_error_type_t error;
1305+ } context;
1306+ yaml_mark_t mark = { 0, 0, 0 };
1307+ yaml_char_t *tag_copy = NULL;
1308+ struct {
1309+ yaml_node_pair_t *start;
1310+ yaml_node_pair_t *end;
1311+ yaml_node_pair_t *top;
1312+ } pairs = { NULL, NULL, NULL };
1313+ yaml_node_t node;
1314+
1315+ assert(document); /* Non-NULL document object is expected. */
1316+
1317+ if (!tag) {
1318+ tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG;
1319+ }
1320+
1321+ if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
1322+ tag_copy = yaml_strdup(tag);
1323+ if (!tag_copy) goto error;
1324+
1325+ if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error;
1326+
1327+ MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end,
1328+ style, mark, mark);
1329+ if (!PUSH(&context, document->nodes, node)) goto error;
1330+
1331+ return document->nodes.top - document->nodes.start;
1332+
1333+error:
1334+ STACK_DEL(&context, pairs);
1335+ yaml_free(tag_copy);
1336+
1337+ return 0;
1338+}
1339+
1340+/*
1341+ * Append an item to a sequence node.
1342+ */
1343+
1344+YAML_DECLARE(int)
1345+yaml_document_append_sequence_item(yaml_document_t *document,
1346+ int sequence, int item)
1347+{
1348+ struct {
1349+ yaml_error_type_t error;
1350+ } context;
1351+
1352+ assert(document); /* Non-NULL document is required. */
1353+ assert(sequence > 0
1354+ && document->nodes.start + sequence <= document->nodes.top);
1355+ /* Valid sequence id is required. */
1356+ assert(document->nodes.start[sequence-1].type == YAML_SEQUENCE_NODE);
1357+ /* A sequence node is required. */
1358+ assert(item > 0 && document->nodes.start + item <= document->nodes.top);
1359+ /* Valid item id is required. */
1360+
1361+ if (!PUSH(&context,
1362+ document->nodes.start[sequence-1].data.sequence.items, item))
1363+ return 0;
1364+
1365+ return 1;
1366+}
1367+
1368+/*
1369+ * Append a pair of a key and a value to a mapping node.
1370+ */
1371+
1372+YAML_DECLARE(int)
1373+yaml_document_append_mapping_pair(yaml_document_t *document,
1374+ int mapping, int key, int value)
1375+{
1376+ struct {
1377+ yaml_error_type_t error;
1378+ } context;
1379+
1380+ yaml_node_pair_t pair;
1381+
1382+ assert(document); /* Non-NULL document is required. */
1383+ assert(mapping > 0
1384+ && document->nodes.start + mapping <= document->nodes.top);
1385+ /* Valid mapping id is required. */
1386+ assert(document->nodes.start[mapping-1].type == YAML_MAPPING_NODE);
1387+ /* A mapping node is required. */
1388+ assert(key > 0 && document->nodes.start + key <= document->nodes.top);
1389+ /* Valid key id is required. */
1390+ assert(value > 0 && document->nodes.start + value <= document->nodes.top);
1391+ /* Valid value id is required. */
1392+
1393+ pair.key = key;
1394+ pair.value = value;
1395+
1396+ if (!PUSH(&context,
1397+ document->nodes.start[mapping-1].data.mapping.pairs, pair))
1398+ return 0;
1399+
1400+ return 1;
1401+}
1402+
1403+
libyaml/dumper.cnew file+394
@@ -0,0 +1,394 @@
1+
2+#include "yaml_private.h"
3+
4+/*
5+ * API functions.
6+ */
7+
8+YAML_DECLARE(int)
9+yaml_emitter_open(yaml_emitter_t *emitter);
10+
11+YAML_DECLARE(int)
12+yaml_emitter_close(yaml_emitter_t *emitter);
13+
14+YAML_DECLARE(int)
15+yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document);
16+
17+/*
18+ * Clean up functions.
19+ */
20+
21+static void
22+yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter);
23+
24+/*
25+ * Anchor functions.
26+ */
27+
28+static void
29+yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index);
30+
31+static yaml_char_t *
32+yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id);
33+
34+
35+/*
36+ * Serialize functions.
37+ */
38+
39+static int
40+yaml_emitter_dump_node(yaml_emitter_t *emitter, int index);
41+
42+static int
43+yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor);
44+
45+static int
46+yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node,
47+ yaml_char_t *anchor);
48+
49+static int
50+yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node,
51+ yaml_char_t *anchor);
52+
53+static int
54+yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node,
55+ yaml_char_t *anchor);
56+
57+/*
58+ * Issue a STREAM-START event.
59+ */
60+
61+YAML_DECLARE(int)
62+yaml_emitter_open(yaml_emitter_t *emitter)
63+{
64+ yaml_event_t event;
65+ yaml_mark_t mark = { 0, 0, 0 };
66+
67+ assert(emitter); /* Non-NULL emitter object is required. */
68+ assert(!emitter->opened); /* Emitter should not be opened yet. */
69+
70+ STREAM_START_EVENT_INIT(event, YAML_ANY_ENCODING, mark, mark);
71+
72+ if (!yaml_emitter_emit(emitter, &event)) {
73+ return 0;
74+ }
75+
76+ emitter->opened = 1;
77+
78+ return 1;
79+}
80+
81+/*
82+ * Issue a STREAM-END event.
83+ */
84+
85+YAML_DECLARE(int)
86+yaml_emitter_close(yaml_emitter_t *emitter)
87+{
88+ yaml_event_t event;
89+ yaml_mark_t mark = { 0, 0, 0 };
90+
91+ assert(emitter); /* Non-NULL emitter object is required. */
92+ assert(emitter->opened); /* Emitter should be opened. */
93+
94+ if (emitter->closed) return 1;
95+
96+ STREAM_END_EVENT_INIT(event, mark, mark);
97+
98+ if (!yaml_emitter_emit(emitter, &event)) {
99+ return 0;
100+ }
101+
102+ emitter->closed = 1;
103+
104+ return 1;
105+}
106+
107+/*
108+ * Dump a YAML document.
109+ */
110+
111+YAML_DECLARE(int)
112+yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document)
113+{
114+ yaml_event_t event;
115+ yaml_mark_t mark = { 0, 0, 0 };
116+
117+ assert(emitter); /* Non-NULL emitter object is required. */
118+ assert(document); /* Non-NULL emitter object is expected. */
119+
120+ emitter->document = document;
121+
122+ if (!emitter->opened) {
123+ if (!yaml_emitter_open(emitter)) goto error;
124+ }
125+
126+ if (STACK_EMPTY(emitter, document->nodes)) {
127+ if (!yaml_emitter_close(emitter)) goto error;
128+ yaml_emitter_delete_document_and_anchors(emitter);
129+ return 1;
130+ }
131+
132+ assert(emitter->opened); /* Emitter should be opened. */
133+
134+ emitter->anchors = yaml_malloc(sizeof(*(emitter->anchors))
135+ * (document->nodes.top - document->nodes.start));
136+ if (!emitter->anchors) goto error;
137+ memset(emitter->anchors, 0, sizeof(*(emitter->anchors))
138+ * (document->nodes.top - document->nodes.start));
139+
140+ DOCUMENT_START_EVENT_INIT(event, document->version_directive,
141+ document->tag_directives.start, document->tag_directives.end,
142+ document->start_implicit, mark, mark);
143+ if (!yaml_emitter_emit(emitter, &event)) goto error;
144+
145+ yaml_emitter_anchor_node(emitter, 1);
146+ if (!yaml_emitter_dump_node(emitter, 1)) goto error;
147+
148+ DOCUMENT_END_EVENT_INIT(event, document->end_implicit, mark, mark);
149+ if (!yaml_emitter_emit(emitter, &event)) goto error;
150+
151+ yaml_emitter_delete_document_and_anchors(emitter);
152+
153+ return 1;
154+
155+error:
156+
157+ yaml_emitter_delete_document_and_anchors(emitter);
158+
159+ return 0;
160+}
161+
162+/*
163+ * Clean up the emitter object after a document is dumped.
164+ */
165+
166+static void
167+yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter)
168+{
169+ int index;
170+
171+ if (!emitter->anchors) {
172+ yaml_document_delete(emitter->document);
173+ emitter->document = NULL;
174+ return;
175+ }
176+
177+ for (index = 0; emitter->document->nodes.start + index
178+ < emitter->document->nodes.top; index ++) {
179+ yaml_node_t node = emitter->document->nodes.start[index];
180+ if (!emitter->anchors[index].serialized) {
181+ yaml_free(node.tag);
182+ if (node.type == YAML_SCALAR_NODE) {
183+ yaml_free(node.data.scalar.value);
184+ }
185+ }
186+ if (node.type == YAML_SEQUENCE_NODE) {
187+ STACK_DEL(emitter, node.data.sequence.items);
188+ }
189+ if (node.type == YAML_MAPPING_NODE) {
190+ STACK_DEL(emitter, node.data.mapping.pairs);
191+ }
192+ }
193+
194+ STACK_DEL(emitter, emitter->document->nodes);
195+ yaml_free(emitter->anchors);
196+
197+ emitter->anchors = NULL;
198+ emitter->last_anchor_id = 0;
199+ emitter->document = NULL;
200+}
201+
202+/*
203+ * Check the references of a node and assign the anchor id if needed.
204+ */
205+
206+static void
207+yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index)
208+{
209+ yaml_node_t *node = emitter->document->nodes.start + index - 1;
210+ yaml_node_item_t *item;
211+ yaml_node_pair_t *pair;
212+
213+ emitter->anchors[index-1].references ++;
214+
215+ if (emitter->anchors[index-1].references == 1) {
216+ switch (node->type) {
217+ case YAML_SEQUENCE_NODE:
218+ for (item = node->data.sequence.items.start;
219+ item < node->data.sequence.items.top; item ++) {
220+ yaml_emitter_anchor_node(emitter, *item);
221+ }
222+ break;
223+ case YAML_MAPPING_NODE:
224+ for (pair = node->data.mapping.pairs.start;
225+ pair < node->data.mapping.pairs.top; pair ++) {
226+ yaml_emitter_anchor_node(emitter, pair->key);
227+ yaml_emitter_anchor_node(emitter, pair->value);
228+ }
229+ break;
230+ default:
231+ break;
232+ }
233+ }
234+
235+ else if (emitter->anchors[index-1].references == 2) {
236+ emitter->anchors[index-1].anchor = (++ emitter->last_anchor_id);
237+ }
238+}
239+
240+/*
241+ * Generate a textual representation for an anchor.
242+ */
243+
244+#define ANCHOR_TEMPLATE "id%03d"
245+#define ANCHOR_TEMPLATE_LENGTH 16
246+
247+static yaml_char_t *
248+yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id)
249+{
250+ yaml_char_t *anchor = yaml_malloc(ANCHOR_TEMPLATE_LENGTH);
251+
252+ if (!anchor) return NULL;
253+
254+ sprintf((char *)anchor, ANCHOR_TEMPLATE, anchor_id);
255+
256+ return anchor;
257+}
258+
259+/*
260+ * Serialize a node.
261+ */
262+
263+static int
264+yaml_emitter_dump_node(yaml_emitter_t *emitter, int index)
265+{
266+ yaml_node_t *node = emitter->document->nodes.start + index - 1;
267+ int anchor_id = emitter->anchors[index-1].anchor;
268+ yaml_char_t *anchor = NULL;
269+
270+ if (anchor_id) {
271+ anchor = yaml_emitter_generate_anchor(emitter, anchor_id);
272+ if (!anchor) return 0;
273+ }
274+
275+ if (emitter->anchors[index-1].serialized) {
276+ return yaml_emitter_dump_alias(emitter, anchor);
277+ }
278+
279+ emitter->anchors[index-1].serialized = 1;
280+
281+ switch (node->type) {
282+ case YAML_SCALAR_NODE:
283+ return yaml_emitter_dump_scalar(emitter, node, anchor);
284+ case YAML_SEQUENCE_NODE:
285+ return yaml_emitter_dump_sequence(emitter, node, anchor);
286+ case YAML_MAPPING_NODE:
287+ return yaml_emitter_dump_mapping(emitter, node, anchor);
288+ default:
289+ assert(0); /* Could not happen. */
290+ break;
291+ }
292+
293+ return 0; /* Could not happen. */
294+}
295+
296+/*
297+ * Serialize an alias.
298+ */
299+
300+static int
301+yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor)
302+{
303+ yaml_event_t event;
304+ yaml_mark_t mark = { 0, 0, 0 };
305+
306+ ALIAS_EVENT_INIT(event, anchor, mark, mark);
307+
308+ return yaml_emitter_emit(emitter, &event);
309+}
310+
311+/*
312+ * Serialize a scalar.
313+ */
314+
315+static int
316+yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node,
317+ yaml_char_t *anchor)
318+{
319+ yaml_event_t event;
320+ yaml_mark_t mark = { 0, 0, 0 };
321+
322+ int plain_implicit = (strcmp((char *)node->tag,
323+ YAML_DEFAULT_SCALAR_TAG) == 0);
324+ int quoted_implicit = (strcmp((char *)node->tag,
325+ YAML_DEFAULT_SCALAR_TAG) == 0);
326+
327+ SCALAR_EVENT_INIT(event, anchor, node->tag, node->data.scalar.value,
328+ node->data.scalar.length, plain_implicit, quoted_implicit,
329+ node->data.scalar.style, mark, mark);
330+
331+ return yaml_emitter_emit(emitter, &event);
332+}
333+
334+/*
335+ * Serialize a sequence.
336+ */
337+
338+static int
339+yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node,
340+ yaml_char_t *anchor)
341+{
342+ yaml_event_t event;
343+ yaml_mark_t mark = { 0, 0, 0 };
344+
345+ int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_SEQUENCE_TAG) == 0);
346+
347+ yaml_node_item_t *item;
348+
349+ SEQUENCE_START_EVENT_INIT(event, anchor, node->tag, implicit,
350+ node->data.sequence.style, mark, mark);
351+ if (!yaml_emitter_emit(emitter, &event)) return 0;
352+
353+ for (item = node->data.sequence.items.start;
354+ item < node->data.sequence.items.top; item ++) {
355+ if (!yaml_emitter_dump_node(emitter, *item)) return 0;
356+ }
357+
358+ SEQUENCE_END_EVENT_INIT(event, mark, mark);
359+ if (!yaml_emitter_emit(emitter, &event)) return 0;
360+
361+ return 1;
362+}
363+
364+/*
365+ * Serialize a mapping.
366+ */
367+
368+static int
369+yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node,
370+ yaml_char_t *anchor)
371+{
372+ yaml_event_t event;
373+ yaml_mark_t mark = { 0, 0, 0 };
374+
375+ int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_MAPPING_TAG) == 0);
376+
377+ yaml_node_pair_t *pair;
378+
379+ MAPPING_START_EVENT_INIT(event, anchor, node->tag, implicit,
380+ node->data.mapping.style, mark, mark);
381+ if (!yaml_emitter_emit(emitter, &event)) return 0;
382+
383+ for (pair = node->data.mapping.pairs.start;
384+ pair < node->data.mapping.pairs.top; pair ++) {
385+ if (!yaml_emitter_dump_node(emitter, pair->key)) return 0;
386+ if (!yaml_emitter_dump_node(emitter, pair->value)) return 0;
387+ }
388+
389+ MAPPING_END_EVENT_INIT(event, mark, mark);
390+ if (!yaml_emitter_emit(emitter, &event)) return 0;
391+
392+ return 1;
393+}
394+
libyaml/emitter.cnew file+2329
@@ -0,0 +1,2329 @@
1+
2+#include "yaml_private.h"
3+
4+/*
5+ * Flush the buffer if needed.
6+ */
7+
8+#define FLUSH(emitter) \
9+ ((emitter->buffer.pointer+5 < emitter->buffer.end) \
10+ || yaml_emitter_flush(emitter))
11+
12+/*
13+ * Put a character to the output buffer.
14+ */
15+
16+#define PUT(emitter,value) \
17+ (FLUSH(emitter) \
18+ && (*(emitter->buffer.pointer++) = (yaml_char_t)(value), \
19+ emitter->column ++, \
20+ 1))
21+
22+/*
23+ * Put a line break to the output buffer.
24+ */
25+
26+#define PUT_BREAK(emitter) \
27+ (FLUSH(emitter) \
28+ && ((emitter->line_break == YAML_CR_BREAK ? \
29+ (*(emitter->buffer.pointer++) = (yaml_char_t) '\r') : \
30+ emitter->line_break == YAML_LN_BREAK ? \
31+ (*(emitter->buffer.pointer++) = (yaml_char_t) '\n') : \
32+ emitter->line_break == YAML_CRLN_BREAK ? \
33+ (*(emitter->buffer.pointer++) = (yaml_char_t) '\r', \
34+ *(emitter->buffer.pointer++) = (yaml_char_t) '\n') : 0), \
35+ emitter->column = 0, \
36+ emitter->line ++, \
37+ 1))
38+
39+/*
40+ * Copy a character from a string into buffer.
41+ */
42+
43+#define WRITE(emitter,string) \
44+ (FLUSH(emitter) \
45+ && (COPY(emitter->buffer,string), \
46+ emitter->column ++, \
47+ 1))
48+
49+/*
50+ * Copy a line break character from a string into buffer.
51+ */
52+
53+#define WRITE_BREAK(emitter,string) \
54+ (FLUSH(emitter) \
55+ && (CHECK(string,'\n') ? \
56+ (PUT_BREAK(emitter), \
57+ string.pointer ++, \
58+ 1) : \
59+ (COPY(emitter->buffer,string), \
60+ emitter->column = 0, \
61+ emitter->line ++, \
62+ 1)))
63+
64+/*
65+ * API functions.
66+ */
67+
68+YAML_DECLARE(int)
69+yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event);
70+
71+/*
72+ * Utility functions.
73+ */
74+
75+static int
76+yaml_emitter_set_emitter_error(yaml_emitter_t *emitter, const char *problem);
77+
78+static int
79+yaml_emitter_need_more_events(yaml_emitter_t *emitter);
80+
81+static int
82+yaml_emitter_append_tag_directive(yaml_emitter_t *emitter,
83+ yaml_tag_directive_t value, int allow_duplicates);
84+
85+static int
86+yaml_emitter_increase_indent(yaml_emitter_t *emitter,
87+ int flow, int indentless);
88+
89+/*
90+ * State functions.
91+ */
92+
93+static int
94+yaml_emitter_state_machine(yaml_emitter_t *emitter, yaml_event_t *event);
95+
96+static int
97+yaml_emitter_emit_stream_start(yaml_emitter_t *emitter,
98+ yaml_event_t *event);
99+
100+static int
101+yaml_emitter_emit_document_start(yaml_emitter_t *emitter,
102+ yaml_event_t *event, int first);
103+
104+static int
105+yaml_emitter_emit_document_content(yaml_emitter_t *emitter,
106+ yaml_event_t *event);
107+
108+static int
109+yaml_emitter_emit_document_end(yaml_emitter_t *emitter,
110+ yaml_event_t *event);
111+
112+static int
113+yaml_emitter_emit_flow_sequence_item(yaml_emitter_t *emitter,
114+ yaml_event_t *event, int first);
115+
116+static int
117+yaml_emitter_emit_flow_mapping_key(yaml_emitter_t *emitter,
118+ yaml_event_t *event, int first);
119+
120+static int
121+yaml_emitter_emit_flow_mapping_value(yaml_emitter_t *emitter,
122+ yaml_event_t *event, int simple);
123+
124+static int
125+yaml_emitter_emit_block_sequence_item(yaml_emitter_t *emitter,
126+ yaml_event_t *event, int first);
127+
128+static int
129+yaml_emitter_emit_block_mapping_key(yaml_emitter_t *emitter,
130+ yaml_event_t *event, int first);
131+
132+static int
133+yaml_emitter_emit_block_mapping_value(yaml_emitter_t *emitter,
134+ yaml_event_t *event, int simple);
135+
136+static int
137+yaml_emitter_emit_node(yaml_emitter_t *emitter, yaml_event_t *event,
138+ int root, int sequence, int mapping, int simple_key);
139+
140+static int
141+yaml_emitter_emit_alias(yaml_emitter_t *emitter, yaml_event_t *event);
142+
143+static int
144+yaml_emitter_emit_scalar(yaml_emitter_t *emitter, yaml_event_t *event);
145+
146+static int
147+yaml_emitter_emit_sequence_start(yaml_emitter_t *emitter, yaml_event_t *event);
148+
149+static int
150+yaml_emitter_emit_mapping_start(yaml_emitter_t *emitter, yaml_event_t *event);
151+
152+/*
153+ * Checkers.
154+ */
155+
156+static int
157+yaml_emitter_check_empty_document(yaml_emitter_t *emitter);
158+
159+static int
160+yaml_emitter_check_empty_sequence(yaml_emitter_t *emitter);
161+
162+static int
163+yaml_emitter_check_empty_mapping(yaml_emitter_t *emitter);
164+
165+static int
166+yaml_emitter_check_simple_key(yaml_emitter_t *emitter);
167+
168+static int
169+yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event);
170+
171+/*
172+ * Processors.
173+ */
174+
175+static int
176+yaml_emitter_process_anchor(yaml_emitter_t *emitter);
177+
178+static int
179+yaml_emitter_process_tag(yaml_emitter_t *emitter);
180+
181+static int
182+yaml_emitter_process_scalar(yaml_emitter_t *emitter);
183+
184+/*
185+ * Analyzers.
186+ */
187+
188+static int
189+yaml_emitter_analyze_version_directive(yaml_emitter_t *emitter,
190+ yaml_version_directive_t version_directive);
191+
192+static int
193+yaml_emitter_analyze_tag_directive(yaml_emitter_t *emitter,
194+ yaml_tag_directive_t tag_directive);
195+
196+static int
197+yaml_emitter_analyze_anchor(yaml_emitter_t *emitter,
198+ yaml_char_t *anchor, int alias);
199+
200+static int
201+yaml_emitter_analyze_tag(yaml_emitter_t *emitter,
202+ yaml_char_t *tag);
203+
204+static int
205+yaml_emitter_analyze_scalar(yaml_emitter_t *emitter,
206+ yaml_char_t *value, size_t length);
207+
208+static int
209+yaml_emitter_analyze_event(yaml_emitter_t *emitter,
210+ yaml_event_t *event);
211+
212+/*
213+ * Writers.
214+ */
215+
216+static int
217+yaml_emitter_write_bom(yaml_emitter_t *emitter);
218+
219+static int
220+yaml_emitter_write_indent(yaml_emitter_t *emitter);
221+
222+static int
223+yaml_emitter_write_indicator(yaml_emitter_t *emitter,
224+ char *indicator, int need_whitespace,
225+ int is_whitespace, int is_indention);
226+
227+static int
228+yaml_emitter_write_anchor(yaml_emitter_t *emitter,
229+ yaml_char_t *value, size_t length);
230+
231+static int
232+yaml_emitter_write_tag_handle(yaml_emitter_t *emitter,
233+ yaml_char_t *value, size_t length);
234+
235+static int
236+yaml_emitter_write_tag_content(yaml_emitter_t *emitter,
237+ yaml_char_t *value, size_t length, int need_whitespace);
238+
239+static int
240+yaml_emitter_write_plain_scalar(yaml_emitter_t *emitter,
241+ yaml_char_t *value, size_t length, int allow_breaks);
242+
243+static int
244+yaml_emitter_write_single_quoted_scalar(yaml_emitter_t *emitter,
245+ yaml_char_t *value, size_t length, int allow_breaks);
246+
247+static int
248+yaml_emitter_write_double_quoted_scalar(yaml_emitter_t *emitter,
249+ yaml_char_t *value, size_t length, int allow_breaks);
250+
251+static int
252+yaml_emitter_write_block_scalar_hints(yaml_emitter_t *emitter,
253+ yaml_string_t string);
254+
255+static int
256+yaml_emitter_write_literal_scalar(yaml_emitter_t *emitter,
257+ yaml_char_t *value, size_t length);
258+
259+static int
260+yaml_emitter_write_folded_scalar(yaml_emitter_t *emitter,
261+ yaml_char_t *value, size_t length);
262+
263+/*
264+ * Set an emitter error and return 0.
265+ */
266+
267+static int
268+yaml_emitter_set_emitter_error(yaml_emitter_t *emitter, const char *problem)
269+{
270+ emitter->error = YAML_EMITTER_ERROR;
271+ emitter->problem = problem;
272+
273+ return 0;
274+}
275+
276+/*
277+ * Emit an event.
278+ */
279+
280+YAML_DECLARE(int)
281+yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event)
282+{
283+ if (!ENQUEUE(emitter, emitter->events, *event)) {
284+ yaml_event_delete(event);
285+ return 0;
286+ }
287+
288+ while (!yaml_emitter_need_more_events(emitter)) {
289+ if (!yaml_emitter_analyze_event(emitter, emitter->events.head))
290+ return 0;
291+ if (!yaml_emitter_state_machine(emitter, emitter->events.head))
292+ return 0;
293+ yaml_event_delete(&DEQUEUE(emitter, emitter->events));
294+ }
295+
296+ return 1;
297+}
298+
299+/*
300+ * Check if we need to accumulate more events before emitting.
301+ *
302+ * We accumulate extra
303+ * - 1 event for DOCUMENT-START
304+ * - 2 events for SEQUENCE-START
305+ * - 3 events for MAPPING-START
306+ */
307+
308+static int
309+yaml_emitter_need_more_events(yaml_emitter_t *emitter)
310+{
311+ int level = 0;
312+ int accumulate = 0;
313+ yaml_event_t *event;
314+
315+ if (QUEUE_EMPTY(emitter, emitter->events))
316+ return 1;
317+
318+ switch (emitter->events.head->type) {
319+ case YAML_DOCUMENT_START_EVENT:
320+ accumulate = 1;
321+ break;
322+ case YAML_SEQUENCE_START_EVENT:
323+ accumulate = 2;
324+ break;
325+ case YAML_MAPPING_START_EVENT:
326+ accumulate = 3;
327+ break;
328+ default:
329+ return 0;
330+ }
331+
332+ if (emitter->events.tail - emitter->events.head > accumulate)
333+ return 0;
334+
335+ for (event = emitter->events.head; event != emitter->events.tail; event ++) {
336+ switch (event->type) {
337+ case YAML_STREAM_START_EVENT:
338+ case YAML_DOCUMENT_START_EVENT:
339+ case YAML_SEQUENCE_START_EVENT:
340+ case YAML_MAPPING_START_EVENT:
341+ level += 1;
342+ break;
343+ case YAML_STREAM_END_EVENT:
344+ case YAML_DOCUMENT_END_EVENT:
345+ case YAML_SEQUENCE_END_EVENT:
346+ case YAML_MAPPING_END_EVENT:
347+ level -= 1;
348+ break;
349+ default:
350+ break;
351+ }
352+ if (!level)
353+ return 0;
354+ }
355+
356+ return 1;
357+}
358+
359+/*
360+ * Append a directive to the directives stack.
361+ */
362+
363+static int
364+yaml_emitter_append_tag_directive(yaml_emitter_t *emitter,
365+ yaml_tag_directive_t value, int allow_duplicates)
366+{
367+ yaml_tag_directive_t *tag_directive;
368+ yaml_tag_directive_t copy = { NULL, NULL };
369+
370+ for (tag_directive = emitter->tag_directives.start;
371+ tag_directive != emitter->tag_directives.top; tag_directive ++) {
372+ if (strcmp((char *)value.handle, (char *)tag_directive->handle) == 0) {
373+ if (allow_duplicates)
374+ return 1;
375+ return yaml_emitter_set_emitter_error(emitter,
376+ "duplicate %TAG directive");
377+ }
378+ }
379+
380+ copy.handle = yaml_strdup(value.handle);
381+ copy.prefix = yaml_strdup(value.prefix);
382+ if (!copy.handle || !copy.prefix) {
383+ emitter->error = YAML_MEMORY_ERROR;
384+ goto error;
385+ }
386+
387+ if (!PUSH(emitter, emitter->tag_directives, copy))
388+ goto error;
389+
390+ return 1;
391+
392+error:
393+ yaml_free(copy.handle);
394+ yaml_free(copy.prefix);
395+ return 0;
396+}
397+
398+/*
399+ * Increase the indentation level.
400+ */
401+
402+static int
403+yaml_emitter_increase_indent(yaml_emitter_t *emitter,
404+ int flow, int indentless)
405+{
406+ if (!PUSH(emitter, emitter->indents, emitter->indent))
407+ return 0;
408+
409+ if (emitter->indent < 0) {
410+ emitter->indent = flow ? emitter->best_indent : 0;
411+ }
412+ else if (!indentless) {
413+ emitter->indent += emitter->best_indent;
414+ }
415+
416+ return 1;
417+}
418+
419+/*
420+ * State dispatcher.
421+ */
422+
423+static int
424+yaml_emitter_state_machine(yaml_emitter_t *emitter, yaml_event_t *event)
425+{
426+ switch (emitter->state)
427+ {
428+ case YAML_EMIT_STREAM_START_STATE:
429+ return yaml_emitter_emit_stream_start(emitter, event);
430+
431+ case YAML_EMIT_FIRST_DOCUMENT_START_STATE:
432+ return yaml_emitter_emit_document_start(emitter, event, 1);
433+
434+ case YAML_EMIT_DOCUMENT_START_STATE:
435+ return yaml_emitter_emit_document_start(emitter, event, 0);
436+
437+ case YAML_EMIT_DOCUMENT_CONTENT_STATE:
438+ return yaml_emitter_emit_document_content(emitter, event);
439+
440+ case YAML_EMIT_DOCUMENT_END_STATE:
441+ return yaml_emitter_emit_document_end(emitter, event);
442+
443+ case YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE:
444+ return yaml_emitter_emit_flow_sequence_item(emitter, event, 1);
445+
446+ case YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE:
447+ return yaml_emitter_emit_flow_sequence_item(emitter, event, 0);
448+
449+ case YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE:
450+ return yaml_emitter_emit_flow_mapping_key(emitter, event, 1);
451+
452+ case YAML_EMIT_FLOW_MAPPING_KEY_STATE:
453+ return yaml_emitter_emit_flow_mapping_key(emitter, event, 0);
454+
455+ case YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE:
456+ return yaml_emitter_emit_flow_mapping_value(emitter, event, 1);
457+
458+ case YAML_EMIT_FLOW_MAPPING_VALUE_STATE:
459+ return yaml_emitter_emit_flow_mapping_value(emitter, event, 0);
460+
461+ case YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE:
462+ return yaml_emitter_emit_block_sequence_item(emitter, event, 1);
463+
464+ case YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE:
465+ return yaml_emitter_emit_block_sequence_item(emitter, event, 0);
466+
467+ case YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE:
468+ return yaml_emitter_emit_block_mapping_key(emitter, event, 1);
469+
470+ case YAML_EMIT_BLOCK_MAPPING_KEY_STATE:
471+ return yaml_emitter_emit_block_mapping_key(emitter, event, 0);
472+
473+ case YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE:
474+ return yaml_emitter_emit_block_mapping_value(emitter, event, 1);
475+
476+ case YAML_EMIT_BLOCK_MAPPING_VALUE_STATE:
477+ return yaml_emitter_emit_block_mapping_value(emitter, event, 0);
478+
479+ case YAML_EMIT_END_STATE:
480+ return yaml_emitter_set_emitter_error(emitter,
481+ "expected nothing after STREAM-END");
482+
483+ default:
484+ assert(1); /* Invalid state. */
485+ }
486+
487+ return 0;
488+}
489+
490+/*
491+ * Expect STREAM-START.
492+ */
493+
494+static int
495+yaml_emitter_emit_stream_start(yaml_emitter_t *emitter,
496+ yaml_event_t *event)
497+{
498+ if (event->type == YAML_STREAM_START_EVENT)
499+ {
500+ if (!emitter->encoding) {
501+ emitter->encoding = event->data.stream_start.encoding;
502+ }
503+
504+ if (!emitter->encoding) {
505+ emitter->encoding = YAML_UTF8_ENCODING;
506+ }
507+
508+ if (emitter->best_indent < 2 || emitter->best_indent > 9) {
509+ emitter->best_indent = 2;
510+ }
511+
512+ if (emitter->best_width >= 0
513+ && emitter->best_width <= emitter->best_indent*2) {
514+ emitter->best_width = 80;
515+ }
516+
517+ if (emitter->best_width < 0) {
518+ emitter->best_width = INT_MAX;
519+ }
520+
521+ if (!emitter->line_break) {
522+ emitter->line_break = YAML_LN_BREAK;
523+ }
524+
525+ emitter->indent = -1;
526+
527+ emitter->line = 0;
528+ emitter->column = 0;
529+ emitter->whitespace = 1;
530+ emitter->indention = 1;
531+
532+ if (emitter->encoding != YAML_UTF8_ENCODING) {
533+ if (!yaml_emitter_write_bom(emitter))
534+ return 0;
535+ }
536+
537+ emitter->state = YAML_EMIT_FIRST_DOCUMENT_START_STATE;
538+
539+ return 1;
540+ }
541+
542+ return yaml_emitter_set_emitter_error(emitter,
543+ "expected STREAM-START");
544+}
545+
546+/*
547+ * Expect DOCUMENT-START or STREAM-END.
548+ */
549+
550+static int
551+yaml_emitter_emit_document_start(yaml_emitter_t *emitter,
552+ yaml_event_t *event, int first)
553+{
554+ if (event->type == YAML_DOCUMENT_START_EVENT)
555+ {
556+ yaml_tag_directive_t default_tag_directives[] = {
557+ {(yaml_char_t *)"!", (yaml_char_t *)"!"},
558+ {(yaml_char_t *)"!!", (yaml_char_t *)"tag:yaml.org,2002:"},
559+ {NULL, NULL}
560+ };
561+ yaml_tag_directive_t *tag_directive;
562+ int implicit;
563+
564+ if (event->data.document_start.version_directive) {
565+ if (!yaml_emitter_analyze_version_directive(emitter,
566+ *event->data.document_start.version_directive))
567+ return 0;
568+ }
569+
570+ for (tag_directive = event->data.document_start.tag_directives.start;
571+ tag_directive != event->data.document_start.tag_directives.end;
572+ tag_directive ++) {
573+ if (!yaml_emitter_analyze_tag_directive(emitter, *tag_directive))
574+ return 0;
575+ if (!yaml_emitter_append_tag_directive(emitter, *tag_directive, 0))
576+ return 0;
577+ }
578+
579+ for (tag_directive = default_tag_directives;
580+ tag_directive->handle; tag_directive ++) {
581+ if (!yaml_emitter_append_tag_directive(emitter, *tag_directive, 1))
582+ return 0;
583+ }
584+
585+ implicit = event->data.document_start.implicit;
586+ if (!first || emitter->canonical) {
587+ implicit = 0;
588+ }
589+
590+ if ((event->data.document_start.version_directive ||
591+ (event->data.document_start.tag_directives.start
592+ != event->data.document_start.tag_directives.end)) &&
593+ emitter->open_ended)
594+ {
595+ if (!yaml_emitter_write_indicator(emitter, "...", 1, 0, 0))
596+ return 0;
597+ if (!yaml_emitter_write_indent(emitter))
598+ return 0;
599+ }
600+
601+ if (event->data.document_start.version_directive) {
602+ implicit = 0;
603+ if (!yaml_emitter_write_indicator(emitter, "%YAML", 1, 0, 0))
604+ return 0;
605+ if (!yaml_emitter_write_indicator(emitter, "1.1", 1, 0, 0))
606+ return 0;
607+ if (!yaml_emitter_write_indent(emitter))
608+ return 0;
609+ }
610+
611+ if (event->data.document_start.tag_directives.start
612+ != event->data.document_start.tag_directives.end) {
613+ implicit = 0;
614+ for (tag_directive = event->data.document_start.tag_directives.start;
615+ tag_directive != event->data.document_start.tag_directives.end;
616+ tag_directive ++) {
617+ if (!yaml_emitter_write_indicator(emitter, "%TAG", 1, 0, 0))
618+ return 0;
619+ if (!yaml_emitter_write_tag_handle(emitter, tag_directive->handle,
620+ strlen((char *)tag_directive->handle)))
621+ return 0;
622+ if (!yaml_emitter_write_tag_content(emitter, tag_directive->prefix,
623+ strlen((char *)tag_directive->prefix), 1))
624+ return 0;
625+ if (!yaml_emitter_write_indent(emitter))
626+ return 0;
627+ }
628+ }
629+
630+ if (yaml_emitter_check_empty_document(emitter)) {
631+ implicit = 0;
632+ }
633+
634+ if (!implicit) {
635+ if (!yaml_emitter_write_indent(emitter))
636+ return 0;
637+ if (!yaml_emitter_write_indicator(emitter, "---", 1, 0, 0))
638+ return 0;
639+ if (emitter->canonical) {
640+ if (!yaml_emitter_write_indent(emitter))
641+ return 0;
642+ }
643+ }
644+
645+ emitter->state = YAML_EMIT_DOCUMENT_CONTENT_STATE;
646+
647+ return 1;
648+ }
649+
650+ else if (event->type == YAML_STREAM_END_EVENT)
651+ {
652+ if (emitter->open_ended)
653+ {
654+ if (!yaml_emitter_write_indicator(emitter, "...", 1, 0, 0))
655+ return 0;
656+ if (!yaml_emitter_write_indent(emitter))
657+ return 0;
658+ }
659+
660+ if (!yaml_emitter_flush(emitter))
661+ return 0;
662+
663+ emitter->state = YAML_EMIT_END_STATE;
664+
665+ return 1;
666+ }
667+
668+ return yaml_emitter_set_emitter_error(emitter,
669+ "expected DOCUMENT-START or STREAM-END");
670+}
671+
672+/*
673+ * Expect the root node.
674+ */
675+
676+static int
677+yaml_emitter_emit_document_content(yaml_emitter_t *emitter,
678+ yaml_event_t *event)
679+{
680+ if (!PUSH(emitter, emitter->states, YAML_EMIT_DOCUMENT_END_STATE))
681+ return 0;
682+
683+ return yaml_emitter_emit_node(emitter, event, 1, 0, 0, 0);
684+}
685+
686+/*
687+ * Expect DOCUMENT-END.
688+ */
689+
690+static int
691+yaml_emitter_emit_document_end(yaml_emitter_t *emitter,
692+ yaml_event_t *event)
693+{
694+ if (event->type == YAML_DOCUMENT_END_EVENT)
695+ {
696+ if (!yaml_emitter_write_indent(emitter))
697+ return 0;
698+ if (!event->data.document_end.implicit) {
699+ if (!yaml_emitter_write_indicator(emitter, "...", 1, 0, 0))
700+ return 0;
701+ if (!yaml_emitter_write_indent(emitter))
702+ return 0;
703+ }
704+ if (!yaml_emitter_flush(emitter))
705+ return 0;
706+
707+ emitter->state = YAML_EMIT_DOCUMENT_START_STATE;
708+
709+ while (!STACK_EMPTY(emitter, emitter->tag_directives)) {
710+ yaml_tag_directive_t tag_directive = POP(emitter,
711+ emitter->tag_directives);
712+ yaml_free(tag_directive.handle);
713+ yaml_free(tag_directive.prefix);
714+ }
715+
716+ return 1;
717+ }
718+
719+ return yaml_emitter_set_emitter_error(emitter,
720+ "expected DOCUMENT-END");
721+}
722+
723+/*
724+ *
725+ * Expect a flow item node.
726+ */
727+
728+static int
729+yaml_emitter_emit_flow_sequence_item(yaml_emitter_t *emitter,
730+ yaml_event_t *event, int first)
731+{
732+ if (first)
733+ {
734+ if (!yaml_emitter_write_indicator(emitter, "[", 1, 1, 0))
735+ return 0;
736+ if (!yaml_emitter_increase_indent(emitter, 1, 0))
737+ return 0;
738+ emitter->flow_level ++;
739+ }
740+
741+ if (event->type == YAML_SEQUENCE_END_EVENT)
742+ {
743+ emitter->flow_level --;
744+ emitter->indent = POP(emitter, emitter->indents);
745+ if (emitter->canonical && !first) {
746+ if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0))
747+ return 0;
748+ if (!yaml_emitter_write_indent(emitter))
749+ return 0;
750+ }
751+ if (!yaml_emitter_write_indicator(emitter, "]", 0, 0, 0))
752+ return 0;
753+ emitter->state = POP(emitter, emitter->states);
754+
755+ return 1;
756+ }
757+
758+ if (!first) {
759+ if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0))
760+ return 0;
761+ }
762+
763+ if (emitter->canonical || emitter->column > emitter->best_width) {
764+ if (!yaml_emitter_write_indent(emitter))
765+ return 0;
766+ }
767+ if (!PUSH(emitter, emitter->states, YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE))
768+ return 0;
769+
770+ return yaml_emitter_emit_node(emitter, event, 0, 1, 0, 0);
771+}
772+
773+/*
774+ * Expect a flow key node.
775+ */
776+
777+static int
778+yaml_emitter_emit_flow_mapping_key(yaml_emitter_t *emitter,
779+ yaml_event_t *event, int first)
780+{
781+ if (first)
782+ {
783+ if (!yaml_emitter_write_indicator(emitter, "{", 1, 1, 0))
784+ return 0;
785+ if (!yaml_emitter_increase_indent(emitter, 1, 0))
786+ return 0;
787+ emitter->flow_level ++;
788+ }
789+
790+ if (event->type == YAML_MAPPING_END_EVENT)
791+ {
792+ emitter->flow_level --;
793+ emitter->indent = POP(emitter, emitter->indents);
794+ if (emitter->canonical && !first) {
795+ if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0))
796+ return 0;
797+ if (!yaml_emitter_write_indent(emitter))
798+ return 0;
799+ }
800+ if (!yaml_emitter_write_indicator(emitter, "}", 0, 0, 0))
801+ return 0;
802+ emitter->state = POP(emitter, emitter->states);
803+
804+ return 1;
805+ }
806+
807+ if (!first) {
808+ if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0))
809+ return 0;
810+ }
811+ if (emitter->canonical || emitter->column > emitter->best_width) {
812+ if (!yaml_emitter_write_indent(emitter))
813+ return 0;
814+ }
815+
816+ if (!emitter->canonical && yaml_emitter_check_simple_key(emitter))
817+ {
818+ if (!PUSH(emitter, emitter->states,
819+ YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE))
820+ return 0;
821+
822+ return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 1);
823+ }
824+ else
825+ {
826+ if (!yaml_emitter_write_indicator(emitter, "?", 1, 0, 0))
827+ return 0;
828+ if (!PUSH(emitter, emitter->states,
829+ YAML_EMIT_FLOW_MAPPING_VALUE_STATE))
830+ return 0;
831+
832+ return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0);
833+ }
834+}
835+
836+/*
837+ * Expect a flow value node.
838+ */
839+
840+static int
841+yaml_emitter_emit_flow_mapping_value(yaml_emitter_t *emitter,
842+ yaml_event_t *event, int simple)
843+{
844+ if (simple) {
845+ if (!yaml_emitter_write_indicator(emitter, ":", 0, 0, 0))
846+ return 0;
847+ }
848+ else {
849+ if (emitter->canonical || emitter->column > emitter->best_width) {
850+ if (!yaml_emitter_write_indent(emitter))
851+ return 0;
852+ }
853+ if (!yaml_emitter_write_indicator(emitter, ":", 1, 0, 0))
854+ return 0;
855+ }
856+ if (!PUSH(emitter, emitter->states, YAML_EMIT_FLOW_MAPPING_KEY_STATE))
857+ return 0;
858+ return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0);
859+}
860+
861+/*
862+ * Expect a block item node.
863+ */
864+
865+static int
866+yaml_emitter_emit_block_sequence_item(yaml_emitter_t *emitter,
867+ yaml_event_t *event, int first)
868+{
869+ if (first)
870+ {
871+ if (!yaml_emitter_increase_indent(emitter, 0,
872+ (emitter->mapping_context && !emitter->indention)))
873+ return 0;
874+ }
875+
876+ if (event->type == YAML_SEQUENCE_END_EVENT)
877+ {
878+ emitter->indent = POP(emitter, emitter->indents);
879+ emitter->state = POP(emitter, emitter->states);
880+
881+ return 1;
882+ }
883+
884+ if (!yaml_emitter_write_indent(emitter))
885+ return 0;
886+ if (!yaml_emitter_write_indicator(emitter, "-", 1, 0, 1))
887+ return 0;
888+ if (!PUSH(emitter, emitter->states,
889+ YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE))
890+ return 0;
891+
892+ return yaml_emitter_emit_node(emitter, event, 0, 1, 0, 0);
893+}
894+
895+/*
896+ * Expect a block key node.
897+ */
898+
899+static int
900+yaml_emitter_emit_block_mapping_key(yaml_emitter_t *emitter,
901+ yaml_event_t *event, int first)
902+{
903+ if (first)
904+ {
905+ if (!yaml_emitter_increase_indent(emitter, 0, 0))
906+ return 0;
907+ }
908+
909+ if (event->type == YAML_MAPPING_END_EVENT)
910+ {
911+ emitter->indent = POP(emitter, emitter->indents);
912+ emitter->state = POP(emitter, emitter->states);
913+
914+ return 1;
915+ }
916+
917+ if (!yaml_emitter_write_indent(emitter))
918+ return 0;
919+
920+ if (yaml_emitter_check_simple_key(emitter))
921+ {
922+ if (!PUSH(emitter, emitter->states,
923+ YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE))
924+ return 0;
925+
926+ return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 1);
927+ }
928+ else
929+ {
930+ if (!yaml_emitter_write_indicator(emitter, "?", 1, 0, 1))
931+ return 0;
932+ if (!PUSH(emitter, emitter->states,
933+ YAML_EMIT_BLOCK_MAPPING_VALUE_STATE))
934+ return 0;
935+
936+ return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0);
937+ }
938+}
939+
940+/*
941+ * Expect a block value node.
942+ */
943+
944+static int
945+yaml_emitter_emit_block_mapping_value(yaml_emitter_t *emitter,
946+ yaml_event_t *event, int simple)
947+{
948+ if (simple) {
949+ if (!yaml_emitter_write_indicator(emitter, ":", 0, 0, 0))
950+ return 0;
951+ }
952+ else {
953+ if (!yaml_emitter_write_indent(emitter))
954+ return 0;
955+ if (!yaml_emitter_write_indicator(emitter, ":", 1, 0, 1))
956+ return 0;
957+ }
958+ if (!PUSH(emitter, emitter->states,
959+ YAML_EMIT_BLOCK_MAPPING_KEY_STATE))
960+ return 0;
961+
962+ return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0);
963+}
964+
965+/*
966+ * Expect a node.
967+ */
968+
969+static int
970+yaml_emitter_emit_node(yaml_emitter_t *emitter, yaml_event_t *event,
971+ int root, int sequence, int mapping, int simple_key)
972+{
973+ emitter->root_context = root;
974+ emitter->sequence_context = sequence;
975+ emitter->mapping_context = mapping;
976+ emitter->simple_key_context = simple_key;
977+
978+ switch (event->type)
979+ {
980+ case YAML_ALIAS_EVENT:
981+ return yaml_emitter_emit_alias(emitter, event);
982+
983+ case YAML_SCALAR_EVENT:
984+ return yaml_emitter_emit_scalar(emitter, event);
985+
986+ case YAML_SEQUENCE_START_EVENT:
987+ return yaml_emitter_emit_sequence_start(emitter, event);
988+
989+ case YAML_MAPPING_START_EVENT:
990+ return yaml_emitter_emit_mapping_start(emitter, event);
991+
992+ default:
993+ return yaml_emitter_set_emitter_error(emitter,
994+ "expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS");
995+ }
996+
997+ return 0;
998+}
999+
1000+/*
1001+ * Expect ALIAS.
1002+ */
1003+
1004+static int
1005+yaml_emitter_emit_alias(yaml_emitter_t *emitter, yaml_event_t *event)
1006+{
1007+ if (!yaml_emitter_process_anchor(emitter))
1008+ return 0;
1009+ emitter->state = POP(emitter, emitter->states);
1010+
1011+ return 1;
1012+}
1013+
1014+/*
1015+ * Expect SCALAR.
1016+ */
1017+
1018+static int
1019+yaml_emitter_emit_scalar(yaml_emitter_t *emitter, yaml_event_t *event)
1020+{
1021+ if (!yaml_emitter_select_scalar_style(emitter, event))
1022+ return 0;
1023+ if (!yaml_emitter_process_anchor(emitter))
1024+ return 0;
1025+ if (!yaml_emitter_process_tag(emitter))
1026+ return 0;
1027+ if (!yaml_emitter_increase_indent(emitter, 1, 0))
1028+ return 0;
1029+ if (!yaml_emitter_process_scalar(emitter))
1030+ return 0;
1031+ emitter->indent = POP(emitter, emitter->indents);
1032+ emitter->state = POP(emitter, emitter->states);
1033+
1034+ return 1;
1035+}
1036+
1037+/*
1038+ * Expect SEQUENCE-START.
1039+ */
1040+
1041+static int
1042+yaml_emitter_emit_sequence_start(yaml_emitter_t *emitter, yaml_event_t *event)
1043+{
1044+ if (!yaml_emitter_process_anchor(emitter))
1045+ return 0;
1046+ if (!yaml_emitter_process_tag(emitter))
1047+ return 0;
1048+
1049+ if (emitter->flow_level || emitter->canonical
1050+ || event->data.sequence_start.style == YAML_FLOW_SEQUENCE_STYLE
1051+ || yaml_emitter_check_empty_sequence(emitter)) {
1052+ emitter->state = YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE;
1053+ }
1054+ else {
1055+ emitter->state = YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE;
1056+ }
1057+
1058+ return 1;
1059+}
1060+
1061+/*
1062+ * Expect MAPPING-START.
1063+ */
1064+
1065+static int
1066+yaml_emitter_emit_mapping_start(yaml_emitter_t *emitter, yaml_event_t *event)
1067+{
1068+ if (!yaml_emitter_process_anchor(emitter))
1069+ return 0;
1070+ if (!yaml_emitter_process_tag(emitter))
1071+ return 0;
1072+
1073+ if (emitter->flow_level || emitter->canonical
1074+ || event->data.mapping_start.style == YAML_FLOW_MAPPING_STYLE
1075+ || yaml_emitter_check_empty_mapping(emitter)) {
1076+ emitter->state = YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE;
1077+ }
1078+ else {
1079+ emitter->state = YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE;
1080+ }
1081+
1082+ return 1;
1083+}
1084+
1085+/*
1086+ * Check if the document content is an empty scalar.
1087+ */
1088+
1089+static int
1090+yaml_emitter_check_empty_document(yaml_emitter_t *emitter)
1091+{
1092+ return 0;
1093+}
1094+
1095+/*
1096+ * Check if the next events represent an empty sequence.
1097+ */
1098+
1099+static int
1100+yaml_emitter_check_empty_sequence(yaml_emitter_t *emitter)
1101+{
1102+ if (emitter->events.tail - emitter->events.head < 2)
1103+ return 0;
1104+
1105+ return (emitter->events.head[0].type == YAML_SEQUENCE_START_EVENT
1106+ && emitter->events.head[1].type == YAML_SEQUENCE_END_EVENT);
1107+}
1108+
1109+/*
1110+ * Check if the next events represent an empty mapping.
1111+ */
1112+
1113+static int
1114+yaml_emitter_check_empty_mapping(yaml_emitter_t *emitter)
1115+{
1116+ if (emitter->events.tail - emitter->events.head < 2)
1117+ return 0;
1118+
1119+ return (emitter->events.head[0].type == YAML_MAPPING_START_EVENT
1120+ && emitter->events.head[1].type == YAML_MAPPING_END_EVENT);
1121+}
1122+
1123+/*
1124+ * Check if the next node can be expressed as a simple key.
1125+ */
1126+
1127+static int
1128+yaml_emitter_check_simple_key(yaml_emitter_t *emitter)
1129+{
1130+ yaml_event_t *event = emitter->events.head;
1131+ size_t length = 0;
1132+
1133+ switch (event->type)
1134+ {
1135+ case YAML_ALIAS_EVENT:
1136+ length += emitter->anchor_data.anchor_length;
1137+ break;
1138+
1139+ case YAML_SCALAR_EVENT:
1140+ if (emitter->scalar_data.multiline)
1141+ return 0;
1142+ length += emitter->anchor_data.anchor_length
1143+ + emitter->tag_data.handle_length
1144+ + emitter->tag_data.suffix_length
1145+ + emitter->scalar_data.length;
1146+ break;
1147+
1148+ case YAML_SEQUENCE_START_EVENT:
1149+ if (!yaml_emitter_check_empty_sequence(emitter))
1150+ return 0;
1151+ length += emitter->anchor_data.anchor_length
1152+ + emitter->tag_data.handle_length
1153+ + emitter->tag_data.suffix_length;
1154+ break;
1155+
1156+ case YAML_MAPPING_START_EVENT:
1157+ if (!yaml_emitter_check_empty_mapping(emitter))
1158+ return 0;
1159+ length += emitter->anchor_data.anchor_length
1160+ + emitter->tag_data.handle_length
1161+ + emitter->tag_data.suffix_length;
1162+ break;
1163+
1164+ default:
1165+ return 0;
1166+ }
1167+
1168+ if (length > 128)
1169+ return 0;
1170+
1171+ return 1;
1172+}
1173+
1174+/*
1175+ * Determine an acceptable scalar style.
1176+ */
1177+
1178+static int
1179+yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event)
1180+{
1181+ yaml_scalar_style_t style = event->data.scalar.style;
1182+ int no_tag = (!emitter->tag_data.handle && !emitter->tag_data.suffix);
1183+
1184+ if (no_tag && !event->data.scalar.plain_implicit
1185+ && !event->data.scalar.quoted_implicit) {
1186+ return yaml_emitter_set_emitter_error(emitter,
1187+ "neither tag nor implicit flags are specified");
1188+ }
1189+
1190+ if (style == YAML_ANY_SCALAR_STYLE)
1191+ style = YAML_PLAIN_SCALAR_STYLE;
1192+
1193+ if (emitter->canonical)
1194+ style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
1195+
1196+ if (emitter->simple_key_context && emitter->scalar_data.multiline)
1197+ style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
1198+
1199+ if (style == YAML_PLAIN_SCALAR_STYLE)
1200+ {
1201+ if ((emitter->flow_level && !emitter->scalar_data.flow_plain_allowed)
1202+ || (!emitter->flow_level && !emitter->scalar_data.block_plain_allowed))
1203+ style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
1204+ if (!emitter->scalar_data.length
1205+ && (emitter->flow_level || emitter->simple_key_context))
1206+ style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
1207+ if (no_tag && !event->data.scalar.plain_implicit)
1208+ style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
1209+ }
1210+
1211+ if (style == YAML_SINGLE_QUOTED_SCALAR_STYLE)
1212+ {
1213+ if (!emitter->scalar_data.single_quoted_allowed)
1214+ style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
1215+ }
1216+
1217+ if (style == YAML_LITERAL_SCALAR_STYLE || style == YAML_FOLDED_SCALAR_STYLE)
1218+ {
1219+ if (!emitter->scalar_data.block_allowed
1220+ || emitter->flow_level || emitter->simple_key_context)
1221+ style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
1222+ }
1223+
1224+ if (no_tag && !event->data.scalar.quoted_implicit
1225+ && style != YAML_PLAIN_SCALAR_STYLE)
1226+ {
1227+ emitter->tag_data.handle = (yaml_char_t *)"!";
1228+ emitter->tag_data.handle_length = 1;
1229+ }
1230+
1231+ emitter->scalar_data.style = style;
1232+
1233+ return 1;
1234+}
1235+
1236+/*
1237+ * Write an achor.
1238+ */
1239+
1240+static int
1241+yaml_emitter_process_anchor(yaml_emitter_t *emitter)
1242+{
1243+ if (!emitter->anchor_data.anchor)
1244+ return 1;
1245+
1246+ if (!yaml_emitter_write_indicator(emitter,
1247+ (emitter->anchor_data.alias ? "*" : "&"), 1, 0, 0))
1248+ return 0;
1249+
1250+ return yaml_emitter_write_anchor(emitter,
1251+ emitter->anchor_data.anchor, emitter->anchor_data.anchor_length);
1252+}
1253+
1254+/*
1255+ * Write a tag.
1256+ */
1257+
1258+static int
1259+yaml_emitter_process_tag(yaml_emitter_t *emitter)
1260+{
1261+ if (!emitter->tag_data.handle && !emitter->tag_data.suffix)
1262+ return 1;
1263+
1264+ if (emitter->tag_data.handle)
1265+ {
1266+ if (!yaml_emitter_write_tag_handle(emitter, emitter->tag_data.handle,
1267+ emitter->tag_data.handle_length))
1268+ return 0;
1269+ if (emitter->tag_data.suffix) {
1270+ if (!yaml_emitter_write_tag_content(emitter, emitter->tag_data.suffix,
1271+ emitter->tag_data.suffix_length, 0))
1272+ return 0;
1273+ }
1274+ }
1275+ else
1276+ {
1277+ if (!yaml_emitter_write_indicator(emitter, "!<", 1, 0, 0))
1278+ return 0;
1279+ if (!yaml_emitter_write_tag_content(emitter, emitter->tag_data.suffix,
1280+ emitter->tag_data.suffix_length, 0))
1281+ return 0;
1282+ if (!yaml_emitter_write_indicator(emitter, ">", 0, 0, 0))
1283+ return 0;
1284+ }
1285+
1286+ return 1;
1287+}
1288+
1289+/*
1290+ * Write a scalar.
1291+ */
1292+
1293+static int
1294+yaml_emitter_process_scalar(yaml_emitter_t *emitter)
1295+{
1296+ switch (emitter->scalar_data.style)
1297+ {
1298+ case YAML_PLAIN_SCALAR_STYLE:
1299+ return yaml_emitter_write_plain_scalar(emitter,
1300+ emitter->scalar_data.value, emitter->scalar_data.length,
1301+ !emitter->simple_key_context);
1302+
1303+ case YAML_SINGLE_QUOTED_SCALAR_STYLE:
1304+ return yaml_emitter_write_single_quoted_scalar(emitter,
1305+ emitter->scalar_data.value, emitter->scalar_data.length,
1306+ !emitter->simple_key_context);
1307+
1308+ case YAML_DOUBLE_QUOTED_SCALAR_STYLE:
1309+ return yaml_emitter_write_double_quoted_scalar(emitter,
1310+ emitter->scalar_data.value, emitter->scalar_data.length,
1311+ !emitter->simple_key_context);
1312+
1313+ case YAML_LITERAL_SCALAR_STYLE:
1314+ return yaml_emitter_write_literal_scalar(emitter,
1315+ emitter->scalar_data.value, emitter->scalar_data.length);
1316+
1317+ case YAML_FOLDED_SCALAR_STYLE:
1318+ return yaml_emitter_write_folded_scalar(emitter,
1319+ emitter->scalar_data.value, emitter->scalar_data.length);
1320+
1321+ default:
1322+ assert(1); /* Impossible. */
1323+ }
1324+
1325+ return 0;
1326+}
1327+
1328+/*
1329+ * Check if a %YAML directive is valid.
1330+ */
1331+
1332+static int
1333+yaml_emitter_analyze_version_directive(yaml_emitter_t *emitter,
1334+ yaml_version_directive_t version_directive)
1335+{
1336+ if (version_directive.major != 1 || version_directive.minor != 1) {
1337+ return yaml_emitter_set_emitter_error(emitter,
1338+ "incompatible %YAML directive");
1339+ }
1340+
1341+ return 1;
1342+}
1343+
1344+/*
1345+ * Check if a %TAG directive is valid.
1346+ */
1347+
1348+static int
1349+yaml_emitter_analyze_tag_directive(yaml_emitter_t *emitter,
1350+ yaml_tag_directive_t tag_directive)
1351+{
1352+ yaml_string_t handle;
1353+ yaml_string_t prefix;
1354+ size_t handle_length;
1355+ size_t prefix_length;
1356+
1357+ handle_length = strlen((char *)tag_directive.handle);
1358+ prefix_length = strlen((char *)tag_directive.prefix);
1359+ STRING_ASSIGN(handle, tag_directive.handle, handle_length);
1360+ STRING_ASSIGN(prefix, tag_directive.prefix, prefix_length);
1361+
1362+ if (handle.start == handle.end) {
1363+ return yaml_emitter_set_emitter_error(emitter,
1364+ "tag handle must not be empty");
1365+ }
1366+
1367+ if (handle.start[0] != '!') {
1368+ return yaml_emitter_set_emitter_error(emitter,
1369+ "tag handle must start with '!'");
1370+ }
1371+
1372+ if (handle.end[-1] != '!') {
1373+ return yaml_emitter_set_emitter_error(emitter,
1374+ "tag handle must end with '!'");
1375+ }
1376+
1377+ handle.pointer ++;
1378+
1379+ while (handle.pointer < handle.end-1) {
1380+ if (!IS_ALPHA(handle)) {
1381+ return yaml_emitter_set_emitter_error(emitter,
1382+ "tag handle must contain alphanumerical characters only");
1383+ }
1384+ MOVE(handle);
1385+ }
1386+
1387+ if (prefix.start == prefix.end) {
1388+ return yaml_emitter_set_emitter_error(emitter,
1389+ "tag prefix must not be empty");
1390+ }
1391+
1392+ return 1;
1393+}
1394+
1395+/*
1396+ * Check if an anchor is valid.
1397+ */
1398+
1399+static int
1400+yaml_emitter_analyze_anchor(yaml_emitter_t *emitter,
1401+ yaml_char_t *anchor, int alias)
1402+{
1403+ size_t anchor_length;
1404+ yaml_string_t string;
1405+
1406+ anchor_length = strlen((char *)anchor);
1407+ STRING_ASSIGN(string, anchor, anchor_length);
1408+
1409+ if (string.start == string.end) {
1410+ return yaml_emitter_set_emitter_error(emitter, alias ?
1411+ "alias value must not be empty" :
1412+ "anchor value must not be empty");
1413+ }
1414+
1415+ while (string.pointer != string.end) {
1416+ if (!IS_ALPHA(string)) {
1417+ return yaml_emitter_set_emitter_error(emitter, alias ?
1418+ "alias value must contain alphanumerical characters only" :
1419+ "anchor value must contain alphanumerical characters only");
1420+ }
1421+ MOVE(string);
1422+ }
1423+
1424+ emitter->anchor_data.anchor = string.start;
1425+ emitter->anchor_data.anchor_length = string.end - string.start;
1426+ emitter->anchor_data.alias = alias;
1427+
1428+ return 1;
1429+}
1430+
1431+/*
1432+ * Check if a tag is valid.
1433+ */
1434+
1435+static int
1436+yaml_emitter_analyze_tag(yaml_emitter_t *emitter,
1437+ yaml_char_t *tag)
1438+{
1439+ size_t tag_length;
1440+ yaml_string_t string;
1441+ yaml_tag_directive_t *tag_directive;
1442+
1443+ tag_length = strlen((char *)tag);
1444+ STRING_ASSIGN(string, tag, tag_length);
1445+
1446+ if (string.start == string.end) {
1447+ return yaml_emitter_set_emitter_error(emitter,
1448+ "tag value must not be empty");
1449+ }
1450+
1451+ for (tag_directive = emitter->tag_directives.start;
1452+ tag_directive != emitter->tag_directives.top; tag_directive ++) {
1453+ size_t prefix_length = strlen((char *)tag_directive->prefix);
1454+ if (prefix_length < (size_t)(string.end - string.start)
1455+ && strncmp((char *)tag_directive->prefix, (char *)string.start,
1456+ prefix_length) == 0)
1457+ {
1458+ emitter->tag_data.handle = tag_directive->handle;
1459+ emitter->tag_data.handle_length =
1460+ strlen((char *)tag_directive->handle);
1461+ emitter->tag_data.suffix = string.start + prefix_length;
1462+ emitter->tag_data.suffix_length =
1463+ (string.end - string.start) - prefix_length;
1464+ return 1;
1465+ }
1466+ }
1467+
1468+ emitter->tag_data.suffix = string.start;
1469+ emitter->tag_data.suffix_length = string.end - string.start;
1470+
1471+ return 1;
1472+}
1473+
1474+/*
1475+ * Check if a scalar is valid.
1476+ */
1477+
1478+static int
1479+yaml_emitter_analyze_scalar(yaml_emitter_t *emitter,
1480+ yaml_char_t *value, size_t length)
1481+{
1482+ yaml_string_t string;
1483+
1484+ int block_indicators = 0;
1485+ int flow_indicators = 0;
1486+ int line_breaks = 0;
1487+ int special_characters = 0;
1488+
1489+ int leading_space = 0;
1490+ int leading_break = 0;
1491+ int trailing_space = 0;
1492+ int trailing_break = 0;
1493+ int break_space = 0;
1494+ int space_break = 0;
1495+
1496+ int preceeded_by_whitespace = 0;
1497+ int followed_by_whitespace = 0;
1498+ int previous_space = 0;
1499+ int previous_break = 0;
1500+
1501+ STRING_ASSIGN(string, value, length);
1502+
1503+ emitter->scalar_data.value = value;
1504+ emitter->scalar_data.length = length;
1505+
1506+ if (string.start == string.end)
1507+ {
1508+ emitter->scalar_data.multiline = 0;
1509+ emitter->scalar_data.flow_plain_allowed = 0;
1510+ emitter->scalar_data.block_plain_allowed = 1;
1511+ emitter->scalar_data.single_quoted_allowed = 1;
1512+ emitter->scalar_data.block_allowed = 0;
1513+
1514+ return 1;
1515+ }
1516+
1517+ if ((CHECK_AT(string, '-', 0)
1518+ && CHECK_AT(string, '-', 1)
1519+ && CHECK_AT(string, '-', 2))
1520+ || (CHECK_AT(string, '.', 0)
1521+ && CHECK_AT(string, '.', 1)
1522+ && CHECK_AT(string, '.', 2))) {
1523+ block_indicators = 1;
1524+ flow_indicators = 1;
1525+ }
1526+
1527+ preceeded_by_whitespace = 1;
1528+ followed_by_whitespace = IS_BLANKZ_AT(string, WIDTH(string));
1529+
1530+ while (string.pointer != string.end)
1531+ {
1532+ if (string.start == string.pointer)
1533+ {
1534+ if (CHECK(string, '#') || CHECK(string, ',')
1535+ || CHECK(string, '[') || CHECK(string, ']')
1536+ || CHECK(string, '{') || CHECK(string, '}')
1537+ || CHECK(string, '&') || CHECK(string, '*')
1538+ || CHECK(string, '!') || CHECK(string, '|')
1539+ || CHECK(string, '>') || CHECK(string, '\'')
1540+ || CHECK(string, '"') || CHECK(string, '%')
1541+ || CHECK(string, '@') || CHECK(string, '`')) {
1542+ flow_indicators = 1;
1543+ block_indicators = 1;
1544+ }
1545+
1546+ if (CHECK(string, '?') || CHECK(string, ':')) {
1547+ flow_indicators = 1;
1548+ if (followed_by_whitespace) {
1549+ block_indicators = 1;
1550+ }
1551+ }
1552+
1553+ if (CHECK(string, '-') && followed_by_whitespace) {
1554+ flow_indicators = 1;
1555+ block_indicators = 1;
1556+ }
1557+ }
1558+ else
1559+ {
1560+ if (CHECK(string, ',') || CHECK(string, '?')
1561+ || CHECK(string, '[') || CHECK(string, ']')
1562+ || CHECK(string, '{') || CHECK(string, '}')) {
1563+ flow_indicators = 1;
1564+ }
1565+
1566+ if (CHECK(string, ':')) {
1567+ flow_indicators = 1;
1568+ if (followed_by_whitespace) {
1569+ block_indicators = 1;
1570+ }
1571+ }
1572+
1573+ if (CHECK(string, '#') && preceeded_by_whitespace) {
1574+ flow_indicators = 1;
1575+ block_indicators = 1;
1576+ }
1577+ }
1578+
1579+ if (!IS_PRINTABLE(string)
1580+ || (!IS_ASCII(string) && !emitter->unicode)) {
1581+ special_characters = 1;
1582+ }
1583+
1584+ if (IS_BREAK(string)) {
1585+ line_breaks = 1;
1586+ }
1587+
1588+ if (IS_SPACE(string))
1589+ {
1590+ if (string.start == string.pointer) {
1591+ leading_space = 1;
1592+ }
1593+ if (string.pointer+WIDTH(string) == string.end) {
1594+ trailing_space = 1;
1595+ }
1596+ if (previous_break) {
1597+ break_space = 1;
1598+ }
1599+ previous_space = 1;
1600+ previous_break = 0;
1601+ }
1602+ else if (IS_BREAK(string))
1603+ {
1604+ if (string.start == string.pointer) {
1605+ leading_break = 1;
1606+ }
1607+ if (string.pointer+WIDTH(string) == string.end) {
1608+ trailing_break = 1;
1609+ }
1610+ if (previous_space) {
1611+ space_break = 1;
1612+ }
1613+ previous_space = 0;
1614+ previous_break = 1;
1615+ }
1616+ else
1617+ {
1618+ previous_space = 0;
1619+ previous_break = 0;
1620+ }
1621+
1622+ preceeded_by_whitespace = IS_BLANKZ(string);
1623+ MOVE(string);
1624+ if (string.pointer != string.end) {
1625+ followed_by_whitespace = IS_BLANKZ_AT(string, WIDTH(string));
1626+ }
1627+ }
1628+
1629+ emitter->scalar_data.multiline = line_breaks;
1630+
1631+ emitter->scalar_data.flow_plain_allowed = 1;
1632+ emitter->scalar_data.block_plain_allowed = 1;
1633+ emitter->scalar_data.single_quoted_allowed = 1;
1634+ emitter->scalar_data.block_allowed = 1;
1635+
1636+ if (leading_space || leading_break || trailing_space || trailing_break) {
1637+ emitter->scalar_data.flow_plain_allowed = 0;
1638+ emitter->scalar_data.block_plain_allowed = 0;
1639+ }
1640+
1641+ if (trailing_space) {
1642+ emitter->scalar_data.block_allowed = 0;
1643+ }
1644+
1645+ if (break_space) {
1646+ emitter->scalar_data.flow_plain_allowed = 0;
1647+ emitter->scalar_data.block_plain_allowed = 0;
1648+ emitter->scalar_data.single_quoted_allowed = 0;
1649+ }
1650+
1651+ if (space_break || special_characters) {
1652+ emitter->scalar_data.flow_plain_allowed = 0;
1653+ emitter->scalar_data.block_plain_allowed = 0;
1654+ emitter->scalar_data.single_quoted_allowed = 0;
1655+ emitter->scalar_data.block_allowed = 0;
1656+ }
1657+
1658+ if (line_breaks) {
1659+ emitter->scalar_data.flow_plain_allowed = 0;
1660+ emitter->scalar_data.block_plain_allowed = 0;
1661+ }
1662+
1663+ if (flow_indicators) {
1664+ emitter->scalar_data.flow_plain_allowed = 0;
1665+ }
1666+
1667+ if (block_indicators) {
1668+ emitter->scalar_data.block_plain_allowed = 0;
1669+ }
1670+
1671+ return 1;
1672+}
1673+
1674+/*
1675+ * Check if the event data is valid.
1676+ */
1677+
1678+static int
1679+yaml_emitter_analyze_event(yaml_emitter_t *emitter,
1680+ yaml_event_t *event)
1681+{
1682+ emitter->anchor_data.anchor = NULL;
1683+ emitter->anchor_data.anchor_length = 0;
1684+ emitter->tag_data.handle = NULL;
1685+ emitter->tag_data.handle_length = 0;
1686+ emitter->tag_data.suffix = NULL;
1687+ emitter->tag_data.suffix_length = 0;
1688+ emitter->scalar_data.value = NULL;
1689+ emitter->scalar_data.length = 0;
1690+
1691+ switch (event->type)
1692+ {
1693+ case YAML_ALIAS_EVENT:
1694+ if (!yaml_emitter_analyze_anchor(emitter,
1695+ event->data.alias.anchor, 1))
1696+ return 0;
1697+ return 1;
1698+
1699+ case YAML_SCALAR_EVENT:
1700+ if (event->data.scalar.anchor) {
1701+ if (!yaml_emitter_analyze_anchor(emitter,
1702+ event->data.scalar.anchor, 0))
1703+ return 0;
1704+ }
1705+ if (event->data.scalar.tag && (emitter->canonical ||
1706+ (!event->data.scalar.plain_implicit
1707+ && !event->data.scalar.quoted_implicit))) {
1708+ if (!yaml_emitter_analyze_tag(emitter, event->data.scalar.tag))
1709+ return 0;
1710+ }
1711+ if (!yaml_emitter_analyze_scalar(emitter,
1712+ event->data.scalar.value, event->data.scalar.length))
1713+ return 0;
1714+ return 1;
1715+
1716+ case YAML_SEQUENCE_START_EVENT:
1717+ if (event->data.sequence_start.anchor) {
1718+ if (!yaml_emitter_analyze_anchor(emitter,
1719+ event->data.sequence_start.anchor, 0))
1720+ return 0;
1721+ }
1722+ if (event->data.sequence_start.tag && (emitter->canonical ||
1723+ !event->data.sequence_start.implicit)) {
1724+ if (!yaml_emitter_analyze_tag(emitter,
1725+ event->data.sequence_start.tag))
1726+ return 0;
1727+ }
1728+ return 1;
1729+
1730+ case YAML_MAPPING_START_EVENT:
1731+ if (event->data.mapping_start.anchor) {
1732+ if (!yaml_emitter_analyze_anchor(emitter,
1733+ event->data.mapping_start.anchor, 0))
1734+ return 0;
1735+ }
1736+ if (event->data.mapping_start.tag && (emitter->canonical ||
1737+ !event->data.mapping_start.implicit)) {
1738+ if (!yaml_emitter_analyze_tag(emitter,
1739+ event->data.mapping_start.tag))
1740+ return 0;
1741+ }
1742+ return 1;
1743+
1744+ default:
1745+ return 1;
1746+ }
1747+}
1748+
1749+/*
1750+ * Write the BOM character.
1751+ */
1752+
1753+static int
1754+yaml_emitter_write_bom(yaml_emitter_t *emitter)
1755+{
1756+ if (!FLUSH(emitter)) return 0;
1757+
1758+ *(emitter->buffer.pointer++) = (yaml_char_t) '\xEF';
1759+ *(emitter->buffer.pointer++) = (yaml_char_t) '\xBB';
1760+ *(emitter->buffer.pointer++) = (yaml_char_t) '\xBF';
1761+
1762+ return 1;
1763+}
1764+
1765+static int
1766+yaml_emitter_write_indent(yaml_emitter_t *emitter)
1767+{
1768+ int indent = (emitter->indent >= 0) ? emitter->indent : 0;
1769+
1770+ if (!emitter->indention || emitter->column > indent
1771+ || (emitter->column == indent && !emitter->whitespace)) {
1772+ if (!PUT_BREAK(emitter)) return 0;
1773+ }
1774+
1775+ while (emitter->column < indent) {
1776+ if (!PUT(emitter, ' ')) return 0;
1777+ }
1778+
1779+ emitter->whitespace = 1;
1780+ emitter->indention = 1;
1781+
1782+ return 1;
1783+}
1784+
1785+static int
1786+yaml_emitter_write_indicator(yaml_emitter_t *emitter,
1787+ char *indicator, int need_whitespace,
1788+ int is_whitespace, int is_indention)
1789+{
1790+ size_t indicator_length;
1791+ yaml_string_t string;
1792+
1793+ indicator_length = strlen(indicator);
1794+ STRING_ASSIGN(string, (yaml_char_t *)indicator, indicator_length);
1795+
1796+ if (need_whitespace && !emitter->whitespace) {
1797+ if (!PUT(emitter, ' ')) return 0;
1798+ }
1799+
1800+ while (string.pointer != string.end) {
1801+ if (!WRITE(emitter, string)) return 0;
1802+ }
1803+
1804+ emitter->whitespace = is_whitespace;
1805+ emitter->indention = (emitter->indention && is_indention);
1806+ emitter->open_ended = 0;
1807+
1808+ return 1;
1809+}
1810+
1811+static int
1812+yaml_emitter_write_anchor(yaml_emitter_t *emitter,
1813+ yaml_char_t *value, size_t length)
1814+{
1815+ yaml_string_t string;
1816+ STRING_ASSIGN(string, value, length);
1817+
1818+ while (string.pointer != string.end) {
1819+ if (!WRITE(emitter, string)) return 0;
1820+ }
1821+
1822+ emitter->whitespace = 0;
1823+ emitter->indention = 0;
1824+
1825+ return 1;
1826+}
1827+
1828+static int
1829+yaml_emitter_write_tag_handle(yaml_emitter_t *emitter,
1830+ yaml_char_t *value, size_t length)
1831+{
1832+ yaml_string_t string;
1833+ STRING_ASSIGN(string, value, length);
1834+
1835+ if (!emitter->whitespace) {
1836+ if (!PUT(emitter, ' ')) return 0;
1837+ }
1838+
1839+ while (string.pointer != string.end) {
1840+ if (!WRITE(emitter, string)) return 0;
1841+ }
1842+
1843+ emitter->whitespace = 0;
1844+ emitter->indention = 0;
1845+
1846+ return 1;
1847+}
1848+
1849+static int
1850+yaml_emitter_write_tag_content(yaml_emitter_t *emitter,
1851+ yaml_char_t *value, size_t length,
1852+ int need_whitespace)
1853+{
1854+ yaml_string_t string;
1855+ STRING_ASSIGN(string, value, length);
1856+
1857+ if (need_whitespace && !emitter->whitespace) {
1858+ if (!PUT(emitter, ' ')) return 0;
1859+ }
1860+
1861+ while (string.pointer != string.end) {
1862+ if (IS_ALPHA(string)
1863+ || CHECK(string, ';') || CHECK(string, '/')
1864+ || CHECK(string, '?') || CHECK(string, ':')
1865+ || CHECK(string, '@') || CHECK(string, '&')
1866+ || CHECK(string, '=') || CHECK(string, '+')
1867+ || CHECK(string, '$') || CHECK(string, ',')
1868+ || CHECK(string, '_') || CHECK(string, '.')
1869+ || CHECK(string, '~') || CHECK(string, '*')
1870+ || CHECK(string, '\'') || CHECK(string, '(')
1871+ || CHECK(string, ')') || CHECK(string, '[')
1872+ || CHECK(string, ']')) {
1873+ if (!WRITE(emitter, string)) return 0;
1874+ }
1875+ else {
1876+ int width = WIDTH(string);
1877+ unsigned int value;
1878+ while (width --) {
1879+ value = *(string.pointer++);
1880+ if (!PUT(emitter, '%')) return 0;
1881+ if (!PUT(emitter, (value >> 4)
1882+ + ((value >> 4) < 10 ? '0' : 'A' - 10)))
1883+ return 0;
1884+ if (!PUT(emitter, (value & 0x0F)
1885+ + ((value & 0x0F) < 10 ? '0' : 'A' - 10)))
1886+ return 0;
1887+ }
1888+ }
1889+ }
1890+
1891+ emitter->whitespace = 0;
1892+ emitter->indention = 0;
1893+
1894+ return 1;
1895+}
1896+
1897+static int
1898+yaml_emitter_write_plain_scalar(yaml_emitter_t *emitter,
1899+ yaml_char_t *value, size_t length, int allow_breaks)
1900+{
1901+ yaml_string_t string;
1902+ int spaces = 0;
1903+ int breaks = 0;
1904+
1905+ STRING_ASSIGN(string, value, length);
1906+
1907+ if (!emitter->whitespace) {
1908+ if (!PUT(emitter, ' ')) return 0;
1909+ }
1910+
1911+ while (string.pointer != string.end)
1912+ {
1913+ if (IS_SPACE(string))
1914+ {
1915+ if (allow_breaks && !spaces
1916+ && emitter->column > emitter->best_width
1917+ && !IS_SPACE_AT(string, 1)) {
1918+ if (!yaml_emitter_write_indent(emitter)) return 0;
1919+ MOVE(string);
1920+ }
1921+ else {
1922+ if (!WRITE(emitter, string)) return 0;
1923+ }
1924+ spaces = 1;
1925+ }
1926+ else if (IS_BREAK(string))
1927+ {
1928+ if (!breaks && CHECK(string, '\n')) {
1929+ if (!PUT_BREAK(emitter)) return 0;
1930+ }
1931+ if (!WRITE_BREAK(emitter, string)) return 0;
1932+ emitter->indention = 1;
1933+ breaks = 1;
1934+ }
1935+ else
1936+ {
1937+ if (breaks) {
1938+ if (!yaml_emitter_write_indent(emitter)) return 0;
1939+ }
1940+ if (!WRITE(emitter, string)) return 0;
1941+ emitter->indention = 0;
1942+ spaces = 0;
1943+ breaks = 0;
1944+ }
1945+ }
1946+
1947+ emitter->whitespace = 0;
1948+ emitter->indention = 0;
1949+ if (emitter->root_context)
1950+ {
1951+ emitter->open_ended = 1;
1952+ }
1953+
1954+ return 1;
1955+}
1956+
1957+static int
1958+yaml_emitter_write_single_quoted_scalar(yaml_emitter_t *emitter,
1959+ yaml_char_t *value, size_t length, int allow_breaks)
1960+{
1961+ yaml_string_t string;
1962+ int spaces = 0;
1963+ int breaks = 0;
1964+
1965+ STRING_ASSIGN(string, value, length);
1966+
1967+ if (!yaml_emitter_write_indicator(emitter, "'", 1, 0, 0))
1968+ return 0;
1969+
1970+ while (string.pointer != string.end)
1971+ {
1972+ if (IS_SPACE(string))
1973+ {
1974+ if (allow_breaks && !spaces
1975+ && emitter->column > emitter->best_width
1976+ && string.pointer != string.start
1977+ && string.pointer != string.end - 1
1978+ && !IS_SPACE_AT(string, 1)) {
1979+ if (!yaml_emitter_write_indent(emitter)) return 0;
1980+ MOVE(string);
1981+ }
1982+ else {
1983+ if (!WRITE(emitter, string)) return 0;
1984+ }
1985+ spaces = 1;
1986+ }
1987+ else if (IS_BREAK(string))
1988+ {
1989+ if (!breaks && CHECK(string, '\n')) {
1990+ if (!PUT_BREAK(emitter)) return 0;
1991+ }
1992+ if (!WRITE_BREAK(emitter, string)) return 0;
1993+ emitter->indention = 1;
1994+ breaks = 1;
1995+ }
1996+ else
1997+ {
1998+ if (breaks) {
1999+ if (!yaml_emitter_write_indent(emitter)) return 0;
2000+ }
2001+ if (CHECK(string, '\'')) {
2002+ if (!PUT(emitter, '\'')) return 0;
2003+ }
2004+ if (!WRITE(emitter, string)) return 0;
2005+ emitter->indention = 0;
2006+ spaces = 0;
2007+ breaks = 0;
2008+ }
2009+ }
2010+
2011+ if (!yaml_emitter_write_indicator(emitter, "'", 0, 0, 0))
2012+ return 0;
2013+
2014+ emitter->whitespace = 0;
2015+ emitter->indention = 0;
2016+
2017+ return 1;
2018+}
2019+
2020+static int
2021+yaml_emitter_write_double_quoted_scalar(yaml_emitter_t *emitter,
2022+ yaml_char_t *value, size_t length, int allow_breaks)
2023+{
2024+ yaml_string_t string;
2025+ int spaces = 0;
2026+
2027+ STRING_ASSIGN(string, value, length);
2028+
2029+ if (!yaml_emitter_write_indicator(emitter, "\"", 1, 0, 0))
2030+ return 0;
2031+
2032+ while (string.pointer != string.end)
2033+ {
2034+ if (!IS_PRINTABLE(string) || (!emitter->unicode && !IS_ASCII(string))
2035+ || IS_BOM(string) || IS_BREAK(string)
2036+ || CHECK(string, '"') || CHECK(string, '\\'))
2037+ {
2038+ unsigned char octet;
2039+ unsigned int width;
2040+ unsigned int value;
2041+ int k;
2042+
2043+ octet = string.pointer[0];
2044+ width = (octet & 0x80) == 0x00 ? 1 :
2045+ (octet & 0xE0) == 0xC0 ? 2 :
2046+ (octet & 0xF0) == 0xE0 ? 3 :
2047+ (octet & 0xF8) == 0xF0 ? 4 : 0;
2048+ value = (octet & 0x80) == 0x00 ? octet & 0x7F :
2049+ (octet & 0xE0) == 0xC0 ? octet & 0x1F :
2050+ (octet & 0xF0) == 0xE0 ? octet & 0x0F :
2051+ (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
2052+ for (k = 1; k < (int)width; k ++) {
2053+ octet = string.pointer[k];
2054+ value = (value << 6) + (octet & 0x3F);
2055+ }
2056+ string.pointer += width;
2057+
2058+ if (!PUT(emitter, '\\')) return 0;
2059+
2060+ switch (value)
2061+ {
2062+ case 0x00:
2063+ if (!PUT(emitter, '0')) return 0;
2064+ break;
2065+
2066+ case 0x07:
2067+ if (!PUT(emitter, 'a')) return 0;
2068+ break;
2069+
2070+ case 0x08:
2071+ if (!PUT(emitter, 'b')) return 0;
2072+ break;
2073+
2074+ case 0x09:
2075+ if (!PUT(emitter, 't')) return 0;
2076+ break;
2077+
2078+ case 0x0A:
2079+ if (!PUT(emitter, 'n')) return 0;
2080+ break;
2081+
2082+ case 0x0B:
2083+ if (!PUT(emitter, 'v')) return 0;
2084+ break;
2085+
2086+ case 0x0C:
2087+ if (!PUT(emitter, 'f')) return 0;
2088+ break;
2089+
2090+ case 0x0D:
2091+ if (!PUT(emitter, 'r')) return 0;
2092+ break;
2093+
2094+ case 0x1B:
2095+ if (!PUT(emitter, 'e')) return 0;
2096+ break;
2097+
2098+ case 0x22:
2099+ if (!PUT(emitter, '\"')) return 0;
2100+ break;
2101+
2102+ case 0x5C:
2103+ if (!PUT(emitter, '\\')) return 0;
2104+ break;
2105+
2106+ case 0x85:
2107+ if (!PUT(emitter, 'N')) return 0;
2108+ break;
2109+
2110+ case 0xA0:
2111+ if (!PUT(emitter, '_')) return 0;
2112+ break;
2113+
2114+ case 0x2028:
2115+ if (!PUT(emitter, 'L')) return 0;
2116+ break;
2117+
2118+ case 0x2029:
2119+ if (!PUT(emitter, 'P')) return 0;
2120+ break;
2121+
2122+ default:
2123+ if (value <= 0xFF) {
2124+ if (!PUT(emitter, 'x')) return 0;
2125+ width = 2;
2126+ }
2127+ else if (value <= 0xFFFF) {
2128+ if (!PUT(emitter, 'u')) return 0;
2129+ width = 4;
2130+ }
2131+ else {
2132+ if (!PUT(emitter, 'U')) return 0;
2133+ width = 8;
2134+ }
2135+ for (k = (width-1)*4; k >= 0; k -= 4) {
2136+ int digit = (value >> k) & 0x0F;
2137+ if (!PUT(emitter, digit + (digit < 10 ? '0' : 'A'-10)))
2138+ return 0;
2139+ }
2140+ }
2141+ spaces = 0;
2142+ }
2143+ else if (IS_SPACE(string))
2144+ {
2145+ if (allow_breaks && !spaces
2146+ && emitter->column > emitter->best_width
2147+ && string.pointer != string.start
2148+ && string.pointer != string.end - 1) {
2149+ if (!yaml_emitter_write_indent(emitter)) return 0;
2150+ if (IS_SPACE_AT(string, 1)) {
2151+ if (!PUT(emitter, '\\')) return 0;
2152+ }
2153+ MOVE(string);
2154+ }
2155+ else {
2156+ if (!WRITE(emitter, string)) return 0;
2157+ }
2158+ spaces = 1;
2159+ }
2160+ else
2161+ {
2162+ if (!WRITE(emitter, string)) return 0;
2163+ spaces = 0;
2164+ }
2165+ }
2166+
2167+ if (!yaml_emitter_write_indicator(emitter, "\"", 0, 0, 0))
2168+ return 0;
2169+
2170+ emitter->whitespace = 0;
2171+ emitter->indention = 0;
2172+
2173+ return 1;
2174+}
2175+
2176+static int
2177+yaml_emitter_write_block_scalar_hints(yaml_emitter_t *emitter,
2178+ yaml_string_t string)
2179+{
2180+ char indent_hint[2];
2181+ char *chomp_hint = NULL;
2182+
2183+ if (IS_SPACE(string) || IS_BREAK(string))
2184+ {
2185+ indent_hint[0] = '0' + (char)emitter->best_indent;
2186+ indent_hint[1] = '\0';
2187+ if (!yaml_emitter_write_indicator(emitter, indent_hint, 0, 0, 0))
2188+ return 0;
2189+ }
2190+
2191+ emitter->open_ended = 0;
2192+
2193+ string.pointer = string.end;
2194+ if (string.start == string.pointer)
2195+ {
2196+ chomp_hint = "-";
2197+ }
2198+ else
2199+ {
2200+ do {
2201+ string.pointer --;
2202+ } while ((*string.pointer & 0xC0) == 0x80);
2203+ if (!IS_BREAK(string))
2204+ {
2205+ chomp_hint = "-";
2206+ }
2207+ else if (string.start == string.pointer)
2208+ {
2209+ chomp_hint = "+";
2210+ emitter->open_ended = 1;
2211+ }
2212+ else
2213+ {
2214+ do {
2215+ string.pointer --;
2216+ } while ((*string.pointer & 0xC0) == 0x80);
2217+ if (IS_BREAK(string))
2218+ {
2219+ chomp_hint = "+";
2220+ emitter->open_ended = 1;
2221+ }
2222+ }
2223+ }
2224+
2225+ if (chomp_hint)
2226+ {
2227+ if (!yaml_emitter_write_indicator(emitter, chomp_hint, 0, 0, 0))
2228+ return 0;
2229+ }
2230+
2231+ return 1;
2232+}
2233+
2234+static int
2235+yaml_emitter_write_literal_scalar(yaml_emitter_t *emitter,
2236+ yaml_char_t *value, size_t length)
2237+{
2238+ yaml_string_t string;
2239+ int breaks = 1;
2240+
2241+ STRING_ASSIGN(string, value, length);
2242+
2243+ if (!yaml_emitter_write_indicator(emitter, "|", 1, 0, 0))
2244+ return 0;
2245+ if (!yaml_emitter_write_block_scalar_hints(emitter, string))
2246+ return 0;
2247+ if (!PUT_BREAK(emitter)) return 0;
2248+ emitter->indention = 1;
2249+ emitter->whitespace = 1;
2250+
2251+ while (string.pointer != string.end)
2252+ {
2253+ if (IS_BREAK(string))
2254+ {
2255+ if (!WRITE_BREAK(emitter, string)) return 0;
2256+ emitter->indention = 1;
2257+ breaks = 1;
2258+ }
2259+ else
2260+ {
2261+ if (breaks) {
2262+ if (!yaml_emitter_write_indent(emitter)) return 0;
2263+ }
2264+ if (!WRITE(emitter, string)) return 0;
2265+ emitter->indention = 0;
2266+ breaks = 0;
2267+ }
2268+ }
2269+
2270+ return 1;
2271+}
2272+
2273+static int
2274+yaml_emitter_write_folded_scalar(yaml_emitter_t *emitter,
2275+ yaml_char_t *value, size_t length)
2276+{
2277+ yaml_string_t string;
2278+ int breaks = 1;
2279+ int leading_spaces = 1;
2280+
2281+ STRING_ASSIGN(string, value, length);
2282+
2283+ if (!yaml_emitter_write_indicator(emitter, ">", 1, 0, 0))
2284+ return 0;
2285+ if (!yaml_emitter_write_block_scalar_hints(emitter, string))
2286+ return 0;
2287+ if (!PUT_BREAK(emitter)) return 0;
2288+ emitter->indention = 1;
2289+ emitter->whitespace = 1;
2290+
2291+ while (string.pointer != string.end)
2292+ {
2293+ if (IS_BREAK(string))
2294+ {
2295+ if (!breaks && !leading_spaces && CHECK(string, '\n')) {
2296+ int k = 0;
2297+ while (IS_BREAK_AT(string, k)) {
2298+ k += WIDTH_AT(string, k);
2299+ }
2300+ if (!IS_BLANKZ_AT(string, k)) {
2301+ if (!PUT_BREAK(emitter)) return 0;
2302+ }
2303+ }
2304+ if (!WRITE_BREAK(emitter, string)) return 0;
2305+ emitter->indention = 1;
2306+ breaks = 1;
2307+ }
2308+ else
2309+ {
2310+ if (breaks) {
2311+ if (!yaml_emitter_write_indent(emitter)) return 0;
2312+ leading_spaces = IS_BLANK(string);
2313+ }
2314+ if (!breaks && IS_SPACE(string) && !IS_SPACE_AT(string, 1)
2315+ && emitter->column > emitter->best_width) {
2316+ if (!yaml_emitter_write_indent(emitter)) return 0;
2317+ MOVE(string);
2318+ }
2319+ else {
2320+ if (!WRITE(emitter, string)) return 0;
2321+ }
2322+ emitter->indention = 0;
2323+ breaks = 0;
2324+ }
2325+ }
2326+
2327+ return 1;
2328+}
2329+
libyaml/libyaml.cabaldeleted−68
@@ -1,68 +0,0 @@
1−cabal-version: 1.12
2−
3−-- This file has been generated from package.yaml by hpack version 0.36.0.
4−--
5−-- see: https://github.com/sol/hpack
6−
7−name: libyaml
8−version: 0.1.4
9−synopsis: Low-level, streaming YAML interface.
10−description: README and API documentation are available at <https://www.stackage.org/package/libyaml>
11−category: Text
12−stability: stable
13−homepage: https://github.com/snoyberg/yaml#readme
14−bug-reports: https://github.com/snoyberg/yaml/issues
15−author: Michael Snoyman <michael@snoyman.com>, Anton Ageev <antage@gmail.com>,Kirill Simonov
16−maintainer: Michael Snoyman <michael@snoyman.com>
17−license: BSD3
18−license-file: LICENSE
19−build-type: Simple
20−extra-source-files:
21− include/helper.h
22− README.md
23− ChangeLog.md
24−
25−source-repository head
26− type: git
27− location: https://github.com/snoyberg/yaml
28−
29−flag no-unicode
30− description: Don't enable unicode output. Instead, unicode characters will be escaped.
31− manual: False
32− default: False
33−
34−flag system-libyaml
35− description: Use the system-wide libyaml instead of the bundled copy
36− manual: False
37− default: False
38−
39−library
40− exposed-modules:
41− Text.Libyaml
42− other-modules:
43− Paths_libyaml
44− hs-source-dirs:
45− src
46− ghc-options: -Wall
47− include-dirs:
48− include
49− c-sources:
50− c/helper.c
51− build-depends:
52− base >=4.9.1 && <5
53− , bytestring >=0.9.1.4
54− , conduit >=1.2.8 && <1.4
55− , resourcet >=0.3 && <1.4
56− default-language: Haskell2010
57− if flag(no-unicode)
58− cpp-options: -D__NO_UNICODE__
59− if !(flag(system-libyaml))
60− build-depends:
61− libyaml-clib
62− else
63− pkgconfig-depends:
64− yaml-0.1
65− if os(windows)
66− cpp-options: -DWINDOWS
67− build-depends:
68− directory
libyaml/loader.cnew file+444
@@ -0,0 +1,444 @@
1+
2+#include "yaml_private.h"
3+
4+/*
5+ * API functions.
6+ */
7+
8+YAML_DECLARE(int)
9+yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document);
10+
11+/*
12+ * Error handling.
13+ */
14+
15+static int
16+yaml_parser_set_composer_error(yaml_parser_t *parser,
17+ const char *problem, yaml_mark_t problem_mark);
18+
19+static int
20+yaml_parser_set_composer_error_context(yaml_parser_t *parser,
21+ const char *context, yaml_mark_t context_mark,
22+ const char *problem, yaml_mark_t problem_mark);
23+
24+
25+/*
26+ * Alias handling.
27+ */
28+
29+static int
30+yaml_parser_register_anchor(yaml_parser_t *parser,
31+ int index, yaml_char_t *anchor);
32+
33+/*
34+ * Clean up functions.
35+ */
36+
37+static void
38+yaml_parser_delete_aliases(yaml_parser_t *parser);
39+
40+/*
41+ * Composer functions.
42+ */
43+
44+static int
45+yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *first_event);
46+
47+static int
48+yaml_parser_load_node(yaml_parser_t *parser, yaml_event_t *first_event);
49+
50+static int
51+yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event);
52+
53+static int
54+yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event);
55+
56+static int
57+yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event);
58+
59+static int
60+yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event);
61+
62+/*
63+ * Load the next document of the stream.
64+ */
65+
66+YAML_DECLARE(int)
67+yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document)
68+{
69+ yaml_event_t event;
70+
71+ assert(parser); /* Non-NULL parser object is expected. */
72+ assert(document); /* Non-NULL document object is expected. */
73+
74+ memset(document, 0, sizeof(yaml_document_t));
75+ if (!STACK_INIT(parser, document->nodes, INITIAL_STACK_SIZE))
76+ goto error;
77+
78+ if (!parser->stream_start_produced) {
79+ if (!yaml_parser_parse(parser, &event)) goto error;
80+ assert(event.type == YAML_STREAM_START_EVENT);
81+ /* STREAM-START is expected. */
82+ }
83+
84+ if (parser->stream_end_produced) {
85+ return 1;
86+ }
87+
88+ if (!yaml_parser_parse(parser, &event)) goto error;
89+ if (event.type == YAML_STREAM_END_EVENT) {
90+ return 1;
91+ }
92+
93+ if (!STACK_INIT(parser, parser->aliases, INITIAL_STACK_SIZE))
94+ goto error;
95+
96+ parser->document = document;
97+
98+ if (!yaml_parser_load_document(parser, &event)) goto error;
99+
100+ yaml_parser_delete_aliases(parser);
101+ parser->document = NULL;
102+
103+ return 1;
104+
105+error:
106+
107+ yaml_parser_delete_aliases(parser);
108+ yaml_document_delete(document);
109+ parser->document = NULL;
110+
111+ return 0;
112+}
113+
114+/*
115+ * Set composer error.
116+ */
117+
118+static int
119+yaml_parser_set_composer_error(yaml_parser_t *parser,
120+ const char *problem, yaml_mark_t problem_mark)
121+{
122+ parser->error = YAML_COMPOSER_ERROR;
123+ parser->problem = problem;
124+ parser->problem_mark = problem_mark;
125+
126+ return 0;
127+}
128+
129+/*
130+ * Set composer error with context.
131+ */
132+
133+static int
134+yaml_parser_set_composer_error_context(yaml_parser_t *parser,
135+ const char *context, yaml_mark_t context_mark,
136+ const char *problem, yaml_mark_t problem_mark)
137+{
138+ parser->error = YAML_COMPOSER_ERROR;
139+ parser->context = context;
140+ parser->context_mark = context_mark;
141+ parser->problem = problem;
142+ parser->problem_mark = problem_mark;
143+
144+ return 0;
145+}
146+
147+/*
148+ * Delete the stack of aliases.
149+ */
150+
151+static void
152+yaml_parser_delete_aliases(yaml_parser_t *parser)
153+{
154+ while (!STACK_EMPTY(parser, parser->aliases)) {
155+ yaml_free(POP(parser, parser->aliases).anchor);
156+ }
157+ STACK_DEL(parser, parser->aliases);
158+}
159+
160+/*
161+ * Compose a document object.
162+ */
163+
164+static int
165+yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *first_event)
166+{
167+ yaml_event_t event;
168+
169+ assert(first_event->type == YAML_DOCUMENT_START_EVENT);
170+ /* DOCUMENT-START is expected. */
171+
172+ parser->document->version_directive
173+ = first_event->data.document_start.version_directive;
174+ parser->document->tag_directives.start
175+ = first_event->data.document_start.tag_directives.start;
176+ parser->document->tag_directives.end
177+ = first_event->data.document_start.tag_directives.end;
178+ parser->document->start_implicit
179+ = first_event->data.document_start.implicit;
180+ parser->document->start_mark = first_event->start_mark;
181+
182+ if (!yaml_parser_parse(parser, &event)) return 0;
183+
184+ if (!yaml_parser_load_node(parser, &event)) return 0;
185+
186+ if (!yaml_parser_parse(parser, &event)) return 0;
187+ assert(event.type == YAML_DOCUMENT_END_EVENT);
188+ /* DOCUMENT-END is expected. */
189+
190+ parser->document->end_implicit = event.data.document_end.implicit;
191+ parser->document->end_mark = event.end_mark;
192+
193+ return 1;
194+}
195+
196+/*
197+ * Compose a node.
198+ */
199+
200+static int
201+yaml_parser_load_node(yaml_parser_t *parser, yaml_event_t *first_event)
202+{
203+ switch (first_event->type) {
204+ case YAML_ALIAS_EVENT:
205+ return yaml_parser_load_alias(parser, first_event);
206+ case YAML_SCALAR_EVENT:
207+ return yaml_parser_load_scalar(parser, first_event);
208+ case YAML_SEQUENCE_START_EVENT:
209+ return yaml_parser_load_sequence(parser, first_event);
210+ case YAML_MAPPING_START_EVENT:
211+ return yaml_parser_load_mapping(parser, first_event);
212+ default:
213+ assert(0); /* Could not happen. */
214+ return 0;
215+ }
216+
217+ return 0;
218+}
219+
220+/*
221+ * Add an anchor.
222+ */
223+
224+static int
225+yaml_parser_register_anchor(yaml_parser_t *parser,
226+ int index, yaml_char_t *anchor)
227+{
228+ yaml_alias_data_t data;
229+ yaml_alias_data_t *alias_data;
230+
231+ if (!anchor) return 1;
232+
233+ data.anchor = anchor;
234+ data.index = index;
235+ data.mark = parser->document->nodes.start[index-1].start_mark;
236+
237+ for (alias_data = parser->aliases.start;
238+ alias_data != parser->aliases.top; alias_data ++) {
239+ if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) {
240+ yaml_free(anchor);
241+ return yaml_parser_set_composer_error_context(parser,
242+ "found duplicate anchor; first occurence",
243+ alias_data->mark, "second occurence", data.mark);
244+ }
245+ }
246+
247+ if (!PUSH(parser, parser->aliases, data)) {
248+ yaml_free(anchor);
249+ return 0;
250+ }
251+
252+ return 1;
253+}
254+
255+/*
256+ * Compose a node corresponding to an alias.
257+ */
258+
259+static int
260+yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event)
261+{
262+ yaml_char_t *anchor = first_event->data.alias.anchor;
263+ yaml_alias_data_t *alias_data;
264+
265+ for (alias_data = parser->aliases.start;
266+ alias_data != parser->aliases.top; alias_data ++) {
267+ if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) {
268+ yaml_free(anchor);
269+ return alias_data->index;
270+ }
271+ }
272+
273+ yaml_free(anchor);
274+ return yaml_parser_set_composer_error(parser, "found undefined alias",
275+ first_event->start_mark);
276+}
277+
278+/*
279+ * Compose a scalar node.
280+ */
281+
282+static int
283+yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event)
284+{
285+ yaml_node_t node;
286+ int index;
287+ yaml_char_t *tag = first_event->data.scalar.tag;
288+
289+ if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error;
290+
291+ if (!tag || strcmp((char *)tag, "!") == 0) {
292+ yaml_free(tag);
293+ tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_SCALAR_TAG);
294+ if (!tag) goto error;
295+ }
296+
297+ SCALAR_NODE_INIT(node, tag, first_event->data.scalar.value,
298+ first_event->data.scalar.length, first_event->data.scalar.style,
299+ first_event->start_mark, first_event->end_mark);
300+
301+ if (!PUSH(parser, parser->document->nodes, node)) goto error;
302+
303+ index = parser->document->nodes.top - parser->document->nodes.start;
304+
305+ if (!yaml_parser_register_anchor(parser, index,
306+ first_event->data.scalar.anchor)) return 0;
307+
308+ return index;
309+
310+error:
311+ yaml_free(tag);
312+ yaml_free(first_event->data.scalar.anchor);
313+ yaml_free(first_event->data.scalar.value);
314+ return 0;
315+}
316+
317+/*
318+ * Compose a sequence node.
319+ */
320+
321+static int
322+yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event)
323+{
324+ yaml_event_t event;
325+ yaml_node_t node;
326+ struct {
327+ yaml_node_item_t *start;
328+ yaml_node_item_t *end;
329+ yaml_node_item_t *top;
330+ } items = { NULL, NULL, NULL };
331+ int index, item_index;
332+ yaml_char_t *tag = first_event->data.sequence_start.tag;
333+
334+ if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error;
335+
336+ if (!tag || strcmp((char *)tag, "!") == 0) {
337+ yaml_free(tag);
338+ tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG);
339+ if (!tag) goto error;
340+ }
341+
342+ if (!STACK_INIT(parser, items, INITIAL_STACK_SIZE)) goto error;
343+
344+ SEQUENCE_NODE_INIT(node, tag, items.start, items.end,
345+ first_event->data.sequence_start.style,
346+ first_event->start_mark, first_event->end_mark);
347+
348+ if (!PUSH(parser, parser->document->nodes, node)) goto error;
349+
350+ index = parser->document->nodes.top - parser->document->nodes.start;
351+
352+ if (!yaml_parser_register_anchor(parser, index,
353+ first_event->data.sequence_start.anchor)) return 0;
354+
355+ if (!yaml_parser_parse(parser, &event)) return 0;
356+
357+ while (event.type != YAML_SEQUENCE_END_EVENT) {
358+ if (!STACK_LIMIT(parser,
359+ parser->document->nodes.start[index-1].data.sequence.items,
360+ INT_MAX-1)) return 0;
361+ item_index = yaml_parser_load_node(parser, &event);
362+ if (!item_index) return 0;
363+ if (!PUSH(parser,
364+ parser->document->nodes.start[index-1].data.sequence.items,
365+ item_index)) return 0;
366+ if (!yaml_parser_parse(parser, &event)) return 0;
367+ }
368+
369+ parser->document->nodes.start[index-1].end_mark = event.end_mark;
370+
371+ return index;
372+
373+error:
374+ yaml_free(tag);
375+ yaml_free(first_event->data.sequence_start.anchor);
376+ return 0;
377+}
378+
379+/*
380+ * Compose a mapping node.
381+ */
382+
383+static int
384+yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event)
385+{
386+ yaml_event_t event;
387+ yaml_node_t node;
388+ struct {
389+ yaml_node_pair_t *start;
390+ yaml_node_pair_t *end;
391+ yaml_node_pair_t *top;
392+ } pairs = { NULL, NULL, NULL };
393+ int index;
394+ yaml_node_pair_t pair;
395+ yaml_char_t *tag = first_event->data.mapping_start.tag;
396+
397+ if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error;
398+
399+ if (!tag || strcmp((char *)tag, "!") == 0) {
400+ yaml_free(tag);
401+ tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_MAPPING_TAG);
402+ if (!tag) goto error;
403+ }
404+
405+ if (!STACK_INIT(parser, pairs, INITIAL_STACK_SIZE)) goto error;
406+
407+ MAPPING_NODE_INIT(node, tag, pairs.start, pairs.end,
408+ first_event->data.mapping_start.style,
409+ first_event->start_mark, first_event->end_mark);
410+
411+ if (!PUSH(parser, parser->document->nodes, node)) goto error;
412+
413+ index = parser->document->nodes.top - parser->document->nodes.start;
414+
415+ if (!yaml_parser_register_anchor(parser, index,
416+ first_event->data.mapping_start.anchor)) return 0;
417+
418+ if (!yaml_parser_parse(parser, &event)) return 0;
419+
420+ while (event.type != YAML_MAPPING_END_EVENT) {
421+ if (!STACK_LIMIT(parser,
422+ parser->document->nodes.start[index-1].data.mapping.pairs,
423+ INT_MAX-1)) return 0;
424+ pair.key = yaml_parser_load_node(parser, &event);
425+ if (!pair.key) return 0;
426+ if (!yaml_parser_parse(parser, &event)) return 0;
427+ pair.value = yaml_parser_load_node(parser, &event);
428+ if (!pair.value) return 0;
429+ if (!PUSH(parser,
430+ parser->document->nodes.start[index-1].data.mapping.pairs,
431+ pair)) return 0;
432+ if (!yaml_parser_parse(parser, &event)) return 0;
433+ }
434+
435+ parser->document->nodes.start[index-1].end_mark = event.end_mark;
436+
437+ return index;
438+
439+error:
440+ yaml_free(tag);
441+ yaml_free(first_event->data.mapping_start.anchor);
442+ return 0;
443+}
444+
libyaml/package.yamldeleted−53
@@ -1,53 +0,0 @@
1−name: libyaml
2−version: 0.1.4
3−synopsis: Low-level, streaming YAML interface.
4−description: README and API documentation are available at <https://www.stackage.org/package/libyaml>
5−category: Text
6−author: Michael Snoyman <michael@snoyman.com>, Anton Ageev <antage@gmail.com>,Kirill Simonov
7−maintainer: Michael Snoyman <michael@snoyman.com>
8−license: BSD3
9−github: snoyberg/yaml
10−stability: stable
11−
12−extra-source-files:
13−- include/helper.h
14−- README.md
15−- ChangeLog.md
16−
17−flags:
18− system-libyaml:
19− description: Use the system-wide libyaml instead of the bundled copy
20− manual: false
21− default: false
22− no-unicode:
23− description: Don't enable unicode output. Instead, unicode characters will be escaped.
24− manual: false
25− default: false
26−
27−dependencies:
28−- base >=4.14 && <5 # GHC 8.10.1 and later
29−- bytestring >=0.9.1.4
30−- conduit >=1.2.8 && <1.4
31−- resourcet >=0.3 && <1.4
32−
33−library:
34− c-sources: c/helper.c
35− ghc-options: -Wall
36− include-dirs:
37− - include
38− source-dirs: src
39− when:
40− - condition: flag(no-unicode)
41− cpp-options: -D__NO_UNICODE__
42− - condition: ! '!(flag(system-libyaml))'
43− then:
44− dependencies:
45− - libyaml-clib
46− else:
47− pkg-config-dependencies:
48− - yaml-0.1
49− - condition: os(windows)
50− cpp-options: -DWINDOWS
51− dependencies:
52− - directory
53−
libyaml/parser.cnew file+1374
@@ -0,0 +1,1374 @@
1+
2+/*
3+ * The parser implements the following grammar:
4+ *
5+ * stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
6+ * implicit_document ::= block_node DOCUMENT-END*
7+ * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
8+ * block_node_or_indentless_sequence ::=
9+ * ALIAS
10+ * | properties (block_content | indentless_block_sequence)?
11+ * | block_content
12+ * | indentless_block_sequence
13+ * block_node ::= ALIAS
14+ * | properties block_content?
15+ * | block_content
16+ * flow_node ::= ALIAS
17+ * | properties flow_content?
18+ * | flow_content
19+ * properties ::= TAG ANCHOR? | ANCHOR TAG?
20+ * block_content ::= block_collection | flow_collection | SCALAR
21+ * flow_content ::= flow_collection | SCALAR
22+ * block_collection ::= block_sequence | block_mapping
23+ * flow_collection ::= flow_sequence | flow_mapping
24+ * block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
25+ * indentless_sequence ::= (BLOCK-ENTRY block_node?)+
26+ * block_mapping ::= BLOCK-MAPPING_START
27+ * ((KEY block_node_or_indentless_sequence?)?
28+ * (VALUE block_node_or_indentless_sequence?)?)*
29+ * BLOCK-END
30+ * flow_sequence ::= FLOW-SEQUENCE-START
31+ * (flow_sequence_entry FLOW-ENTRY)*
32+ * flow_sequence_entry?
33+ * FLOW-SEQUENCE-END
34+ * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
35+ * flow_mapping ::= FLOW-MAPPING-START
36+ * (flow_mapping_entry FLOW-ENTRY)*
37+ * flow_mapping_entry?
38+ * FLOW-MAPPING-END
39+ * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
40+ */
41+
42+#include "yaml_private.h"
43+
44+/*
45+ * Peek the next token in the token queue.
46+ */
47+
48+#define PEEK_TOKEN(parser) \
49+ ((parser->token_available || yaml_parser_fetch_more_tokens(parser)) ? \
50+ parser->tokens.head : NULL)
51+
52+/*
53+ * Remove the next token from the queue (must be called after PEEK_TOKEN).
54+ */
55+
56+#define SKIP_TOKEN(parser) \
57+ (parser->token_available = 0, \
58+ parser->tokens_parsed ++, \
59+ parser->stream_end_produced = \
60+ (parser->tokens.head->type == YAML_STREAM_END_TOKEN), \
61+ parser->tokens.head ++)
62+
63+/*
64+ * Public API declarations.
65+ */
66+
67+YAML_DECLARE(int)
68+yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event);
69+
70+/*
71+ * Error handling.
72+ */
73+
74+static int
75+yaml_parser_set_parser_error(yaml_parser_t *parser,
76+ const char *problem, yaml_mark_t problem_mark);
77+
78+static int
79+yaml_parser_set_parser_error_context(yaml_parser_t *parser,
80+ const char *context, yaml_mark_t context_mark,
81+ const char *problem, yaml_mark_t problem_mark);
82+
83+/*
84+ * State functions.
85+ */
86+
87+static int
88+yaml_parser_state_machine(yaml_parser_t *parser, yaml_event_t *event);
89+
90+static int
91+yaml_parser_parse_stream_start(yaml_parser_t *parser, yaml_event_t *event);
92+
93+static int
94+yaml_parser_parse_document_start(yaml_parser_t *parser, yaml_event_t *event,
95+ int implicit);
96+
97+static int
98+yaml_parser_parse_document_content(yaml_parser_t *parser, yaml_event_t *event);
99+
100+static int
101+yaml_parser_parse_document_end(yaml_parser_t *parser, yaml_event_t *event);
102+
103+static int
104+yaml_parser_parse_node(yaml_parser_t *parser, yaml_event_t *event,
105+ int block, int indentless_sequence);
106+
107+static int
108+yaml_parser_parse_block_sequence_entry(yaml_parser_t *parser,
109+ yaml_event_t *event, int first);
110+
111+static int
112+yaml_parser_parse_indentless_sequence_entry(yaml_parser_t *parser,
113+ yaml_event_t *event);
114+
115+static int
116+yaml_parser_parse_block_mapping_key(yaml_parser_t *parser,
117+ yaml_event_t *event, int first);
118+
119+static int
120+yaml_parser_parse_block_mapping_value(yaml_parser_t *parser,
121+ yaml_event_t *event);
122+
123+static int
124+yaml_parser_parse_flow_sequence_entry(yaml_parser_t *parser,
125+ yaml_event_t *event, int first);
126+
127+static int
128+yaml_parser_parse_flow_sequence_entry_mapping_key(yaml_parser_t *parser,
129+ yaml_event_t *event);
130+
131+static int
132+yaml_parser_parse_flow_sequence_entry_mapping_value(yaml_parser_t *parser,
133+ yaml_event_t *event);
134+
135+static int
136+yaml_parser_parse_flow_sequence_entry_mapping_end(yaml_parser_t *parser,
137+ yaml_event_t *event);
138+
139+static int
140+yaml_parser_parse_flow_mapping_key(yaml_parser_t *parser,
141+ yaml_event_t *event, int first);
142+
143+static int
144+yaml_parser_parse_flow_mapping_value(yaml_parser_t *parser,
145+ yaml_event_t *event, int empty);
146+
147+/*
148+ * Utility functions.
149+ */
150+
151+static int
152+yaml_parser_process_empty_scalar(yaml_parser_t *parser,
153+ yaml_event_t *event, yaml_mark_t mark);
154+
155+static int
156+yaml_parser_process_directives(yaml_parser_t *parser,
157+ yaml_version_directive_t **version_directive_ref,
158+ yaml_tag_directive_t **tag_directives_start_ref,
159+ yaml_tag_directive_t **tag_directives_end_ref);
160+
161+static int
162+yaml_parser_append_tag_directive(yaml_parser_t *parser,
163+ yaml_tag_directive_t value, int allow_duplicates, yaml_mark_t mark);
164+
165+/*
166+ * Get the next event.
167+ */
168+
169+YAML_DECLARE(int)
170+yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event)
171+{
172+ assert(parser); /* Non-NULL parser object is expected. */
173+ assert(event); /* Non-NULL event object is expected. */
174+
175+ /* Erase the event object. */
176+
177+ memset(event, 0, sizeof(yaml_event_t));
178+
179+ /* No events after the end of the stream or error. */
180+
181+ if (parser->stream_end_produced || parser->error ||
182+ parser->state == YAML_PARSE_END_STATE) {
183+ return 1;
184+ }
185+
186+ /* Generate the next event. */
187+
188+ return yaml_parser_state_machine(parser, event);
189+}
190+
191+/*
192+ * Set parser error.
193+ */
194+
195+static int
196+yaml_parser_set_parser_error(yaml_parser_t *parser,
197+ const char *problem, yaml_mark_t problem_mark)
198+{
199+ parser->error = YAML_PARSER_ERROR;
200+ parser->problem = problem;
201+ parser->problem_mark = problem_mark;
202+
203+ return 0;
204+}
205+
206+static int
207+yaml_parser_set_parser_error_context(yaml_parser_t *parser,
208+ const char *context, yaml_mark_t context_mark,
209+ const char *problem, yaml_mark_t problem_mark)
210+{
211+ parser->error = YAML_PARSER_ERROR;
212+ parser->context = context;
213+ parser->context_mark = context_mark;
214+ parser->problem = problem;
215+ parser->problem_mark = problem_mark;
216+
217+ return 0;
218+}
219+
220+
221+/*
222+ * State dispatcher.
223+ */
224+
225+static int
226+yaml_parser_state_machine(yaml_parser_t *parser, yaml_event_t *event)
227+{
228+ switch (parser->state)
229+ {
230+ case YAML_PARSE_STREAM_START_STATE:
231+ return yaml_parser_parse_stream_start(parser, event);
232+
233+ case YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE:
234+ return yaml_parser_parse_document_start(parser, event, 1);
235+
236+ case YAML_PARSE_DOCUMENT_START_STATE:
237+ return yaml_parser_parse_document_start(parser, event, 0);
238+
239+ case YAML_PARSE_DOCUMENT_CONTENT_STATE:
240+ return yaml_parser_parse_document_content(parser, event);
241+
242+ case YAML_PARSE_DOCUMENT_END_STATE:
243+ return yaml_parser_parse_document_end(parser, event);
244+
245+ case YAML_PARSE_BLOCK_NODE_STATE:
246+ return yaml_parser_parse_node(parser, event, 1, 0);
247+
248+ case YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
249+ return yaml_parser_parse_node(parser, event, 1, 1);
250+
251+ case YAML_PARSE_FLOW_NODE_STATE:
252+ return yaml_parser_parse_node(parser, event, 0, 0);
253+
254+ case YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
255+ return yaml_parser_parse_block_sequence_entry(parser, event, 1);
256+
257+ case YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
258+ return yaml_parser_parse_block_sequence_entry(parser, event, 0);
259+
260+ case YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
261+ return yaml_parser_parse_indentless_sequence_entry(parser, event);
262+
263+ case YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
264+ return yaml_parser_parse_block_mapping_key(parser, event, 1);
265+
266+ case YAML_PARSE_BLOCK_MAPPING_KEY_STATE:
267+ return yaml_parser_parse_block_mapping_key(parser, event, 0);
268+
269+ case YAML_PARSE_BLOCK_MAPPING_VALUE_STATE:
270+ return yaml_parser_parse_block_mapping_value(parser, event);
271+
272+ case YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
273+ return yaml_parser_parse_flow_sequence_entry(parser, event, 1);
274+
275+ case YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
276+ return yaml_parser_parse_flow_sequence_entry(parser, event, 0);
277+
278+ case YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
279+ return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event);
280+
281+ case YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
282+ return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event);
283+
284+ case YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
285+ return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event);
286+
287+ case YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
288+ return yaml_parser_parse_flow_mapping_key(parser, event, 1);
289+
290+ case YAML_PARSE_FLOW_MAPPING_KEY_STATE:
291+ return yaml_parser_parse_flow_mapping_key(parser, event, 0);
292+
293+ case YAML_PARSE_FLOW_MAPPING_VALUE_STATE:
294+ return yaml_parser_parse_flow_mapping_value(parser, event, 0);
295+
296+ case YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
297+ return yaml_parser_parse_flow_mapping_value(parser, event, 1);
298+
299+ default:
300+ assert(1); /* Invalid state. */
301+ }
302+
303+ return 0;
304+}
305+
306+/*
307+ * Parse the production:
308+ * stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
309+ * ************
310+ */
311+
312+static int
313+yaml_parser_parse_stream_start(yaml_parser_t *parser, yaml_event_t *event)
314+{
315+ yaml_token_t *token;
316+
317+ token = PEEK_TOKEN(parser);
318+ if (!token) return 0;
319+
320+ if (token->type != YAML_STREAM_START_TOKEN) {
321+ return yaml_parser_set_parser_error(parser,
322+ "did not find expected <stream-start>", token->start_mark);
323+ }
324+
325+ parser->state = YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE;
326+ STREAM_START_EVENT_INIT(*event, token->data.stream_start.encoding,
327+ token->start_mark, token->start_mark);
328+ SKIP_TOKEN(parser);
329+
330+ return 1;
331+}
332+
333+/*
334+ * Parse the productions:
335+ * implicit_document ::= block_node DOCUMENT-END*
336+ * *
337+ * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
338+ * *************************
339+ */
340+
341+static int
342+yaml_parser_parse_document_start(yaml_parser_t *parser, yaml_event_t *event,
343+ int implicit)
344+{
345+ yaml_token_t *token;
346+ yaml_version_directive_t *version_directive = NULL;
347+ struct {
348+ yaml_tag_directive_t *start;
349+ yaml_tag_directive_t *end;
350+ } tag_directives = { NULL, NULL };
351+
352+ token = PEEK_TOKEN(parser);
353+ if (!token) return 0;
354+
355+ /* Parse extra document end indicators. */
356+
357+ if (!implicit)
358+ {
359+ while (token->type == YAML_DOCUMENT_END_TOKEN) {
360+ SKIP_TOKEN(parser);
361+ token = PEEK_TOKEN(parser);
362+ if (!token) return 0;
363+ }
364+ }
365+
366+ /* Parse an implicit document. */
367+
368+ if (implicit && token->type != YAML_VERSION_DIRECTIVE_TOKEN &&
369+ token->type != YAML_TAG_DIRECTIVE_TOKEN &&
370+ token->type != YAML_DOCUMENT_START_TOKEN &&
371+ token->type != YAML_STREAM_END_TOKEN)
372+ {
373+ if (!yaml_parser_process_directives(parser, NULL, NULL, NULL))
374+ return 0;
375+ if (!PUSH(parser, parser->states, YAML_PARSE_DOCUMENT_END_STATE))
376+ return 0;
377+ parser->state = YAML_PARSE_BLOCK_NODE_STATE;
378+ DOCUMENT_START_EVENT_INIT(*event, NULL, NULL, NULL, 1,
379+ token->start_mark, token->start_mark);
380+ return 1;
381+ }
382+
383+ /* Parse an explicit document. */
384+
385+ else if (token->type != YAML_STREAM_END_TOKEN)
386+ {
387+ yaml_mark_t start_mark, end_mark;
388+ start_mark = token->start_mark;
389+ if (!yaml_parser_process_directives(parser, &version_directive,
390+ &tag_directives.start, &tag_directives.end))
391+ return 0;
392+ token = PEEK_TOKEN(parser);
393+ if (!token) goto error;
394+ if (token->type != YAML_DOCUMENT_START_TOKEN) {
395+ yaml_parser_set_parser_error(parser,
396+ "did not find expected <document start>", token->start_mark);
397+ goto error;
398+ }
399+ if (!PUSH(parser, parser->states, YAML_PARSE_DOCUMENT_END_STATE))
400+ goto error;
401+ parser->state = YAML_PARSE_DOCUMENT_CONTENT_STATE;
402+ end_mark = token->end_mark;
403+ DOCUMENT_START_EVENT_INIT(*event, version_directive,
404+ tag_directives.start, tag_directives.end, 0,
405+ start_mark, end_mark);
406+ SKIP_TOKEN(parser);
407+ version_directive = NULL;
408+ tag_directives.start = tag_directives.end = NULL;
409+ return 1;
410+ }
411+
412+ /* Parse the stream end. */
413+
414+ else
415+ {
416+ parser->state = YAML_PARSE_END_STATE;
417+ STREAM_END_EVENT_INIT(*event, token->start_mark, token->end_mark);
418+ SKIP_TOKEN(parser);
419+ return 1;
420+ }
421+
422+error:
423+ yaml_free(version_directive);
424+ while (tag_directives.start != tag_directives.end) {
425+ yaml_free(tag_directives.end[-1].handle);
426+ yaml_free(tag_directives.end[-1].prefix);
427+ tag_directives.end --;
428+ }
429+ yaml_free(tag_directives.start);
430+ return 0;
431+}
432+
433+/*
434+ * Parse the productions:
435+ * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
436+ * ***********
437+ */
438+
439+static int
440+yaml_parser_parse_document_content(yaml_parser_t *parser, yaml_event_t *event)
441+{
442+ yaml_token_t *token;
443+
444+ token = PEEK_TOKEN(parser);
445+ if (!token) return 0;
446+
447+ if (token->type == YAML_VERSION_DIRECTIVE_TOKEN ||
448+ token->type == YAML_TAG_DIRECTIVE_TOKEN ||
449+ token->type == YAML_DOCUMENT_START_TOKEN ||
450+ token->type == YAML_DOCUMENT_END_TOKEN ||
451+ token->type == YAML_STREAM_END_TOKEN) {
452+ parser->state = POP(parser, parser->states);
453+ return yaml_parser_process_empty_scalar(parser, event,
454+ token->start_mark);
455+ }
456+ else {
457+ return yaml_parser_parse_node(parser, event, 1, 0);
458+ }
459+}
460+
461+/*
462+ * Parse the productions:
463+ * implicit_document ::= block_node DOCUMENT-END*
464+ * *************
465+ * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
466+ * *************
467+ */
468+
469+static int
470+yaml_parser_parse_document_end(yaml_parser_t *parser, yaml_event_t *event)
471+{
472+ yaml_token_t *token;
473+ yaml_mark_t start_mark, end_mark;
474+ int implicit = 1;
475+
476+ token = PEEK_TOKEN(parser);
477+ if (!token) return 0;
478+
479+ start_mark = end_mark = token->start_mark;
480+
481+ if (token->type == YAML_DOCUMENT_END_TOKEN) {
482+ end_mark = token->end_mark;
483+ SKIP_TOKEN(parser);
484+ implicit = 0;
485+ }
486+
487+ while (!STACK_EMPTY(parser, parser->tag_directives)) {
488+ yaml_tag_directive_t tag_directive = POP(parser, parser->tag_directives);
489+ yaml_free(tag_directive.handle);
490+ yaml_free(tag_directive.prefix);
491+ }
492+
493+ parser->state = YAML_PARSE_DOCUMENT_START_STATE;
494+ DOCUMENT_END_EVENT_INIT(*event, implicit, start_mark, end_mark);
495+
496+ return 1;
497+}
498+
499+/*
500+ * Parse the productions:
501+ * block_node_or_indentless_sequence ::=
502+ * ALIAS
503+ * *****
504+ * | properties (block_content | indentless_block_sequence)?
505+ * ********** *
506+ * | block_content | indentless_block_sequence
507+ * *
508+ * block_node ::= ALIAS
509+ * *****
510+ * | properties block_content?
511+ * ********** *
512+ * | block_content
513+ * *
514+ * flow_node ::= ALIAS
515+ * *****
516+ * | properties flow_content?
517+ * ********** *
518+ * | flow_content
519+ * *
520+ * properties ::= TAG ANCHOR? | ANCHOR TAG?
521+ * *************************
522+ * block_content ::= block_collection | flow_collection | SCALAR
523+ * ******
524+ * flow_content ::= flow_collection | SCALAR
525+ * ******
526+ */
527+
528+static int
529+yaml_parser_parse_node(yaml_parser_t *parser, yaml_event_t *event,
530+ int block, int indentless_sequence)
531+{
532+ yaml_token_t *token;
533+ yaml_char_t *anchor = NULL;
534+ yaml_char_t *tag_handle = NULL;
535+ yaml_char_t *tag_suffix = NULL;
536+ yaml_char_t *tag = NULL;
537+ yaml_mark_t start_mark, end_mark, tag_mark;
538+ int implicit;
539+
540+ token = PEEK_TOKEN(parser);
541+ if (!token) return 0;
542+
543+ if (token->type == YAML_ALIAS_TOKEN)
544+ {
545+ parser->state = POP(parser, parser->states);
546+ ALIAS_EVENT_INIT(*event, token->data.alias.value,
547+ token->start_mark, token->end_mark);
548+ SKIP_TOKEN(parser);
549+ return 1;
550+ }
551+
552+ else
553+ {
554+ start_mark = end_mark = token->start_mark;
555+
556+ if (token->type == YAML_ANCHOR_TOKEN)
557+ {
558+ anchor = token->data.anchor.value;
559+ start_mark = token->start_mark;
560+ end_mark = token->end_mark;
561+ SKIP_TOKEN(parser);
562+ token = PEEK_TOKEN(parser);
563+ if (!token) goto error;
564+ if (token->type == YAML_TAG_TOKEN)
565+ {
566+ tag_handle = token->data.tag.handle;
567+ tag_suffix = token->data.tag.suffix;
568+ tag_mark = token->start_mark;
569+ end_mark = token->end_mark;
570+ SKIP_TOKEN(parser);
571+ token = PEEK_TOKEN(parser);
572+ if (!token) goto error;
573+ }
574+ }
575+ else if (token->type == YAML_TAG_TOKEN)
576+ {
577+ tag_handle = token->data.tag.handle;
578+ tag_suffix = token->data.tag.suffix;
579+ start_mark = tag_mark = token->start_mark;
580+ end_mark = token->end_mark;
581+ SKIP_TOKEN(parser);
582+ token = PEEK_TOKEN(parser);
583+ if (!token) goto error;
584+ if (token->type == YAML_ANCHOR_TOKEN)
585+ {
586+ anchor = token->data.anchor.value;
587+ end_mark = token->end_mark;
588+ SKIP_TOKEN(parser);
589+ token = PEEK_TOKEN(parser);
590+ if (!token) goto error;
591+ }
592+ }
593+
594+ if (tag_handle) {
595+ if (!*tag_handle) {
596+ tag = tag_suffix;
597+ yaml_free(tag_handle);
598+ tag_handle = tag_suffix = NULL;
599+ }
600+ else {
601+ yaml_tag_directive_t *tag_directive;
602+ for (tag_directive = parser->tag_directives.start;
603+ tag_directive != parser->tag_directives.top;
604+ tag_directive ++) {
605+ if (strcmp((char *)tag_directive->handle, (char *)tag_handle) == 0) {
606+ size_t prefix_len = strlen((char *)tag_directive->prefix);
607+ size_t suffix_len = strlen((char *)tag_suffix);
608+ tag = yaml_malloc(prefix_len+suffix_len+1);
609+ if (!tag) {
610+ parser->error = YAML_MEMORY_ERROR;
611+ goto error;
612+ }
613+ memcpy(tag, tag_directive->prefix, prefix_len);
614+ memcpy(tag+prefix_len, tag_suffix, suffix_len);
615+ tag[prefix_len+suffix_len] = '\0';
616+ yaml_free(tag_handle);
617+ yaml_free(tag_suffix);
618+ tag_handle = tag_suffix = NULL;
619+ break;
620+ }
621+ }
622+ if (!tag) {
623+ yaml_parser_set_parser_error_context(parser,
624+ "while parsing a node", start_mark,
625+ "found undefined tag handle", tag_mark);
626+ goto error;
627+ }
628+ }
629+ }
630+
631+ implicit = (!tag || !*tag);
632+ if (indentless_sequence && token->type == YAML_BLOCK_ENTRY_TOKEN) {
633+ end_mark = token->end_mark;
634+ parser->state = YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE;
635+ SEQUENCE_START_EVENT_INIT(*event, anchor, tag, implicit,
636+ YAML_BLOCK_SEQUENCE_STYLE, start_mark, end_mark);
637+ return 1;
638+ }
639+ else {
640+ if (token->type == YAML_SCALAR_TOKEN) {
641+ int plain_implicit = 0;
642+ int quoted_implicit = 0;
643+ end_mark = token->end_mark;
644+ if ((token->data.scalar.style == YAML_PLAIN_SCALAR_STYLE && !tag)
645+ || (tag && strcmp((char *)tag, "!") == 0)) {
646+ plain_implicit = 1;
647+ }
648+ else if (!tag) {
649+ quoted_implicit = 1;
650+ }
651+ parser->state = POP(parser, parser->states);
652+ SCALAR_EVENT_INIT(*event, anchor, tag,
653+ token->data.scalar.value, token->data.scalar.length,
654+ plain_implicit, quoted_implicit,
655+ token->data.scalar.style, start_mark, end_mark);
656+ SKIP_TOKEN(parser);
657+ return 1;
658+ }
659+ else if (token->type == YAML_FLOW_SEQUENCE_START_TOKEN) {
660+ end_mark = token->end_mark;
661+ parser->state = YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE;
662+ SEQUENCE_START_EVENT_INIT(*event, anchor, tag, implicit,
663+ YAML_FLOW_SEQUENCE_STYLE, start_mark, end_mark);
664+ return 1;
665+ }
666+ else if (token->type == YAML_FLOW_MAPPING_START_TOKEN) {
667+ end_mark = token->end_mark;
668+ parser->state = YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE;
669+ MAPPING_START_EVENT_INIT(*event, anchor, tag, implicit,
670+ YAML_FLOW_MAPPING_STYLE, start_mark, end_mark);
671+ return 1;
672+ }
673+ else if (block && token->type == YAML_BLOCK_SEQUENCE_START_TOKEN) {
674+ end_mark = token->end_mark;
675+ parser->state = YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE;
676+ SEQUENCE_START_EVENT_INIT(*event, anchor, tag, implicit,
677+ YAML_BLOCK_SEQUENCE_STYLE, start_mark, end_mark);
678+ return 1;
679+ }
680+ else if (block && token->type == YAML_BLOCK_MAPPING_START_TOKEN) {
681+ end_mark = token->end_mark;
682+ parser->state = YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE;
683+ MAPPING_START_EVENT_INIT(*event, anchor, tag, implicit,
684+ YAML_BLOCK_MAPPING_STYLE, start_mark, end_mark);
685+ return 1;
686+ }
687+ else if (anchor || tag) {
688+ yaml_char_t *value = yaml_malloc(1);
689+ if (!value) {
690+ parser->error = YAML_MEMORY_ERROR;
691+ goto error;
692+ }
693+ value[0] = '\0';
694+ parser->state = POP(parser, parser->states);
695+ SCALAR_EVENT_INIT(*event, anchor, tag, value, 0,
696+ implicit, 0, YAML_PLAIN_SCALAR_STYLE,
697+ start_mark, end_mark);
698+ return 1;
699+ }
700+ else {
701+ yaml_parser_set_parser_error_context(parser,
702+ (block ? "while parsing a block node"
703+ : "while parsing a flow node"), start_mark,
704+ "did not find expected node content", token->start_mark);
705+ goto error;
706+ }
707+ }
708+ }
709+
710+error:
711+ yaml_free(anchor);
712+ yaml_free(tag_handle);
713+ yaml_free(tag_suffix);
714+ yaml_free(tag);
715+
716+ return 0;
717+}
718+
719+/*
720+ * Parse the productions:
721+ * block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
722+ * ******************** *********** * *********
723+ */
724+
725+static int
726+yaml_parser_parse_block_sequence_entry(yaml_parser_t *parser,
727+ yaml_event_t *event, int first)
728+{
729+ yaml_token_t *token;
730+
731+ if (first) {
732+ token = PEEK_TOKEN(parser);
733+ if (!PUSH(parser, parser->marks, token->start_mark))
734+ return 0;
735+ SKIP_TOKEN(parser);
736+ }
737+
738+ token = PEEK_TOKEN(parser);
739+ if (!token) return 0;
740+
741+ if (token->type == YAML_BLOCK_ENTRY_TOKEN)
742+ {
743+ yaml_mark_t mark = token->end_mark;
744+ SKIP_TOKEN(parser);
745+ token = PEEK_TOKEN(parser);
746+ if (!token) return 0;
747+ if (token->type != YAML_BLOCK_ENTRY_TOKEN &&
748+ token->type != YAML_BLOCK_END_TOKEN) {
749+ if (!PUSH(parser, parser->states,
750+ YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE))
751+ return 0;
752+ return yaml_parser_parse_node(parser, event, 1, 0);
753+ }
754+ else {
755+ parser->state = YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE;
756+ return yaml_parser_process_empty_scalar(parser, event, mark);
757+ }
758+ }
759+
760+ else if (token->type == YAML_BLOCK_END_TOKEN)
761+ {
762+ yaml_mark_t dummy_mark; /* Used to eliminate a compiler warning. */
763+ parser->state = POP(parser, parser->states);
764+ dummy_mark = POP(parser, parser->marks);
765+ SEQUENCE_END_EVENT_INIT(*event, token->start_mark, token->end_mark);
766+ SKIP_TOKEN(parser);
767+ return 1;
768+ }
769+
770+ else
771+ {
772+ return yaml_parser_set_parser_error_context(parser,
773+ "while parsing a block collection", POP(parser, parser->marks),
774+ "did not find expected '-' indicator", token->start_mark);
775+ }
776+}
777+
778+/*
779+ * Parse the productions:
780+ * indentless_sequence ::= (BLOCK-ENTRY block_node?)+
781+ * *********** *
782+ */
783+
784+static int
785+yaml_parser_parse_indentless_sequence_entry(yaml_parser_t *parser,
786+ yaml_event_t *event)
787+{
788+ yaml_token_t *token;
789+
790+ token = PEEK_TOKEN(parser);
791+ if (!token) return 0;
792+
793+ if (token->type == YAML_BLOCK_ENTRY_TOKEN)
794+ {
795+ yaml_mark_t mark = token->end_mark;
796+ SKIP_TOKEN(parser);
797+ token = PEEK_TOKEN(parser);
798+ if (!token) return 0;
799+ if (token->type != YAML_BLOCK_ENTRY_TOKEN &&
800+ token->type != YAML_KEY_TOKEN &&
801+ token->type != YAML_VALUE_TOKEN &&
802+ token->type != YAML_BLOCK_END_TOKEN) {
803+ if (!PUSH(parser, parser->states,
804+ YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE))
805+ return 0;
806+ return yaml_parser_parse_node(parser, event, 1, 0);
807+ }
808+ else {
809+ parser->state = YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE;
810+ return yaml_parser_process_empty_scalar(parser, event, mark);
811+ }
812+ }
813+
814+ else
815+ {
816+ parser->state = POP(parser, parser->states);
817+ SEQUENCE_END_EVENT_INIT(*event, token->start_mark, token->start_mark);
818+ return 1;
819+ }
820+}
821+
822+/*
823+ * Parse the productions:
824+ * block_mapping ::= BLOCK-MAPPING_START
825+ * *******************
826+ * ((KEY block_node_or_indentless_sequence?)?
827+ * *** *
828+ * (VALUE block_node_or_indentless_sequence?)?)*
829+ *
830+ * BLOCK-END
831+ * *********
832+ */
833+
834+static int
835+yaml_parser_parse_block_mapping_key(yaml_parser_t *parser,
836+ yaml_event_t *event, int first)
837+{
838+ yaml_token_t *token;
839+
840+ if (first) {
841+ token = PEEK_TOKEN(parser);
842+ if (!PUSH(parser, parser->marks, token->start_mark))
843+ return 0;
844+ SKIP_TOKEN(parser);
845+ }
846+
847+ token = PEEK_TOKEN(parser);
848+ if (!token) return 0;
849+
850+ if (token->type == YAML_KEY_TOKEN)
851+ {
852+ yaml_mark_t mark = token->end_mark;
853+ SKIP_TOKEN(parser);
854+ token = PEEK_TOKEN(parser);
855+ if (!token) return 0;
856+ if (token->type != YAML_KEY_TOKEN &&
857+ token->type != YAML_VALUE_TOKEN &&
858+ token->type != YAML_BLOCK_END_TOKEN) {
859+ if (!PUSH(parser, parser->states,
860+ YAML_PARSE_BLOCK_MAPPING_VALUE_STATE))
861+ return 0;
862+ return yaml_parser_parse_node(parser, event, 1, 1);
863+ }
864+ else {
865+ parser->state = YAML_PARSE_BLOCK_MAPPING_VALUE_STATE;
866+ return yaml_parser_process_empty_scalar(parser, event, mark);
867+ }
868+ }
869+
870+ else if (token->type == YAML_BLOCK_END_TOKEN)
871+ {
872+ yaml_mark_t dummy_mark; /* Used to eliminate a compiler warning. */
873+ parser->state = POP(parser, parser->states);
874+ dummy_mark = POP(parser, parser->marks);
875+ MAPPING_END_EVENT_INIT(*event, token->start_mark, token->end_mark);
876+ SKIP_TOKEN(parser);
877+ return 1;
878+ }
879+
880+ else
881+ {
882+ return yaml_parser_set_parser_error_context(parser,
883+ "while parsing a block mapping", POP(parser, parser->marks),
884+ "did not find expected key", token->start_mark);
885+ }
886+}
887+
888+/*
889+ * Parse the productions:
890+ * block_mapping ::= BLOCK-MAPPING_START
891+ *
892+ * ((KEY block_node_or_indentless_sequence?)?
893+ *
894+ * (VALUE block_node_or_indentless_sequence?)?)*
895+ * ***** *
896+ * BLOCK-END
897+ *
898+ */
899+
900+static int
901+yaml_parser_parse_block_mapping_value(yaml_parser_t *parser,
902+ yaml_event_t *event)
903+{
904+ yaml_token_t *token;
905+
906+ token = PEEK_TOKEN(parser);
907+ if (!token) return 0;
908+
909+ if (token->type == YAML_VALUE_TOKEN)
910+ {
911+ yaml_mark_t mark = token->end_mark;
912+ SKIP_TOKEN(parser);
913+ token = PEEK_TOKEN(parser);
914+ if (!token) return 0;
915+ if (token->type != YAML_KEY_TOKEN &&
916+ token->type != YAML_VALUE_TOKEN &&
917+ token->type != YAML_BLOCK_END_TOKEN) {
918+ if (!PUSH(parser, parser->states,
919+ YAML_PARSE_BLOCK_MAPPING_KEY_STATE))
920+ return 0;
921+ return yaml_parser_parse_node(parser, event, 1, 1);
922+ }
923+ else {
924+ parser->state = YAML_PARSE_BLOCK_MAPPING_KEY_STATE;
925+ return yaml_parser_process_empty_scalar(parser, event, mark);
926+ }
927+ }
928+
929+ else
930+ {
931+ parser->state = YAML_PARSE_BLOCK_MAPPING_KEY_STATE;
932+ return yaml_parser_process_empty_scalar(parser, event, token->start_mark);
933+ }
934+}
935+
936+/*
937+ * Parse the productions:
938+ * flow_sequence ::= FLOW-SEQUENCE-START
939+ * *******************
940+ * (flow_sequence_entry FLOW-ENTRY)*
941+ * * **********
942+ * flow_sequence_entry?
943+ * *
944+ * FLOW-SEQUENCE-END
945+ * *****************
946+ * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
947+ * *
948+ */
949+
950+static int
951+yaml_parser_parse_flow_sequence_entry(yaml_parser_t *parser,
952+ yaml_event_t *event, int first)
953+{
954+ yaml_token_t *token;
955+ yaml_mark_t dummy_mark; /* Used to eliminate a compiler warning. */
956+
957+ if (first) {
958+ token = PEEK_TOKEN(parser);
959+ if (!PUSH(parser, parser->marks, token->start_mark))
960+ return 0;
961+ SKIP_TOKEN(parser);
962+ }
963+
964+ token = PEEK_TOKEN(parser);
965+ if (!token) return 0;
966+
967+ if (token->type != YAML_FLOW_SEQUENCE_END_TOKEN)
968+ {
969+ if (!first) {
970+ if (token->type == YAML_FLOW_ENTRY_TOKEN) {
971+ SKIP_TOKEN(parser);
972+ token = PEEK_TOKEN(parser);
973+ if (!token) return 0;
974+ }
975+ else {
976+ return yaml_parser_set_parser_error_context(parser,
977+ "while parsing a flow sequence", POP(parser, parser->marks),
978+ "did not find expected ',' or ']'", token->start_mark);
979+ }
980+ }
981+
982+ if (token->type == YAML_KEY_TOKEN) {
983+ parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE;
984+ MAPPING_START_EVENT_INIT(*event, NULL, NULL,
985+ 1, YAML_FLOW_MAPPING_STYLE,
986+ token->start_mark, token->end_mark);
987+ SKIP_TOKEN(parser);
988+ return 1;
989+ }
990+
991+ else if (token->type != YAML_FLOW_SEQUENCE_END_TOKEN) {
992+ if (!PUSH(parser, parser->states,
993+ YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE))
994+ return 0;
995+ return yaml_parser_parse_node(parser, event, 0, 0);
996+ }
997+ }
998+
999+ parser->state = POP(parser, parser->states);
1000+ dummy_mark = POP(parser, parser->marks);
1001+ SEQUENCE_END_EVENT_INIT(*event, token->start_mark, token->end_mark);
1002+ SKIP_TOKEN(parser);
1003+ return 1;
1004+}
1005+
1006+/*
1007+ * Parse the productions:
1008+ * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
1009+ * *** *
1010+ */
1011+
1012+static int
1013+yaml_parser_parse_flow_sequence_entry_mapping_key(yaml_parser_t *parser,
1014+ yaml_event_t *event)
1015+{
1016+ yaml_token_t *token;
1017+
1018+ token = PEEK_TOKEN(parser);
1019+ if (!token) return 0;
1020+
1021+ if (token->type != YAML_VALUE_TOKEN && token->type != YAML_FLOW_ENTRY_TOKEN
1022+ && token->type != YAML_FLOW_SEQUENCE_END_TOKEN) {
1023+ if (!PUSH(parser, parser->states,
1024+ YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE))
1025+ return 0;
1026+ return yaml_parser_parse_node(parser, event, 0, 0);
1027+ }
1028+ else {
1029+ yaml_mark_t mark = token->end_mark;
1030+ SKIP_TOKEN(parser);
1031+ parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE;
1032+ return yaml_parser_process_empty_scalar(parser, event, mark);
1033+ }
1034+}
1035+
1036+/*
1037+ * Parse the productions:
1038+ * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
1039+ * ***** *
1040+ */
1041+
1042+static int
1043+yaml_parser_parse_flow_sequence_entry_mapping_value(yaml_parser_t *parser,
1044+ yaml_event_t *event)
1045+{
1046+ yaml_token_t *token;
1047+
1048+ token = PEEK_TOKEN(parser);
1049+ if (!token) return 0;
1050+
1051+ if (token->type == YAML_VALUE_TOKEN) {
1052+ SKIP_TOKEN(parser);
1053+ token = PEEK_TOKEN(parser);
1054+ if (!token) return 0;
1055+ if (token->type != YAML_FLOW_ENTRY_TOKEN
1056+ && token->type != YAML_FLOW_SEQUENCE_END_TOKEN) {
1057+ if (!PUSH(parser, parser->states,
1058+ YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE))
1059+ return 0;
1060+ return yaml_parser_parse_node(parser, event, 0, 0);
1061+ }
1062+ }
1063+ parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE;
1064+ return yaml_parser_process_empty_scalar(parser, event, token->start_mark);
1065+}
1066+
1067+/*
1068+ * Parse the productions:
1069+ * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
1070+ * *
1071+ */
1072+
1073+static int
1074+yaml_parser_parse_flow_sequence_entry_mapping_end(yaml_parser_t *parser,
1075+ yaml_event_t *event)
1076+{
1077+ yaml_token_t *token;
1078+
1079+ token = PEEK_TOKEN(parser);
1080+ if (!token) return 0;
1081+
1082+ parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE;
1083+
1084+ MAPPING_END_EVENT_INIT(*event, token->start_mark, token->start_mark);
1085+ return 1;
1086+}
1087+
1088+/*
1089+ * Parse the productions:
1090+ * flow_mapping ::= FLOW-MAPPING-START
1091+ * ******************
1092+ * (flow_mapping_entry FLOW-ENTRY)*
1093+ * * **********
1094+ * flow_mapping_entry?
1095+ * ******************
1096+ * FLOW-MAPPING-END
1097+ * ****************
1098+ * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
1099+ * * *** *
1100+ */
1101+
1102+static int
1103+yaml_parser_parse_flow_mapping_key(yaml_parser_t *parser,
1104+ yaml_event_t *event, int first)
1105+{
1106+ yaml_token_t *token;
1107+ yaml_mark_t dummy_mark; /* Used to eliminate a compiler warning. */
1108+
1109+ if (first) {
1110+ token = PEEK_TOKEN(parser);
1111+ if (!PUSH(parser, parser->marks, token->start_mark))
1112+ return 0;
1113+ SKIP_TOKEN(parser);
1114+ }
1115+
1116+ token = PEEK_TOKEN(parser);
1117+ if (!token) return 0;
1118+
1119+ if (token->type != YAML_FLOW_MAPPING_END_TOKEN)
1120+ {
1121+ if (!first) {
1122+ if (token->type == YAML_FLOW_ENTRY_TOKEN) {
1123+ SKIP_TOKEN(parser);
1124+ token = PEEK_TOKEN(parser);
1125+ if (!token) return 0;
1126+ }
1127+ else {
1128+ return yaml_parser_set_parser_error_context(parser,
1129+ "while parsing a flow mapping", POP(parser, parser->marks),
1130+ "did not find expected ',' or '}'", token->start_mark);
1131+ }
1132+ }
1133+
1134+ if (token->type == YAML_KEY_TOKEN) {
1135+ SKIP_TOKEN(parser);
1136+ token = PEEK_TOKEN(parser);
1137+ if (!token) return 0;
1138+ if (token->type != YAML_VALUE_TOKEN
1139+ && token->type != YAML_FLOW_ENTRY_TOKEN
1140+ && token->type != YAML_FLOW_MAPPING_END_TOKEN) {
1141+ if (!PUSH(parser, parser->states,
1142+ YAML_PARSE_FLOW_MAPPING_VALUE_STATE))
1143+ return 0;
1144+ return yaml_parser_parse_node(parser, event, 0, 0);
1145+ }
1146+ else {
1147+ parser->state = YAML_PARSE_FLOW_MAPPING_VALUE_STATE;
1148+ return yaml_parser_process_empty_scalar(parser, event,
1149+ token->start_mark);
1150+ }
1151+ }
1152+ else if (token->type != YAML_FLOW_MAPPING_END_TOKEN) {
1153+ if (!PUSH(parser, parser->states,
1154+ YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE))
1155+ return 0;
1156+ return yaml_parser_parse_node(parser, event, 0, 0);
1157+ }
1158+ }
1159+
1160+ parser->state = POP(parser, parser->states);
1161+ dummy_mark = POP(parser, parser->marks);
1162+ MAPPING_END_EVENT_INIT(*event, token->start_mark, token->end_mark);
1163+ SKIP_TOKEN(parser);
1164+ return 1;
1165+}
1166+
1167+/*
1168+ * Parse the productions:
1169+ * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
1170+ * * ***** *
1171+ */
1172+
1173+static int
1174+yaml_parser_parse_flow_mapping_value(yaml_parser_t *parser,
1175+ yaml_event_t *event, int empty)
1176+{
1177+ yaml_token_t *token;
1178+
1179+ token = PEEK_TOKEN(parser);
1180+ if (!token) return 0;
1181+
1182+ if (empty) {
1183+ parser->state = YAML_PARSE_FLOW_MAPPING_KEY_STATE;
1184+ return yaml_parser_process_empty_scalar(parser, event,
1185+ token->start_mark);
1186+ }
1187+
1188+ if (token->type == YAML_VALUE_TOKEN) {
1189+ SKIP_TOKEN(parser);
1190+ token = PEEK_TOKEN(parser);
1191+ if (!token) return 0;
1192+ if (token->type != YAML_FLOW_ENTRY_TOKEN
1193+ && token->type != YAML_FLOW_MAPPING_END_TOKEN) {
1194+ if (!PUSH(parser, parser->states,
1195+ YAML_PARSE_FLOW_MAPPING_KEY_STATE))
1196+ return 0;
1197+ return yaml_parser_parse_node(parser, event, 0, 0);
1198+ }
1199+ }
1200+
1201+ parser->state = YAML_PARSE_FLOW_MAPPING_KEY_STATE;
1202+ return yaml_parser_process_empty_scalar(parser, event, token->start_mark);
1203+}
1204+
1205+/*
1206+ * Generate an empty scalar event.
1207+ */
1208+
1209+static int
1210+yaml_parser_process_empty_scalar(yaml_parser_t *parser, yaml_event_t *event,
1211+ yaml_mark_t mark)
1212+{
1213+ yaml_char_t *value;
1214+
1215+ value = yaml_malloc(1);
1216+ if (!value) {
1217+ parser->error = YAML_MEMORY_ERROR;
1218+ return 0;
1219+ }
1220+ value[0] = '\0';
1221+
1222+ SCALAR_EVENT_INIT(*event, NULL, NULL, value, 0,
1223+ 1, 0, YAML_PLAIN_SCALAR_STYLE, mark, mark);
1224+
1225+ return 1;
1226+}
1227+
1228+/*
1229+ * Parse directives.
1230+ */
1231+
1232+static int
1233+yaml_parser_process_directives(yaml_parser_t *parser,
1234+ yaml_version_directive_t **version_directive_ref,
1235+ yaml_tag_directive_t **tag_directives_start_ref,
1236+ yaml_tag_directive_t **tag_directives_end_ref)
1237+{
1238+ yaml_tag_directive_t default_tag_directives[] = {
1239+ {(yaml_char_t *)"!", (yaml_char_t *)"!"},
1240+ {(yaml_char_t *)"!!", (yaml_char_t *)"tag:yaml.org,2002:"},
1241+ {NULL, NULL}
1242+ };
1243+ yaml_tag_directive_t *default_tag_directive;
1244+ yaml_version_directive_t *version_directive = NULL;
1245+ struct {
1246+ yaml_tag_directive_t *start;
1247+ yaml_tag_directive_t *end;
1248+ yaml_tag_directive_t *top;
1249+ } tag_directives = { NULL, NULL, NULL };
1250+ yaml_token_t *token;
1251+
1252+ if (!STACK_INIT(parser, tag_directives, INITIAL_STACK_SIZE))
1253+ goto error;
1254+
1255+ token = PEEK_TOKEN(parser);
1256+ if (!token) goto error;
1257+
1258+ while (token->type == YAML_VERSION_DIRECTIVE_TOKEN ||
1259+ token->type == YAML_TAG_DIRECTIVE_TOKEN)
1260+ {
1261+ if (token->type == YAML_VERSION_DIRECTIVE_TOKEN) {
1262+ if (version_directive) {
1263+ yaml_parser_set_parser_error(parser,
1264+ "found duplicate %YAML directive", token->start_mark);
1265+ goto error;
1266+ }
1267+ if (token->data.version_directive.major != 1
1268+ || token->data.version_directive.minor != 1) {
1269+ yaml_parser_set_parser_error(parser,
1270+ "found incompatible YAML document", token->start_mark);
1271+ goto error;
1272+ }
1273+ version_directive = yaml_malloc(sizeof(yaml_version_directive_t));
1274+ if (!version_directive) {
1275+ parser->error = YAML_MEMORY_ERROR;
1276+ goto error;
1277+ }
1278+ version_directive->major = token->data.version_directive.major;
1279+ version_directive->minor = token->data.version_directive.minor;
1280+ }
1281+
1282+ else if (token->type == YAML_TAG_DIRECTIVE_TOKEN) {
1283+ yaml_tag_directive_t value;
1284+ value.handle = token->data.tag_directive.handle;
1285+ value.prefix = token->data.tag_directive.prefix;
1286+
1287+ if (!yaml_parser_append_tag_directive(parser, value, 0,
1288+ token->start_mark))
1289+ goto error;
1290+ if (!PUSH(parser, tag_directives, value))
1291+ goto error;
1292+ }
1293+
1294+ SKIP_TOKEN(parser);
1295+ token = PEEK_TOKEN(parser);
1296+ if (!token) goto error;
1297+ }
1298+
1299+ for (default_tag_directive = default_tag_directives;
1300+ default_tag_directive->handle; default_tag_directive++) {
1301+ if (!yaml_parser_append_tag_directive(parser, *default_tag_directive, 1,
1302+ token->start_mark))
1303+ goto error;
1304+ }
1305+
1306+ if (version_directive_ref) {
1307+ *version_directive_ref = version_directive;
1308+ }
1309+ if (tag_directives_start_ref) {
1310+ if (STACK_EMPTY(parser, tag_directives)) {
1311+ *tag_directives_start_ref = *tag_directives_end_ref = NULL;
1312+ STACK_DEL(parser, tag_directives);
1313+ }
1314+ else {
1315+ *tag_directives_start_ref = tag_directives.start;
1316+ *tag_directives_end_ref = tag_directives.top;
1317+ }
1318+ }
1319+ else {
1320+ STACK_DEL(parser, tag_directives);
1321+ }
1322+
1323+ return 1;
1324+
1325+error:
1326+ yaml_free(version_directive);
1327+ while (!STACK_EMPTY(parser, tag_directives)) {
1328+ yaml_tag_directive_t tag_directive = POP(parser, tag_directives);
1329+ yaml_free(tag_directive.handle);
1330+ yaml_free(tag_directive.prefix);
1331+ }
1332+ STACK_DEL(parser, tag_directives);
1333+ return 0;
1334+}
1335+
1336+/*
1337+ * Append a tag directive to the directives stack.
1338+ */
1339+
1340+static int
1341+yaml_parser_append_tag_directive(yaml_parser_t *parser,
1342+ yaml_tag_directive_t value, int allow_duplicates, yaml_mark_t mark)
1343+{
1344+ yaml_tag_directive_t *tag_directive;
1345+ yaml_tag_directive_t copy = { NULL, NULL };
1346+
1347+ for (tag_directive = parser->tag_directives.start;
1348+ tag_directive != parser->tag_directives.top; tag_directive ++) {
1349+ if (strcmp((char *)value.handle, (char *)tag_directive->handle) == 0) {
1350+ if (allow_duplicates)
1351+ return 1;
1352+ return yaml_parser_set_parser_error(parser,
1353+ "found duplicate %TAG directive", mark);
1354+ }
1355+ }
1356+
1357+ copy.handle = yaml_strdup(value.handle);
1358+ copy.prefix = yaml_strdup(value.prefix);
1359+ if (!copy.handle || !copy.prefix) {
1360+ parser->error = YAML_MEMORY_ERROR;
1361+ goto error;
1362+ }
1363+
1364+ if (!PUSH(parser, parser->tag_directives, copy))
1365+ goto error;
1366+
1367+ return 1;
1368+
1369+error:
1370+ yaml_free(copy.handle);
1371+ yaml_free(copy.prefix);
1372+ return 0;
1373+}
1374+
libyaml/reader.cnew file+469
@@ -0,0 +1,469 @@
1+
2+#include "yaml_private.h"
3+
4+/*
5+ * Declarations.
6+ */
7+
8+static int
9+yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem,
10+ size_t offset, int value);
11+
12+static int
13+yaml_parser_update_raw_buffer(yaml_parser_t *parser);
14+
15+static int
16+yaml_parser_determine_encoding(yaml_parser_t *parser);
17+
18+YAML_DECLARE(int)
19+yaml_parser_update_buffer(yaml_parser_t *parser, size_t length);
20+
21+/*
22+ * Set the reader error and return 0.
23+ */
24+
25+static int
26+yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem,
27+ size_t offset, int value)
28+{
29+ parser->error = YAML_READER_ERROR;
30+ parser->problem = problem;
31+ parser->problem_offset = offset;
32+ parser->problem_value = value;
33+
34+ return 0;
35+}
36+
37+/*
38+ * Byte order marks.
39+ */
40+
41+#define BOM_UTF8 "\xef\xbb\xbf"
42+#define BOM_UTF16LE "\xff\xfe"
43+#define BOM_UTF16BE "\xfe\xff"
44+
45+/*
46+ * Determine the input stream encoding by checking the BOM symbol. If no BOM is
47+ * found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure.
48+ */
49+
50+static int
51+yaml_parser_determine_encoding(yaml_parser_t *parser)
52+{
53+ /* Ensure that we had enough bytes in the raw buffer. */
54+
55+ while (!parser->eof
56+ && parser->raw_buffer.last - parser->raw_buffer.pointer < 3) {
57+ if (!yaml_parser_update_raw_buffer(parser)) {
58+ return 0;
59+ }
60+ }
61+
62+ /* Determine the encoding. */
63+
64+ if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 2
65+ && !memcmp(parser->raw_buffer.pointer, BOM_UTF16LE, 2)) {
66+ parser->encoding = YAML_UTF16LE_ENCODING;
67+ parser->raw_buffer.pointer += 2;
68+ parser->offset += 2;
69+ }
70+ else if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 2
71+ && !memcmp(parser->raw_buffer.pointer, BOM_UTF16BE, 2)) {
72+ parser->encoding = YAML_UTF16BE_ENCODING;
73+ parser->raw_buffer.pointer += 2;
74+ parser->offset += 2;
75+ }
76+ else if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 3
77+ && !memcmp(parser->raw_buffer.pointer, BOM_UTF8, 3)) {
78+ parser->encoding = YAML_UTF8_ENCODING;
79+ parser->raw_buffer.pointer += 3;
80+ parser->offset += 3;
81+ }
82+ else {
83+ parser->encoding = YAML_UTF8_ENCODING;
84+ }
85+
86+ return 1;
87+}
88+
89+/*
90+ * Update the raw buffer.
91+ */
92+
93+static int
94+yaml_parser_update_raw_buffer(yaml_parser_t *parser)
95+{
96+ size_t size_read = 0;
97+
98+ /* Return if the raw buffer is full. */
99+
100+ if (parser->raw_buffer.start == parser->raw_buffer.pointer
101+ && parser->raw_buffer.last == parser->raw_buffer.end)
102+ return 1;
103+
104+ /* Return on EOF. */
105+
106+ if (parser->eof) return 1;
107+
108+ /* Move the remaining bytes in the raw buffer to the beginning. */
109+
110+ if (parser->raw_buffer.start < parser->raw_buffer.pointer
111+ && parser->raw_buffer.pointer < parser->raw_buffer.last) {
112+ memmove(parser->raw_buffer.start, parser->raw_buffer.pointer,
113+ parser->raw_buffer.last - parser->raw_buffer.pointer);
114+ }
115+ parser->raw_buffer.last -=
116+ parser->raw_buffer.pointer - parser->raw_buffer.start;
117+ parser->raw_buffer.pointer = parser->raw_buffer.start;
118+
119+ /* Call the read handler to fill the buffer. */
120+
121+ if (!parser->read_handler(parser->read_handler_data, parser->raw_buffer.last,
122+ parser->raw_buffer.end - parser->raw_buffer.last, &size_read)) {
123+ return yaml_parser_set_reader_error(parser, "input error",
124+ parser->offset, -1);
125+ }
126+ parser->raw_buffer.last += size_read;
127+ if (!size_read) {
128+ parser->eof = 1;
129+ }
130+
131+ return 1;
132+}
133+
134+/*
135+ * Ensure that the buffer contains at least `length` characters.
136+ * Return 1 on success, 0 on failure.
137+ *
138+ * The length is supposed to be significantly less that the buffer size.
139+ */
140+
141+YAML_DECLARE(int)
142+yaml_parser_update_buffer(yaml_parser_t *parser, size_t length)
143+{
144+ int first = 1;
145+
146+ assert(parser->read_handler); /* Read handler must be set. */
147+
148+ /* If the EOF flag is set and the raw buffer is empty, do nothing. */
149+
150+ if (parser->eof && parser->raw_buffer.pointer == parser->raw_buffer.last)
151+ return 1;
152+
153+ /* Return if the buffer contains enough characters. */
154+
155+ if (parser->unread >= length)
156+ return 1;
157+
158+ /* Determine the input encoding if it is not known yet. */
159+
160+ if (!parser->encoding) {
161+ if (!yaml_parser_determine_encoding(parser))
162+ return 0;
163+ }
164+
165+ /* Move the unread characters to the beginning of the buffer. */
166+
167+ if (parser->buffer.start < parser->buffer.pointer
168+ && parser->buffer.pointer < parser->buffer.last) {
169+ size_t size = parser->buffer.last - parser->buffer.pointer;
170+ memmove(parser->buffer.start, parser->buffer.pointer, size);
171+ parser->buffer.pointer = parser->buffer.start;
172+ parser->buffer.last = parser->buffer.start + size;
173+ }
174+ else if (parser->buffer.pointer == parser->buffer.last) {
175+ parser->buffer.pointer = parser->buffer.start;
176+ parser->buffer.last = parser->buffer.start;
177+ }
178+
179+ /* Fill the buffer until it has enough characters. */
180+
181+ while (parser->unread < length)
182+ {
183+ /* Fill the raw buffer if necessary. */
184+
185+ if (!first || parser->raw_buffer.pointer == parser->raw_buffer.last) {
186+ if (!yaml_parser_update_raw_buffer(parser)) return 0;
187+ }
188+ first = 0;
189+
190+ /* Decode the raw buffer. */
191+
192+ while (parser->raw_buffer.pointer != parser->raw_buffer.last)
193+ {
194+ unsigned int value = 0, value2 = 0;
195+ int incomplete = 0;
196+ unsigned char octet;
197+ unsigned int width = 0;
198+ int low, high;
199+ size_t k;
200+ size_t raw_unread = parser->raw_buffer.last - parser->raw_buffer.pointer;
201+
202+ /* Decode the next character. */
203+
204+ switch (parser->encoding)
205+ {
206+ case YAML_UTF8_ENCODING:
207+
208+ /*
209+ * Decode a UTF-8 character. Check RFC 3629
210+ * (http://www.ietf.org/rfc/rfc3629.txt) for more details.
211+ *
212+ * The following table (taken from the RFC) is used for
213+ * decoding.
214+ *
215+ * Char. number range | UTF-8 octet sequence
216+ * (hexadecimal) | (binary)
217+ * --------------------+------------------------------------
218+ * 0000 0000-0000 007F | 0xxxxxxx
219+ * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
220+ * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
221+ * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
222+ *
223+ * Additionally, the characters in the range 0xD800-0xDFFF
224+ * are prohibited as they are reserved for use with UTF-16
225+ * surrogate pairs.
226+ */
227+
228+ /* Determine the length of the UTF-8 sequence. */
229+
230+ octet = parser->raw_buffer.pointer[0];
231+ width = (octet & 0x80) == 0x00 ? 1 :
232+ (octet & 0xE0) == 0xC0 ? 2 :
233+ (octet & 0xF0) == 0xE0 ? 3 :
234+ (octet & 0xF8) == 0xF0 ? 4 : 0;
235+
236+ /* Check if the leading octet is valid. */
237+
238+ if (!width)
239+ return yaml_parser_set_reader_error(parser,
240+ "invalid leading UTF-8 octet",
241+ parser->offset, octet);
242+
243+ /* Check if the raw buffer contains an incomplete character. */
244+
245+ if (width > raw_unread) {
246+ if (parser->eof) {
247+ return yaml_parser_set_reader_error(parser,
248+ "incomplete UTF-8 octet sequence",
249+ parser->offset, -1);
250+ }
251+ incomplete = 1;
252+ break;
253+ }
254+
255+ /* Decode the leading octet. */
256+
257+ value = (octet & 0x80) == 0x00 ? octet & 0x7F :
258+ (octet & 0xE0) == 0xC0 ? octet & 0x1F :
259+ (octet & 0xF0) == 0xE0 ? octet & 0x0F :
260+ (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
261+
262+ /* Check and decode the trailing octets. */
263+
264+ for (k = 1; k < width; k ++)
265+ {
266+ octet = parser->raw_buffer.pointer[k];
267+
268+ /* Check if the octet is valid. */
269+
270+ if ((octet & 0xC0) != 0x80)
271+ return yaml_parser_set_reader_error(parser,
272+ "invalid trailing UTF-8 octet",
273+ parser->offset+k, octet);
274+
275+ /* Decode the octet. */
276+
277+ value = (value << 6) + (octet & 0x3F);
278+ }
279+
280+ /* Check the length of the sequence against the value. */
281+
282+ if (!((width == 1) ||
283+ (width == 2 && value >= 0x80) ||
284+ (width == 3 && value >= 0x800) ||
285+ (width == 4 && value >= 0x10000)))
286+ return yaml_parser_set_reader_error(parser,
287+ "invalid length of a UTF-8 sequence",
288+ parser->offset, -1);
289+
290+ /* Check the range of the value. */
291+
292+ if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF)
293+ return yaml_parser_set_reader_error(parser,
294+ "invalid Unicode character",
295+ parser->offset, value);
296+
297+ break;
298+
299+ case YAML_UTF16LE_ENCODING:
300+ case YAML_UTF16BE_ENCODING:
301+
302+ low = (parser->encoding == YAML_UTF16LE_ENCODING ? 0 : 1);
303+ high = (parser->encoding == YAML_UTF16LE_ENCODING ? 1 : 0);
304+
305+ /*
306+ * The UTF-16 encoding is not as simple as one might
307+ * naively think. Check RFC 2781
308+ * (http://www.ietf.org/rfc/rfc2781.txt).
309+ *
310+ * Normally, two subsequent bytes describe a Unicode
311+ * character. However a special technique (called a
312+ * surrogate pair) is used for specifying character
313+ * values larger than 0xFFFF.
314+ *
315+ * A surrogate pair consists of two pseudo-characters:
316+ * high surrogate area (0xD800-0xDBFF)
317+ * low surrogate area (0xDC00-0xDFFF)
318+ *
319+ * The following formulas are used for decoding
320+ * and encoding characters using surrogate pairs:
321+ *
322+ * U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF)
323+ * U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF)
324+ * W1 = 110110yyyyyyyyyy
325+ * W2 = 110111xxxxxxxxxx
326+ *
327+ * where U is the character value, W1 is the high surrogate
328+ * area, W2 is the low surrogate area.
329+ */
330+
331+ /* Check for incomplete UTF-16 character. */
332+
333+ if (raw_unread < 2) {
334+ if (parser->eof) {
335+ return yaml_parser_set_reader_error(parser,
336+ "incomplete UTF-16 character",
337+ parser->offset, -1);
338+ }
339+ incomplete = 1;
340+ break;
341+ }
342+
343+ /* Get the character. */
344+
345+ value = parser->raw_buffer.pointer[low]
346+ + (parser->raw_buffer.pointer[high] << 8);
347+
348+ /* Check for unexpected low surrogate area. */
349+
350+ if ((value & 0xFC00) == 0xDC00)
351+ return yaml_parser_set_reader_error(parser,
352+ "unexpected low surrogate area",
353+ parser->offset, value);
354+
355+ /* Check for a high surrogate area. */
356+
357+ if ((value & 0xFC00) == 0xD800) {
358+
359+ width = 4;
360+
361+ /* Check for incomplete surrogate pair. */
362+
363+ if (raw_unread < 4) {
364+ if (parser->eof) {
365+ return yaml_parser_set_reader_error(parser,
366+ "incomplete UTF-16 surrogate pair",
367+ parser->offset, -1);
368+ }
369+ incomplete = 1;
370+ break;
371+ }
372+
373+ /* Get the next character. */
374+
375+ value2 = parser->raw_buffer.pointer[low+2]
376+ + (parser->raw_buffer.pointer[high+2] << 8);
377+
378+ /* Check for a low surrogate area. */
379+
380+ if ((value2 & 0xFC00) != 0xDC00)
381+ return yaml_parser_set_reader_error(parser,
382+ "expected low surrogate area",
383+ parser->offset+2, value2);
384+
385+ /* Generate the value of the surrogate pair. */
386+
387+ value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF);
388+ }
389+
390+ else {
391+ width = 2;
392+ }
393+
394+ break;
395+
396+ default:
397+ assert(1); /* Impossible. */
398+ }
399+
400+ /* Check if the raw buffer contains enough bytes to form a character. */
401+
402+ if (incomplete) break;
403+
404+ /*
405+ * Check if the character is in the allowed range:
406+ * #x9 | #xA | #xD | [#x20-#x7E] (8 bit)
407+ * | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit)
408+ * | [#x10000-#x10FFFF] (32 bit)
409+ */
410+
411+ if (! (value == 0x09 || value == 0x0A || value == 0x0D
412+ || (value >= 0x20 && value <= 0x7E)
413+ || (value == 0x85) || (value >= 0xA0 && value <= 0xD7FF)
414+ || (value >= 0xE000 && value <= 0xFFFD)
415+ || (value >= 0x10000 && value <= 0x10FFFF)))
416+ return yaml_parser_set_reader_error(parser,
417+ "control characters are not allowed",
418+ parser->offset, value);
419+
420+ /* Move the raw pointers. */
421+
422+ parser->raw_buffer.pointer += width;
423+ parser->offset += width;
424+
425+ /* Finally put the character into the buffer. */
426+
427+ /* 0000 0000-0000 007F -> 0xxxxxxx */
428+ if (value <= 0x7F) {
429+ *(parser->buffer.last++) = value;
430+ }
431+ /* 0000 0080-0000 07FF -> 110xxxxx 10xxxxxx */
432+ else if (value <= 0x7FF) {
433+ *(parser->buffer.last++) = 0xC0 + (value >> 6);
434+ *(parser->buffer.last++) = 0x80 + (value & 0x3F);
435+ }
436+ /* 0000 0800-0000 FFFF -> 1110xxxx 10xxxxxx 10xxxxxx */
437+ else if (value <= 0xFFFF) {
438+ *(parser->buffer.last++) = 0xE0 + (value >> 12);
439+ *(parser->buffer.last++) = 0x80 + ((value >> 6) & 0x3F);
440+ *(parser->buffer.last++) = 0x80 + (value & 0x3F);
441+ }
442+ /* 0001 0000-0010 FFFF -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
443+ else {
444+ *(parser->buffer.last++) = 0xF0 + (value >> 18);
445+ *(parser->buffer.last++) = 0x80 + ((value >> 12) & 0x3F);
446+ *(parser->buffer.last++) = 0x80 + ((value >> 6) & 0x3F);
447+ *(parser->buffer.last++) = 0x80 + (value & 0x3F);
448+ }
449+
450+ parser->unread ++;
451+ }
452+
453+ /* On EOF, put NUL into the buffer and return. */
454+
455+ if (parser->eof) {
456+ *(parser->buffer.last++) = '\0';
457+ parser->unread ++;
458+ return 1;
459+ }
460+
461+ }
462+
463+ if (parser->offset >= PTRDIFF_MAX)
464+ return yaml_parser_set_reader_error(parser, "input is too long",
465+ PTRDIFF_MAX, -1);
466+
467+ return 1;
468+}
469+
libyaml/scanner.cnew file+3580
@@ -0,0 +1,3580 @@
1+
2+/*
3+ * Introduction
4+ * ************
5+ *
6+ * The following notes assume that you are familiar with the YAML specification
7+ * (http://yaml.org/spec/cvs/current.html). We mostly follow it, although in
8+ * some cases we are less restrictive that it requires.
9+ *
10+ * The process of transforming a YAML stream into a sequence of events is
11+ * divided on two steps: Scanning and Parsing.
12+ *
13+ * The Scanner transforms the input stream into a sequence of tokens, while the
14+ * parser transform the sequence of tokens produced by the Scanner into a
15+ * sequence of parsing events.
16+ *
17+ * The Scanner is rather clever and complicated. The Parser, on the contrary,
18+ * is a straightforward implementation of a recursive-descendant parser (or,
19+ * LL(1) parser, as it is usually called).
20+ *
21+ * Actually there are two issues of Scanning that might be called "clever", the
22+ * rest is quite straightforward. The issues are "block collection start" and
23+ * "simple keys". Both issues are explained below in details.
24+ *
25+ * Here the Scanning step is explained and implemented. We start with the list
26+ * of all the tokens produced by the Scanner together with short descriptions.
27+ *
28+ * Now, tokens:
29+ *
30+ * STREAM-START(encoding) # The stream start.
31+ * STREAM-END # The stream end.
32+ * VERSION-DIRECTIVE(major,minor) # The '%YAML' directive.
33+ * TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive.
34+ * DOCUMENT-START # '---'
35+ * DOCUMENT-END # '...'
36+ * BLOCK-SEQUENCE-START # Indentation increase denoting a block
37+ * BLOCK-MAPPING-START # sequence or a block mapping.
38+ * BLOCK-END # Indentation decrease.
39+ * FLOW-SEQUENCE-START # '['
40+ * FLOW-SEQUENCE-END # ']'
41+ * BLOCK-SEQUENCE-START # '{'
42+ * BLOCK-SEQUENCE-END # '}'
43+ * BLOCK-ENTRY # '-'
44+ * FLOW-ENTRY # ','
45+ * KEY # '?' or nothing (simple keys).
46+ * VALUE # ':'
47+ * ALIAS(anchor) # '*anchor'
48+ * ANCHOR(anchor) # '&anchor'
49+ * TAG(handle,suffix) # '!handle!suffix'
50+ * SCALAR(value,style) # A scalar.
51+ *
52+ * The following two tokens are "virtual" tokens denoting the beginning and the
53+ * end of the stream:
54+ *
55+ * STREAM-START(encoding)
56+ * STREAM-END
57+ *
58+ * We pass the information about the input stream encoding with the
59+ * STREAM-START token.
60+ *
61+ * The next two tokens are responsible for tags:
62+ *
63+ * VERSION-DIRECTIVE(major,minor)
64+ * TAG-DIRECTIVE(handle,prefix)
65+ *
66+ * Example:
67+ *
68+ * %YAML 1.1
69+ * %TAG ! !foo
70+ * %TAG !yaml! tag:yaml.org,2002:
71+ * ---
72+ *
73+ * The correspoding sequence of tokens:
74+ *
75+ * STREAM-START(utf-8)
76+ * VERSION-DIRECTIVE(1,1)
77+ * TAG-DIRECTIVE("!","!foo")
78+ * TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:")
79+ * DOCUMENT-START
80+ * STREAM-END
81+ *
82+ * Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole
83+ * line.
84+ *
85+ * The document start and end indicators are represented by:
86+ *
87+ * DOCUMENT-START
88+ * DOCUMENT-END
89+ *
90+ * Note that if a YAML stream contains an implicit document (without '---'
91+ * and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be
92+ * produced.
93+ *
94+ * In the following examples, we present whole documents together with the
95+ * produced tokens.
96+ *
97+ * 1. An implicit document:
98+ *
99+ * 'a scalar'
100+ *
101+ * Tokens:
102+ *
103+ * STREAM-START(utf-8)
104+ * SCALAR("a scalar",single-quoted)
105+ * STREAM-END
106+ *
107+ * 2. An explicit document:
108+ *
109+ * ---
110+ * 'a scalar'
111+ * ...
112+ *
113+ * Tokens:
114+ *
115+ * STREAM-START(utf-8)
116+ * DOCUMENT-START
117+ * SCALAR("a scalar",single-quoted)
118+ * DOCUMENT-END
119+ * STREAM-END
120+ *
121+ * 3. Several documents in a stream:
122+ *
123+ * 'a scalar'
124+ * ---
125+ * 'another scalar'
126+ * ---
127+ * 'yet another scalar'
128+ *
129+ * Tokens:
130+ *
131+ * STREAM-START(utf-8)
132+ * SCALAR("a scalar",single-quoted)
133+ * DOCUMENT-START
134+ * SCALAR("another scalar",single-quoted)
135+ * DOCUMENT-START
136+ * SCALAR("yet another scalar",single-quoted)
137+ * STREAM-END
138+ *
139+ * We have already introduced the SCALAR token above. The following tokens are
140+ * used to describe aliases, anchors, tag, and scalars:
141+ *
142+ * ALIAS(anchor)
143+ * ANCHOR(anchor)
144+ * TAG(handle,suffix)
145+ * SCALAR(value,style)
146+ *
147+ * The following series of examples illustrate the usage of these tokens:
148+ *
149+ * 1. A recursive sequence:
150+ *
151+ * &A [ *A ]
152+ *
153+ * Tokens:
154+ *
155+ * STREAM-START(utf-8)
156+ * ANCHOR("A")
157+ * FLOW-SEQUENCE-START
158+ * ALIAS("A")
159+ * FLOW-SEQUENCE-END
160+ * STREAM-END
161+ *
162+ * 2. A tagged scalar:
163+ *
164+ * !!float "3.14" # A good approximation.
165+ *
166+ * Tokens:
167+ *
168+ * STREAM-START(utf-8)
169+ * TAG("!!","float")
170+ * SCALAR("3.14",double-quoted)
171+ * STREAM-END
172+ *
173+ * 3. Various scalar styles:
174+ *
175+ * --- # Implicit empty plain scalars do not produce tokens.
176+ * --- a plain scalar
177+ * --- 'a single-quoted scalar'
178+ * --- "a double-quoted scalar"
179+ * --- |-
180+ * a literal scalar
181+ * --- >-
182+ * a folded
183+ * scalar
184+ *
185+ * Tokens:
186+ *
187+ * STREAM-START(utf-8)
188+ * DOCUMENT-START
189+ * DOCUMENT-START
190+ * SCALAR("a plain scalar",plain)
191+ * DOCUMENT-START
192+ * SCALAR("a single-quoted scalar",single-quoted)
193+ * DOCUMENT-START
194+ * SCALAR("a double-quoted scalar",double-quoted)
195+ * DOCUMENT-START
196+ * SCALAR("a literal scalar",literal)
197+ * DOCUMENT-START
198+ * SCALAR("a folded scalar",folded)
199+ * STREAM-END
200+ *
201+ * Now it's time to review collection-related tokens. We will start with
202+ * flow collections:
203+ *
204+ * FLOW-SEQUENCE-START
205+ * FLOW-SEQUENCE-END
206+ * FLOW-MAPPING-START
207+ * FLOW-MAPPING-END
208+ * FLOW-ENTRY
209+ * KEY
210+ * VALUE
211+ *
212+ * The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and
213+ * FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}'
214+ * correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the
215+ * indicators '?' and ':', which are used for denoting mapping keys and values,
216+ * are represented by the KEY and VALUE tokens.
217+ *
218+ * The following examples show flow collections:
219+ *
220+ * 1. A flow sequence:
221+ *
222+ * [item 1, item 2, item 3]
223+ *
224+ * Tokens:
225+ *
226+ * STREAM-START(utf-8)
227+ * FLOW-SEQUENCE-START
228+ * SCALAR("item 1",plain)
229+ * FLOW-ENTRY
230+ * SCALAR("item 2",plain)
231+ * FLOW-ENTRY
232+ * SCALAR("item 3",plain)
233+ * FLOW-SEQUENCE-END
234+ * STREAM-END
235+ *
236+ * 2. A flow mapping:
237+ *
238+ * {
239+ * a simple key: a value, # Note that the KEY token is produced.
240+ * ? a complex key: another value,
241+ * }
242+ *
243+ * Tokens:
244+ *
245+ * STREAM-START(utf-8)
246+ * FLOW-MAPPING-START
247+ * KEY
248+ * SCALAR("a simple key",plain)
249+ * VALUE
250+ * SCALAR("a value",plain)
251+ * FLOW-ENTRY
252+ * KEY
253+ * SCALAR("a complex key",plain)
254+ * VALUE
255+ * SCALAR("another value",plain)
256+ * FLOW-ENTRY
257+ * FLOW-MAPPING-END
258+ * STREAM-END
259+ *
260+ * A simple key is a key which is not denoted by the '?' indicator. Note that
261+ * the Scanner still produce the KEY token whenever it encounters a simple key.
262+ *
263+ * For scanning block collections, the following tokens are used (note that we
264+ * repeat KEY and VALUE here):
265+ *
266+ * BLOCK-SEQUENCE-START
267+ * BLOCK-MAPPING-START
268+ * BLOCK-END
269+ * BLOCK-ENTRY
270+ * KEY
271+ * VALUE
272+ *
273+ * The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation
274+ * increase that precedes a block collection (cf. the INDENT token in Python).
275+ * The token BLOCK-END denote indentation decrease that ends a block collection
276+ * (cf. the DEDENT token in Python). However YAML has some syntax pecularities
277+ * that makes detections of these tokens more complex.
278+ *
279+ * The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators
280+ * '-', '?', and ':' correspondingly.
281+ *
282+ * The following examples show how the tokens BLOCK-SEQUENCE-START,
283+ * BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner:
284+ *
285+ * 1. Block sequences:
286+ *
287+ * - item 1
288+ * - item 2
289+ * -
290+ * - item 3.1
291+ * - item 3.2
292+ * -
293+ * key 1: value 1
294+ * key 2: value 2
295+ *
296+ * Tokens:
297+ *
298+ * STREAM-START(utf-8)
299+ * BLOCK-SEQUENCE-START
300+ * BLOCK-ENTRY
301+ * SCALAR("item 1",plain)
302+ * BLOCK-ENTRY
303+ * SCALAR("item 2",plain)
304+ * BLOCK-ENTRY
305+ * BLOCK-SEQUENCE-START
306+ * BLOCK-ENTRY
307+ * SCALAR("item 3.1",plain)
308+ * BLOCK-ENTRY
309+ * SCALAR("item 3.2",plain)
310+ * BLOCK-END
311+ * BLOCK-ENTRY
312+ * BLOCK-MAPPING-START
313+ * KEY
314+ * SCALAR("key 1",plain)
315+ * VALUE
316+ * SCALAR("value 1",plain)
317+ * KEY
318+ * SCALAR("key 2",plain)
319+ * VALUE
320+ * SCALAR("value 2",plain)
321+ * BLOCK-END
322+ * BLOCK-END
323+ * STREAM-END
324+ *
325+ * 2. Block mappings:
326+ *
327+ * a simple key: a value # The KEY token is produced here.
328+ * ? a complex key
329+ * : another value
330+ * a mapping:
331+ * key 1: value 1
332+ * key 2: value 2
333+ * a sequence:
334+ * - item 1
335+ * - item 2
336+ *
337+ * Tokens:
338+ *
339+ * STREAM-START(utf-8)
340+ * BLOCK-MAPPING-START
341+ * KEY
342+ * SCALAR("a simple key",plain)
343+ * VALUE
344+ * SCALAR("a value",plain)
345+ * KEY
346+ * SCALAR("a complex key",plain)
347+ * VALUE
348+ * SCALAR("another value",plain)
349+ * KEY
350+ * SCALAR("a mapping",plain)
351+ * BLOCK-MAPPING-START
352+ * KEY
353+ * SCALAR("key 1",plain)
354+ * VALUE
355+ * SCALAR("value 1",plain)
356+ * KEY
357+ * SCALAR("key 2",plain)
358+ * VALUE
359+ * SCALAR("value 2",plain)
360+ * BLOCK-END
361+ * KEY
362+ * SCALAR("a sequence",plain)
363+ * VALUE
364+ * BLOCK-SEQUENCE-START
365+ * BLOCK-ENTRY
366+ * SCALAR("item 1",plain)
367+ * BLOCK-ENTRY
368+ * SCALAR("item 2",plain)
369+ * BLOCK-END
370+ * BLOCK-END
371+ * STREAM-END
372+ *
373+ * YAML does not always require to start a new block collection from a new
374+ * line. If the current line contains only '-', '?', and ':' indicators, a new
375+ * block collection may start at the current line. The following examples
376+ * illustrate this case:
377+ *
378+ * 1. Collections in a sequence:
379+ *
380+ * - - item 1
381+ * - item 2
382+ * - key 1: value 1
383+ * key 2: value 2
384+ * - ? complex key
385+ * : complex value
386+ *
387+ * Tokens:
388+ *
389+ * STREAM-START(utf-8)
390+ * BLOCK-SEQUENCE-START
391+ * BLOCK-ENTRY
392+ * BLOCK-SEQUENCE-START
393+ * BLOCK-ENTRY
394+ * SCALAR("item 1",plain)
395+ * BLOCK-ENTRY
396+ * SCALAR("item 2",plain)
397+ * BLOCK-END
398+ * BLOCK-ENTRY
399+ * BLOCK-MAPPING-START
400+ * KEY
401+ * SCALAR("key 1",plain)
402+ * VALUE
403+ * SCALAR("value 1",plain)
404+ * KEY
405+ * SCALAR("key 2",plain)
406+ * VALUE
407+ * SCALAR("value 2",plain)
408+ * BLOCK-END
409+ * BLOCK-ENTRY
410+ * BLOCK-MAPPING-START
411+ * KEY
412+ * SCALAR("complex key")
413+ * VALUE
414+ * SCALAR("complex value")
415+ * BLOCK-END
416+ * BLOCK-END
417+ * STREAM-END
418+ *
419+ * 2. Collections in a mapping:
420+ *
421+ * ? a sequence
422+ * : - item 1
423+ * - item 2
424+ * ? a mapping
425+ * : key 1: value 1
426+ * key 2: value 2
427+ *
428+ * Tokens:
429+ *
430+ * STREAM-START(utf-8)
431+ * BLOCK-MAPPING-START
432+ * KEY
433+ * SCALAR("a sequence",plain)
434+ * VALUE
435+ * BLOCK-SEQUENCE-START
436+ * BLOCK-ENTRY
437+ * SCALAR("item 1",plain)
438+ * BLOCK-ENTRY
439+ * SCALAR("item 2",plain)
440+ * BLOCK-END
441+ * KEY
442+ * SCALAR("a mapping",plain)
443+ * VALUE
444+ * BLOCK-MAPPING-START
445+ * KEY
446+ * SCALAR("key 1",plain)
447+ * VALUE
448+ * SCALAR("value 1",plain)
449+ * KEY
450+ * SCALAR("key 2",plain)
451+ * VALUE
452+ * SCALAR("value 2",plain)
453+ * BLOCK-END
454+ * BLOCK-END
455+ * STREAM-END
456+ *
457+ * YAML also permits non-indented sequences if they are included into a block
458+ * mapping. In this case, the token BLOCK-SEQUENCE-START is not produced:
459+ *
460+ * key:
461+ * - item 1 # BLOCK-SEQUENCE-START is NOT produced here.
462+ * - item 2
463+ *
464+ * Tokens:
465+ *
466+ * STREAM-START(utf-8)
467+ * BLOCK-MAPPING-START
468+ * KEY
469+ * SCALAR("key",plain)
470+ * VALUE
471+ * BLOCK-ENTRY
472+ * SCALAR("item 1",plain)
473+ * BLOCK-ENTRY
474+ * SCALAR("item 2",plain)
475+ * BLOCK-END
476+ */
477+
478+#include "yaml_private.h"
479+
480+/*
481+ * Ensure that the buffer contains the required number of characters.
482+ * Return 1 on success, 0 on failure (reader error or memory error).
483+ */
484+
485+#define CACHE(parser,length) \
486+ (parser->unread >= (length) \
487+ ? 1 \
488+ : yaml_parser_update_buffer(parser, (length)))
489+
490+/*
491+ * Advance the buffer pointer.
492+ */
493+
494+#define SKIP(parser) \
495+ (parser->mark.index ++, \
496+ parser->mark.column ++, \
497+ parser->unread --, \
498+ parser->buffer.pointer += WIDTH(parser->buffer))
499+
500+#define SKIP_LINE(parser) \
501+ (IS_CRLF(parser->buffer) ? \
502+ (parser->mark.index += 2, \
503+ parser->mark.column = 0, \
504+ parser->mark.line ++, \
505+ parser->unread -= 2, \
506+ parser->buffer.pointer += 2) : \
507+ IS_BREAK(parser->buffer) ? \
508+ (parser->mark.index ++, \
509+ parser->mark.column = 0, \
510+ parser->mark.line ++, \
511+ parser->unread --, \
512+ parser->buffer.pointer += WIDTH(parser->buffer)) : 0)
513+
514+/*
515+ * Copy a character to a string buffer and advance pointers.
516+ */
517+
518+#define READ(parser,string) \
519+ (STRING_EXTEND(parser,string) ? \
520+ (COPY(string,parser->buffer), \
521+ parser->mark.index ++, \
522+ parser->mark.column ++, \
523+ parser->unread --, \
524+ 1) : 0)
525+
526+/*
527+ * Copy a line break character to a string buffer and advance pointers.
528+ */
529+
530+#define READ_LINE(parser,string) \
531+ (STRING_EXTEND(parser,string) ? \
532+ (((CHECK_AT(parser->buffer,'\r',0) \
533+ && CHECK_AT(parser->buffer,'\n',1)) ? /* CR LF -> LF */ \
534+ (*((string).pointer++) = (yaml_char_t) '\n', \
535+ parser->buffer.pointer += 2, \
536+ parser->mark.index += 2, \
537+ parser->mark.column = 0, \
538+ parser->mark.line ++, \
539+ parser->unread -= 2) : \
540+ (CHECK_AT(parser->buffer,'\r',0) \
541+ || CHECK_AT(parser->buffer,'\n',0)) ? /* CR|LF -> LF */ \
542+ (*((string).pointer++) = (yaml_char_t) '\n', \
543+ parser->buffer.pointer ++, \
544+ parser->mark.index ++, \
545+ parser->mark.column = 0, \
546+ parser->mark.line ++, \
547+ parser->unread --) : \
548+ (CHECK_AT(parser->buffer,'\xC2',0) \
549+ && CHECK_AT(parser->buffer,'\x85',1)) ? /* NEL -> LF */ \
550+ (*((string).pointer++) = (yaml_char_t) '\n', \
551+ parser->buffer.pointer += 2, \
552+ parser->mark.index ++, \
553+ parser->mark.column = 0, \
554+ parser->mark.line ++, \
555+ parser->unread --) : \
556+ (CHECK_AT(parser->buffer,'\xE2',0) && \
557+ CHECK_AT(parser->buffer,'\x80',1) && \
558+ (CHECK_AT(parser->buffer,'\xA8',2) || \
559+ CHECK_AT(parser->buffer,'\xA9',2))) ? /* LS|PS -> LS|PS */ \
560+ (*((string).pointer++) = *(parser->buffer.pointer++), \
561+ *((string).pointer++) = *(parser->buffer.pointer++), \
562+ *((string).pointer++) = *(parser->buffer.pointer++), \
563+ parser->mark.index ++, \
564+ parser->mark.column = 0, \
565+ parser->mark.line ++, \
566+ parser->unread --) : 0), \
567+ 1) : 0)
568+
569+/*
570+ * Public API declarations.
571+ */
572+
573+YAML_DECLARE(int)
574+yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token);
575+
576+/*
577+ * Error handling.
578+ */
579+
580+static int
581+yaml_parser_set_scanner_error(yaml_parser_t *parser, const char *context,
582+ yaml_mark_t context_mark, const char *problem);
583+
584+/*
585+ * High-level token API.
586+ */
587+
588+YAML_DECLARE(int)
589+yaml_parser_fetch_more_tokens(yaml_parser_t *parser);
590+
591+static int
592+yaml_parser_fetch_next_token(yaml_parser_t *parser);
593+
594+/*
595+ * Potential simple keys.
596+ */
597+
598+static int
599+yaml_parser_stale_simple_keys(yaml_parser_t *parser);
600+
601+static int
602+yaml_parser_save_simple_key(yaml_parser_t *parser);
603+
604+static int
605+yaml_parser_remove_simple_key(yaml_parser_t *parser);
606+
607+static int
608+yaml_parser_increase_flow_level(yaml_parser_t *parser);
609+
610+static int
611+yaml_parser_decrease_flow_level(yaml_parser_t *parser);
612+
613+/*
614+ * Indentation treatment.
615+ */
616+
617+static int
618+yaml_parser_roll_indent(yaml_parser_t *parser, ptrdiff_t column,
619+ ptrdiff_t number, yaml_token_type_t type, yaml_mark_t mark);
620+
621+static int
622+yaml_parser_unroll_indent(yaml_parser_t *parser, ptrdiff_t column);
623+
624+/*
625+ * Token fetchers.
626+ */
627+
628+static int
629+yaml_parser_fetch_stream_start(yaml_parser_t *parser);
630+
631+static int
632+yaml_parser_fetch_stream_end(yaml_parser_t *parser);
633+
634+static int
635+yaml_parser_fetch_directive(yaml_parser_t *parser);
636+
637+static int
638+yaml_parser_fetch_document_indicator(yaml_parser_t *parser,
639+ yaml_token_type_t type);
640+
641+static int
642+yaml_parser_fetch_flow_collection_start(yaml_parser_t *parser,
643+ yaml_token_type_t type);
644+
645+static int
646+yaml_parser_fetch_flow_collection_end(yaml_parser_t *parser,
647+ yaml_token_type_t type);
648+
649+static int
650+yaml_parser_fetch_flow_entry(yaml_parser_t *parser);
651+
652+static int
653+yaml_parser_fetch_block_entry(yaml_parser_t *parser);
654+
655+static int
656+yaml_parser_fetch_key(yaml_parser_t *parser);
657+
658+static int
659+yaml_parser_fetch_value(yaml_parser_t *parser);
660+
661+static int
662+yaml_parser_fetch_anchor(yaml_parser_t *parser, yaml_token_type_t type);
663+
664+static int
665+yaml_parser_fetch_tag(yaml_parser_t *parser);
666+
667+static int
668+yaml_parser_fetch_block_scalar(yaml_parser_t *parser, int literal);
669+
670+static int
671+yaml_parser_fetch_flow_scalar(yaml_parser_t *parser, int single);
672+
673+static int
674+yaml_parser_fetch_plain_scalar(yaml_parser_t *parser);
675+
676+/*
677+ * Token scanners.
678+ */
679+
680+static int
681+yaml_parser_scan_to_next_token(yaml_parser_t *parser);
682+
683+static int
684+yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token);
685+
686+static int
687+yaml_parser_scan_directive_name(yaml_parser_t *parser,
688+ yaml_mark_t start_mark, yaml_char_t **name);
689+
690+static int
691+yaml_parser_scan_version_directive_value(yaml_parser_t *parser,
692+ yaml_mark_t start_mark, int *major, int *minor);
693+
694+static int
695+yaml_parser_scan_version_directive_number(yaml_parser_t *parser,
696+ yaml_mark_t start_mark, int *number);
697+
698+static int
699+yaml_parser_scan_tag_directive_value(yaml_parser_t *parser,
700+ yaml_mark_t mark, yaml_char_t **handle, yaml_char_t **prefix);
701+
702+static int
703+yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token,
704+ yaml_token_type_t type);
705+
706+static int
707+yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token);
708+
709+static int
710+yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive,
711+ yaml_mark_t start_mark, yaml_char_t **handle);
712+
713+static int
714+yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive,
715+ yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri);
716+
717+static int
718+yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive,
719+ yaml_mark_t start_mark, yaml_string_t *string);
720+
721+static int
722+yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
723+ int literal);
724+
725+static int
726+yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser,
727+ int *indent, yaml_string_t *breaks,
728+ yaml_mark_t start_mark, yaml_mark_t *end_mark);
729+
730+static int
731+yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token,
732+ int single);
733+
734+static int
735+yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token);
736+
737+/*
738+ * Get the next token.
739+ */
740+
741+YAML_DECLARE(int)
742+yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token)
743+{
744+ assert(parser); /* Non-NULL parser object is expected. */
745+ assert(token); /* Non-NULL token object is expected. */
746+
747+ /* Erase the token object. */
748+
749+ memset(token, 0, sizeof(yaml_token_t));
750+
751+ /* No tokens after STREAM-END or error. */
752+
753+ if (parser->stream_end_produced || parser->error) {
754+ return 1;
755+ }
756+
757+ /* Ensure that the tokens queue contains enough tokens. */
758+
759+ if (!parser->token_available) {
760+ if (!yaml_parser_fetch_more_tokens(parser))
761+ return 0;
762+ }
763+
764+ /* Fetch the next token from the queue. */
765+
766+ *token = DEQUEUE(parser, parser->tokens);
767+ parser->token_available = 0;
768+ parser->tokens_parsed ++;
769+
770+ if (token->type == YAML_STREAM_END_TOKEN) {
771+ parser->stream_end_produced = 1;
772+ }
773+
774+ return 1;
775+}
776+
777+/*
778+ * Set the scanner error and return 0.
779+ */
780+
781+static int
782+yaml_parser_set_scanner_error(yaml_parser_t *parser, const char *context,
783+ yaml_mark_t context_mark, const char *problem)
784+{
785+ parser->error = YAML_SCANNER_ERROR;
786+ parser->context = context;
787+ parser->context_mark = context_mark;
788+ parser->problem = problem;
789+ parser->problem_mark = parser->mark;
790+
791+ return 0;
792+}
793+
794+/*
795+ * Ensure that the tokens queue contains at least one token which can be
796+ * returned to the Parser.
797+ */
798+
799+YAML_DECLARE(int)
800+yaml_parser_fetch_more_tokens(yaml_parser_t *parser)
801+{
802+ int need_more_tokens;
803+
804+ /* While we need more tokens to fetch, do it. */
805+
806+ while (1)
807+ {
808+ /*
809+ * Check if we really need to fetch more tokens.
810+ */
811+
812+ need_more_tokens = 0;
813+
814+ if (parser->tokens.head == parser->tokens.tail)
815+ {
816+ /* Queue is empty. */
817+
818+ need_more_tokens = 1;
819+ }
820+ else
821+ {
822+ yaml_simple_key_t *simple_key;
823+
824+ /* Check if any potential simple key may occupy the head position. */
825+
826+ if (!yaml_parser_stale_simple_keys(parser))
827+ return 0;
828+
829+ for (simple_key = parser->simple_keys.start;
830+ simple_key != parser->simple_keys.top; simple_key++) {
831+ if (simple_key->possible
832+ && simple_key->token_number == parser->tokens_parsed) {
833+ need_more_tokens = 1;
834+ break;
835+ }
836+ }
837+ }
838+
839+ /* We are finished. */
840+
841+ if (!need_more_tokens)
842+ break;
843+
844+ /* Fetch the next token. */
845+
846+ if (!yaml_parser_fetch_next_token(parser))
847+ return 0;
848+ }
849+
850+ parser->token_available = 1;
851+
852+ return 1;
853+}
854+
855+/*
856+ * The dispatcher for token fetchers.
857+ */
858+
859+static int
860+yaml_parser_fetch_next_token(yaml_parser_t *parser)
861+{
862+ /* Ensure that the buffer is initialized. */
863+
864+ if (!CACHE(parser, 1))
865+ return 0;
866+
867+ /* Check if we just started scanning. Fetch STREAM-START then. */
868+
869+ if (!parser->stream_start_produced)
870+ return yaml_parser_fetch_stream_start(parser);
871+
872+ /* Eat whitespaces and comments until we reach the next token. */
873+
874+ if (!yaml_parser_scan_to_next_token(parser))
875+ return 0;
876+
877+ /* Remove obsolete potential simple keys. */
878+
879+ if (!yaml_parser_stale_simple_keys(parser))
880+ return 0;
881+
882+ /* Check the indentation level against the current column. */
883+
884+ if (!yaml_parser_unroll_indent(parser, parser->mark.column))
885+ return 0;
886+
887+ /*
888+ * Ensure that the buffer contains at least 4 characters. 4 is the length
889+ * of the longest indicators ('--- ' and '... ').
890+ */
891+
892+ if (!CACHE(parser, 4))
893+ return 0;
894+
895+ /* Is it the end of the stream? */
896+
897+ if (IS_Z(parser->buffer))
898+ return yaml_parser_fetch_stream_end(parser);
899+
900+ /* Is it a directive? */
901+
902+ if (parser->mark.column == 0 && CHECK(parser->buffer, '%'))
903+ return yaml_parser_fetch_directive(parser);
904+
905+ /* Is it the document start indicator? */
906+
907+ if (parser->mark.column == 0
908+ && CHECK_AT(parser->buffer, '-', 0)
909+ && CHECK_AT(parser->buffer, '-', 1)
910+ && CHECK_AT(parser->buffer, '-', 2)
911+ && IS_BLANKZ_AT(parser->buffer, 3))
912+ return yaml_parser_fetch_document_indicator(parser,
913+ YAML_DOCUMENT_START_TOKEN);
914+
915+ /* Is it the document end indicator? */
916+
917+ if (parser->mark.column == 0
918+ && CHECK_AT(parser->buffer, '.', 0)
919+ && CHECK_AT(parser->buffer, '.', 1)
920+ && CHECK_AT(parser->buffer, '.', 2)
921+ && IS_BLANKZ_AT(parser->buffer, 3))
922+ return yaml_parser_fetch_document_indicator(parser,
923+ YAML_DOCUMENT_END_TOKEN);
924+
925+ /* Is it the flow sequence start indicator? */
926+
927+ if (CHECK(parser->buffer, '['))
928+ return yaml_parser_fetch_flow_collection_start(parser,
929+ YAML_FLOW_SEQUENCE_START_TOKEN);
930+
931+ /* Is it the flow mapping start indicator? */
932+
933+ if (CHECK(parser->buffer, '{'))
934+ return yaml_parser_fetch_flow_collection_start(parser,
935+ YAML_FLOW_MAPPING_START_TOKEN);
936+
937+ /* Is it the flow sequence end indicator? */
938+
939+ if (CHECK(parser->buffer, ']'))
940+ return yaml_parser_fetch_flow_collection_end(parser,
941+ YAML_FLOW_SEQUENCE_END_TOKEN);
942+
943+ /* Is it the flow mapping end indicator? */
944+
945+ if (CHECK(parser->buffer, '}'))
946+ return yaml_parser_fetch_flow_collection_end(parser,
947+ YAML_FLOW_MAPPING_END_TOKEN);
948+
949+ /* Is it the flow entry indicator? */
950+
951+ if (CHECK(parser->buffer, ','))
952+ return yaml_parser_fetch_flow_entry(parser);
953+
954+ /* Is it the block entry indicator? */
955+
956+ if (CHECK(parser->buffer, '-') && IS_BLANKZ_AT(parser->buffer, 1))
957+ return yaml_parser_fetch_block_entry(parser);
958+
959+ /* Is it the key indicator? */
960+
961+ if (CHECK(parser->buffer, '?')
962+ && (parser->flow_level || IS_BLANKZ_AT(parser->buffer, 1)))
963+ return yaml_parser_fetch_key(parser);
964+
965+ /* Is it the value indicator? */
966+
967+ if (CHECK(parser->buffer, ':')
968+ && (parser->flow_level || IS_BLANKZ_AT(parser->buffer, 1)))
969+ return yaml_parser_fetch_value(parser);
970+
971+ /* Is it an alias? */
972+
973+ if (CHECK(parser->buffer, '*'))
974+ return yaml_parser_fetch_anchor(parser, YAML_ALIAS_TOKEN);
975+
976+ /* Is it an anchor? */
977+
978+ if (CHECK(parser->buffer, '&'))
979+ return yaml_parser_fetch_anchor(parser, YAML_ANCHOR_TOKEN);
980+
981+ /* Is it a tag? */
982+
983+ if (CHECK(parser->buffer, '!'))
984+ return yaml_parser_fetch_tag(parser);
985+
986+ /* Is it a literal scalar? */
987+
988+ if (CHECK(parser->buffer, '|') && !parser->flow_level)
989+ return yaml_parser_fetch_block_scalar(parser, 1);
990+
991+ /* Is it a folded scalar? */
992+
993+ if (CHECK(parser->buffer, '>') && !parser->flow_level)
994+ return yaml_parser_fetch_block_scalar(parser, 0);
995+
996+ /* Is it a single-quoted scalar? */
997+
998+ if (CHECK(parser->buffer, '\''))
999+ return yaml_parser_fetch_flow_scalar(parser, 1);
1000+
1001+ /* Is it a double-quoted scalar? */
1002+
1003+ if (CHECK(parser->buffer, '"'))
1004+ return yaml_parser_fetch_flow_scalar(parser, 0);
1005+
1006+ /*
1007+ * Is it a plain scalar?
1008+ *
1009+ * A plain scalar may start with any non-blank characters except
1010+ *
1011+ * '-', '?', ':', ',', '[', ']', '{', '}',
1012+ * '#', '&', '*', '!', '|', '>', '\'', '\"',
1013+ * '%', '@', '`'.
1014+ *
1015+ * In the block context (and, for the '-' indicator, in the flow context
1016+ * too), it may also start with the characters
1017+ *
1018+ * '-', '?', ':'
1019+ *
1020+ * if it is followed by a non-space character.
1021+ *
1022+ * The last rule is more restrictive than the specification requires.
1023+ */
1024+
1025+ if (!(IS_BLANKZ(parser->buffer) || CHECK(parser->buffer, '-')
1026+ || CHECK(parser->buffer, '?') || CHECK(parser->buffer, ':')
1027+ || CHECK(parser->buffer, ',') || CHECK(parser->buffer, '[')
1028+ || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '{')
1029+ || CHECK(parser->buffer, '}') || CHECK(parser->buffer, '#')
1030+ || CHECK(parser->buffer, '&') || CHECK(parser->buffer, '*')
1031+ || CHECK(parser->buffer, '!') || CHECK(parser->buffer, '|')
1032+ || CHECK(parser->buffer, '>') || CHECK(parser->buffer, '\'')
1033+ || CHECK(parser->buffer, '"') || CHECK(parser->buffer, '%')
1034+ || CHECK(parser->buffer, '@') || CHECK(parser->buffer, '`')) ||
1035+ (CHECK(parser->buffer, '-') && !IS_BLANK_AT(parser->buffer, 1)) ||
1036+ (!parser->flow_level &&
1037+ (CHECK(parser->buffer, '?') || CHECK(parser->buffer, ':'))
1038+ && !IS_BLANKZ_AT(parser->buffer, 1)))
1039+ return yaml_parser_fetch_plain_scalar(parser);
1040+
1041+ /*
1042+ * If we don't determine the token type so far, it is an error.
1043+ */
1044+
1045+ return yaml_parser_set_scanner_error(parser,
1046+ "while scanning for the next token", parser->mark,
1047+ "found character that cannot start any token");
1048+}
1049+
1050+/*
1051+ * Check the list of potential simple keys and remove the positions that
1052+ * cannot contain simple keys anymore.
1053+ */
1054+
1055+static int
1056+yaml_parser_stale_simple_keys(yaml_parser_t *parser)
1057+{
1058+ yaml_simple_key_t *simple_key;
1059+
1060+ /* Check for a potential simple key for each flow level. */
1061+
1062+ for (simple_key = parser->simple_keys.start;
1063+ simple_key != parser->simple_keys.top; simple_key ++)
1064+ {
1065+ /*
1066+ * The specification requires that a simple key
1067+ *
1068+ * - is limited to a single line,
1069+ * - is shorter than 1024 characters.
1070+ */
1071+
1072+ if (simple_key->possible
1073+ && (simple_key->mark.line < parser->mark.line
1074+ || simple_key->mark.index+1024 < parser->mark.index)) {
1075+
1076+ /* Check if the potential simple key to be removed is required. */
1077+
1078+ if (simple_key->required) {
1079+ return yaml_parser_set_scanner_error(parser,
1080+ "while scanning a simple key", simple_key->mark,
1081+ "could not find expected ':'");
1082+ }
1083+
1084+ simple_key->possible = 0;
1085+ }
1086+ }
1087+
1088+ return 1;
1089+}
1090+
1091+/*
1092+ * Check if a simple key may start at the current position and add it if
1093+ * needed.
1094+ */
1095+
1096+static int
1097+yaml_parser_save_simple_key(yaml_parser_t *parser)
1098+{
1099+ /*
1100+ * A simple key is required at the current position if the scanner is in
1101+ * the block context and the current column coincides with the indentation
1102+ * level.
1103+ */
1104+
1105+ int required = (!parser->flow_level
1106+ && parser->indent == (ptrdiff_t)parser->mark.column);
1107+
1108+ /*
1109+ * A simple key is required only when it is the first token in the current
1110+ * line. Therefore it is always allowed. But we add a check anyway.
1111+ */
1112+
1113+ assert(parser->simple_key_allowed || !required); /* Impossible. */
1114+
1115+ /*
1116+ * If the current position may start a simple key, save it.
1117+ */
1118+
1119+ if (parser->simple_key_allowed)
1120+ {
1121+ yaml_simple_key_t simple_key;
1122+ simple_key.possible = 1;
1123+ simple_key.required = required;
1124+ simple_key.token_number =
1125+ parser->tokens_parsed + (parser->tokens.tail - parser->tokens.head);
1126+ simple_key.mark = parser->mark;
1127+
1128+ if (!yaml_parser_remove_simple_key(parser)) return 0;
1129+
1130+ *(parser->simple_keys.top-1) = simple_key;
1131+ }
1132+
1133+ return 1;
1134+}
1135+
1136+/*
1137+ * Remove a potential simple key at the current flow level.
1138+ */
1139+
1140+static int
1141+yaml_parser_remove_simple_key(yaml_parser_t *parser)
1142+{
1143+ yaml_simple_key_t *simple_key = parser->simple_keys.top-1;
1144+
1145+ if (simple_key->possible)
1146+ {
1147+ /* If the key is required, it is an error. */
1148+
1149+ if (simple_key->required) {
1150+ return yaml_parser_set_scanner_error(parser,
1151+ "while scanning a simple key", simple_key->mark,
1152+ "could not find expected ':'");
1153+ }
1154+ }
1155+
1156+ /* Remove the key from the stack. */
1157+
1158+ simple_key->possible = 0;
1159+
1160+ return 1;
1161+}
1162+
1163+/*
1164+ * Increase the flow level and resize the simple key list if needed.
1165+ */
1166+
1167+static int
1168+yaml_parser_increase_flow_level(yaml_parser_t *parser)
1169+{
1170+ yaml_simple_key_t empty_simple_key = { 0, 0, 0, { 0, 0, 0 } };
1171+
1172+ /* Reset the simple key on the next level. */
1173+
1174+ if (!PUSH(parser, parser->simple_keys, empty_simple_key))
1175+ return 0;
1176+
1177+ /* Increase the flow level. */
1178+
1179+ if (parser->flow_level == INT_MAX) {
1180+ parser->error = YAML_MEMORY_ERROR;
1181+ return 0;
1182+ }
1183+
1184+ parser->flow_level++;
1185+
1186+ return 1;
1187+}
1188+
1189+/*
1190+ * Decrease the flow level.
1191+ */
1192+
1193+static int
1194+yaml_parser_decrease_flow_level(yaml_parser_t *parser)
1195+{
1196+ yaml_simple_key_t dummy_key; /* Used to eliminate a compiler warning. */
1197+
1198+ if (parser->flow_level) {
1199+ parser->flow_level --;
1200+ dummy_key = POP(parser, parser->simple_keys);
1201+ }
1202+
1203+ return 1;
1204+}
1205+
1206+/*
1207+ * Push the current indentation level to the stack and set the new level
1208+ * the current column is greater than the indentation level. In this case,
1209+ * append or insert the specified token into the token queue.
1210+ *
1211+ */
1212+
1213+static int
1214+yaml_parser_roll_indent(yaml_parser_t *parser, ptrdiff_t column,
1215+ ptrdiff_t number, yaml_token_type_t type, yaml_mark_t mark)
1216+{
1217+ yaml_token_t token;
1218+
1219+ /* In the flow context, do nothing. */
1220+
1221+ if (parser->flow_level)
1222+ return 1;
1223+
1224+ if (parser->indent < column)
1225+ {
1226+ /*
1227+ * Push the current indentation level to the stack and set the new
1228+ * indentation level.
1229+ */
1230+
1231+ if (!PUSH(parser, parser->indents, parser->indent))
1232+ return 0;
1233+
1234+ if (column > INT_MAX) {
1235+ parser->error = YAML_MEMORY_ERROR;
1236+ return 0;
1237+ }
1238+
1239+ parser->indent = column;
1240+
1241+ /* Create a token and insert it into the queue. */
1242+
1243+ TOKEN_INIT(token, type, mark, mark);
1244+
1245+ if (number == -1) {
1246+ if (!ENQUEUE(parser, parser->tokens, token))
1247+ return 0;
1248+ }
1249+ else {
1250+ if (!QUEUE_INSERT(parser,
1251+ parser->tokens, number - parser->tokens_parsed, token))
1252+ return 0;
1253+ }
1254+ }
1255+
1256+ return 1;
1257+}
1258+
1259+/*
1260+ * Pop indentation levels from the indents stack until the current level
1261+ * becomes less or equal to the column. For each intendation level, append
1262+ * the BLOCK-END token.
1263+ */
1264+
1265+
1266+static int
1267+yaml_parser_unroll_indent(yaml_parser_t *parser, ptrdiff_t column)
1268+{
1269+ yaml_token_t token;
1270+
1271+ /* In the flow context, do nothing. */
1272+
1273+ if (parser->flow_level)
1274+ return 1;
1275+
1276+ /* Loop through the intendation levels in the stack. */
1277+
1278+ while (parser->indent > column)
1279+ {
1280+ /* Create a token and append it to the queue. */
1281+
1282+ TOKEN_INIT(token, YAML_BLOCK_END_TOKEN, parser->mark, parser->mark);
1283+
1284+ if (!ENQUEUE(parser, parser->tokens, token))
1285+ return 0;
1286+
1287+ /* Pop the indentation level. */
1288+
1289+ parser->indent = POP(parser, parser->indents);
1290+ }
1291+
1292+ return 1;
1293+}
1294+
1295+/*
1296+ * Initialize the scanner and produce the STREAM-START token.
1297+ */
1298+
1299+static int
1300+yaml_parser_fetch_stream_start(yaml_parser_t *parser)
1301+{
1302+ yaml_simple_key_t simple_key = { 0, 0, 0, { 0, 0, 0 } };
1303+ yaml_token_t token;
1304+
1305+ /* Set the initial indentation. */
1306+
1307+ parser->indent = -1;
1308+
1309+ /* Initialize the simple key stack. */
1310+
1311+ if (!PUSH(parser, parser->simple_keys, simple_key))
1312+ return 0;
1313+
1314+ /* A simple key is allowed at the beginning of the stream. */
1315+
1316+ parser->simple_key_allowed = 1;
1317+
1318+ /* We have started. */
1319+
1320+ parser->stream_start_produced = 1;
1321+
1322+ /* Create the STREAM-START token and append it to the queue. */
1323+
1324+ STREAM_START_TOKEN_INIT(token, parser->encoding,
1325+ parser->mark, parser->mark);
1326+
1327+ if (!ENQUEUE(parser, parser->tokens, token))
1328+ return 0;
1329+
1330+ return 1;
1331+}
1332+
1333+/*
1334+ * Produce the STREAM-END token and shut down the scanner.
1335+ */
1336+
1337+static int
1338+yaml_parser_fetch_stream_end(yaml_parser_t *parser)
1339+{
1340+ yaml_token_t token;
1341+
1342+ /* Force new line. */
1343+
1344+ if (parser->mark.column != 0) {
1345+ parser->mark.column = 0;
1346+ parser->mark.line ++;
1347+ }
1348+
1349+ /* Reset the indentation level. */
1350+
1351+ if (!yaml_parser_unroll_indent(parser, -1))
1352+ return 0;
1353+
1354+ /* Reset simple keys. */
1355+
1356+ if (!yaml_parser_remove_simple_key(parser))
1357+ return 0;
1358+
1359+ parser->simple_key_allowed = 0;
1360+
1361+ /* Create the STREAM-END token and append it to the queue. */
1362+
1363+ STREAM_END_TOKEN_INIT(token, parser->mark, parser->mark);
1364+
1365+ if (!ENQUEUE(parser, parser->tokens, token))
1366+ return 0;
1367+
1368+ return 1;
1369+}
1370+
1371+/*
1372+ * Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token.
1373+ */
1374+
1375+static int
1376+yaml_parser_fetch_directive(yaml_parser_t *parser)
1377+{
1378+ yaml_token_t token;
1379+
1380+ /* Reset the indentation level. */
1381+
1382+ if (!yaml_parser_unroll_indent(parser, -1))
1383+ return 0;
1384+
1385+ /* Reset simple keys. */
1386+
1387+ if (!yaml_parser_remove_simple_key(parser))
1388+ return 0;
1389+
1390+ parser->simple_key_allowed = 0;
1391+
1392+ /* Create the YAML-DIRECTIVE or TAG-DIRECTIVE token. */
1393+
1394+ if (!yaml_parser_scan_directive(parser, &token))
1395+ return 0;
1396+
1397+ /* Append the token to the queue. */
1398+
1399+ if (!ENQUEUE(parser, parser->tokens, token)) {
1400+ yaml_token_delete(&token);
1401+ return 0;
1402+ }
1403+
1404+ return 1;
1405+}
1406+
1407+/*
1408+ * Produce the DOCUMENT-START or DOCUMENT-END token.
1409+ */
1410+
1411+static int
1412+yaml_parser_fetch_document_indicator(yaml_parser_t *parser,
1413+ yaml_token_type_t type)
1414+{
1415+ yaml_mark_t start_mark, end_mark;
1416+ yaml_token_t token;
1417+
1418+ /* Reset the indentation level. */
1419+
1420+ if (!yaml_parser_unroll_indent(parser, -1))
1421+ return 0;
1422+
1423+ /* Reset simple keys. */
1424+
1425+ if (!yaml_parser_remove_simple_key(parser))
1426+ return 0;
1427+
1428+ parser->simple_key_allowed = 0;
1429+
1430+ /* Consume the token. */
1431+
1432+ start_mark = parser->mark;
1433+
1434+ SKIP(parser);
1435+ SKIP(parser);
1436+ SKIP(parser);
1437+
1438+ end_mark = parser->mark;
1439+
1440+ /* Create the DOCUMENT-START or DOCUMENT-END token. */
1441+
1442+ TOKEN_INIT(token, type, start_mark, end_mark);
1443+
1444+ /* Append the token to the queue. */
1445+
1446+ if (!ENQUEUE(parser, parser->tokens, token))
1447+ return 0;
1448+
1449+ return 1;
1450+}
1451+
1452+/*
1453+ * Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token.
1454+ */
1455+
1456+static int
1457+yaml_parser_fetch_flow_collection_start(yaml_parser_t *parser,
1458+ yaml_token_type_t type)
1459+{
1460+ yaml_mark_t start_mark, end_mark;
1461+ yaml_token_t token;
1462+
1463+ /* The indicators '[' and '{' may start a simple key. */
1464+
1465+ if (!yaml_parser_save_simple_key(parser))
1466+ return 0;
1467+
1468+ /* Increase the flow level. */
1469+
1470+ if (!yaml_parser_increase_flow_level(parser))
1471+ return 0;
1472+
1473+ /* A simple key may follow the indicators '[' and '{'. */
1474+
1475+ parser->simple_key_allowed = 1;
1476+
1477+ /* Consume the token. */
1478+
1479+ start_mark = parser->mark;
1480+ SKIP(parser);
1481+ end_mark = parser->mark;
1482+
1483+ /* Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token. */
1484+
1485+ TOKEN_INIT(token, type, start_mark, end_mark);
1486+
1487+ /* Append the token to the queue. */
1488+
1489+ if (!ENQUEUE(parser, parser->tokens, token))
1490+ return 0;
1491+
1492+ return 1;
1493+}
1494+
1495+/*
1496+ * Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token.
1497+ */
1498+
1499+static int
1500+yaml_parser_fetch_flow_collection_end(yaml_parser_t *parser,
1501+ yaml_token_type_t type)
1502+{
1503+ yaml_mark_t start_mark, end_mark;
1504+ yaml_token_t token;
1505+
1506+ /* Reset any potential simple key on the current flow level. */
1507+
1508+ if (!yaml_parser_remove_simple_key(parser))
1509+ return 0;
1510+
1511+ /* Decrease the flow level. */
1512+
1513+ if (!yaml_parser_decrease_flow_level(parser))
1514+ return 0;
1515+
1516+ /* No simple keys after the indicators ']' and '}'. */
1517+
1518+ parser->simple_key_allowed = 0;
1519+
1520+ /* Consume the token. */
1521+
1522+ start_mark = parser->mark;
1523+ SKIP(parser);
1524+ end_mark = parser->mark;
1525+
1526+ /* Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token. */
1527+
1528+ TOKEN_INIT(token, type, start_mark, end_mark);
1529+
1530+ /* Append the token to the queue. */
1531+
1532+ if (!ENQUEUE(parser, parser->tokens, token))
1533+ return 0;
1534+
1535+ return 1;
1536+}
1537+
1538+/*
1539+ * Produce the FLOW-ENTRY token.
1540+ */
1541+
1542+static int
1543+yaml_parser_fetch_flow_entry(yaml_parser_t *parser)
1544+{
1545+ yaml_mark_t start_mark, end_mark;
1546+ yaml_token_t token;
1547+
1548+ /* Reset any potential simple keys on the current flow level. */
1549+
1550+ if (!yaml_parser_remove_simple_key(parser))
1551+ return 0;
1552+
1553+ /* Simple keys are allowed after ','. */
1554+
1555+ parser->simple_key_allowed = 1;
1556+
1557+ /* Consume the token. */
1558+
1559+ start_mark = parser->mark;
1560+ SKIP(parser);
1561+ end_mark = parser->mark;
1562+
1563+ /* Create the FLOW-ENTRY token and append it to the queue. */
1564+
1565+ TOKEN_INIT(token, YAML_FLOW_ENTRY_TOKEN, start_mark, end_mark);
1566+
1567+ if (!ENQUEUE(parser, parser->tokens, token))
1568+ return 0;
1569+
1570+ return 1;
1571+}
1572+
1573+/*
1574+ * Produce the BLOCK-ENTRY token.
1575+ */
1576+
1577+static int
1578+yaml_parser_fetch_block_entry(yaml_parser_t *parser)
1579+{
1580+ yaml_mark_t start_mark, end_mark;
1581+ yaml_token_t token;
1582+
1583+ /* Check if the scanner is in the block context. */
1584+
1585+ if (!parser->flow_level)
1586+ {
1587+ /* Check if we are allowed to start a new entry. */
1588+
1589+ if (!parser->simple_key_allowed) {
1590+ return yaml_parser_set_scanner_error(parser, NULL, parser->mark,
1591+ "block sequence entries are not allowed in this context");
1592+ }
1593+
1594+ /* Add the BLOCK-SEQUENCE-START token if needed. */
1595+
1596+ if (!yaml_parser_roll_indent(parser, parser->mark.column, -1,
1597+ YAML_BLOCK_SEQUENCE_START_TOKEN, parser->mark))
1598+ return 0;
1599+ }
1600+ else
1601+ {
1602+ /*
1603+ * It is an error for the '-' indicator to occur in the flow context,
1604+ * but we let the Parser detect and report about it because the Parser
1605+ * is able to point to the context.
1606+ */
1607+ }
1608+
1609+ /* Reset any potential simple keys on the current flow level. */
1610+
1611+ if (!yaml_parser_remove_simple_key(parser))
1612+ return 0;
1613+
1614+ /* Simple keys are allowed after '-'. */
1615+
1616+ parser->simple_key_allowed = 1;
1617+
1618+ /* Consume the token. */
1619+
1620+ start_mark = parser->mark;
1621+ SKIP(parser);
1622+ end_mark = parser->mark;
1623+
1624+ /* Create the BLOCK-ENTRY token and append it to the queue. */
1625+
1626+ TOKEN_INIT(token, YAML_BLOCK_ENTRY_TOKEN, start_mark, end_mark);
1627+
1628+ if (!ENQUEUE(parser, parser->tokens, token))
1629+ return 0;
1630+
1631+ return 1;
1632+}
1633+
1634+/*
1635+ * Produce the KEY token.
1636+ */
1637+
1638+static int
1639+yaml_parser_fetch_key(yaml_parser_t *parser)
1640+{
1641+ yaml_mark_t start_mark, end_mark;
1642+ yaml_token_t token;
1643+
1644+ /* In the block context, additional checks are required. */
1645+
1646+ if (!parser->flow_level)
1647+ {
1648+ /* Check if we are allowed to start a new key (not nessesary simple). */
1649+
1650+ if (!parser->simple_key_allowed) {
1651+ return yaml_parser_set_scanner_error(parser, NULL, parser->mark,
1652+ "mapping keys are not allowed in this context");
1653+ }
1654+
1655+ /* Add the BLOCK-MAPPING-START token if needed. */
1656+
1657+ if (!yaml_parser_roll_indent(parser, parser->mark.column, -1,
1658+ YAML_BLOCK_MAPPING_START_TOKEN, parser->mark))
1659+ return 0;
1660+ }
1661+
1662+ /* Reset any potential simple keys on the current flow level. */
1663+
1664+ if (!yaml_parser_remove_simple_key(parser))
1665+ return 0;
1666+
1667+ /* Simple keys are allowed after '?' in the block context. */
1668+
1669+ parser->simple_key_allowed = (!parser->flow_level);
1670+
1671+ /* Consume the token. */
1672+
1673+ start_mark = parser->mark;
1674+ SKIP(parser);
1675+ end_mark = parser->mark;
1676+
1677+ /* Create the KEY token and append it to the queue. */
1678+
1679+ TOKEN_INIT(token, YAML_KEY_TOKEN, start_mark, end_mark);
1680+
1681+ if (!ENQUEUE(parser, parser->tokens, token))
1682+ return 0;
1683+
1684+ return 1;
1685+}
1686+
1687+/*
1688+ * Produce the VALUE token.
1689+ */
1690+
1691+static int
1692+yaml_parser_fetch_value(yaml_parser_t *parser)
1693+{
1694+ yaml_mark_t start_mark, end_mark;
1695+ yaml_token_t token;
1696+ yaml_simple_key_t *simple_key = parser->simple_keys.top-1;
1697+
1698+ /* Have we found a simple key? */
1699+
1700+ if (simple_key->possible)
1701+ {
1702+
1703+ /* Create the KEY token and insert it into the queue. */
1704+
1705+ TOKEN_INIT(token, YAML_KEY_TOKEN, simple_key->mark, simple_key->mark);
1706+
1707+ if (!QUEUE_INSERT(parser, parser->tokens,
1708+ simple_key->token_number - parser->tokens_parsed, token))
1709+ return 0;
1710+
1711+ /* In the block context, we may need to add the BLOCK-MAPPING-START token. */
1712+
1713+ if (!yaml_parser_roll_indent(parser, simple_key->mark.column,
1714+ simple_key->token_number,
1715+ YAML_BLOCK_MAPPING_START_TOKEN, simple_key->mark))
1716+ return 0;
1717+
1718+ /* Remove the simple key. */
1719+
1720+ simple_key->possible = 0;
1721+
1722+ /* A simple key cannot follow another simple key. */
1723+
1724+ parser->simple_key_allowed = 0;
1725+ }
1726+ else
1727+ {
1728+ /* The ':' indicator follows a complex key. */
1729+
1730+ /* In the block context, extra checks are required. */
1731+
1732+ if (!parser->flow_level)
1733+ {
1734+ /* Check if we are allowed to start a complex value. */
1735+
1736+ if (!parser->simple_key_allowed) {
1737+ return yaml_parser_set_scanner_error(parser, NULL, parser->mark,
1738+ "mapping values are not allowed in this context");
1739+ }
1740+
1741+ /* Add the BLOCK-MAPPING-START token if needed. */
1742+
1743+ if (!yaml_parser_roll_indent(parser, parser->mark.column, -1,
1744+ YAML_BLOCK_MAPPING_START_TOKEN, parser->mark))
1745+ return 0;
1746+ }
1747+
1748+ /* Simple keys after ':' are allowed in the block context. */
1749+
1750+ parser->simple_key_allowed = (!parser->flow_level);
1751+ }
1752+
1753+ /* Consume the token. */
1754+
1755+ start_mark = parser->mark;
1756+ SKIP(parser);
1757+ end_mark = parser->mark;
1758+
1759+ /* Create the VALUE token and append it to the queue. */
1760+
1761+ TOKEN_INIT(token, YAML_VALUE_TOKEN, start_mark, end_mark);
1762+
1763+ if (!ENQUEUE(parser, parser->tokens, token))
1764+ return 0;
1765+
1766+ return 1;
1767+}
1768+
1769+/*
1770+ * Produce the ALIAS or ANCHOR token.
1771+ */
1772+
1773+static int
1774+yaml_parser_fetch_anchor(yaml_parser_t *parser, yaml_token_type_t type)
1775+{
1776+ yaml_token_t token;
1777+
1778+ /* An anchor or an alias could be a simple key. */
1779+
1780+ if (!yaml_parser_save_simple_key(parser))
1781+ return 0;
1782+
1783+ /* A simple key cannot follow an anchor or an alias. */
1784+
1785+ parser->simple_key_allowed = 0;
1786+
1787+ /* Create the ALIAS or ANCHOR token and append it to the queue. */
1788+
1789+ if (!yaml_parser_scan_anchor(parser, &token, type))
1790+ return 0;
1791+
1792+ if (!ENQUEUE(parser, parser->tokens, token)) {
1793+ yaml_token_delete(&token);
1794+ return 0;
1795+ }
1796+ return 1;
1797+}
1798+
1799+/*
1800+ * Produce the TAG token.
1801+ */
1802+
1803+static int
1804+yaml_parser_fetch_tag(yaml_parser_t *parser)
1805+{
1806+ yaml_token_t token;
1807+
1808+ /* A tag could be a simple key. */
1809+
1810+ if (!yaml_parser_save_simple_key(parser))
1811+ return 0;
1812+
1813+ /* A simple key cannot follow a tag. */
1814+
1815+ parser->simple_key_allowed = 0;
1816+
1817+ /* Create the TAG token and append it to the queue. */
1818+
1819+ if (!yaml_parser_scan_tag(parser, &token))
1820+ return 0;
1821+
1822+ if (!ENQUEUE(parser, parser->tokens, token)) {
1823+ yaml_token_delete(&token);
1824+ return 0;
1825+ }
1826+
1827+ return 1;
1828+}
1829+
1830+/*
1831+ * Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens.
1832+ */
1833+
1834+static int
1835+yaml_parser_fetch_block_scalar(yaml_parser_t *parser, int literal)
1836+{
1837+ yaml_token_t token;
1838+
1839+ /* Remove any potential simple keys. */
1840+
1841+ if (!yaml_parser_remove_simple_key(parser))
1842+ return 0;
1843+
1844+ /* A simple key may follow a block scalar. */
1845+
1846+ parser->simple_key_allowed = 1;
1847+
1848+ /* Create the SCALAR token and append it to the queue. */
1849+
1850+ if (!yaml_parser_scan_block_scalar(parser, &token, literal))
1851+ return 0;
1852+
1853+ if (!ENQUEUE(parser, parser->tokens, token)) {
1854+ yaml_token_delete(&token);
1855+ return 0;
1856+ }
1857+
1858+ return 1;
1859+}
1860+
1861+/*
1862+ * Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens.
1863+ */
1864+
1865+static int
1866+yaml_parser_fetch_flow_scalar(yaml_parser_t *parser, int single)
1867+{
1868+ yaml_token_t token;
1869+
1870+ /* A plain scalar could be a simple key. */
1871+
1872+ if (!yaml_parser_save_simple_key(parser))
1873+ return 0;
1874+
1875+ /* A simple key cannot follow a flow scalar. */
1876+
1877+ parser->simple_key_allowed = 0;
1878+
1879+ /* Create the SCALAR token and append it to the queue. */
1880+
1881+ if (!yaml_parser_scan_flow_scalar(parser, &token, single))
1882+ return 0;
1883+
1884+ if (!ENQUEUE(parser, parser->tokens, token)) {
1885+ yaml_token_delete(&token);
1886+ return 0;
1887+ }
1888+
1889+ return 1;
1890+}
1891+
1892+/*
1893+ * Produce the SCALAR(...,plain) token.
1894+ */
1895+
1896+static int
1897+yaml_parser_fetch_plain_scalar(yaml_parser_t *parser)
1898+{
1899+ yaml_token_t token;
1900+
1901+ /* A plain scalar could be a simple key. */
1902+
1903+ if (!yaml_parser_save_simple_key(parser))
1904+ return 0;
1905+
1906+ /* A simple key cannot follow a flow scalar. */
1907+
1908+ parser->simple_key_allowed = 0;
1909+
1910+ /* Create the SCALAR token and append it to the queue. */
1911+
1912+ if (!yaml_parser_scan_plain_scalar(parser, &token))
1913+ return 0;
1914+
1915+ if (!ENQUEUE(parser, parser->tokens, token)) {
1916+ yaml_token_delete(&token);
1917+ return 0;
1918+ }
1919+
1920+ return 1;
1921+}
1922+
1923+/*
1924+ * Eat whitespaces and comments until the next token is found.
1925+ */
1926+
1927+static int
1928+yaml_parser_scan_to_next_token(yaml_parser_t *parser)
1929+{
1930+ /* Until the next token is not found. */
1931+
1932+ while (1)
1933+ {
1934+ /* Allow the BOM mark to start a line. */
1935+
1936+ if (!CACHE(parser, 1)) return 0;
1937+
1938+ if (parser->mark.column == 0 && IS_BOM(parser->buffer))
1939+ SKIP(parser);
1940+
1941+ /*
1942+ * Eat whitespaces.
1943+ *
1944+ * Tabs are allowed:
1945+ *
1946+ * - in the flow context;
1947+ * - in the block context, but not at the beginning of the line or
1948+ * after '-', '?', or ':' (complex value).
1949+ */
1950+
1951+ if (!CACHE(parser, 1)) return 0;
1952+
1953+ while (CHECK(parser->buffer,' ') ||
1954+ ((parser->flow_level || !parser->simple_key_allowed) &&
1955+ CHECK(parser->buffer, '\t'))) {
1956+ SKIP(parser);
1957+ if (!CACHE(parser, 1)) return 0;
1958+ }
1959+
1960+ /* Eat a comment until a line break. */
1961+
1962+ if (CHECK(parser->buffer, '#')) {
1963+ while (!IS_BREAKZ(parser->buffer)) {
1964+ SKIP(parser);
1965+ if (!CACHE(parser, 1)) return 0;
1966+ }
1967+ }
1968+
1969+ /* If it is a line break, eat it. */
1970+
1971+ if (IS_BREAK(parser->buffer))
1972+ {
1973+ if (!CACHE(parser, 2)) return 0;
1974+ SKIP_LINE(parser);
1975+
1976+ /* In the block context, a new line may start a simple key. */
1977+
1978+ if (!parser->flow_level) {
1979+ parser->simple_key_allowed = 1;
1980+ }
1981+ }
1982+ else
1983+ {
1984+ /* We have found a token. */
1985+
1986+ break;
1987+ }
1988+ }
1989+
1990+ return 1;
1991+}
1992+
1993+/*
1994+ * Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token.
1995+ *
1996+ * Scope:
1997+ * %YAML 1.1 # a comment \n
1998+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1999+ * %TAG !yaml! tag:yaml.org,2002: \n
2000+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2001+ */
2002+
2003+int
2004+yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token)
2005+{
2006+ yaml_mark_t start_mark, end_mark;
2007+ yaml_char_t *name = NULL;
2008+ int major, minor;
2009+ yaml_char_t *handle = NULL, *prefix = NULL;
2010+
2011+ /* Eat '%'. */
2012+
2013+ start_mark = parser->mark;
2014+
2015+ SKIP(parser);
2016+
2017+ /* Scan the directive name. */
2018+
2019+ if (!yaml_parser_scan_directive_name(parser, start_mark, &name))
2020+ goto error;
2021+
2022+ /* Is it a YAML directive? */
2023+
2024+ if (strcmp((char *)name, "YAML") == 0)
2025+ {
2026+ /* Scan the VERSION directive value. */
2027+
2028+ if (!yaml_parser_scan_version_directive_value(parser, start_mark,
2029+ &major, &minor))
2030+ goto error;
2031+
2032+ end_mark = parser->mark;
2033+
2034+ /* Create a VERSION-DIRECTIVE token. */
2035+
2036+ VERSION_DIRECTIVE_TOKEN_INIT(*token, major, minor,
2037+ start_mark, end_mark);
2038+ }
2039+
2040+ /* Is it a TAG directive? */
2041+
2042+ else if (strcmp((char *)name, "TAG") == 0)
2043+ {
2044+ /* Scan the TAG directive value. */
2045+
2046+ if (!yaml_parser_scan_tag_directive_value(parser, start_mark,
2047+ &handle, &prefix))
2048+ goto error;
2049+
2050+ end_mark = parser->mark;
2051+
2052+ /* Create a TAG-DIRECTIVE token. */
2053+
2054+ TAG_DIRECTIVE_TOKEN_INIT(*token, handle, prefix,
2055+ start_mark, end_mark);
2056+ }
2057+
2058+ /* Unknown directive. */
2059+
2060+ else
2061+ {
2062+ yaml_parser_set_scanner_error(parser, "while scanning a directive",
2063+ start_mark, "found uknown directive name");
2064+ goto error;
2065+ }
2066+
2067+ /* Eat the rest of the line including any comments. */
2068+
2069+ if (!CACHE(parser, 1)) goto error;
2070+
2071+ while (IS_BLANK(parser->buffer)) {
2072+ SKIP(parser);
2073+ if (!CACHE(parser, 1)) goto error;
2074+ }
2075+
2076+ if (CHECK(parser->buffer, '#')) {
2077+ while (!IS_BREAKZ(parser->buffer)) {
2078+ SKIP(parser);
2079+ if (!CACHE(parser, 1)) goto error;
2080+ }
2081+ }
2082+
2083+ /* Check if we are at the end of the line. */
2084+
2085+ if (!IS_BREAKZ(parser->buffer)) {
2086+ yaml_parser_set_scanner_error(parser, "while scanning a directive",
2087+ start_mark, "did not find expected comment or line break");
2088+ goto error;
2089+ }
2090+
2091+ /* Eat a line break. */
2092+
2093+ if (IS_BREAK(parser->buffer)) {
2094+ if (!CACHE(parser, 2)) goto error;
2095+ SKIP_LINE(parser);
2096+ }
2097+
2098+ yaml_free(name);
2099+
2100+ return 1;
2101+
2102+error:
2103+ yaml_free(prefix);
2104+ yaml_free(handle);
2105+ yaml_free(name);
2106+ return 0;
2107+}
2108+
2109+/*
2110+ * Scan the directive name.
2111+ *
2112+ * Scope:
2113+ * %YAML 1.1 # a comment \n
2114+ * ^^^^
2115+ * %TAG !yaml! tag:yaml.org,2002: \n
2116+ * ^^^
2117+ */
2118+
2119+static int
2120+yaml_parser_scan_directive_name(yaml_parser_t *parser,
2121+ yaml_mark_t start_mark, yaml_char_t **name)
2122+{
2123+ yaml_string_t string = NULL_STRING;
2124+
2125+ if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
2126+
2127+ /* Consume the directive name. */
2128+
2129+ if (!CACHE(parser, 1)) goto error;
2130+
2131+ while (IS_ALPHA(parser->buffer))
2132+ {
2133+ if (!READ(parser, string)) goto error;
2134+ if (!CACHE(parser, 1)) goto error;
2135+ }
2136+
2137+ /* Check if the name is empty. */
2138+
2139+ if (string.start == string.pointer) {
2140+ yaml_parser_set_scanner_error(parser, "while scanning a directive",
2141+ start_mark, "could not find expected directive name");
2142+ goto error;
2143+ }
2144+
2145+ /* Check for an blank character after the name. */
2146+
2147+ if (!IS_BLANKZ(parser->buffer)) {
2148+ yaml_parser_set_scanner_error(parser, "while scanning a directive",
2149+ start_mark, "found unexpected non-alphabetical character");
2150+ goto error;
2151+ }
2152+
2153+ *name = string.start;
2154+
2155+ return 1;
2156+
2157+error:
2158+ STRING_DEL(parser, string);
2159+ return 0;
2160+}
2161+
2162+/*
2163+ * Scan the value of VERSION-DIRECTIVE.
2164+ *
2165+ * Scope:
2166+ * %YAML 1.1 # a comment \n
2167+ * ^^^^^^
2168+ */
2169+
2170+static int
2171+yaml_parser_scan_version_directive_value(yaml_parser_t *parser,
2172+ yaml_mark_t start_mark, int *major, int *minor)
2173+{
2174+ /* Eat whitespaces. */
2175+
2176+ if (!CACHE(parser, 1)) return 0;
2177+
2178+ while (IS_BLANK(parser->buffer)) {
2179+ SKIP(parser);
2180+ if (!CACHE(parser, 1)) return 0;
2181+ }
2182+
2183+ /* Consume the major version number. */
2184+
2185+ if (!yaml_parser_scan_version_directive_number(parser, start_mark, major))
2186+ return 0;
2187+
2188+ /* Eat '.'. */
2189+
2190+ if (!CHECK(parser->buffer, '.')) {
2191+ return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
2192+ start_mark, "did not find expected digit or '.' character");
2193+ }
2194+
2195+ SKIP(parser);
2196+
2197+ /* Consume the minor version number. */
2198+
2199+ if (!yaml_parser_scan_version_directive_number(parser, start_mark, minor))
2200+ return 0;
2201+
2202+ return 1;
2203+}
2204+
2205+#define MAX_NUMBER_LENGTH 9
2206+
2207+/*
2208+ * Scan the version number of VERSION-DIRECTIVE.
2209+ *
2210+ * Scope:
2211+ * %YAML 1.1 # a comment \n
2212+ * ^
2213+ * %YAML 1.1 # a comment \n
2214+ * ^
2215+ */
2216+
2217+static int
2218+yaml_parser_scan_version_directive_number(yaml_parser_t *parser,
2219+ yaml_mark_t start_mark, int *number)
2220+{
2221+ int value = 0;
2222+ size_t length = 0;
2223+
2224+ /* Repeat while the next character is digit. */
2225+
2226+ if (!CACHE(parser, 1)) return 0;
2227+
2228+ while (IS_DIGIT(parser->buffer))
2229+ {
2230+ /* Check if the number is too long. */
2231+
2232+ if (++length > MAX_NUMBER_LENGTH) {
2233+ return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
2234+ start_mark, "found extremely long version number");
2235+ }
2236+
2237+ value = value*10 + AS_DIGIT(parser->buffer);
2238+
2239+ SKIP(parser);
2240+
2241+ if (!CACHE(parser, 1)) return 0;
2242+ }
2243+
2244+ /* Check if the number was present. */
2245+
2246+ if (!length) {
2247+ return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
2248+ start_mark, "did not find expected version number");
2249+ }
2250+
2251+ *number = value;
2252+
2253+ return 1;
2254+}
2255+
2256+/*
2257+ * Scan the value of a TAG-DIRECTIVE token.
2258+ *
2259+ * Scope:
2260+ * %TAG !yaml! tag:yaml.org,2002: \n
2261+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2262+ */
2263+
2264+static int
2265+yaml_parser_scan_tag_directive_value(yaml_parser_t *parser,
2266+ yaml_mark_t start_mark, yaml_char_t **handle, yaml_char_t **prefix)
2267+{
2268+ yaml_char_t *handle_value = NULL;
2269+ yaml_char_t *prefix_value = NULL;
2270+
2271+ /* Eat whitespaces. */
2272+
2273+ if (!CACHE(parser, 1)) goto error;
2274+
2275+ while (IS_BLANK(parser->buffer)) {
2276+ SKIP(parser);
2277+ if (!CACHE(parser, 1)) goto error;
2278+ }
2279+
2280+ /* Scan a handle. */
2281+
2282+ if (!yaml_parser_scan_tag_handle(parser, 1, start_mark, &handle_value))
2283+ goto error;
2284+
2285+ /* Expect a whitespace. */
2286+
2287+ if (!CACHE(parser, 1)) goto error;
2288+
2289+ if (!IS_BLANK(parser->buffer)) {
2290+ yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
2291+ start_mark, "did not find expected whitespace");
2292+ goto error;
2293+ }
2294+
2295+ /* Eat whitespaces. */
2296+
2297+ while (IS_BLANK(parser->buffer)) {
2298+ SKIP(parser);
2299+ if (!CACHE(parser, 1)) goto error;
2300+ }
2301+
2302+ /* Scan a prefix. */
2303+
2304+ if (!yaml_parser_scan_tag_uri(parser, 1, NULL, start_mark, &prefix_value))
2305+ goto error;
2306+
2307+ /* Expect a whitespace or line break. */
2308+
2309+ if (!CACHE(parser, 1)) goto error;
2310+
2311+ if (!IS_BLANKZ(parser->buffer)) {
2312+ yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
2313+ start_mark, "did not find expected whitespace or line break");
2314+ goto error;
2315+ }
2316+
2317+ *handle = handle_value;
2318+ *prefix = prefix_value;
2319+
2320+ return 1;
2321+
2322+error:
2323+ yaml_free(handle_value);
2324+ yaml_free(prefix_value);
2325+ return 0;
2326+}
2327+
2328+static int
2329+yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token,
2330+ yaml_token_type_t type)
2331+{
2332+ int length = 0;
2333+ yaml_mark_t start_mark, end_mark;
2334+ yaml_string_t string = NULL_STRING;
2335+
2336+ if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
2337+
2338+ /* Eat the indicator character. */
2339+
2340+ start_mark = parser->mark;
2341+
2342+ SKIP(parser);
2343+
2344+ /* Consume the value. */
2345+
2346+ if (!CACHE(parser, 1)) goto error;
2347+
2348+ while (IS_ALPHA(parser->buffer)) {
2349+ if (!READ(parser, string)) goto error;
2350+ if (!CACHE(parser, 1)) goto error;
2351+ length ++;
2352+ }
2353+
2354+ end_mark = parser->mark;
2355+
2356+ /*
2357+ * Check if length of the anchor is greater than 0 and it is followed by
2358+ * a whitespace character or one of the indicators:
2359+ *
2360+ * '?', ':', ',', ']', '}', '%', '@', '`'.
2361+ */
2362+
2363+ if (!length || !(IS_BLANKZ(parser->buffer) || CHECK(parser->buffer, '?')
2364+ || CHECK(parser->buffer, ':') || CHECK(parser->buffer, ',')
2365+ || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '}')
2366+ || CHECK(parser->buffer, '%') || CHECK(parser->buffer, '@')
2367+ || CHECK(parser->buffer, '`'))) {
2368+ yaml_parser_set_scanner_error(parser, type == YAML_ANCHOR_TOKEN ?
2369+ "while scanning an anchor" : "while scanning an alias", start_mark,
2370+ "did not find expected alphabetic or numeric character");
2371+ goto error;
2372+ }
2373+
2374+ /* Create a token. */
2375+
2376+ if (type == YAML_ANCHOR_TOKEN) {
2377+ ANCHOR_TOKEN_INIT(*token, string.start, start_mark, end_mark);
2378+ }
2379+ else {
2380+ ALIAS_TOKEN_INIT(*token, string.start, start_mark, end_mark);
2381+ }
2382+
2383+ return 1;
2384+
2385+error:
2386+ STRING_DEL(parser, string);
2387+ return 0;
2388+}
2389+
2390+/*
2391+ * Scan a TAG token.
2392+ */
2393+
2394+static int
2395+yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token)
2396+{
2397+ yaml_char_t *handle = NULL;
2398+ yaml_char_t *suffix = NULL;
2399+ yaml_mark_t start_mark, end_mark;
2400+
2401+ start_mark = parser->mark;
2402+
2403+ /* Check if the tag is in the canonical form. */
2404+
2405+ if (!CACHE(parser, 2)) goto error;
2406+
2407+ if (CHECK_AT(parser->buffer, '<', 1))
2408+ {
2409+ /* Set the handle to '' */
2410+
2411+ handle = yaml_malloc(1);
2412+ if (!handle) goto error;
2413+ handle[0] = '\0';
2414+
2415+ /* Eat '!<' */
2416+
2417+ SKIP(parser);
2418+ SKIP(parser);
2419+
2420+ /* Consume the tag value. */
2421+
2422+ if (!yaml_parser_scan_tag_uri(parser, 0, NULL, start_mark, &suffix))
2423+ goto error;
2424+
2425+ /* Check for '>' and eat it. */
2426+
2427+ if (!CHECK(parser->buffer, '>')) {
2428+ yaml_parser_set_scanner_error(parser, "while scanning a tag",
2429+ start_mark, "did not find the expected '>'");
2430+ goto error;
2431+ }
2432+
2433+ SKIP(parser);
2434+ }
2435+ else
2436+ {
2437+ /* The tag has either the '!suffix' or the '!handle!suffix' form. */
2438+
2439+ /* First, try to scan a handle. */
2440+
2441+ if (!yaml_parser_scan_tag_handle(parser, 0, start_mark, &handle))
2442+ goto error;
2443+
2444+ /* Check if it is, indeed, handle. */
2445+
2446+ if (handle[0] == '!' && handle[1] != '\0' && handle[strlen((char *)handle)-1] == '!')
2447+ {
2448+ /* Scan the suffix now. */
2449+
2450+ if (!yaml_parser_scan_tag_uri(parser, 0, NULL, start_mark, &suffix))
2451+ goto error;
2452+ }
2453+ else
2454+ {
2455+ /* It wasn't a handle after all. Scan the rest of the tag. */
2456+
2457+ if (!yaml_parser_scan_tag_uri(parser, 0, handle, start_mark, &suffix))
2458+ goto error;
2459+
2460+ /* Set the handle to '!'. */
2461+
2462+ yaml_free(handle);
2463+ handle = yaml_malloc(2);
2464+ if (!handle) goto error;
2465+ handle[0] = '!';
2466+ handle[1] = '\0';
2467+
2468+ /*
2469+ * A special case: the '!' tag. Set the handle to '' and the
2470+ * suffix to '!'.
2471+ */
2472+
2473+ if (suffix[0] == '\0') {
2474+ yaml_char_t *tmp = handle;
2475+ handle = suffix;
2476+ suffix = tmp;
2477+ }
2478+ }
2479+ }
2480+
2481+ /* Check the character which ends the tag. */
2482+
2483+ if (!CACHE(parser, 1)) goto error;
2484+
2485+ if (!IS_BLANKZ(parser->buffer)) {
2486+ yaml_parser_set_scanner_error(parser, "while scanning a tag",
2487+ start_mark, "did not find expected whitespace or line break");
2488+ goto error;
2489+ }
2490+
2491+ end_mark = parser->mark;
2492+
2493+ /* Create a token. */
2494+
2495+ TAG_TOKEN_INIT(*token, handle, suffix, start_mark, end_mark);
2496+
2497+ return 1;
2498+
2499+error:
2500+ yaml_free(handle);
2501+ yaml_free(suffix);
2502+ return 0;
2503+}
2504+
2505+/*
2506+ * Scan a tag handle.
2507+ */
2508+
2509+static int
2510+yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive,
2511+ yaml_mark_t start_mark, yaml_char_t **handle)
2512+{
2513+ yaml_string_t string = NULL_STRING;
2514+
2515+ if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
2516+
2517+ /* Check the initial '!' character. */
2518+
2519+ if (!CACHE(parser, 1)) goto error;
2520+
2521+ if (!CHECK(parser->buffer, '!')) {
2522+ yaml_parser_set_scanner_error(parser, directive ?
2523+ "while scanning a tag directive" : "while scanning a tag",
2524+ start_mark, "did not find expected '!'");
2525+ goto error;
2526+ }
2527+
2528+ /* Copy the '!' character. */
2529+
2530+ if (!READ(parser, string)) goto error;
2531+
2532+ /* Copy all subsequent alphabetical and numerical characters. */
2533+
2534+ if (!CACHE(parser, 1)) goto error;
2535+
2536+ while (IS_ALPHA(parser->buffer))
2537+ {
2538+ if (!READ(parser, string)) goto error;
2539+ if (!CACHE(parser, 1)) goto error;
2540+ }
2541+
2542+ /* Check if the trailing character is '!' and copy it. */
2543+
2544+ if (CHECK(parser->buffer, '!'))
2545+ {
2546+ if (!READ(parser, string)) goto error;
2547+ }
2548+ else
2549+ {
2550+ /*
2551+ * It's either the '!' tag or not really a tag handle. If it's a %TAG
2552+ * directive, it's an error. If it's a tag token, it must be a part of
2553+ * URI.
2554+ */
2555+
2556+ if (directive && !(string.start[0] == '!' && string.start[1] == '\0')) {
2557+ yaml_parser_set_scanner_error(parser, "while parsing a tag directive",
2558+ start_mark, "did not find expected '!'");
2559+ goto error;
2560+ }
2561+ }
2562+
2563+ *handle = string.start;
2564+
2565+ return 1;
2566+
2567+error:
2568+ STRING_DEL(parser, string);
2569+ return 0;
2570+}
2571+
2572+/*
2573+ * Scan a tag.
2574+ */
2575+
2576+static int
2577+yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive,
2578+ yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri)
2579+{
2580+ size_t length = head ? strlen((char *)head) : 0;
2581+ yaml_string_t string = NULL_STRING;
2582+
2583+ if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
2584+
2585+ /* Resize the string to include the head. */
2586+
2587+ while ((size_t)(string.end - string.start) <= length) {
2588+ if (!yaml_string_extend(&string.start, &string.pointer, &string.end)) {
2589+ parser->error = YAML_MEMORY_ERROR;
2590+ goto error;
2591+ }
2592+ }
2593+
2594+ /*
2595+ * Copy the head if needed.
2596+ *
2597+ * Note that we don't copy the leading '!' character.
2598+ */
2599+
2600+ if (length > 1) {
2601+ memcpy(string.start, head+1, length-1);
2602+ string.pointer += length-1;
2603+ }
2604+
2605+ /* Scan the tag. */
2606+
2607+ if (!CACHE(parser, 1)) goto error;
2608+
2609+ /*
2610+ * The set of characters that may appear in URI is as follows:
2611+ *
2612+ * '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&',
2613+ * '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']',
2614+ * '%'.
2615+ */
2616+
2617+ while (IS_ALPHA(parser->buffer) || CHECK(parser->buffer, ';')
2618+ || CHECK(parser->buffer, '/') || CHECK(parser->buffer, '?')
2619+ || CHECK(parser->buffer, ':') || CHECK(parser->buffer, '@')
2620+ || CHECK(parser->buffer, '&') || CHECK(parser->buffer, '=')
2621+ || CHECK(parser->buffer, '+') || CHECK(parser->buffer, '$')
2622+ || CHECK(parser->buffer, ',') || CHECK(parser->buffer, '.')
2623+ || CHECK(parser->buffer, '!') || CHECK(parser->buffer, '~')
2624+ || CHECK(parser->buffer, '*') || CHECK(parser->buffer, '\'')
2625+ || CHECK(parser->buffer, '(') || CHECK(parser->buffer, ')')
2626+ || CHECK(parser->buffer, '[') || CHECK(parser->buffer, ']')
2627+ || CHECK(parser->buffer, '%'))
2628+ {
2629+ /* Check if it is a URI-escape sequence. */
2630+
2631+ if (CHECK(parser->buffer, '%')) {
2632+ if (!yaml_parser_scan_uri_escapes(parser,
2633+ directive, start_mark, &string)) goto error;
2634+ }
2635+ else {
2636+ if (!READ(parser, string)) goto error;
2637+ }
2638+
2639+ length ++;
2640+ if (!CACHE(parser, 1)) goto error;
2641+ }
2642+
2643+ /* Check if the tag is non-empty. */
2644+
2645+ if (!length) {
2646+ if (!STRING_EXTEND(parser, string))
2647+ goto error;
2648+
2649+ yaml_parser_set_scanner_error(parser, directive ?
2650+ "while parsing a %TAG directive" : "while parsing a tag",
2651+ start_mark, "did not find expected tag URI");
2652+ goto error;
2653+ }
2654+
2655+ *uri = string.start;
2656+
2657+ return 1;
2658+
2659+error:
2660+ STRING_DEL(parser, string);
2661+ return 0;
2662+}
2663+
2664+/*
2665+ * Decode an URI-escape sequence corresponding to a single UTF-8 character.
2666+ */
2667+
2668+static int
2669+yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive,
2670+ yaml_mark_t start_mark, yaml_string_t *string)
2671+{
2672+ int width = 0;
2673+
2674+ /* Decode the required number of characters. */
2675+
2676+ do {
2677+
2678+ unsigned char octet = 0;
2679+
2680+ /* Check for a URI-escaped octet. */
2681+
2682+ if (!CACHE(parser, 3)) return 0;
2683+
2684+ if (!(CHECK(parser->buffer, '%')
2685+ && IS_HEX_AT(parser->buffer, 1)
2686+ && IS_HEX_AT(parser->buffer, 2))) {
2687+ return yaml_parser_set_scanner_error(parser, directive ?
2688+ "while parsing a %TAG directive" : "while parsing a tag",
2689+ start_mark, "did not find URI escaped octet");
2690+ }
2691+
2692+ /* Get the octet. */
2693+
2694+ octet = (AS_HEX_AT(parser->buffer, 1) << 4) + AS_HEX_AT(parser->buffer, 2);
2695+
2696+ /* If it is the leading octet, determine the length of the UTF-8 sequence. */
2697+
2698+ if (!width)
2699+ {
2700+ width = (octet & 0x80) == 0x00 ? 1 :
2701+ (octet & 0xE0) == 0xC0 ? 2 :
2702+ (octet & 0xF0) == 0xE0 ? 3 :
2703+ (octet & 0xF8) == 0xF0 ? 4 : 0;
2704+ if (!width) {
2705+ return yaml_parser_set_scanner_error(parser, directive ?
2706+ "while parsing a %TAG directive" : "while parsing a tag",
2707+ start_mark, "found an incorrect leading UTF-8 octet");
2708+ }
2709+ }
2710+ else
2711+ {
2712+ /* Check if the trailing octet is correct. */
2713+
2714+ if ((octet & 0xC0) != 0x80) {
2715+ return yaml_parser_set_scanner_error(parser, directive ?
2716+ "while parsing a %TAG directive" : "while parsing a tag",
2717+ start_mark, "found an incorrect trailing UTF-8 octet");
2718+ }
2719+ }
2720+
2721+ /* Copy the octet and move the pointers. */
2722+
2723+ *(string->pointer++) = octet;
2724+ SKIP(parser);
2725+ SKIP(parser);
2726+ SKIP(parser);
2727+
2728+ } while (--width);
2729+
2730+ return 1;
2731+}
2732+
2733+/*
2734+ * Scan a block scalar.
2735+ */
2736+
2737+static int
2738+yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
2739+ int literal)
2740+{
2741+ yaml_mark_t start_mark;
2742+ yaml_mark_t end_mark;
2743+ yaml_string_t string = NULL_STRING;
2744+ yaml_string_t leading_break = NULL_STRING;
2745+ yaml_string_t trailing_breaks = NULL_STRING;
2746+ int chomping = 0;
2747+ int increment = 0;
2748+ int indent = 0;
2749+ int leading_blank = 0;
2750+ int trailing_blank = 0;
2751+
2752+ if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
2753+ if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error;
2754+ if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error;
2755+
2756+ /* Eat the indicator '|' or '>'. */
2757+
2758+ start_mark = parser->mark;
2759+
2760+ SKIP(parser);
2761+
2762+ /* Scan the additional block scalar indicators. */
2763+
2764+ if (!CACHE(parser, 1)) goto error;
2765+
2766+ /* Check for a chomping indicator. */
2767+
2768+ if (CHECK(parser->buffer, '+') || CHECK(parser->buffer, '-'))
2769+ {
2770+ /* Set the chomping method and eat the indicator. */
2771+
2772+ chomping = CHECK(parser->buffer, '+') ? +1 : -1;
2773+
2774+ SKIP(parser);
2775+
2776+ /* Check for an indentation indicator. */
2777+
2778+ if (!CACHE(parser, 1)) goto error;
2779+
2780+ if (IS_DIGIT(parser->buffer))
2781+ {
2782+ /* Check that the intendation is greater than 0. */
2783+
2784+ if (CHECK(parser->buffer, '0')) {
2785+ yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
2786+ start_mark, "found an intendation indicator equal to 0");
2787+ goto error;
2788+ }
2789+
2790+ /* Get the intendation level and eat the indicator. */
2791+
2792+ increment = AS_DIGIT(parser->buffer);
2793+
2794+ SKIP(parser);
2795+ }
2796+ }
2797+
2798+ /* Do the same as above, but in the opposite order. */
2799+
2800+ else if (IS_DIGIT(parser->buffer))
2801+ {
2802+ if (CHECK(parser->buffer, '0')) {
2803+ yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
2804+ start_mark, "found an intendation indicator equal to 0");
2805+ goto error;
2806+ }
2807+
2808+ increment = AS_DIGIT(parser->buffer);
2809+
2810+ SKIP(parser);
2811+
2812+ if (!CACHE(parser, 1)) goto error;
2813+
2814+ if (CHECK(parser->buffer, '+') || CHECK(parser->buffer, '-')) {
2815+ chomping = CHECK(parser->buffer, '+') ? +1 : -1;
2816+
2817+ SKIP(parser);
2818+ }
2819+ }
2820+
2821+ /* Eat whitespaces and comments to the end of the line. */
2822+
2823+ if (!CACHE(parser, 1)) goto error;
2824+
2825+ while (IS_BLANK(parser->buffer)) {
2826+ SKIP(parser);
2827+ if (!CACHE(parser, 1)) goto error;
2828+ }
2829+
2830+ if (CHECK(parser->buffer, '#')) {
2831+ while (!IS_BREAKZ(parser->buffer)) {
2832+ SKIP(parser);
2833+ if (!CACHE(parser, 1)) goto error;
2834+ }
2835+ }
2836+
2837+ /* Check if we are at the end of the line. */
2838+
2839+ if (!IS_BREAKZ(parser->buffer)) {
2840+ yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
2841+ start_mark, "did not find expected comment or line break");
2842+ goto error;
2843+ }
2844+
2845+ /* Eat a line break. */
2846+
2847+ if (IS_BREAK(parser->buffer)) {
2848+ if (!CACHE(parser, 2)) goto error;
2849+ SKIP_LINE(parser);
2850+ }
2851+
2852+ end_mark = parser->mark;
2853+
2854+ /* Set the intendation level if it was specified. */
2855+
2856+ if (increment) {
2857+ indent = parser->indent >= 0 ? parser->indent+increment : increment;
2858+ }
2859+
2860+ /* Scan the leading line breaks and determine the indentation level if needed. */
2861+
2862+ if (!yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks,
2863+ start_mark, &end_mark)) goto error;
2864+
2865+ /* Scan the block scalar content. */
2866+
2867+ if (!CACHE(parser, 1)) goto error;
2868+
2869+ while ((int)parser->mark.column == indent && !IS_Z(parser->buffer))
2870+ {
2871+ /*
2872+ * We are at the beginning of a non-empty line.
2873+ */
2874+
2875+ /* Is it a trailing whitespace? */
2876+
2877+ trailing_blank = IS_BLANK(parser->buffer);
2878+
2879+ /* Check if we need to fold the leading line break. */
2880+
2881+ if (!literal && (*leading_break.start == '\n')
2882+ && !leading_blank && !trailing_blank)
2883+ {
2884+ /* Do we need to join the lines by space? */
2885+
2886+ if (*trailing_breaks.start == '\0') {
2887+ if (!STRING_EXTEND(parser, string)) goto error;
2888+ *(string.pointer ++) = ' ';
2889+ }
2890+
2891+ CLEAR(parser, leading_break);
2892+ }
2893+ else {
2894+ if (!JOIN(parser, string, leading_break)) goto error;
2895+ CLEAR(parser, leading_break);
2896+ }
2897+
2898+ /* Append the remaining line breaks. */
2899+
2900+ if (!JOIN(parser, string, trailing_breaks)) goto error;
2901+ CLEAR(parser, trailing_breaks);
2902+
2903+ /* Is it a leading whitespace? */
2904+
2905+ leading_blank = IS_BLANK(parser->buffer);
2906+
2907+ /* Consume the current line. */
2908+
2909+ while (!IS_BREAKZ(parser->buffer)) {
2910+ if (!READ(parser, string)) goto error;
2911+ if (!CACHE(parser, 1)) goto error;
2912+ }
2913+
2914+ /* Consume the line break. */
2915+
2916+ if (!CACHE(parser, 2)) goto error;
2917+
2918+ if (!READ_LINE(parser, leading_break)) goto error;
2919+
2920+ /* Eat the following intendation spaces and line breaks. */
2921+
2922+ if (!yaml_parser_scan_block_scalar_breaks(parser,
2923+ &indent, &trailing_breaks, start_mark, &end_mark)) goto error;
2924+ }
2925+
2926+ /* Chomp the tail. */
2927+
2928+ if (chomping != -1) {
2929+ if (!JOIN(parser, string, leading_break)) goto error;
2930+ }
2931+ if (chomping == 1) {
2932+ if (!JOIN(parser, string, trailing_breaks)) goto error;
2933+ }
2934+
2935+ /* Create a token. */
2936+
2937+ SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start,
2938+ literal ? YAML_LITERAL_SCALAR_STYLE : YAML_FOLDED_SCALAR_STYLE,
2939+ start_mark, end_mark);
2940+
2941+ STRING_DEL(parser, leading_break);
2942+ STRING_DEL(parser, trailing_breaks);
2943+
2944+ return 1;
2945+
2946+error:
2947+ STRING_DEL(parser, string);
2948+ STRING_DEL(parser, leading_break);
2949+ STRING_DEL(parser, trailing_breaks);
2950+
2951+ return 0;
2952+}
2953+
2954+/*
2955+ * Scan intendation spaces and line breaks for a block scalar. Determine the
2956+ * intendation level if needed.
2957+ */
2958+
2959+static int
2960+yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser,
2961+ int *indent, yaml_string_t *breaks,
2962+ yaml_mark_t start_mark, yaml_mark_t *end_mark)
2963+{
2964+ int max_indent = 0;
2965+
2966+ *end_mark = parser->mark;
2967+
2968+ /* Eat the intendation spaces and line breaks. */
2969+
2970+ while (1)
2971+ {
2972+ /* Eat the intendation spaces. */
2973+
2974+ if (!CACHE(parser, 1)) return 0;
2975+
2976+ while ((!*indent || (int)parser->mark.column < *indent)
2977+ && IS_SPACE(parser->buffer)) {
2978+ SKIP(parser);
2979+ if (!CACHE(parser, 1)) return 0;
2980+ }
2981+
2982+ if ((int)parser->mark.column > max_indent)
2983+ max_indent = (int)parser->mark.column;
2984+
2985+ /* Check for a tab character messing the intendation. */
2986+
2987+ if ((!*indent || (int)parser->mark.column < *indent)
2988+ && IS_TAB(parser->buffer)) {
2989+ return yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
2990+ start_mark, "found a tab character where an intendation space is expected");
2991+ }
2992+
2993+ /* Have we found a non-empty line? */
2994+
2995+ if (!IS_BREAK(parser->buffer)) break;
2996+
2997+ /* Consume the line break. */
2998+
2999+ if (!CACHE(parser, 2)) return 0;
3000+ if (!READ_LINE(parser, *breaks)) return 0;
3001+ *end_mark = parser->mark;
3002+ }
3003+
3004+ /* Determine the indentation level if needed. */
3005+
3006+ if (!*indent) {
3007+ *indent = max_indent;
3008+ if (*indent < parser->indent + 1)
3009+ *indent = parser->indent + 1;
3010+ if (*indent < 1)
3011+ *indent = 1;
3012+ }
3013+
3014+ return 1;
3015+}
3016+
3017+/*
3018+ * Scan a quoted scalar.
3019+ */
3020+
3021+static int
3022+yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token,
3023+ int single)
3024+{
3025+ yaml_mark_t start_mark;
3026+ yaml_mark_t end_mark;
3027+ yaml_string_t string = NULL_STRING;
3028+ yaml_string_t leading_break = NULL_STRING;
3029+ yaml_string_t trailing_breaks = NULL_STRING;
3030+ yaml_string_t whitespaces = NULL_STRING;
3031+ int leading_blanks;
3032+
3033+ if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
3034+ if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error;
3035+ if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error;
3036+ if (!STRING_INIT(parser, whitespaces, INITIAL_STRING_SIZE)) goto error;
3037+
3038+ /* Eat the left quote. */
3039+
3040+ start_mark = parser->mark;
3041+
3042+ SKIP(parser);
3043+
3044+ /* Consume the content of the quoted scalar. */
3045+
3046+ while (1)
3047+ {
3048+ /* Check that there are no document indicators at the beginning of the line. */
3049+
3050+ if (!CACHE(parser, 4)) goto error;
3051+
3052+ if (parser->mark.column == 0 &&
3053+ ((CHECK_AT(parser->buffer, '-', 0) &&
3054+ CHECK_AT(parser->buffer, '-', 1) &&
3055+ CHECK_AT(parser->buffer, '-', 2)) ||
3056+ (CHECK_AT(parser->buffer, '.', 0) &&
3057+ CHECK_AT(parser->buffer, '.', 1) &&
3058+ CHECK_AT(parser->buffer, '.', 2))) &&
3059+ IS_BLANKZ_AT(parser->buffer, 3))
3060+ {
3061+ yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
3062+ start_mark, "found unexpected document indicator");
3063+ goto error;
3064+ }
3065+
3066+ /* Check for EOF. */
3067+
3068+ if (IS_Z(parser->buffer)) {
3069+ yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
3070+ start_mark, "found unexpected end of stream");
3071+ goto error;
3072+ }
3073+
3074+ /* Consume non-blank characters. */
3075+
3076+ if (!CACHE(parser, 2)) goto error;
3077+
3078+ leading_blanks = 0;
3079+
3080+ while (!IS_BLANKZ(parser->buffer))
3081+ {
3082+ /* Check for an escaped single quote. */
3083+
3084+ if (single && CHECK_AT(parser->buffer, '\'', 0)
3085+ && CHECK_AT(parser->buffer, '\'', 1))
3086+ {
3087+ if (!STRING_EXTEND(parser, string)) goto error;
3088+ *(string.pointer++) = '\'';
3089+ SKIP(parser);
3090+ SKIP(parser);
3091+ }
3092+
3093+ /* Check for the right quote. */
3094+
3095+ else if (CHECK(parser->buffer, single ? '\'' : '"'))
3096+ {
3097+ break;
3098+ }
3099+
3100+ /* Check for an escaped line break. */
3101+
3102+ else if (!single && CHECK(parser->buffer, '\\')
3103+ && IS_BREAK_AT(parser->buffer, 1))
3104+ {
3105+ if (!CACHE(parser, 3)) goto error;
3106+ SKIP(parser);
3107+ SKIP_LINE(parser);
3108+ leading_blanks = 1;
3109+ break;
3110+ }
3111+
3112+ /* Check for an escape sequence. */
3113+
3114+ else if (!single && CHECK(parser->buffer, '\\'))
3115+ {
3116+ size_t code_length = 0;
3117+
3118+ if (!STRING_EXTEND(parser, string)) goto error;
3119+
3120+ /* Check the escape character. */
3121+
3122+ switch (parser->buffer.pointer[1])
3123+ {
3124+ case '0':
3125+ *(string.pointer++) = '\0';
3126+ break;
3127+
3128+ case 'a':
3129+ *(string.pointer++) = '\x07';
3130+ break;
3131+
3132+ case 'b':
3133+ *(string.pointer++) = '\x08';
3134+ break;
3135+
3136+ case 't':
3137+ case '\t':
3138+ *(string.pointer++) = '\x09';
3139+ break;
3140+
3141+ case 'n':
3142+ *(string.pointer++) = '\x0A';
3143+ break;
3144+
3145+ case 'v':
3146+ *(string.pointer++) = '\x0B';
3147+ break;
3148+
3149+ case 'f':
3150+ *(string.pointer++) = '\x0C';
3151+ break;
3152+
3153+ case 'r':
3154+ *(string.pointer++) = '\x0D';
3155+ break;
3156+
3157+ case 'e':
3158+ *(string.pointer++) = '\x1B';
3159+ break;
3160+
3161+ case ' ':
3162+ *(string.pointer++) = '\x20';
3163+ break;
3164+
3165+ case '"':
3166+ *(string.pointer++) = '"';
3167+ break;
3168+
3169+ case '\'':
3170+ *(string.pointer++) = '\'';
3171+ break;
3172+
3173+ case '\\':
3174+ *(string.pointer++) = '\\';
3175+ break;
3176+
3177+ case 'N': /* NEL (#x85) */
3178+ *(string.pointer++) = '\xC2';
3179+ *(string.pointer++) = '\x85';
3180+ break;
3181+
3182+ case '_': /* #xA0 */
3183+ *(string.pointer++) = '\xC2';
3184+ *(string.pointer++) = '\xA0';
3185+ break;
3186+
3187+ case 'L': /* LS (#x2028) */
3188+ *(string.pointer++) = '\xE2';
3189+ *(string.pointer++) = '\x80';
3190+ *(string.pointer++) = '\xA8';
3191+ break;
3192+
3193+ case 'P': /* PS (#x2029) */
3194+ *(string.pointer++) = '\xE2';
3195+ *(string.pointer++) = '\x80';
3196+ *(string.pointer++) = '\xA9';
3197+ break;
3198+
3199+ case 'x':
3200+ code_length = 2;
3201+ break;
3202+
3203+ case 'u':
3204+ code_length = 4;
3205+ break;
3206+
3207+ case 'U':
3208+ code_length = 8;
3209+ break;
3210+
3211+ default:
3212+ yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
3213+ start_mark, "found unknown escape character");
3214+ goto error;
3215+ }
3216+
3217+ SKIP(parser);
3218+ SKIP(parser);
3219+
3220+ /* Consume an arbitrary escape code. */
3221+
3222+ if (code_length)
3223+ {
3224+ unsigned int value = 0;
3225+ size_t k;
3226+
3227+ /* Scan the character value. */
3228+
3229+ if (!CACHE(parser, code_length)) goto error;
3230+
3231+ for (k = 0; k < code_length; k ++) {
3232+ if (!IS_HEX_AT(parser->buffer, k)) {
3233+ yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
3234+ start_mark, "did not find expected hexdecimal number");
3235+ goto error;
3236+ }
3237+ value = (value << 4) + AS_HEX_AT(parser->buffer, k);
3238+ }
3239+
3240+ /* Check the value and write the character. */
3241+
3242+ if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) {
3243+ yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
3244+ start_mark, "found invalid Unicode character escape code");
3245+ goto error;
3246+ }
3247+
3248+ if (value <= 0x7F) {
3249+ *(string.pointer++) = value;
3250+ }
3251+ else if (value <= 0x7FF) {
3252+ *(string.pointer++) = 0xC0 + (value >> 6);
3253+ *(string.pointer++) = 0x80 + (value & 0x3F);
3254+ }
3255+ else if (value <= 0xFFFF) {
3256+ *(string.pointer++) = 0xE0 + (value >> 12);
3257+ *(string.pointer++) = 0x80 + ((value >> 6) & 0x3F);
3258+ *(string.pointer++) = 0x80 + (value & 0x3F);
3259+ }
3260+ else {
3261+ *(string.pointer++) = 0xF0 + (value >> 18);
3262+ *(string.pointer++) = 0x80 + ((value >> 12) & 0x3F);
3263+ *(string.pointer++) = 0x80 + ((value >> 6) & 0x3F);
3264+ *(string.pointer++) = 0x80 + (value & 0x3F);
3265+ }
3266+
3267+ /* Advance the pointer. */
3268+
3269+ for (k = 0; k < code_length; k ++) {
3270+ SKIP(parser);
3271+ }
3272+ }
3273+ }
3274+
3275+ else
3276+ {
3277+ /* It is a non-escaped non-blank character. */
3278+
3279+ if (!READ(parser, string)) goto error;
3280+ }
3281+
3282+ if (!CACHE(parser, 2)) goto error;
3283+ }
3284+
3285+ /* Check if we are at the end of the scalar. */
3286+
3287+ if (CHECK(parser->buffer, single ? '\'' : '"'))
3288+ break;
3289+
3290+ /* Consume blank characters. */
3291+
3292+ if (!CACHE(parser, 1)) goto error;
3293+
3294+ while (IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer))
3295+ {
3296+ if (IS_BLANK(parser->buffer))
3297+ {
3298+ /* Consume a space or a tab character. */
3299+
3300+ if (!leading_blanks) {
3301+ if (!READ(parser, whitespaces)) goto error;
3302+ }
3303+ else {
3304+ SKIP(parser);
3305+ }
3306+ }
3307+ else
3308+ {
3309+ if (!CACHE(parser, 2)) goto error;
3310+
3311+ /* Check if it is a first line break. */
3312+
3313+ if (!leading_blanks)
3314+ {
3315+ CLEAR(parser, whitespaces);
3316+ if (!READ_LINE(parser, leading_break)) goto error;
3317+ leading_blanks = 1;
3318+ }
3319+ else
3320+ {
3321+ if (!READ_LINE(parser, trailing_breaks)) goto error;
3322+ }
3323+ }
3324+ if (!CACHE(parser, 1)) goto error;
3325+ }
3326+
3327+ /* Join the whitespaces or fold line breaks. */
3328+
3329+ if (leading_blanks)
3330+ {
3331+ /* Do we need to fold line breaks? */
3332+
3333+ if (leading_break.start[0] == '\n') {
3334+ if (trailing_breaks.start[0] == '\0') {
3335+ if (!STRING_EXTEND(parser, string)) goto error;
3336+ *(string.pointer++) = ' ';
3337+ }
3338+ else {
3339+ if (!JOIN(parser, string, trailing_breaks)) goto error;
3340+ CLEAR(parser, trailing_breaks);
3341+ }
3342+ CLEAR(parser, leading_break);
3343+ }
3344+ else {
3345+ if (!JOIN(parser, string, leading_break)) goto error;
3346+ if (!JOIN(parser, string, trailing_breaks)) goto error;
3347+ CLEAR(parser, leading_break);
3348+ CLEAR(parser, trailing_breaks);
3349+ }
3350+ }
3351+ else
3352+ {
3353+ if (!JOIN(parser, string, whitespaces)) goto error;
3354+ CLEAR(parser, whitespaces);
3355+ }
3356+ }
3357+
3358+ /* Eat the right quote. */
3359+
3360+ SKIP(parser);
3361+
3362+ end_mark = parser->mark;
3363+
3364+ /* Create a token. */
3365+
3366+ SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start,
3367+ single ? YAML_SINGLE_QUOTED_SCALAR_STYLE : YAML_DOUBLE_QUOTED_SCALAR_STYLE,
3368+ start_mark, end_mark);
3369+
3370+ STRING_DEL(parser, leading_break);
3371+ STRING_DEL(parser, trailing_breaks);
3372+ STRING_DEL(parser, whitespaces);
3373+
3374+ return 1;
3375+
3376+error:
3377+ STRING_DEL(parser, string);
3378+ STRING_DEL(parser, leading_break);
3379+ STRING_DEL(parser, trailing_breaks);
3380+ STRING_DEL(parser, whitespaces);
3381+
3382+ return 0;
3383+}
3384+
3385+/*
3386+ * Scan a plain scalar.
3387+ */
3388+
3389+static int
3390+yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token)
3391+{
3392+ yaml_mark_t start_mark;
3393+ yaml_mark_t end_mark;
3394+ yaml_string_t string = NULL_STRING;
3395+ yaml_string_t leading_break = NULL_STRING;
3396+ yaml_string_t trailing_breaks = NULL_STRING;
3397+ yaml_string_t whitespaces = NULL_STRING;
3398+ int leading_blanks = 0;
3399+ int indent = parser->indent+1;
3400+
3401+ if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
3402+ if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error;
3403+ if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error;
3404+ if (!STRING_INIT(parser, whitespaces, INITIAL_STRING_SIZE)) goto error;
3405+
3406+ start_mark = end_mark = parser->mark;
3407+
3408+ /* Consume the content of the plain scalar. */
3409+
3410+ while (1)
3411+ {
3412+ /* Check for a document indicator. */
3413+
3414+ if (!CACHE(parser, 4)) goto error;
3415+
3416+ if (parser->mark.column == 0 &&
3417+ ((CHECK_AT(parser->buffer, '-', 0) &&
3418+ CHECK_AT(parser->buffer, '-', 1) &&
3419+ CHECK_AT(parser->buffer, '-', 2)) ||
3420+ (CHECK_AT(parser->buffer, '.', 0) &&
3421+ CHECK_AT(parser->buffer, '.', 1) &&
3422+ CHECK_AT(parser->buffer, '.', 2))) &&
3423+ IS_BLANKZ_AT(parser->buffer, 3)) break;
3424+
3425+ /* Check for a comment. */
3426+
3427+ if (CHECK(parser->buffer, '#'))
3428+ break;
3429+
3430+ /* Consume non-blank characters. */
3431+
3432+ while (!IS_BLANKZ(parser->buffer))
3433+ {
3434+ /* Check for 'x:x' in the flow context. TODO: Fix the test "spec-08-13". */
3435+
3436+ if (parser->flow_level
3437+ && CHECK(parser->buffer, ':')
3438+ && !IS_BLANKZ_AT(parser->buffer, 1)) {
3439+ yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
3440+ start_mark, "found unexpected ':'");
3441+ goto error;
3442+ }
3443+
3444+ /* Check for indicators that may end a plain scalar. */
3445+
3446+ if ((CHECK(parser->buffer, ':') && IS_BLANKZ_AT(parser->buffer, 1))
3447+ || (parser->flow_level &&
3448+ (CHECK(parser->buffer, ',') || CHECK(parser->buffer, ':')
3449+ || CHECK(parser->buffer, '?') || CHECK(parser->buffer, '[')
3450+ || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '{')
3451+ || CHECK(parser->buffer, '}'))))
3452+ break;
3453+
3454+ /* Check if we need to join whitespaces and breaks. */
3455+
3456+ if (leading_blanks || whitespaces.start != whitespaces.pointer)
3457+ {
3458+ if (leading_blanks)
3459+ {
3460+ /* Do we need to fold line breaks? */
3461+
3462+ if (leading_break.start[0] == '\n') {
3463+ if (trailing_breaks.start[0] == '\0') {
3464+ if (!STRING_EXTEND(parser, string)) goto error;
3465+ *(string.pointer++) = ' ';
3466+ }
3467+ else {
3468+ if (!JOIN(parser, string, trailing_breaks)) goto error;
3469+ CLEAR(parser, trailing_breaks);
3470+ }
3471+ CLEAR(parser, leading_break);
3472+ }
3473+ else {
3474+ if (!JOIN(parser, string, leading_break)) goto error;
3475+ if (!JOIN(parser, string, trailing_breaks)) goto error;
3476+ CLEAR(parser, leading_break);
3477+ CLEAR(parser, trailing_breaks);
3478+ }
3479+
3480+ leading_blanks = 0;
3481+ }
3482+ else
3483+ {
3484+ if (!JOIN(parser, string, whitespaces)) goto error;
3485+ CLEAR(parser, whitespaces);
3486+ }
3487+ }
3488+
3489+ /* Copy the character. */
3490+
3491+ if (!READ(parser, string)) goto error;
3492+
3493+ end_mark = parser->mark;
3494+
3495+ if (!CACHE(parser, 2)) goto error;
3496+ }
3497+
3498+ /* Is it the end? */
3499+
3500+ if (!(IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer)))
3501+ break;
3502+
3503+ /* Consume blank characters. */
3504+
3505+ if (!CACHE(parser, 1)) goto error;
3506+
3507+ while (IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer))
3508+ {
3509+ if (IS_BLANK(parser->buffer))
3510+ {
3511+ /* Check for tab character that abuse intendation. */
3512+
3513+ if (leading_blanks && (int)parser->mark.column < indent
3514+ && IS_TAB(parser->buffer)) {
3515+ yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
3516+ start_mark, "found a tab character that violate intendation");
3517+ goto error;
3518+ }
3519+
3520+ /* Consume a space or a tab character. */
3521+
3522+ if (!leading_blanks) {
3523+ if (!READ(parser, whitespaces)) goto error;
3524+ }
3525+ else {
3526+ SKIP(parser);
3527+ }
3528+ }
3529+ else
3530+ {
3531+ if (!CACHE(parser, 2)) goto error;
3532+
3533+ /* Check if it is a first line break. */
3534+
3535+ if (!leading_blanks)
3536+ {
3537+ CLEAR(parser, whitespaces);
3538+ if (!READ_LINE(parser, leading_break)) goto error;
3539+ leading_blanks = 1;
3540+ }
3541+ else
3542+ {
3543+ if (!READ_LINE(parser, trailing_breaks)) goto error;
3544+ }
3545+ }
3546+ if (!CACHE(parser, 1)) goto error;
3547+ }
3548+
3549+ /* Check intendation level. */
3550+
3551+ if (!parser->flow_level && (int)parser->mark.column < indent)
3552+ break;
3553+ }
3554+
3555+ /* Create a token. */
3556+
3557+ SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start,
3558+ YAML_PLAIN_SCALAR_STYLE, start_mark, end_mark);
3559+
3560+ /* Note that we change the 'simple_key_allowed' flag. */
3561+
3562+ if (leading_blanks) {
3563+ parser->simple_key_allowed = 1;
3564+ }
3565+
3566+ STRING_DEL(parser, leading_break);
3567+ STRING_DEL(parser, trailing_breaks);
3568+ STRING_DEL(parser, whitespaces);
3569+
3570+ return 1;
3571+
3572+error:
3573+ STRING_DEL(parser, string);
3574+ STRING_DEL(parser, leading_break);
3575+ STRING_DEL(parser, trailing_breaks);
3576+ STRING_DEL(parser, whitespaces);
3577+
3578+ return 0;
3579+}
3580+
libyaml/writer.cnew file+141
@@ -0,0 +1,141 @@
1+
2+#include "yaml_private.h"
3+
4+/*
5+ * Declarations.
6+ */
7+
8+static int
9+yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem);
10+
11+YAML_DECLARE(int)
12+yaml_emitter_flush(yaml_emitter_t *emitter);
13+
14+/*
15+ * Set the writer error and return 0.
16+ */
17+
18+static int
19+yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem)
20+{
21+ emitter->error = YAML_WRITER_ERROR;
22+ emitter->problem = problem;
23+
24+ return 0;
25+}
26+
27+/*
28+ * Flush the output buffer.
29+ */
30+
31+YAML_DECLARE(int)
32+yaml_emitter_flush(yaml_emitter_t *emitter)
33+{
34+ int low, high;
35+
36+ assert(emitter); /* Non-NULL emitter object is expected. */
37+ assert(emitter->write_handler); /* Write handler must be set. */
38+ assert(emitter->encoding); /* Output encoding must be set. */
39+
40+ emitter->buffer.last = emitter->buffer.pointer;
41+ emitter->buffer.pointer = emitter->buffer.start;
42+
43+ /* Check if the buffer is empty. */
44+
45+ if (emitter->buffer.start == emitter->buffer.last) {
46+ return 1;
47+ }
48+
49+ /* If the output encoding is UTF-8, we don't need to recode the buffer. */
50+
51+ if (emitter->encoding == YAML_UTF8_ENCODING)
52+ {
53+ if (emitter->write_handler(emitter->write_handler_data,
54+ emitter->buffer.start,
55+ emitter->buffer.last - emitter->buffer.start)) {
56+ emitter->buffer.last = emitter->buffer.start;
57+ emitter->buffer.pointer = emitter->buffer.start;
58+ return 1;
59+ }
60+ else {
61+ return yaml_emitter_set_writer_error(emitter, "write error");
62+ }
63+ }
64+
65+ /* Recode the buffer into the raw buffer. */
66+
67+ low = (emitter->encoding == YAML_UTF16LE_ENCODING ? 0 : 1);
68+ high = (emitter->encoding == YAML_UTF16LE_ENCODING ? 1 : 0);
69+
70+ while (emitter->buffer.pointer != emitter->buffer.last)
71+ {
72+ unsigned char octet;
73+ unsigned int width;
74+ unsigned int value;
75+ size_t k;
76+
77+ /*
78+ * See the "reader.c" code for more details on UTF-8 encoding. Note
79+ * that we assume that the buffer contains a valid UTF-8 sequence.
80+ */
81+
82+ /* Read the next UTF-8 character. */
83+
84+ octet = emitter->buffer.pointer[0];
85+
86+ width = (octet & 0x80) == 0x00 ? 1 :
87+ (octet & 0xE0) == 0xC0 ? 2 :
88+ (octet & 0xF0) == 0xE0 ? 3 :
89+ (octet & 0xF8) == 0xF0 ? 4 : 0;
90+
91+ value = (octet & 0x80) == 0x00 ? octet & 0x7F :
92+ (octet & 0xE0) == 0xC0 ? octet & 0x1F :
93+ (octet & 0xF0) == 0xE0 ? octet & 0x0F :
94+ (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
95+
96+ for (k = 1; k < width; k ++) {
97+ octet = emitter->buffer.pointer[k];
98+ value = (value << 6) + (octet & 0x3F);
99+ }
100+
101+ emitter->buffer.pointer += width;
102+
103+ /* Write the character. */
104+
105+ if (value < 0x10000)
106+ {
107+ emitter->raw_buffer.last[high] = value >> 8;
108+ emitter->raw_buffer.last[low] = value & 0xFF;
109+
110+ emitter->raw_buffer.last += 2;
111+ }
112+ else
113+ {
114+ /* Write the character using a surrogate pair (check "reader.c"). */
115+
116+ value -= 0x10000;
117+ emitter->raw_buffer.last[high] = 0xD8 + (value >> 18);
118+ emitter->raw_buffer.last[low] = (value >> 10) & 0xFF;
119+ emitter->raw_buffer.last[high+2] = 0xDC + ((value >> 8) & 0xFF);
120+ emitter->raw_buffer.last[low+2] = value & 0xFF;
121+
122+ emitter->raw_buffer.last += 4;
123+ }
124+ }
125+
126+ /* Write the raw buffer. */
127+
128+ if (emitter->write_handler(emitter->write_handler_data,
129+ emitter->raw_buffer.start,
130+ emitter->raw_buffer.last - emitter->raw_buffer.start)) {
131+ emitter->buffer.last = emitter->buffer.start;
132+ emitter->buffer.pointer = emitter->buffer.start;
133+ emitter->raw_buffer.last = emitter->raw_buffer.start;
134+ emitter->raw_buffer.pointer = emitter->raw_buffer.start;
135+ return 1;
136+ }
137+ else {
138+ return yaml_emitter_set_writer_error(emitter, "write error");
139+ }
140+}
141+
libyaml/yaml.hnew file+1973
@@ -0,0 +1,1973 @@
1+/**
2+ * @file yaml.h
3+ * @brief Public interface for libyaml.
4+ *
5+ * Include the header file with the code:
6+ * @code
7+ * #include <yaml.h>
8+ * @endcode
9+ */
10+
11+#ifndef YAML_H
12+#define YAML_H
13+
14+#ifdef __cplusplus
15+extern "C" {
16+#endif
17+
18+#include <stdlib.h>
19+#include <stdio.h>
20+#include <string.h>
21+
22+/**
23+ * @defgroup export Export Definitions
24+ * @{
25+ */
26+
27+/** The public API declaration. */
28+
29+#if defined(__MINGW32__)
30+# define YAML_DECLARE(type) type
31+#elif defined(_WIN32)
32+# if defined(YAML_DECLARE_STATIC)
33+# define YAML_DECLARE(type) type
34+# elif defined(YAML_DECLARE_EXPORT)
35+# define YAML_DECLARE(type) __declspec(dllexport) type
36+# else
37+# define YAML_DECLARE(type) __declspec(dllimport) type
38+# endif
39+#else
40+# define YAML_DECLARE(type) type
41+#endif
42+
43+/** @} */
44+
45+/**
46+ * @defgroup version Version Information
47+ * @{
48+ */
49+
50+/**
51+ * Get the library version as a string.
52+ *
53+ * @returns The function returns the pointer to a static string of the form
54+ * @c "X.Y.Z", where @c X is the major version number, @c Y is a minor version
55+ * number, and @c Z is the patch version number.
56+ */
57+
58+YAML_DECLARE(const char *)
59+yaml_get_version_string(void);
60+
61+/**
62+ * Get the library version numbers.
63+ *
64+ * @param[out] major Major version number.
65+ * @param[out] minor Minor version number.
66+ * @param[out] patch Patch version number.
67+ */
68+
69+YAML_DECLARE(void)
70+yaml_get_version(int *major, int *minor, int *patch);
71+
72+/** @} */
73+
74+/**
75+ * @defgroup basic Basic Types
76+ * @{
77+ */
78+
79+/** The character type (UTF-8 octet). */
80+typedef unsigned char yaml_char_t;
81+
82+/** The version directive data. */
83+typedef struct yaml_version_directive_s {
84+ /** The major version number. */
85+ int major;
86+ /** The minor version number. */
87+ int minor;
88+} yaml_version_directive_t;
89+
90+/** The tag directive data. */
91+typedef struct yaml_tag_directive_s {
92+ /** The tag handle. */
93+ yaml_char_t *handle;
94+ /** The tag prefix. */
95+ yaml_char_t *prefix;
96+} yaml_tag_directive_t;
97+
98+/** The stream encoding. */
99+typedef enum yaml_encoding_e {
100+ /** Let the parser choose the encoding. */
101+ YAML_ANY_ENCODING,
102+ /** The default UTF-8 encoding. */
103+ YAML_UTF8_ENCODING,
104+ /** The UTF-16-LE encoding with BOM. */
105+ YAML_UTF16LE_ENCODING,
106+ /** The UTF-16-BE encoding with BOM. */
107+ YAML_UTF16BE_ENCODING
108+} yaml_encoding_t;
109+
110+/** Line break types. */
111+
112+typedef enum yaml_break_e {
113+ /** Let the parser choose the break type. */
114+ YAML_ANY_BREAK,
115+ /** Use CR for line breaks (Mac style). */
116+ YAML_CR_BREAK,
117+ /** Use LN for line breaks (Unix style). */
118+ YAML_LN_BREAK,
119+ /** Use CR LN for line breaks (DOS style). */
120+ YAML_CRLN_BREAK
121+} yaml_break_t;
122+
123+/** Many bad things could happen with the parser and emitter. */
124+typedef enum yaml_error_type_e {
125+ /** No error is produced. */
126+ YAML_NO_ERROR,
127+
128+ /** Cannot allocate or reallocate a block of memory. */
129+ YAML_MEMORY_ERROR,
130+
131+ /** Cannot read or decode the input stream. */
132+ YAML_READER_ERROR,
133+ /** Cannot scan the input stream. */
134+ YAML_SCANNER_ERROR,
135+ /** Cannot parse the input stream. */
136+ YAML_PARSER_ERROR,
137+ /** Cannot compose a YAML document. */
138+ YAML_COMPOSER_ERROR,
139+
140+ /** Cannot write to the output stream. */
141+ YAML_WRITER_ERROR,
142+ /** Cannot emit a YAML stream. */
143+ YAML_EMITTER_ERROR
144+} yaml_error_type_t;
145+
146+/** The pointer position. */
147+typedef struct yaml_mark_s {
148+ /** The position index. */
149+ size_t index;
150+
151+ /** The position line. */
152+ size_t line;
153+
154+ /** The position column. */
155+ size_t column;
156+} yaml_mark_t;
157+
158+/** @} */
159+
160+/**
161+ * @defgroup styles Node Styles
162+ * @{
163+ */
164+
165+/** Scalar styles. */
166+typedef enum yaml_scalar_style_e {
167+ /** Let the emitter choose the style. */
168+ YAML_ANY_SCALAR_STYLE,
169+
170+ /** The plain scalar style. */
171+ YAML_PLAIN_SCALAR_STYLE,
172+
173+ /** The single-quoted scalar style. */
174+ YAML_SINGLE_QUOTED_SCALAR_STYLE,
175+ /** The double-quoted scalar style. */
176+ YAML_DOUBLE_QUOTED_SCALAR_STYLE,
177+
178+ /** The literal scalar style. */
179+ YAML_LITERAL_SCALAR_STYLE,
180+ /** The folded scalar style. */
181+ YAML_FOLDED_SCALAR_STYLE
182+} yaml_scalar_style_t;
183+
184+/** Sequence styles. */
185+typedef enum yaml_sequence_style_e {
186+ /** Let the emitter choose the style. */
187+ YAML_ANY_SEQUENCE_STYLE,
188+
189+ /** The block sequence style. */
190+ YAML_BLOCK_SEQUENCE_STYLE,
191+ /** The flow sequence style. */
192+ YAML_FLOW_SEQUENCE_STYLE
193+} yaml_sequence_style_t;
194+
195+/** Mapping styles. */
196+typedef enum yaml_mapping_style_e {
197+ /** Let the emitter choose the style. */
198+ YAML_ANY_MAPPING_STYLE,
199+
200+ /** The block mapping style. */
201+ YAML_BLOCK_MAPPING_STYLE,
202+ /** The flow mapping style. */
203+ YAML_FLOW_MAPPING_STYLE
204+/* YAML_FLOW_SET_MAPPING_STYLE */
205+} yaml_mapping_style_t;
206+
207+/** @} */
208+
209+/**
210+ * @defgroup tokens Tokens
211+ * @{
212+ */
213+
214+/** Token types. */
215+typedef enum yaml_token_type_e {
216+ /** An empty token. */
217+ YAML_NO_TOKEN,
218+
219+ /** A STREAM-START token. */
220+ YAML_STREAM_START_TOKEN,
221+ /** A STREAM-END token. */
222+ YAML_STREAM_END_TOKEN,
223+
224+ /** A VERSION-DIRECTIVE token. */
225+ YAML_VERSION_DIRECTIVE_TOKEN,
226+ /** A TAG-DIRECTIVE token. */
227+ YAML_TAG_DIRECTIVE_TOKEN,
228+ /** A DOCUMENT-START token. */
229+ YAML_DOCUMENT_START_TOKEN,
230+ /** A DOCUMENT-END token. */
231+ YAML_DOCUMENT_END_TOKEN,
232+
233+ /** A BLOCK-SEQUENCE-START token. */
234+ YAML_BLOCK_SEQUENCE_START_TOKEN,
235+ /** A BLOCK-SEQUENCE-END token. */
236+ YAML_BLOCK_MAPPING_START_TOKEN,
237+ /** A BLOCK-END token. */
238+ YAML_BLOCK_END_TOKEN,
239+
240+ /** A FLOW-SEQUENCE-START token. */
241+ YAML_FLOW_SEQUENCE_START_TOKEN,
242+ /** A FLOW-SEQUENCE-END token. */
243+ YAML_FLOW_SEQUENCE_END_TOKEN,
244+ /** A FLOW-MAPPING-START token. */
245+ YAML_FLOW_MAPPING_START_TOKEN,
246+ /** A FLOW-MAPPING-END token. */
247+ YAML_FLOW_MAPPING_END_TOKEN,
248+
249+ /** A BLOCK-ENTRY token. */
250+ YAML_BLOCK_ENTRY_TOKEN,
251+ /** A FLOW-ENTRY token. */
252+ YAML_FLOW_ENTRY_TOKEN,
253+ /** A KEY token. */
254+ YAML_KEY_TOKEN,
255+ /** A VALUE token. */
256+ YAML_VALUE_TOKEN,
257+
258+ /** An ALIAS token. */
259+ YAML_ALIAS_TOKEN,
260+ /** An ANCHOR token. */
261+ YAML_ANCHOR_TOKEN,
262+ /** A TAG token. */
263+ YAML_TAG_TOKEN,
264+ /** A SCALAR token. */
265+ YAML_SCALAR_TOKEN
266+} yaml_token_type_t;
267+
268+/** The token structure. */
269+typedef struct yaml_token_s {
270+
271+ /** The token type. */
272+ yaml_token_type_t type;
273+
274+ /** The token data. */
275+ union {
276+
277+ /** The stream start (for @c YAML_STREAM_START_TOKEN). */
278+ struct {
279+ /** The stream encoding. */
280+ yaml_encoding_t encoding;
281+ } stream_start;
282+
283+ /** The alias (for @c YAML_ALIAS_TOKEN). */
284+ struct {
285+ /** The alias value. */
286+ yaml_char_t *value;
287+ } alias;
288+
289+ /** The anchor (for @c YAML_ANCHOR_TOKEN). */
290+ struct {
291+ /** The anchor value. */
292+ yaml_char_t *value;
293+ } anchor;
294+
295+ /** The tag (for @c YAML_TAG_TOKEN). */
296+ struct {
297+ /** The tag handle. */
298+ yaml_char_t *handle;
299+ /** The tag suffix. */
300+ yaml_char_t *suffix;
301+ } tag;
302+
303+ /** The scalar value (for @c YAML_SCALAR_TOKEN). */
304+ struct {
305+ /** The scalar value. */
306+ yaml_char_t *value;
307+ /** The length of the scalar value. */
308+ size_t length;
309+ /** The scalar style. */
310+ yaml_scalar_style_t style;
311+ } scalar;
312+
313+ /** The version directive (for @c YAML_VERSION_DIRECTIVE_TOKEN). */
314+ struct {
315+ /** The major version number. */
316+ int major;
317+ /** The minor version number. */
318+ int minor;
319+ } version_directive;
320+
321+ /** The tag directive (for @c YAML_TAG_DIRECTIVE_TOKEN). */
322+ struct {
323+ /** The tag handle. */
324+ yaml_char_t *handle;
325+ /** The tag prefix. */
326+ yaml_char_t *prefix;
327+ } tag_directive;
328+
329+ } data;
330+
331+ /** The beginning of the token. */
332+ yaml_mark_t start_mark;
333+ /** The end of the token. */
334+ yaml_mark_t end_mark;
335+
336+} yaml_token_t;
337+
338+/**
339+ * Free any memory allocated for a token object.
340+ *
341+ * @param[in,out] token A token object.
342+ */
343+
344+YAML_DECLARE(void)
345+yaml_token_delete(yaml_token_t *token);
346+
347+/** @} */
348+
349+/**
350+ * @defgroup events Events
351+ * @{
352+ */
353+
354+/** Event types. */
355+typedef enum yaml_event_type_e {
356+ /** An empty event. */
357+ YAML_NO_EVENT,
358+
359+ /** A STREAM-START event. */
360+ YAML_STREAM_START_EVENT,
361+ /** A STREAM-END event. */
362+ YAML_STREAM_END_EVENT,
363+
364+ /** A DOCUMENT-START event. */
365+ YAML_DOCUMENT_START_EVENT,
366+ /** A DOCUMENT-END event. */
367+ YAML_DOCUMENT_END_EVENT,
368+
369+ /** An ALIAS event. */
370+ YAML_ALIAS_EVENT,
371+ /** A SCALAR event. */
372+ YAML_SCALAR_EVENT,
373+
374+ /** A SEQUENCE-START event. */
375+ YAML_SEQUENCE_START_EVENT,
376+ /** A SEQUENCE-END event. */
377+ YAML_SEQUENCE_END_EVENT,
378+
379+ /** A MAPPING-START event. */
380+ YAML_MAPPING_START_EVENT,
381+ /** A MAPPING-END event. */
382+ YAML_MAPPING_END_EVENT
383+} yaml_event_type_t;
384+
385+/** The event structure. */
386+typedef struct yaml_event_s {
387+
388+ /** The event type. */
389+ yaml_event_type_t type;
390+
391+ /** The event data. */
392+ union {
393+
394+ /** The stream parameters (for @c YAML_STREAM_START_EVENT). */
395+ struct {
396+ /** The document encoding. */
397+ yaml_encoding_t encoding;
398+ } stream_start;
399+
400+ /** The document parameters (for @c YAML_DOCUMENT_START_EVENT). */
401+ struct {
402+ /** The version directive. */
403+ yaml_version_directive_t *version_directive;
404+
405+ /** The list of tag directives. */
406+ struct {
407+ /** The beginning of the tag directives list. */
408+ yaml_tag_directive_t *start;
409+ /** The end of the tag directives list. */
410+ yaml_tag_directive_t *end;
411+ } tag_directives;
412+
413+ /** Is the document indicator implicit? */
414+ int implicit;
415+ } document_start;
416+
417+ /** The document end parameters (for @c YAML_DOCUMENT_END_EVENT). */
418+ struct {
419+ /** Is the document end indicator implicit? */
420+ int implicit;
421+ } document_end;
422+
423+ /** The alias parameters (for @c YAML_ALIAS_EVENT). */
424+ struct {
425+ /** The anchor. */
426+ yaml_char_t *anchor;
427+ } alias;
428+
429+ /** The scalar parameters (for @c YAML_SCALAR_EVENT). */
430+ struct {
431+ /** The anchor. */
432+ yaml_char_t *anchor;
433+ /** The tag. */
434+ yaml_char_t *tag;
435+ /** The scalar value. */
436+ yaml_char_t *value;
437+ /** The length of the scalar value. */
438+ size_t length;
439+ /** Is the tag optional for the plain style? */
440+ int plain_implicit;
441+ /** Is the tag optional for any non-plain style? */
442+ int quoted_implicit;
443+ /** The scalar style. */
444+ yaml_scalar_style_t style;
445+ } scalar;
446+
447+ /** The sequence parameters (for @c YAML_SEQUENCE_START_EVENT). */
448+ struct {
449+ /** The anchor. */
450+ yaml_char_t *anchor;
451+ /** The tag. */
452+ yaml_char_t *tag;
453+ /** Is the tag optional? */
454+ int implicit;
455+ /** The sequence style. */
456+ yaml_sequence_style_t style;
457+ } sequence_start;
458+
459+ /** The mapping parameters (for @c YAML_MAPPING_START_EVENT). */
460+ struct {
461+ /** The anchor. */
462+ yaml_char_t *anchor;
463+ /** The tag. */
464+ yaml_char_t *tag;
465+ /** Is the tag optional? */
466+ int implicit;
467+ /** The mapping style. */
468+ yaml_mapping_style_t style;
469+ } mapping_start;
470+
471+ } data;
472+
473+ /** The beginning of the event. */
474+ yaml_mark_t start_mark;
475+ /** The end of the event. */
476+ yaml_mark_t end_mark;
477+
478+} yaml_event_t;
479+
480+/**
481+ * Create the STREAM-START event.
482+ *
483+ * @param[out] event An empty event object.
484+ * @param[in] encoding The stream encoding.
485+ *
486+ * @returns @c 1 if the function succeeded, @c 0 on error.
487+ */
488+
489+YAML_DECLARE(int)
490+yaml_stream_start_event_initialize(yaml_event_t *event,
491+ yaml_encoding_t encoding);
492+
493+/**
494+ * Create the STREAM-END event.
495+ *
496+ * @param[out] event An empty event object.
497+ *
498+ * @returns @c 1 if the function succeeded, @c 0 on error.
499+ */
500+
501+YAML_DECLARE(int)
502+yaml_stream_end_event_initialize(yaml_event_t *event);
503+
504+/**
505+ * Create the DOCUMENT-START event.
506+ *
507+ * The @a implicit argument is considered as a stylistic parameter and may be
508+ * ignored by the emitter.
509+ *
510+ * @param[out] event An empty event object.
511+ * @param[in] version_directive The %YAML directive value or
512+ * @c NULL.
513+ * @param[in] tag_directives_start The beginning of the %TAG
514+ * directives list.
515+ * @param[in] tag_directives_end The end of the %TAG directives
516+ * list.
517+ * @param[in] implicit If the document start indicator is
518+ * implicit.
519+ *
520+ * @returns @c 1 if the function succeeded, @c 0 on error.
521+ */
522+
523+YAML_DECLARE(int)
524+yaml_document_start_event_initialize(yaml_event_t *event,
525+ yaml_version_directive_t *version_directive,
526+ yaml_tag_directive_t *tag_directives_start,
527+ yaml_tag_directive_t *tag_directives_end,
528+ int implicit);
529+
530+/**
531+ * Create the DOCUMENT-END event.
532+ *
533+ * The @a implicit argument is considered as a stylistic parameter and may be
534+ * ignored by the emitter.
535+ *
536+ * @param[out] event An empty event object.
537+ * @param[in] implicit If the document end indicator is implicit.
538+ *
539+ * @returns @c 1 if the function succeeded, @c 0 on error.
540+ */
541+
542+YAML_DECLARE(int)
543+yaml_document_end_event_initialize(yaml_event_t *event, int implicit);
544+
545+/**
546+ * Create an ALIAS event.
547+ *
548+ * @param[out] event An empty event object.
549+ * @param[in] anchor The anchor value.
550+ *
551+ * @returns @c 1 if the function succeeded, @c 0 on error.
552+ */
553+
554+YAML_DECLARE(int)
555+yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor);
556+
557+/**
558+ * Create a SCALAR event.
559+ *
560+ * The @a style argument may be ignored by the emitter.
561+ *
562+ * Either the @a tag attribute or one of the @a plain_implicit and
563+ * @a quoted_implicit flags must be set.
564+ *
565+ * @param[out] event An empty event object.
566+ * @param[in] anchor The scalar anchor or @c NULL.
567+ * @param[in] tag The scalar tag or @c NULL.
568+ * @param[in] value The scalar value.
569+ * @param[in] length The length of the scalar value.
570+ * @param[in] plain_implicit If the tag may be omitted for the plain
571+ * style.
572+ * @param[in] quoted_implicit If the tag may be omitted for any
573+ * non-plain style.
574+ * @param[in] style The scalar style.
575+ *
576+ * @returns @c 1 if the function succeeded, @c 0 on error.
577+ */
578+
579+YAML_DECLARE(int)
580+yaml_scalar_event_initialize(yaml_event_t *event,
581+ yaml_char_t *anchor, yaml_char_t *tag,
582+ yaml_char_t *value, int length,
583+ int plain_implicit, int quoted_implicit,
584+ yaml_scalar_style_t style);
585+
586+/**
587+ * Create a SEQUENCE-START event.
588+ *
589+ * The @a style argument may be ignored by the emitter.
590+ *
591+ * Either the @a tag attribute or the @a implicit flag must be set.
592+ *
593+ * @param[out] event An empty event object.
594+ * @param[in] anchor The sequence anchor or @c NULL.
595+ * @param[in] tag The sequence tag or @c NULL.
596+ * @param[in] implicit If the tag may be omitted.
597+ * @param[in] style The sequence style.
598+ *
599+ * @returns @c 1 if the function succeeded, @c 0 on error.
600+ */
601+
602+YAML_DECLARE(int)
603+yaml_sequence_start_event_initialize(yaml_event_t *event,
604+ yaml_char_t *anchor, yaml_char_t *tag, int implicit,
605+ yaml_sequence_style_t style);
606+
607+/**
608+ * Create a SEQUENCE-END event.
609+ *
610+ * @param[out] event An empty event object.
611+ *
612+ * @returns @c 1 if the function succeeded, @c 0 on error.
613+ */
614+
615+YAML_DECLARE(int)
616+yaml_sequence_end_event_initialize(yaml_event_t *event);
617+
618+/**
619+ * Create a MAPPING-START event.
620+ *
621+ * The @a style argument may be ignored by the emitter.
622+ *
623+ * Either the @a tag attribute or the @a implicit flag must be set.
624+ *
625+ * @param[out] event An empty event object.
626+ * @param[in] anchor The mapping anchor or @c NULL.
627+ * @param[in] tag The mapping tag or @c NULL.
628+ * @param[in] implicit If the tag may be omitted.
629+ * @param[in] style The mapping style.
630+ *
631+ * @returns @c 1 if the function succeeded, @c 0 on error.
632+ */
633+
634+YAML_DECLARE(int)
635+yaml_mapping_start_event_initialize(yaml_event_t *event,
636+ yaml_char_t *anchor, yaml_char_t *tag, int implicit,
637+ yaml_mapping_style_t style);
638+
639+/**
640+ * Create a MAPPING-END event.
641+ *
642+ * @param[out] event An empty event object.
643+ *
644+ * @returns @c 1 if the function succeeded, @c 0 on error.
645+ */
646+
647+YAML_DECLARE(int)
648+yaml_mapping_end_event_initialize(yaml_event_t *event);
649+
650+/**
651+ * Free any memory allocated for an event object.
652+ *
653+ * @param[in,out] event An event object.
654+ */
655+
656+YAML_DECLARE(void)
657+yaml_event_delete(yaml_event_t *event);
658+
659+/** @} */
660+
661+/**
662+ * @defgroup nodes Nodes
663+ * @{
664+ */
665+
666+/** The tag @c !!null with the only possible value: @c null. */
667+#define YAML_NULL_TAG "tag:yaml.org,2002:null"
668+/** The tag @c !!bool with the values: @c true and @c falce. */
669+#define YAML_BOOL_TAG "tag:yaml.org,2002:bool"
670+/** The tag @c !!str for string values. */
671+#define YAML_STR_TAG "tag:yaml.org,2002:str"
672+/** The tag @c !!int for integer values. */
673+#define YAML_INT_TAG "tag:yaml.org,2002:int"
674+/** The tag @c !!float for float values. */
675+#define YAML_FLOAT_TAG "tag:yaml.org,2002:float"
676+/** The tag @c !!timestamp for date and time values. */
677+#define YAML_TIMESTAMP_TAG "tag:yaml.org,2002:timestamp"
678+
679+/** The tag @c !!seq is used to denote sequences. */
680+#define YAML_SEQ_TAG "tag:yaml.org,2002:seq"
681+/** The tag @c !!map is used to denote mapping. */
682+#define YAML_MAP_TAG "tag:yaml.org,2002:map"
683+
684+/** The default scalar tag is @c !!str. */
685+#define YAML_DEFAULT_SCALAR_TAG YAML_STR_TAG
686+/** The default sequence tag is @c !!seq. */
687+#define YAML_DEFAULT_SEQUENCE_TAG YAML_SEQ_TAG
688+/** The default mapping tag is @c !!map. */
689+#define YAML_DEFAULT_MAPPING_TAG YAML_MAP_TAG
690+
691+/** Node types. */
692+typedef enum yaml_node_type_e {
693+ /** An empty node. */
694+ YAML_NO_NODE,
695+
696+ /** A scalar node. */
697+ YAML_SCALAR_NODE,
698+ /** A sequence node. */
699+ YAML_SEQUENCE_NODE,
700+ /** A mapping node. */
701+ YAML_MAPPING_NODE
702+} yaml_node_type_t;
703+
704+/** The forward definition of a document node structure. */
705+typedef struct yaml_node_s yaml_node_t;
706+
707+/** An element of a sequence node. */
708+typedef int yaml_node_item_t;
709+
710+/** An element of a mapping node. */
711+typedef struct yaml_node_pair_s {
712+ /** The key of the element. */
713+ int key;
714+ /** The value of the element. */
715+ int value;
716+} yaml_node_pair_t;
717+
718+/** The node structure. */
719+struct yaml_node_s {
720+
721+ /** The node type. */
722+ yaml_node_type_t type;
723+
724+ /** The node tag. */
725+ yaml_char_t *tag;
726+
727+ /** The node data. */
728+ union {
729+
730+ /** The scalar parameters (for @c YAML_SCALAR_NODE). */
731+ struct {
732+ /** The scalar value. */
733+ yaml_char_t *value;
734+ /** The length of the scalar value. */
735+ size_t length;
736+ /** The scalar style. */
737+ yaml_scalar_style_t style;
738+ } scalar;
739+
740+ /** The sequence parameters (for @c YAML_SEQUENCE_NODE). */
741+ struct {
742+ /** The stack of sequence items. */
743+ struct {
744+ /** The beginning of the stack. */
745+ yaml_node_item_t *start;
746+ /** The end of the stack. */
747+ yaml_node_item_t *end;
748+ /** The top of the stack. */
749+ yaml_node_item_t *top;
750+ } items;
751+ /** The sequence style. */
752+ yaml_sequence_style_t style;
753+ } sequence;
754+
755+ /** The mapping parameters (for @c YAML_MAPPING_NODE). */
756+ struct {
757+ /** The stack of mapping pairs (key, value). */
758+ struct {
759+ /** The beginning of the stack. */
760+ yaml_node_pair_t *start;
761+ /** The end of the stack. */
762+ yaml_node_pair_t *end;
763+ /** The top of the stack. */
764+ yaml_node_pair_t *top;
765+ } pairs;
766+ /** The mapping style. */
767+ yaml_mapping_style_t style;
768+ } mapping;
769+
770+ } data;
771+
772+ /** The beginning of the node. */
773+ yaml_mark_t start_mark;
774+ /** The end of the node. */
775+ yaml_mark_t end_mark;
776+
777+};
778+
779+/** The document structure. */
780+typedef struct yaml_document_s {
781+
782+ /** The document nodes. */
783+ struct {
784+ /** The beginning of the stack. */
785+ yaml_node_t *start;
786+ /** The end of the stack. */
787+ yaml_node_t *end;
788+ /** The top of the stack. */
789+ yaml_node_t *top;
790+ } nodes;
791+
792+ /** The version directive. */
793+ yaml_version_directive_t *version_directive;
794+
795+ /** The list of tag directives. */
796+ struct {
797+ /** The beginning of the tag directives list. */
798+ yaml_tag_directive_t *start;
799+ /** The end of the tag directives list. */
800+ yaml_tag_directive_t *end;
801+ } tag_directives;
802+
803+ /** Is the document start indicator implicit? */
804+ int start_implicit;
805+ /** Is the document end indicator implicit? */
806+ int end_implicit;
807+
808+ /** The beginning of the document. */
809+ yaml_mark_t start_mark;
810+ /** The end of the document. */
811+ yaml_mark_t end_mark;
812+
813+} yaml_document_t;
814+
815+/**
816+ * Create a YAML document.
817+ *
818+ * @param[out] document An empty document object.
819+ * @param[in] version_directive The %YAML directive value or
820+ * @c NULL.
821+ * @param[in] tag_directives_start The beginning of the %TAG
822+ * directives list.
823+ * @param[in] tag_directives_end The end of the %TAG directives
824+ * list.
825+ * @param[in] start_implicit If the document start indicator is
826+ * implicit.
827+ * @param[in] end_implicit If the document end indicator is
828+ * implicit.
829+ *
830+ * @returns @c 1 if the function succeeded, @c 0 on error.
831+ */
832+
833+YAML_DECLARE(int)
834+yaml_document_initialize(yaml_document_t *document,
835+ yaml_version_directive_t *version_directive,
836+ yaml_tag_directive_t *tag_directives_start,
837+ yaml_tag_directive_t *tag_directives_end,
838+ int start_implicit, int end_implicit);
839+
840+/**
841+ * Delete a YAML document and all its nodes.
842+ *
843+ * @param[in,out] document A document object.
844+ */
845+
846+YAML_DECLARE(void)
847+yaml_document_delete(yaml_document_t *document);
848+
849+/**
850+ * Get a node of a YAML document.
851+ *
852+ * The pointer returned by this function is valid until any of the functions
853+ * modifying the documents are called.
854+ *
855+ * @param[in] document A document object.
856+ * @param[in] index The node id.
857+ *
858+ * @returns the node objct or @c NULL if @c node_id is out of range.
859+ */
860+
861+YAML_DECLARE(yaml_node_t *)
862+yaml_document_get_node(yaml_document_t *document, int index);
863+
864+/**
865+ * Get the root of a YAML document node.
866+ *
867+ * The root object is the first object added to the document.
868+ *
869+ * The pointer returned by this function is valid until any of the functions
870+ * modifying the documents are called.
871+ *
872+ * An empty document produced by the parser signifies the end of a YAML
873+ * stream.
874+ *
875+ * @param[in] document A document object.
876+ *
877+ * @returns the node object or @c NULL if the document is empty.
878+ */
879+
880+YAML_DECLARE(yaml_node_t *)
881+yaml_document_get_root_node(yaml_document_t *document);
882+
883+/**
884+ * Create a SCALAR node and attach it to the document.
885+ *
886+ * The @a style argument may be ignored by the emitter.
887+ *
888+ * @param[in,out] document A document object.
889+ * @param[in] tag The scalar tag.
890+ * @param[in] value The scalar value.
891+ * @param[in] length The length of the scalar value.
892+ * @param[in] style The scalar style.
893+ *
894+ * @returns the node id or @c 0 on error.
895+ */
896+
897+YAML_DECLARE(int)
898+yaml_document_add_scalar(yaml_document_t *document,
899+ yaml_char_t *tag, yaml_char_t *value, int length,
900+ yaml_scalar_style_t style);
901+
902+/**
903+ * Create a SEQUENCE node and attach it to the document.
904+ *
905+ * The @a style argument may be ignored by the emitter.
906+ *
907+ * @param[in,out] document A document object.
908+ * @param[in] tag The sequence tag.
909+ * @param[in] style The sequence style.
910+ *
911+ * @returns the node id or @c 0 on error.
912+ */
913+
914+YAML_DECLARE(int)
915+yaml_document_add_sequence(yaml_document_t *document,
916+ yaml_char_t *tag, yaml_sequence_style_t style);
917+
918+/**
919+ * Create a MAPPING node and attach it to the document.
920+ *
921+ * The @a style argument may be ignored by the emitter.
922+ *
923+ * @param[in,out] document A document object.
924+ * @param[in] tag The sequence tag.
925+ * @param[in] style The sequence style.
926+ *
927+ * @returns the node id or @c 0 on error.
928+ */
929+
930+YAML_DECLARE(int)
931+yaml_document_add_mapping(yaml_document_t *document,
932+ yaml_char_t *tag, yaml_mapping_style_t style);
933+
934+/**
935+ * Add an item to a SEQUENCE node.
936+ *
937+ * @param[in,out] document A document object.
938+ * @param[in] sequence The sequence node id.
939+ * @param[in] item The item node id.
940+*
941+ * @returns @c 1 if the function succeeded, @c 0 on error.
942+ */
943+
944+YAML_DECLARE(int)
945+yaml_document_append_sequence_item(yaml_document_t *document,
946+ int sequence, int item);
947+
948+/**
949+ * Add a pair of a key and a value to a MAPPING node.
950+ *
951+ * @param[in,out] document A document object.
952+ * @param[in] mapping The mapping node id.
953+ * @param[in] key The key node id.
954+ * @param[in] value The value node id.
955+*
956+ * @returns @c 1 if the function succeeded, @c 0 on error.
957+ */
958+
959+YAML_DECLARE(int)
960+yaml_document_append_mapping_pair(yaml_document_t *document,
961+ int mapping, int key, int value);
962+
963+/** @} */
964+
965+/**
966+ * @defgroup parser Parser Definitions
967+ * @{
968+ */
969+
970+/**
971+ * The prototype of a read handler.
972+ *
973+ * The read handler is called when the parser needs to read more bytes from the
974+ * source. The handler should write not more than @a size bytes to the @a
975+ * buffer. The number of written bytes should be set to the @a length variable.
976+ *
977+ * @param[in,out] data A pointer to an application data specified by
978+ * yaml_parser_set_input().
979+ * @param[out] buffer The buffer to write the data from the source.
980+ * @param[in] size The size of the buffer.
981+ * @param[out] size_read The actual number of bytes read from the source.
982+ *
983+ * @returns On success, the handler should return @c 1. If the handler failed,
984+ * the returned value should be @c 0. On EOF, the handler should set the
985+ * @a size_read to @c 0 and return @c 1.
986+ */
987+
988+typedef int yaml_read_handler_t(void *data, unsigned char *buffer, size_t size,
989+ size_t *size_read);
990+
991+/**
992+ * This structure holds information about a potential simple key.
993+ */
994+
995+typedef struct yaml_simple_key_s {
996+ /** Is a simple key possible? */
997+ int possible;
998+
999+ /** Is a simple key required? */
1000+ int required;
1001+
1002+ /** The number of the token. */
1003+ size_t token_number;
1004+
1005+ /** The position mark. */
1006+ yaml_mark_t mark;
1007+} yaml_simple_key_t;
1008+
1009+/**
1010+ * The states of the parser.
1011+ */
1012+typedef enum yaml_parser_state_e {
1013+ /** Expect STREAM-START. */
1014+ YAML_PARSE_STREAM_START_STATE,
1015+ /** Expect the beginning of an implicit document. */
1016+ YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE,
1017+ /** Expect DOCUMENT-START. */
1018+ YAML_PARSE_DOCUMENT_START_STATE,
1019+ /** Expect the content of a document. */
1020+ YAML_PARSE_DOCUMENT_CONTENT_STATE,
1021+ /** Expect DOCUMENT-END. */
1022+ YAML_PARSE_DOCUMENT_END_STATE,
1023+ /** Expect a block node. */
1024+ YAML_PARSE_BLOCK_NODE_STATE,
1025+ /** Expect a block node or indentless sequence. */
1026+ YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE,
1027+ /** Expect a flow node. */
1028+ YAML_PARSE_FLOW_NODE_STATE,
1029+ /** Expect the first entry of a block sequence. */
1030+ YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE,
1031+ /** Expect an entry of a block sequence. */
1032+ YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE,
1033+ /** Expect an entry of an indentless sequence. */
1034+ YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE,
1035+ /** Expect the first key of a block mapping. */
1036+ YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE,
1037+ /** Expect a block mapping key. */
1038+ YAML_PARSE_BLOCK_MAPPING_KEY_STATE,
1039+ /** Expect a block mapping value. */
1040+ YAML_PARSE_BLOCK_MAPPING_VALUE_STATE,
1041+ /** Expect the first entry of a flow sequence. */
1042+ YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE,
1043+ /** Expect an entry of a flow sequence. */
1044+ YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE,
1045+ /** Expect a key of an ordered mapping. */
1046+ YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE,
1047+ /** Expect a value of an ordered mapping. */
1048+ YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE,
1049+ /** Expect the and of an ordered mapping entry. */
1050+ YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE,
1051+ /** Expect the first key of a flow mapping. */
1052+ YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE,
1053+ /** Expect a key of a flow mapping. */
1054+ YAML_PARSE_FLOW_MAPPING_KEY_STATE,
1055+ /** Expect a value of a flow mapping. */
1056+ YAML_PARSE_FLOW_MAPPING_VALUE_STATE,
1057+ /** Expect an empty value of a flow mapping. */
1058+ YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE,
1059+ /** Expect nothing. */
1060+ YAML_PARSE_END_STATE
1061+} yaml_parser_state_t;
1062+
1063+/**
1064+ * This structure holds aliases data.
1065+ */
1066+
1067+typedef struct yaml_alias_data_s {
1068+ /** The anchor. */
1069+ yaml_char_t *anchor;
1070+ /** The node id. */
1071+ int index;
1072+ /** The anchor mark. */
1073+ yaml_mark_t mark;
1074+} yaml_alias_data_t;
1075+
1076+/**
1077+ * The parser structure.
1078+ *
1079+ * All members are internal. Manage the structure using the @c yaml_parser_
1080+ * family of functions.
1081+ */
1082+
1083+typedef struct yaml_parser_s {
1084+
1085+ /**
1086+ * @name Error handling
1087+ * @{
1088+ */
1089+
1090+ /** Error type. */
1091+ yaml_error_type_t error;
1092+ /** Error description. */
1093+ const char *problem;
1094+ /** The byte about which the problem occured. */
1095+ size_t problem_offset;
1096+ /** The problematic value (@c -1 is none). */
1097+ int problem_value;
1098+ /** The problem position. */
1099+ yaml_mark_t problem_mark;
1100+ /** The error context. */
1101+ const char *context;
1102+ /** The context position. */
1103+ yaml_mark_t context_mark;
1104+
1105+ /**
1106+ * @}
1107+ */
1108+
1109+ /**
1110+ * @name Reader stuff
1111+ * @{
1112+ */
1113+
1114+ /** Read handler. */
1115+ yaml_read_handler_t *read_handler;
1116+
1117+ /** A pointer for passing to the read handler. */
1118+ void *read_handler_data;
1119+
1120+ /** Standard (string or file) input data. */
1121+ union {
1122+ /** String input data. */
1123+ struct {
1124+ /** The string start pointer. */
1125+ const unsigned char *start;
1126+ /** The string end pointer. */
1127+ const unsigned char *end;
1128+ /** The string current position. */
1129+ const unsigned char *current;
1130+ } string;
1131+
1132+ /** File input data. */
1133+ FILE *file;
1134+ } input;
1135+
1136+ /** EOF flag */
1137+ int eof;
1138+
1139+ /** The working buffer. */
1140+ struct {
1141+ /** The beginning of the buffer. */
1142+ yaml_char_t *start;
1143+ /** The end of the buffer. */
1144+ yaml_char_t *end;
1145+ /** The current position of the buffer. */
1146+ yaml_char_t *pointer;
1147+ /** The last filled position of the buffer. */
1148+ yaml_char_t *last;
1149+ } buffer;
1150+
1151+ /* The number of unread characters in the buffer. */
1152+ size_t unread;
1153+
1154+ /** The raw buffer. */
1155+ struct {
1156+ /** The beginning of the buffer. */
1157+ unsigned char *start;
1158+ /** The end of the buffer. */
1159+ unsigned char *end;
1160+ /** The current position of the buffer. */
1161+ unsigned char *pointer;
1162+ /** The last filled position of the buffer. */
1163+ unsigned char *last;
1164+ } raw_buffer;
1165+
1166+ /** The input encoding. */
1167+ yaml_encoding_t encoding;
1168+
1169+ /** The offset of the current position (in bytes). */
1170+ size_t offset;
1171+
1172+ /** The mark of the current position. */
1173+ yaml_mark_t mark;
1174+
1175+ /**
1176+ * @}
1177+ */
1178+
1179+ /**
1180+ * @name Scanner stuff
1181+ * @{
1182+ */
1183+
1184+ /** Have we started to scan the input stream? */
1185+ int stream_start_produced;
1186+
1187+ /** Have we reached the end of the input stream? */
1188+ int stream_end_produced;
1189+
1190+ /** The number of unclosed '[' and '{' indicators. */
1191+ int flow_level;
1192+
1193+ /** The tokens queue. */
1194+ struct {
1195+ /** The beginning of the tokens queue. */
1196+ yaml_token_t *start;
1197+ /** The end of the tokens queue. */
1198+ yaml_token_t *end;
1199+ /** The head of the tokens queue. */
1200+ yaml_token_t *head;
1201+ /** The tail of the tokens queue. */
1202+ yaml_token_t *tail;
1203+ } tokens;
1204+
1205+ /** The number of tokens fetched from the queue. */
1206+ size_t tokens_parsed;
1207+
1208+ /* Does the tokens queue contain a token ready for dequeueing. */
1209+ int token_available;
1210+
1211+ /** The indentation levels stack. */
1212+ struct {
1213+ /** The beginning of the stack. */
1214+ int *start;
1215+ /** The end of the stack. */
1216+ int *end;
1217+ /** The top of the stack. */
1218+ int *top;
1219+ } indents;
1220+
1221+ /** The current indentation level. */
1222+ int indent;
1223+
1224+ /** May a simple key occur at the current position? */
1225+ int simple_key_allowed;
1226+
1227+ /** The stack of simple keys. */
1228+ struct {
1229+ /** The beginning of the stack. */
1230+ yaml_simple_key_t *start;
1231+ /** The end of the stack. */
1232+ yaml_simple_key_t *end;
1233+ /** The top of the stack. */
1234+ yaml_simple_key_t *top;
1235+ } simple_keys;
1236+
1237+ /**
1238+ * @}
1239+ */
1240+
1241+ /**
1242+ * @name Parser stuff
1243+ * @{
1244+ */
1245+
1246+ /** The parser states stack. */
1247+ struct {
1248+ /** The beginning of the stack. */
1249+ yaml_parser_state_t *start;
1250+ /** The end of the stack. */
1251+ yaml_parser_state_t *end;
1252+ /** The top of the stack. */
1253+ yaml_parser_state_t *top;
1254+ } states;
1255+
1256+ /** The current parser state. */
1257+ yaml_parser_state_t state;
1258+
1259+ /** The stack of marks. */
1260+ struct {
1261+ /** The beginning of the stack. */
1262+ yaml_mark_t *start;
1263+ /** The end of the stack. */
1264+ yaml_mark_t *end;
1265+ /** The top of the stack. */
1266+ yaml_mark_t *top;
1267+ } marks;
1268+
1269+ /** The list of TAG directives. */
1270+ struct {
1271+ /** The beginning of the list. */
1272+ yaml_tag_directive_t *start;
1273+ /** The end of the list. */
1274+ yaml_tag_directive_t *end;
1275+ /** The top of the list. */
1276+ yaml_tag_directive_t *top;
1277+ } tag_directives;
1278+
1279+ /**
1280+ * @}
1281+ */
1282+
1283+ /**
1284+ * @name Dumper stuff
1285+ * @{
1286+ */
1287+
1288+ /** The alias data. */
1289+ struct {
1290+ /** The beginning of the list. */
1291+ yaml_alias_data_t *start;
1292+ /** The end of the list. */
1293+ yaml_alias_data_t *end;
1294+ /** The top of the list. */
1295+ yaml_alias_data_t *top;
1296+ } aliases;
1297+
1298+ /** The currently parsed document. */
1299+ yaml_document_t *document;
1300+
1301+ /**
1302+ * @}
1303+ */
1304+
1305+} yaml_parser_t;
1306+
1307+/**
1308+ * Initialize a parser.
1309+ *
1310+ * This function creates a new parser object. An application is responsible
1311+ * for destroying the object using the yaml_parser_delete() function.
1312+ *
1313+ * @param[out] parser An empty parser object.
1314+ *
1315+ * @returns @c 1 if the function succeeded, @c 0 on error.
1316+ */
1317+
1318+YAML_DECLARE(int)
1319+yaml_parser_initialize(yaml_parser_t *parser);
1320+
1321+/**
1322+ * Destroy a parser.
1323+ *
1324+ * @param[in,out] parser A parser object.
1325+ */
1326+
1327+YAML_DECLARE(void)
1328+yaml_parser_delete(yaml_parser_t *parser);
1329+
1330+/**
1331+ * Set a string input.
1332+ *
1333+ * Note that the @a input pointer must be valid while the @a parser object
1334+ * exists. The application is responsible for destroing @a input after
1335+ * destroying the @a parser.
1336+ *
1337+ * @param[in,out] parser A parser object.
1338+ * @param[in] input A source data.
1339+ * @param[in] size The length of the source data in bytes.
1340+ */
1341+
1342+YAML_DECLARE(void)
1343+yaml_parser_set_input_string(yaml_parser_t *parser,
1344+ const unsigned char *input, size_t size);
1345+
1346+/**
1347+ * Set a file input.
1348+ *
1349+ * @a file should be a file object open for reading. The application is
1350+ * responsible for closing the @a file.
1351+ *
1352+ * @param[in,out] parser A parser object.
1353+ * @param[in] file An open file.
1354+ */
1355+
1356+YAML_DECLARE(void)
1357+yaml_parser_set_input_file(yaml_parser_t *parser, FILE *file);
1358+
1359+/**
1360+ * Set a generic input handler.
1361+ *
1362+ * @param[in,out] parser A parser object.
1363+ * @param[in] handler A read handler.
1364+ * @param[in] data Any application data for passing to the read
1365+ * handler.
1366+ */
1367+
1368+YAML_DECLARE(void)
1369+yaml_parser_set_input(yaml_parser_t *parser,
1370+ yaml_read_handler_t *handler, void *data);
1371+
1372+/**
1373+ * Set the source encoding.
1374+ *
1375+ * @param[in,out] parser A parser object.
1376+ * @param[in] encoding The source encoding.
1377+ */
1378+
1379+YAML_DECLARE(void)
1380+yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding);
1381+
1382+/**
1383+ * Scan the input stream and produce the next token.
1384+ *
1385+ * Call the function subsequently to produce a sequence of tokens corresponding
1386+ * to the input stream. The initial token has the type
1387+ * @c YAML_STREAM_START_TOKEN while the ending token has the type
1388+ * @c YAML_STREAM_END_TOKEN.
1389+ *
1390+ * An application is responsible for freeing any buffers associated with the
1391+ * produced token object using the @c yaml_token_delete function.
1392+ *
1393+ * An application must not alternate the calls of yaml_parser_scan() with the
1394+ * calls of yaml_parser_parse() or yaml_parser_load(). Doing this will break
1395+ * the parser.
1396+ *
1397+ * @param[in,out] parser A parser object.
1398+ * @param[out] token An empty token object.
1399+ *
1400+ * @returns @c 1 if the function succeeded, @c 0 on error.
1401+ */
1402+
1403+YAML_DECLARE(int)
1404+yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token);
1405+
1406+/**
1407+ * Parse the input stream and produce the next parsing event.
1408+ *
1409+ * Call the function subsequently to produce a sequence of events corresponding
1410+ * to the input stream. The initial event has the type
1411+ * @c YAML_STREAM_START_EVENT while the ending event has the type
1412+ * @c YAML_STREAM_END_EVENT.
1413+ *
1414+ * An application is responsible for freeing any buffers associated with the
1415+ * produced event object using the yaml_event_delete() function.
1416+ *
1417+ * An application must not alternate the calls of yaml_parser_parse() with the
1418+ * calls of yaml_parser_scan() or yaml_parser_load(). Doing this will break the
1419+ * parser.
1420+ *
1421+ * @param[in,out] parser A parser object.
1422+ * @param[out] event An empty event object.
1423+ *
1424+ * @returns @c 1 if the function succeeded, @c 0 on error.
1425+ */
1426+
1427+YAML_DECLARE(int)
1428+yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event);
1429+
1430+/**
1431+ * Parse the input stream and produce the next YAML document.
1432+ *
1433+ * Call this function subsequently to produce a sequence of documents
1434+ * constituting the input stream.
1435+ *
1436+ * If the produced document has no root node, it means that the document
1437+ * end has been reached.
1438+ *
1439+ * An application is responsible for freeing any data associated with the
1440+ * produced document object using the yaml_document_delete() function.
1441+ *
1442+ * An application must not alternate the calls of yaml_parser_load() with the
1443+ * calls of yaml_parser_scan() or yaml_parser_parse(). Doing this will break
1444+ * the parser.
1445+ *
1446+ * @param[in,out] parser A parser object.
1447+ * @param[out] document An empty document object.
1448+ *
1449+ * @return @c 1 if the function succeeded, @c 0 on error.
1450+ */
1451+
1452+YAML_DECLARE(int)
1453+yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document);
1454+
1455+/** @} */
1456+
1457+/**
1458+ * @defgroup emitter Emitter Definitions
1459+ * @{
1460+ */
1461+
1462+/**
1463+ * The prototype of a write handler.
1464+ *
1465+ * The write handler is called when the emitter needs to flush the accumulated
1466+ * characters to the output. The handler should write @a size bytes of the
1467+ * @a buffer to the output.
1468+ *
1469+ * @param[in,out] data A pointer to an application data specified by
1470+ * yaml_emitter_set_output().
1471+ * @param[in] buffer The buffer with bytes to be written.
1472+ * @param[in] size The size of the buffer.
1473+ *
1474+ * @returns On success, the handler should return @c 1. If the handler failed,
1475+ * the returned value should be @c 0.
1476+ */
1477+
1478+typedef int yaml_write_handler_t(void *data, unsigned char *buffer, size_t size);
1479+
1480+/** The emitter states. */
1481+typedef enum yaml_emitter_state_e {
1482+ /** Expect STREAM-START. */
1483+ YAML_EMIT_STREAM_START_STATE,
1484+ /** Expect the first DOCUMENT-START or STREAM-END. */
1485+ YAML_EMIT_FIRST_DOCUMENT_START_STATE,
1486+ /** Expect DOCUMENT-START or STREAM-END. */
1487+ YAML_EMIT_DOCUMENT_START_STATE,
1488+ /** Expect the content of a document. */
1489+ YAML_EMIT_DOCUMENT_CONTENT_STATE,
1490+ /** Expect DOCUMENT-END. */
1491+ YAML_EMIT_DOCUMENT_END_STATE,
1492+ /** Expect the first item of a flow sequence. */
1493+ YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE,
1494+ /** Expect an item of a flow sequence. */
1495+ YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE,
1496+ /** Expect the first key of a flow mapping. */
1497+ YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE,
1498+ /** Expect a key of a flow mapping. */
1499+ YAML_EMIT_FLOW_MAPPING_KEY_STATE,
1500+ /** Expect a value for a simple key of a flow mapping. */
1501+ YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE,
1502+ /** Expect a value of a flow mapping. */
1503+ YAML_EMIT_FLOW_MAPPING_VALUE_STATE,
1504+ /** Expect the first item of a block sequence. */
1505+ YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE,
1506+ /** Expect an item of a block sequence. */
1507+ YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE,
1508+ /** Expect the first key of a block mapping. */
1509+ YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE,
1510+ /** Expect the key of a block mapping. */
1511+ YAML_EMIT_BLOCK_MAPPING_KEY_STATE,
1512+ /** Expect a value for a simple key of a block mapping. */
1513+ YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE,
1514+ /** Expect a value of a block mapping. */
1515+ YAML_EMIT_BLOCK_MAPPING_VALUE_STATE,
1516+ /** Expect nothing. */
1517+ YAML_EMIT_END_STATE
1518+} yaml_emitter_state_t;
1519+
1520+/**
1521+ * The emitter structure.
1522+ *
1523+ * All members are internal. Manage the structure using the @c yaml_emitter_
1524+ * family of functions.
1525+ */
1526+
1527+typedef struct yaml_emitter_s {
1528+
1529+ /**
1530+ * @name Error handling
1531+ * @{
1532+ */
1533+
1534+ /** Error type. */
1535+ yaml_error_type_t error;
1536+ /** Error description. */
1537+ const char *problem;
1538+
1539+ /**
1540+ * @}
1541+ */
1542+
1543+ /**
1544+ * @name Writer stuff
1545+ * @{
1546+ */
1547+
1548+ /** Write handler. */
1549+ yaml_write_handler_t *write_handler;
1550+
1551+ /** A pointer for passing to the white handler. */
1552+ void *write_handler_data;
1553+
1554+ /** Standard (string or file) output data. */
1555+ union {
1556+ /** String output data. */
1557+ struct {
1558+ /** The buffer pointer. */
1559+ unsigned char *buffer;
1560+ /** The buffer size. */
1561+ size_t size;
1562+ /** The number of written bytes. */
1563+ size_t *size_written;
1564+ } string;
1565+
1566+ /** File output data. */
1567+ FILE *file;
1568+ } output;
1569+
1570+ /** The working buffer. */
1571+ struct {
1572+ /** The beginning of the buffer. */
1573+ yaml_char_t *start;
1574+ /** The end of the buffer. */
1575+ yaml_char_t *end;
1576+ /** The current position of the buffer. */
1577+ yaml_char_t *pointer;
1578+ /** The last filled position of the buffer. */
1579+ yaml_char_t *last;
1580+ } buffer;
1581+
1582+ /** The raw buffer. */
1583+ struct {
1584+ /** The beginning of the buffer. */
1585+ unsigned char *start;
1586+ /** The end of the buffer. */
1587+ unsigned char *end;
1588+ /** The current position of the buffer. */
1589+ unsigned char *pointer;
1590+ /** The last filled position of the buffer. */
1591+ unsigned char *last;
1592+ } raw_buffer;
1593+
1594+ /** The stream encoding. */
1595+ yaml_encoding_t encoding;
1596+
1597+ /**
1598+ * @}
1599+ */
1600+
1601+ /**
1602+ * @name Emitter stuff
1603+ * @{
1604+ */
1605+
1606+ /** If the output is in the canonical style? */
1607+ int canonical;
1608+ /** The number of indentation spaces. */
1609+ int best_indent;
1610+ /** The preferred width of the output lines. */
1611+ int best_width;
1612+ /** Allow unescaped non-ASCII characters? */
1613+ int unicode;
1614+ /** The preferred line break. */
1615+ yaml_break_t line_break;
1616+
1617+ /** The stack of states. */
1618+ struct {
1619+ /** The beginning of the stack. */
1620+ yaml_emitter_state_t *start;
1621+ /** The end of the stack. */
1622+ yaml_emitter_state_t *end;
1623+ /** The top of the stack. */
1624+ yaml_emitter_state_t *top;
1625+ } states;
1626+
1627+ /** The current emitter state. */
1628+ yaml_emitter_state_t state;
1629+
1630+ /** The event queue. */
1631+ struct {
1632+ /** The beginning of the event queue. */
1633+ yaml_event_t *start;
1634+ /** The end of the event queue. */
1635+ yaml_event_t *end;
1636+ /** The head of the event queue. */
1637+ yaml_event_t *head;
1638+ /** The tail of the event queue. */
1639+ yaml_event_t *tail;
1640+ } events;
1641+
1642+ /** The stack of indentation levels. */
1643+ struct {
1644+ /** The beginning of the stack. */
1645+ int *start;
1646+ /** The end of the stack. */
1647+ int *end;
1648+ /** The top of the stack. */
1649+ int *top;
1650+ } indents;
1651+
1652+ /** The list of tag directives. */
1653+ struct {
1654+ /** The beginning of the list. */
1655+ yaml_tag_directive_t *start;
1656+ /** The end of the list. */
1657+ yaml_tag_directive_t *end;
1658+ /** The top of the list. */
1659+ yaml_tag_directive_t *top;
1660+ } tag_directives;
1661+
1662+ /** The current indentation level. */
1663+ int indent;
1664+
1665+ /** The current flow level. */
1666+ int flow_level;
1667+
1668+ /** Is it the document root context? */
1669+ int root_context;
1670+ /** Is it a sequence context? */
1671+ int sequence_context;
1672+ /** Is it a mapping context? */
1673+ int mapping_context;
1674+ /** Is it a simple mapping key context? */
1675+ int simple_key_context;
1676+
1677+ /** The current line. */
1678+ int line;
1679+ /** The current column. */
1680+ int column;
1681+ /** If the last character was a whitespace? */
1682+ int whitespace;
1683+ /** If the last character was an indentation character (' ', '-', '?', ':')? */
1684+ int indention;
1685+ /** If an explicit document end is required? */
1686+ int open_ended;
1687+
1688+ /** Anchor analysis. */
1689+ struct {
1690+ /** The anchor value. */
1691+ yaml_char_t *anchor;
1692+ /** The anchor length. */
1693+ size_t anchor_length;
1694+ /** Is it an alias? */
1695+ int alias;
1696+ } anchor_data;
1697+
1698+ /** Tag analysis. */
1699+ struct {
1700+ /** The tag handle. */
1701+ yaml_char_t *handle;
1702+ /** The tag handle length. */
1703+ size_t handle_length;
1704+ /** The tag suffix. */
1705+ yaml_char_t *suffix;
1706+ /** The tag suffix length. */
1707+ size_t suffix_length;
1708+ } tag_data;
1709+
1710+ /** Scalar analysis. */
1711+ struct {
1712+ /** The scalar value. */
1713+ yaml_char_t *value;
1714+ /** The scalar length. */
1715+ size_t length;
1716+ /** Does the scalar contain line breaks? */
1717+ int multiline;
1718+ /** Can the scalar be expessed in the flow plain style? */
1719+ int flow_plain_allowed;
1720+ /** Can the scalar be expressed in the block plain style? */
1721+ int block_plain_allowed;
1722+ /** Can the scalar be expressed in the single quoted style? */
1723+ int single_quoted_allowed;
1724+ /** Can the scalar be expressed in the literal or folded styles? */
1725+ int block_allowed;
1726+ /** The output style. */
1727+ yaml_scalar_style_t style;
1728+ } scalar_data;
1729+
1730+ /**
1731+ * @}
1732+ */
1733+
1734+ /**
1735+ * @name Dumper stuff
1736+ * @{
1737+ */
1738+
1739+ /** If the stream was already opened? */
1740+ int opened;
1741+ /** If the stream was already closed? */
1742+ int closed;
1743+
1744+ /** The information associated with the document nodes. */
1745+ struct {
1746+ /** The number of references. */
1747+ int references;
1748+ /** The anchor id. */
1749+ int anchor;
1750+ /** If the node has been emitted? */
1751+ int serialized;
1752+ } *anchors;
1753+
1754+ /** The last assigned anchor id. */
1755+ int last_anchor_id;
1756+
1757+ /** The currently emitted document. */
1758+ yaml_document_t *document;
1759+
1760+ /**
1761+ * @}
1762+ */
1763+
1764+} yaml_emitter_t;
1765+
1766+/**
1767+ * Initialize an emitter.
1768+ *
1769+ * This function creates a new emitter object. An application is responsible
1770+ * for destroying the object using the yaml_emitter_delete() function.
1771+ *
1772+ * @param[out] emitter An empty parser object.
1773+ *
1774+ * @returns @c 1 if the function succeeded, @c 0 on error.
1775+ */
1776+
1777+YAML_DECLARE(int)
1778+yaml_emitter_initialize(yaml_emitter_t *emitter);
1779+
1780+/**
1781+ * Destroy an emitter.
1782+ *
1783+ * @param[in,out] emitter An emitter object.
1784+ */
1785+
1786+YAML_DECLARE(void)
1787+yaml_emitter_delete(yaml_emitter_t *emitter);
1788+
1789+/**
1790+ * Set a string output.
1791+ *
1792+ * The emitter will write the output characters to the @a output buffer of the
1793+ * size @a size. The emitter will set @a size_written to the number of written
1794+ * bytes. If the buffer is smaller than required, the emitter produces the
1795+ * YAML_WRITE_ERROR error.
1796+ *
1797+ * @param[in,out] emitter An emitter object.
1798+ * @param[in] output An output buffer.
1799+ * @param[in] size The buffer size.
1800+ * @param[in] size_written The pointer to save the number of written
1801+ * bytes.
1802+ */
1803+
1804+YAML_DECLARE(void)
1805+yaml_emitter_set_output_string(yaml_emitter_t *emitter,
1806+ unsigned char *output, size_t size, size_t *size_written);
1807+
1808+/**
1809+ * Set a file output.
1810+ *
1811+ * @a file should be a file object open for writing. The application is
1812+ * responsible for closing the @a file.
1813+ *
1814+ * @param[in,out] emitter An emitter object.
1815+ * @param[in] file An open file.
1816+ */
1817+
1818+YAML_DECLARE(void)
1819+yaml_emitter_set_output_file(yaml_emitter_t *emitter, FILE *file);
1820+
1821+/**
1822+ * Set a generic output handler.
1823+ *
1824+ * @param[in,out] emitter An emitter object.
1825+ * @param[in] handler A write handler.
1826+ * @param[in] data Any application data for passing to the write
1827+ * handler.
1828+ */
1829+
1830+YAML_DECLARE(void)
1831+yaml_emitter_set_output(yaml_emitter_t *emitter,
1832+ yaml_write_handler_t *handler, void *data);
1833+
1834+/**
1835+ * Set the output encoding.
1836+ *
1837+ * @param[in,out] emitter An emitter object.
1838+ * @param[in] encoding The output encoding.
1839+ */
1840+
1841+YAML_DECLARE(void)
1842+yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding);
1843+
1844+/**
1845+ * Set if the output should be in the "canonical" format as in the YAML
1846+ * specification.
1847+ *
1848+ * @param[in,out] emitter An emitter object.
1849+ * @param[in] canonical If the output is canonical.
1850+ */
1851+
1852+YAML_DECLARE(void)
1853+yaml_emitter_set_canonical(yaml_emitter_t *emitter, int canonical);
1854+
1855+/**
1856+ * Set the intendation increment.
1857+ *
1858+ * @param[in,out] emitter An emitter object.
1859+ * @param[in] indent The indentation increment (1 < . < 10).
1860+ */
1861+
1862+YAML_DECLARE(void)
1863+yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent);
1864+
1865+/**
1866+ * Set the preferred line width. @c -1 means unlimited.
1867+ *
1868+ * @param[in,out] emitter An emitter object.
1869+ * @param[in] width The preferred line width.
1870+ */
1871+
1872+YAML_DECLARE(void)
1873+yaml_emitter_set_width(yaml_emitter_t *emitter, int width);
1874+
1875+/**
1876+ * Set if unescaped non-ASCII characters are allowed.
1877+ *
1878+ * @param[in,out] emitter An emitter object.
1879+ * @param[in] unicode If unescaped Unicode characters are allowed.
1880+ */
1881+
1882+YAML_DECLARE(void)
1883+yaml_emitter_set_unicode(yaml_emitter_t *emitter, int unicode);
1884+
1885+/**
1886+ * Set the preferred line break.
1887+ *
1888+ * @param[in,out] emitter An emitter object.
1889+ * @param[in] line_break The preferred line break.
1890+ */
1891+
1892+YAML_DECLARE(void)
1893+yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break);
1894+
1895+/**
1896+ * Emit an event.
1897+ *
1898+ * The event object may be generated using the yaml_parser_parse() function.
1899+ * The emitter takes the responsibility for the event object and destroys its
1900+ * content after it is emitted. The event object is destroyed even if the
1901+ * function fails.
1902+ *
1903+ * @param[in,out] emitter An emitter object.
1904+ * @param[in,out] event An event object.
1905+ *
1906+ * @returns @c 1 if the function succeeded, @c 0 on error.
1907+ */
1908+
1909+YAML_DECLARE(int)
1910+yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event);
1911+
1912+/**
1913+ * Start a YAML stream.
1914+ *
1915+ * This function should be used before yaml_emitter_dump() is called.
1916+ *
1917+ * @param[in,out] emitter An emitter object.
1918+ *
1919+ * @returns @c 1 if the function succeeded, @c 0 on error.
1920+ */
1921+
1922+YAML_DECLARE(int)
1923+yaml_emitter_open(yaml_emitter_t *emitter);
1924+
1925+/**
1926+ * Finish a YAML stream.
1927+ *
1928+ * This function should be used after yaml_emitter_dump() is called.
1929+ *
1930+ * @param[in,out] emitter An emitter object.
1931+ *
1932+ * @returns @c 1 if the function succeeded, @c 0 on error.
1933+ */
1934+
1935+YAML_DECLARE(int)
1936+yaml_emitter_close(yaml_emitter_t *emitter);
1937+
1938+/**
1939+ * Emit a YAML document.
1940+ *
1941+ * The documen object may be generated using the yaml_parser_load() function
1942+ * or the yaml_document_initialize() function. The emitter takes the
1943+ * responsibility for the document object and destoys its content after
1944+ * it is emitted. The document object is destroyedeven if the function fails.
1945+ *
1946+ * @param[in,out] emitter An emitter object.
1947+ * @param[in,out] document A document object.
1948+ *
1949+ * @returns @c 1 if the function succeeded, @c 0 on error.
1950+ */
1951+
1952+YAML_DECLARE(int)
1953+yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document);
1954+
1955+/**
1956+ * Flush the accumulated characters to the output.
1957+ *
1958+ * @param[in,out] emitter An emitter object.
1959+ *
1960+ * @returns @c 1 if the function succeeded, @c 0 on error.
1961+ */
1962+
1963+YAML_DECLARE(int)
1964+yaml_emitter_flush(yaml_emitter_t *emitter);
1965+
1966+/** @} */
1967+
1968+#ifdef __cplusplus
1969+}
1970+#endif
1971+
1972+#endif /* #ifndef YAML_H */
1973+
libyaml/yaml_private.hnew file+661
@@ -0,0 +1,661 @@
1+
2+#if HAVE_CONFIG_H
3+#include <config.h>
4+#endif
5+
6+#include <yaml.h>
7+
8+#include <assert.h>
9+#include <limits.h>
10+#include <stddef.h>
11+
12+#ifndef _MSC_VER
13+#include <stdint.h>
14+#else
15+#ifdef _WIN64
16+#define PTRDIFF_MAX _I64_MAX
17+#else
18+#define PTRDIFF_MAX INT_MAX
19+#endif
20+#endif
21+
22+/*
23+ * Memory management.
24+ */
25+
26+YAML_DECLARE(void *)
27+yaml_malloc(size_t size);
28+
29+YAML_DECLARE(void *)
30+yaml_realloc(void *ptr, size_t size);
31+
32+YAML_DECLARE(void)
33+yaml_free(void *ptr);
34+
35+YAML_DECLARE(yaml_char_t *)
36+yaml_strdup(const yaml_char_t *);
37+
38+/*
39+ * Reader: Ensure that the buffer contains at least `length` characters.
40+ */
41+
42+YAML_DECLARE(int)
43+yaml_parser_update_buffer(yaml_parser_t *parser, size_t length);
44+
45+/*
46+ * Scanner: Ensure that the token stack contains at least one token ready.
47+ */
48+
49+YAML_DECLARE(int)
50+yaml_parser_fetch_more_tokens(yaml_parser_t *parser);
51+
52+/*
53+ * The size of the input raw buffer.
54+ */
55+
56+#define INPUT_RAW_BUFFER_SIZE 16384
57+
58+/*
59+ * The size of the input buffer.
60+ *
61+ * It should be possible to decode the whole raw buffer.
62+ */
63+
64+#define INPUT_BUFFER_SIZE (INPUT_RAW_BUFFER_SIZE*3)
65+
66+/*
67+ * The size of the output buffer.
68+ */
69+
70+#define OUTPUT_BUFFER_SIZE 16384
71+
72+/*
73+ * The size of the output raw buffer.
74+ *
75+ * It should be possible to encode the whole output buffer.
76+ */
77+
78+#define OUTPUT_RAW_BUFFER_SIZE (OUTPUT_BUFFER_SIZE*2+2)
79+
80+/*
81+ * The size of other stacks and queues.
82+ */
83+
84+#define INITIAL_STACK_SIZE 16
85+#define INITIAL_QUEUE_SIZE 16
86+#define INITIAL_STRING_SIZE 16
87+
88+/*
89+ * Buffer management.
90+ */
91+
92+#define BUFFER_INIT(context,buffer,size) \
93+ (((buffer).start = yaml_malloc(size)) ? \
94+ ((buffer).last = (buffer).pointer = (buffer).start, \
95+ (buffer).end = (buffer).start+(size), \
96+ 1) : \
97+ ((context)->error = YAML_MEMORY_ERROR, \
98+ 0))
99+
100+#define BUFFER_DEL(context,buffer) \
101+ (yaml_free((buffer).start), \
102+ (buffer).start = (buffer).pointer = (buffer).end = 0)
103+
104+/*
105+ * String management.
106+ */
107+
108+typedef struct {
109+ yaml_char_t *start;
110+ yaml_char_t *end;
111+ yaml_char_t *pointer;
112+} yaml_string_t;
113+
114+YAML_DECLARE(int)
115+yaml_string_extend(yaml_char_t **start,
116+ yaml_char_t **pointer, yaml_char_t **end);
117+
118+YAML_DECLARE(int)
119+yaml_string_join(
120+ yaml_char_t **a_start, yaml_char_t **a_pointer, yaml_char_t **a_end,
121+ yaml_char_t **b_start, yaml_char_t **b_pointer, yaml_char_t **b_end);
122+
123+#define NULL_STRING { NULL, NULL, NULL }
124+
125+#define STRING(string,length) { (string), (string)+(length), (string) }
126+
127+#define STRING_ASSIGN(value,string,length) \
128+ ((value).start = (string), \
129+ (value).end = (string)+(length), \
130+ (value).pointer = (string))
131+
132+#define STRING_INIT(context,string,size) \
133+ (((string).start = yaml_malloc(size)) ? \
134+ ((string).pointer = (string).start, \
135+ (string).end = (string).start+(size), \
136+ memset((string).start, 0, (size)), \
137+ 1) : \
138+ ((context)->error = YAML_MEMORY_ERROR, \
139+ 0))
140+
141+#define STRING_DEL(context,string) \
142+ (yaml_free((string).start), \
143+ (string).start = (string).pointer = (string).end = 0)
144+
145+#define STRING_EXTEND(context,string) \
146+ (((string).pointer+5 < (string).end) \
147+ || yaml_string_extend(&(string).start, \
148+ &(string).pointer, &(string).end))
149+
150+#define CLEAR(context,string) \
151+ ((string).pointer = (string).start, \
152+ memset((string).start, 0, (string).end-(string).start))
153+
154+#define JOIN(context,string_a,string_b) \
155+ ((yaml_string_join(&(string_a).start, &(string_a).pointer, \
156+ &(string_a).end, &(string_b).start, \
157+ &(string_b).pointer, &(string_b).end)) ? \
158+ ((string_b).pointer = (string_b).start, \
159+ 1) : \
160+ ((context)->error = YAML_MEMORY_ERROR, \
161+ 0))
162+
163+/*
164+ * String check operations.
165+ */
166+
167+/*
168+ * Check the octet at the specified position.
169+ */
170+
171+#define CHECK_AT(string,octet,offset) \
172+ ((string).pointer[offset] == (yaml_char_t)(octet))
173+
174+/*
175+ * Check the current octet in the buffer.
176+ */
177+
178+#define CHECK(string,octet) CHECK_AT((string),(octet),0)
179+
180+/*
181+ * Check if the character at the specified position is an alphabetical
182+ * character, a digit, '_', or '-'.
183+ */
184+
185+#define IS_ALPHA_AT(string,offset) \
186+ (((string).pointer[offset] >= (yaml_char_t) '0' && \
187+ (string).pointer[offset] <= (yaml_char_t) '9') || \
188+ ((string).pointer[offset] >= (yaml_char_t) 'A' && \
189+ (string).pointer[offset] <= (yaml_char_t) 'Z') || \
190+ ((string).pointer[offset] >= (yaml_char_t) 'a' && \
191+ (string).pointer[offset] <= (yaml_char_t) 'z') || \
192+ (string).pointer[offset] == '_' || \
193+ (string).pointer[offset] == '-')
194+
195+#define IS_ALPHA(string) IS_ALPHA_AT((string),0)
196+
197+/*
198+ * Check if the character at the specified position is a digit.
199+ */
200+
201+#define IS_DIGIT_AT(string,offset) \
202+ (((string).pointer[offset] >= (yaml_char_t) '0' && \
203+ (string).pointer[offset] <= (yaml_char_t) '9'))
204+
205+#define IS_DIGIT(string) IS_DIGIT_AT((string),0)
206+
207+/*
208+ * Get the value of a digit.
209+ */
210+
211+#define AS_DIGIT_AT(string,offset) \
212+ ((string).pointer[offset] - (yaml_char_t) '0')
213+
214+#define AS_DIGIT(string) AS_DIGIT_AT((string),0)
215+
216+/*
217+ * Check if the character at the specified position is a hex-digit.
218+ */
219+
220+#define IS_HEX_AT(string,offset) \
221+ (((string).pointer[offset] >= (yaml_char_t) '0' && \
222+ (string).pointer[offset] <= (yaml_char_t) '9') || \
223+ ((string).pointer[offset] >= (yaml_char_t) 'A' && \
224+ (string).pointer[offset] <= (yaml_char_t) 'F') || \
225+ ((string).pointer[offset] >= (yaml_char_t) 'a' && \
226+ (string).pointer[offset] <= (yaml_char_t) 'f'))
227+
228+#define IS_HEX(string) IS_HEX_AT((string),0)
229+
230+/*
231+ * Get the value of a hex-digit.
232+ */
233+
234+#define AS_HEX_AT(string,offset) \
235+ (((string).pointer[offset] >= (yaml_char_t) 'A' && \
236+ (string).pointer[offset] <= (yaml_char_t) 'F') ? \
237+ ((string).pointer[offset] - (yaml_char_t) 'A' + 10) : \
238+ ((string).pointer[offset] >= (yaml_char_t) 'a' && \
239+ (string).pointer[offset] <= (yaml_char_t) 'f') ? \
240+ ((string).pointer[offset] - (yaml_char_t) 'a' + 10) : \
241+ ((string).pointer[offset] - (yaml_char_t) '0'))
242+
243+#define AS_HEX(string) AS_HEX_AT((string),0)
244+
245+/*
246+ * Check if the character is ASCII.
247+ */
248+
249+#define IS_ASCII_AT(string,offset) \
250+ ((string).pointer[offset] <= (yaml_char_t) '\x7F')
251+
252+#define IS_ASCII(string) IS_ASCII_AT((string),0)
253+
254+/*
255+ * Check if the character can be printed unescaped.
256+ */
257+
258+#define IS_PRINTABLE_AT(string,offset) \
259+ (((string).pointer[offset] == 0x0A) /* . == #x0A */ \
260+ || ((string).pointer[offset] >= 0x20 /* #x20 <= . <= #x7E */ \
261+ && (string).pointer[offset] <= 0x7E) \
262+ || ((string).pointer[offset] == 0xC2 /* #0xA0 <= . <= #xD7FF */ \
263+ && (string).pointer[offset+1] >= 0xA0) \
264+ || ((string).pointer[offset] > 0xC2 \
265+ && (string).pointer[offset] < 0xED) \
266+ || ((string).pointer[offset] == 0xED \
267+ && (string).pointer[offset+1] < 0xA0) \
268+ || ((string).pointer[offset] == 0xEE) \
269+ || ((string).pointer[offset] == 0xEF /* #xE000 <= . <= #xFFFD */ \
270+ && !((string).pointer[offset+1] == 0xBB /* && . != #xFEFF */ \
271+ && (string).pointer[offset+2] == 0xBF) \
272+ && !((string).pointer[offset+1] == 0xBF \
273+ && ((string).pointer[offset+2] == 0xBE \
274+ || (string).pointer[offset+2] == 0xBF))))
275+
276+#define IS_PRINTABLE(string) IS_PRINTABLE_AT((string),0)
277+
278+/*
279+ * Check if the character at the specified position is NUL.
280+ */
281+
282+#define IS_Z_AT(string,offset) CHECK_AT((string),'\0',(offset))
283+
284+#define IS_Z(string) IS_Z_AT((string),0)
285+
286+/*
287+ * Check if the character at the specified position is BOM.
288+ */
289+
290+#define IS_BOM_AT(string,offset) \
291+ (CHECK_AT((string),'\xEF',(offset)) \
292+ && CHECK_AT((string),'\xBB',(offset)+1) \
293+ && CHECK_AT((string),'\xBF',(offset)+2)) /* BOM (#xFEFF) */
294+
295+#define IS_BOM(string) IS_BOM_AT(string,0)
296+
297+/*
298+ * Check if the character at the specified position is space.
299+ */
300+
301+#define IS_SPACE_AT(string,offset) CHECK_AT((string),' ',(offset))
302+
303+#define IS_SPACE(string) IS_SPACE_AT((string),0)
304+
305+/*
306+ * Check if the character at the specified position is tab.
307+ */
308+
309+#define IS_TAB_AT(string,offset) CHECK_AT((string),'\t',(offset))
310+
311+#define IS_TAB(string) IS_TAB_AT((string),0)
312+
313+/*
314+ * Check if the character at the specified position is blank (space or tab).
315+ */
316+
317+#define IS_BLANK_AT(string,offset) \
318+ (IS_SPACE_AT((string),(offset)) || IS_TAB_AT((string),(offset)))
319+
320+#define IS_BLANK(string) IS_BLANK_AT((string),0)
321+
322+/*
323+ * Check if the character at the specified position is a line break.
324+ */
325+
326+#define IS_BREAK_AT(string,offset) \
327+ (CHECK_AT((string),'\r',(offset)) /* CR (#xD)*/ \
328+ || CHECK_AT((string),'\n',(offset)) /* LF (#xA) */ \
329+ || (CHECK_AT((string),'\xC2',(offset)) \
330+ && CHECK_AT((string),'\x85',(offset)+1)) /* NEL (#x85) */ \
331+ || (CHECK_AT((string),'\xE2',(offset)) \
332+ && CHECK_AT((string),'\x80',(offset)+1) \
333+ && CHECK_AT((string),'\xA8',(offset)+2)) /* LS (#x2028) */ \
334+ || (CHECK_AT((string),'\xE2',(offset)) \
335+ && CHECK_AT((string),'\x80',(offset)+1) \
336+ && CHECK_AT((string),'\xA9',(offset)+2))) /* PS (#x2029) */
337+
338+#define IS_BREAK(string) IS_BREAK_AT((string),0)
339+
340+#define IS_CRLF_AT(string,offset) \
341+ (CHECK_AT((string),'\r',(offset)) && CHECK_AT((string),'\n',(offset)+1))
342+
343+#define IS_CRLF(string) IS_CRLF_AT((string),0)
344+
345+/*
346+ * Check if the character is a line break or NUL.
347+ */
348+
349+#define IS_BREAKZ_AT(string,offset) \
350+ (IS_BREAK_AT((string),(offset)) || IS_Z_AT((string),(offset)))
351+
352+#define IS_BREAKZ(string) IS_BREAKZ_AT((string),0)
353+
354+/*
355+ * Check if the character is a line break, space, or NUL.
356+ */
357+
358+#define IS_SPACEZ_AT(string,offset) \
359+ (IS_SPACE_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset)))
360+
361+#define IS_SPACEZ(string) IS_SPACEZ_AT((string),0)
362+
363+/*
364+ * Check if the character is a line break, space, tab, or NUL.
365+ */
366+
367+#define IS_BLANKZ_AT(string,offset) \
368+ (IS_BLANK_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset)))
369+
370+#define IS_BLANKZ(string) IS_BLANKZ_AT((string),0)
371+
372+/*
373+ * Determine the width of the character.
374+ */
375+
376+#define WIDTH_AT(string,offset) \
377+ (((string).pointer[offset] & 0x80) == 0x00 ? 1 : \
378+ ((string).pointer[offset] & 0xE0) == 0xC0 ? 2 : \
379+ ((string).pointer[offset] & 0xF0) == 0xE0 ? 3 : \
380+ ((string).pointer[offset] & 0xF8) == 0xF0 ? 4 : 0)
381+
382+#define WIDTH(string) WIDTH_AT((string),0)
383+
384+/*
385+ * Move the string pointer to the next character.
386+ */
387+
388+#define MOVE(string) ((string).pointer += WIDTH((string)))
389+
390+/*
391+ * Copy a character and move the pointers of both strings.
392+ */
393+
394+#define COPY(string_a,string_b) \
395+ ((*(string_b).pointer & 0x80) == 0x00 ? \
396+ (*((string_a).pointer++) = *((string_b).pointer++)) : \
397+ (*(string_b).pointer & 0xE0) == 0xC0 ? \
398+ (*((string_a).pointer++) = *((string_b).pointer++), \
399+ *((string_a).pointer++) = *((string_b).pointer++)) : \
400+ (*(string_b).pointer & 0xF0) == 0xE0 ? \
401+ (*((string_a).pointer++) = *((string_b).pointer++), \
402+ *((string_a).pointer++) = *((string_b).pointer++), \
403+ *((string_a).pointer++) = *((string_b).pointer++)) : \
404+ (*(string_b).pointer & 0xF8) == 0xF0 ? \
405+ (*((string_a).pointer++) = *((string_b).pointer++), \
406+ *((string_a).pointer++) = *((string_b).pointer++), \
407+ *((string_a).pointer++) = *((string_b).pointer++), \
408+ *((string_a).pointer++) = *((string_b).pointer++)) : 0)
409+
410+/*
411+ * Stack and queue management.
412+ */
413+
414+YAML_DECLARE(int)
415+yaml_stack_extend(void **start, void **top, void **end);
416+
417+YAML_DECLARE(int)
418+yaml_queue_extend(void **start, void **head, void **tail, void **end);
419+
420+#define STACK_INIT(context,stack,size) \
421+ (((stack).start = yaml_malloc((size)*sizeof(*(stack).start))) ? \
422+ ((stack).top = (stack).start, \
423+ (stack).end = (stack).start+(size), \
424+ 1) : \
425+ ((context)->error = YAML_MEMORY_ERROR, \
426+ 0))
427+
428+#define STACK_DEL(context,stack) \
429+ (yaml_free((stack).start), \
430+ (stack).start = (stack).top = (stack).end = 0)
431+
432+#define STACK_EMPTY(context,stack) \
433+ ((stack).start == (stack).top)
434+
435+#define STACK_LIMIT(context,stack,size) \
436+ ((stack).top - (stack).start < (size) ? \
437+ 1 : \
438+ ((context)->error = YAML_MEMORY_ERROR, \
439+ 0))
440+
441+#define PUSH(context,stack,value) \
442+ (((stack).top != (stack).end \
443+ || yaml_stack_extend((void **)&(stack).start, \
444+ (void **)&(stack).top, (void **)&(stack).end)) ? \
445+ (*((stack).top++) = value, \
446+ 1) : \
447+ ((context)->error = YAML_MEMORY_ERROR, \
448+ 0))
449+
450+#define POP(context,stack) \
451+ (*(--(stack).top))
452+
453+#define QUEUE_INIT(context,queue,size) \
454+ (((queue).start = yaml_malloc((size)*sizeof(*(queue).start))) ? \
455+ ((queue).head = (queue).tail = (queue).start, \
456+ (queue).end = (queue).start+(size), \
457+ 1) : \
458+ ((context)->error = YAML_MEMORY_ERROR, \
459+ 0))
460+
461+#define QUEUE_DEL(context,queue) \
462+ (yaml_free((queue).start), \
463+ (queue).start = (queue).head = (queue).tail = (queue).end = 0)
464+
465+#define QUEUE_EMPTY(context,queue) \
466+ ((queue).head == (queue).tail)
467+
468+#define ENQUEUE(context,queue,value) \
469+ (((queue).tail != (queue).end \
470+ || yaml_queue_extend((void **)&(queue).start, (void **)&(queue).head, \
471+ (void **)&(queue).tail, (void **)&(queue).end)) ? \
472+ (*((queue).tail++) = value, \
473+ 1) : \
474+ ((context)->error = YAML_MEMORY_ERROR, \
475+ 0))
476+
477+#define DEQUEUE(context,queue) \
478+ (*((queue).head++))
479+
480+#define QUEUE_INSERT(context,queue,index,value) \
481+ (((queue).tail != (queue).end \
482+ || yaml_queue_extend((void **)&(queue).start, (void **)&(queue).head, \
483+ (void **)&(queue).tail, (void **)&(queue).end)) ? \
484+ (memmove((queue).head+(index)+1,(queue).head+(index), \
485+ ((queue).tail-(queue).head-(index))*sizeof(*(queue).start)), \
486+ *((queue).head+(index)) = value, \
487+ (queue).tail++, \
488+ 1) : \
489+ ((context)->error = YAML_MEMORY_ERROR, \
490+ 0))
491+
492+/*
493+ * Token initializers.
494+ */
495+
496+#define TOKEN_INIT(token,token_type,token_start_mark,token_end_mark) \
497+ (memset(&(token), 0, sizeof(yaml_token_t)), \
498+ (token).type = (token_type), \
499+ (token).start_mark = (token_start_mark), \
500+ (token).end_mark = (token_end_mark))
501+
502+#define STREAM_START_TOKEN_INIT(token,token_encoding,start_mark,end_mark) \
503+ (TOKEN_INIT((token),YAML_STREAM_START_TOKEN,(start_mark),(end_mark)), \
504+ (token).data.stream_start.encoding = (token_encoding))
505+
506+#define STREAM_END_TOKEN_INIT(token,start_mark,end_mark) \
507+ (TOKEN_INIT((token),YAML_STREAM_END_TOKEN,(start_mark),(end_mark)))
508+
509+#define ALIAS_TOKEN_INIT(token,token_value,start_mark,end_mark) \
510+ (TOKEN_INIT((token),YAML_ALIAS_TOKEN,(start_mark),(end_mark)), \
511+ (token).data.alias.value = (token_value))
512+
513+#define ANCHOR_TOKEN_INIT(token,token_value,start_mark,end_mark) \
514+ (TOKEN_INIT((token),YAML_ANCHOR_TOKEN,(start_mark),(end_mark)), \
515+ (token).data.anchor.value = (token_value))
516+
517+#define TAG_TOKEN_INIT(token,token_handle,token_suffix,start_mark,end_mark) \
518+ (TOKEN_INIT((token),YAML_TAG_TOKEN,(start_mark),(end_mark)), \
519+ (token).data.tag.handle = (token_handle), \
520+ (token).data.tag.suffix = (token_suffix))
521+
522+#define SCALAR_TOKEN_INIT(token,token_value,token_length,token_style,start_mark,end_mark) \
523+ (TOKEN_INIT((token),YAML_SCALAR_TOKEN,(start_mark),(end_mark)), \
524+ (token).data.scalar.value = (token_value), \
525+ (token).data.scalar.length = (token_length), \
526+ (token).data.scalar.style = (token_style))
527+
528+#define VERSION_DIRECTIVE_TOKEN_INIT(token,token_major,token_minor,start_mark,end_mark) \
529+ (TOKEN_INIT((token),YAML_VERSION_DIRECTIVE_TOKEN,(start_mark),(end_mark)), \
530+ (token).data.version_directive.major = (token_major), \
531+ (token).data.version_directive.minor = (token_minor))
532+
533+#define TAG_DIRECTIVE_TOKEN_INIT(token,token_handle,token_prefix,start_mark,end_mark) \
534+ (TOKEN_INIT((token),YAML_TAG_DIRECTIVE_TOKEN,(start_mark),(end_mark)), \
535+ (token).data.tag_directive.handle = (token_handle), \
536+ (token).data.tag_directive.prefix = (token_prefix))
537+
538+/*
539+ * Event initializers.
540+ */
541+
542+#define EVENT_INIT(event,event_type,event_start_mark,event_end_mark) \
543+ (memset(&(event), 0, sizeof(yaml_event_t)), \
544+ (event).type = (event_type), \
545+ (event).start_mark = (event_start_mark), \
546+ (event).end_mark = (event_end_mark))
547+
548+#define STREAM_START_EVENT_INIT(event,event_encoding,start_mark,end_mark) \
549+ (EVENT_INIT((event),YAML_STREAM_START_EVENT,(start_mark),(end_mark)), \
550+ (event).data.stream_start.encoding = (event_encoding))
551+
552+#define STREAM_END_EVENT_INIT(event,start_mark,end_mark) \
553+ (EVENT_INIT((event),YAML_STREAM_END_EVENT,(start_mark),(end_mark)))
554+
555+#define DOCUMENT_START_EVENT_INIT(event,event_version_directive, \
556+ event_tag_directives_start,event_tag_directives_end,event_implicit,start_mark,end_mark) \
557+ (EVENT_INIT((event),YAML_DOCUMENT_START_EVENT,(start_mark),(end_mark)), \
558+ (event).data.document_start.version_directive = (event_version_directive), \
559+ (event).data.document_start.tag_directives.start = (event_tag_directives_start), \
560+ (event).data.document_start.tag_directives.end = (event_tag_directives_end), \
561+ (event).data.document_start.implicit = (event_implicit))
562+
563+#define DOCUMENT_END_EVENT_INIT(event,event_implicit,start_mark,end_mark) \
564+ (EVENT_INIT((event),YAML_DOCUMENT_END_EVENT,(start_mark),(end_mark)), \
565+ (event).data.document_end.implicit = (event_implicit))
566+
567+#define ALIAS_EVENT_INIT(event,event_anchor,start_mark,end_mark) \
568+ (EVENT_INIT((event),YAML_ALIAS_EVENT,(start_mark),(end_mark)), \
569+ (event).data.alias.anchor = (event_anchor))
570+
571+#define SCALAR_EVENT_INIT(event,event_anchor,event_tag,event_value,event_length, \
572+ event_plain_implicit, event_quoted_implicit,event_style,start_mark,end_mark) \
573+ (EVENT_INIT((event),YAML_SCALAR_EVENT,(start_mark),(end_mark)), \
574+ (event).data.scalar.anchor = (event_anchor), \
575+ (event).data.scalar.tag = (event_tag), \
576+ (event).data.scalar.value = (event_value), \
577+ (event).data.scalar.length = (event_length), \
578+ (event).data.scalar.plain_implicit = (event_plain_implicit), \
579+ (event).data.scalar.quoted_implicit = (event_quoted_implicit), \
580+ (event).data.scalar.style = (event_style))
581+
582+#define SEQUENCE_START_EVENT_INIT(event,event_anchor,event_tag, \
583+ event_implicit,event_style,start_mark,end_mark) \
584+ (EVENT_INIT((event),YAML_SEQUENCE_START_EVENT,(start_mark),(end_mark)), \
585+ (event).data.sequence_start.anchor = (event_anchor), \
586+ (event).data.sequence_start.tag = (event_tag), \
587+ (event).data.sequence_start.implicit = (event_implicit), \
588+ (event).data.sequence_start.style = (event_style))
589+
590+#define SEQUENCE_END_EVENT_INIT(event,start_mark,end_mark) \
591+ (EVENT_INIT((event),YAML_SEQUENCE_END_EVENT,(start_mark),(end_mark)))
592+
593+#define MAPPING_START_EVENT_INIT(event,event_anchor,event_tag, \
594+ event_implicit,event_style,start_mark,end_mark) \
595+ (EVENT_INIT((event),YAML_MAPPING_START_EVENT,(start_mark),(end_mark)), \
596+ (event).data.mapping_start.anchor = (event_anchor), \
597+ (event).data.mapping_start.tag = (event_tag), \
598+ (event).data.mapping_start.implicit = (event_implicit), \
599+ (event).data.mapping_start.style = (event_style))
600+
601+#define MAPPING_END_EVENT_INIT(event,start_mark,end_mark) \
602+ (EVENT_INIT((event),YAML_MAPPING_END_EVENT,(start_mark),(end_mark)))
603+
604+/*
605+ * Document initializer.
606+ */
607+
608+#define DOCUMENT_INIT(document,document_nodes_start,document_nodes_end, \
609+ document_version_directive,document_tag_directives_start, \
610+ document_tag_directives_end,document_start_implicit, \
611+ document_end_implicit,document_start_mark,document_end_mark) \
612+ (memset(&(document), 0, sizeof(yaml_document_t)), \
613+ (document).nodes.start = (document_nodes_start), \
614+ (document).nodes.end = (document_nodes_end), \
615+ (document).nodes.top = (document_nodes_start), \
616+ (document).version_directive = (document_version_directive), \
617+ (document).tag_directives.start = (document_tag_directives_start), \
618+ (document).tag_directives.end = (document_tag_directives_end), \
619+ (document).start_implicit = (document_start_implicit), \
620+ (document).end_implicit = (document_end_implicit), \
621+ (document).start_mark = (document_start_mark), \
622+ (document).end_mark = (document_end_mark))
623+
624+/*
625+ * Node initializers.
626+ */
627+
628+#define NODE_INIT(node,node_type,node_tag,node_start_mark,node_end_mark) \
629+ (memset(&(node), 0, sizeof(yaml_node_t)), \
630+ (node).type = (node_type), \
631+ (node).tag = (node_tag), \
632+ (node).start_mark = (node_start_mark), \
633+ (node).end_mark = (node_end_mark))
634+
635+#define SCALAR_NODE_INIT(node,node_tag,node_value,node_length, \
636+ node_style,start_mark,end_mark) \
637+ (NODE_INIT((node),YAML_SCALAR_NODE,(node_tag),(start_mark),(end_mark)), \
638+ (node).data.scalar.value = (node_value), \
639+ (node).data.scalar.length = (node_length), \
640+ (node).data.scalar.style = (node_style))
641+
642+#define SEQUENCE_NODE_INIT(node,node_tag,node_items_start,node_items_end, \
643+ node_style,start_mark,end_mark) \
644+ (NODE_INIT((node),YAML_SEQUENCE_NODE,(node_tag),(start_mark),(end_mark)), \
645+ (node).data.sequence.items.start = (node_items_start), \
646+ (node).data.sequence.items.end = (node_items_end), \
647+ (node).data.sequence.items.top = (node_items_start), \
648+ (node).data.sequence.style = (node_style))
649+
650+#define MAPPING_NODE_INIT(node,node_tag,node_pairs_start,node_pairs_end, \
651+ node_style,start_mark,end_mark) \
652+ (NODE_INIT((node),YAML_MAPPING_NODE,(node_tag),(start_mark),(end_mark)), \
653+ (node).data.mapping.pairs.start = (node_pairs_start), \
654+ (node).data.mapping.pairs.end = (node_pairs_end), \
655+ (node).data.mapping.pairs.top = (node_pairs_start), \
656+ (node).data.mapping.style = (node_style))
657+
658+#define YAML_VERSION_STRING "0.1.5"
659+#define YAML_VERSION_MAJOR 0
660+#define YAML_VERSION_MINOR 1
661+#define YAML_VERSION_PATCH 5
yaml/parser-test.hs → parser-test.hsrenamed

The content is the same.

stack.yaml+1−8
@@ -1,12 +1,5 @@
1−resolver: lts-22.13
1+resolver: lts-6.14
22
33flags:
44 yaml:
55 no-examples: false
6−
7−packages:
8− - yaml
9− - libyaml
10−
11−extra-deps:
12− - libyaml-clib-0.2.5
test/Data/Yaml/IncludeSpec.hsnew file+44
@@ -0,0 +1,44 @@
1+{-# LANGUAGE QuasiQuotes #-}
2+module Data.Yaml.IncludeSpec (main, spec) where
3+
4+import Test.Hspec
5+import Data.Either.Compat
6+import Data.Aeson
7+import Data.Aeson.QQ
8+import Data.Yaml (ParseException)
9+
10+import Data.Yaml.Include
11+
12+main :: IO ()
13+main = hspec spec
14+
15+spec :: Spec
16+spec = do
17+ describe "decodeFile" $ do
18+ it "supports includes" $ do
19+ decodeFile "test/resources/foo.yaml" `shouldReturn` Just [aesonQQ|
20+ {
21+ foo: 23,
22+ bar: {one: 1, two: 2},
23+ baz: 42
24+ }
25+ |]
26+
27+ it "supports recursive includes" $ do
28+ decodeFile "test/resources/baz.yaml" `shouldReturn` Just [aesonQQ|
29+ {
30+ foo: {
31+ foo: 23,
32+ bar: {one: 1, two: 2},
33+ baz: 42
34+ }
35+ }
36+ |]
37+
38+ it "aborts on cyclic includes" $ do
39+ (decodeFile "test/resources/loop/foo.yaml" :: IO (Maybe Value)) `shouldThrow` anyException
40+
41+ describe "decodeFileEither" $ do
42+ context "when file does not exist" $ do
43+ it "returns Left" $ do
44+ (decodeFileEither "./does_not_exist.yaml" :: IO (Either ParseException Value)) >>= (`shouldSatisfy` isLeft)
test/Data/YamlSpec.hsnew file+517
@@ -0,0 +1,517 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE PackageImports #-}
3+{-# LANGUAGE ScopedTypeVariables #-}
4+{-# LANGUAGE OverloadedStrings #-}
5+{-# LANGUAGE TemplateHaskell #-}
6+
7+module Data.YamlSpec (main, spec) where
8+
9+import qualified Text.Libyaml as Y
10+import qualified Data.ByteString.Char8 as B8
11+
12+import Test.HUnit hiding (Test, path)
13+
14+import qualified Data.Conduit as C
15+import qualified Control.Monad.Trans.Resource as C
16+import qualified Data.Conduit.List as CL
17+
18+import Control.Monad
19+import Control.Exception (try, SomeException)
20+import Test.Hspec
21+import Data.Either.Compat
22+import System.Directory (createDirectory, createDirectoryIfMissing)
23+import Test.Mockery.Directory
24+
25+import qualified Data.Yaml as D
26+import qualified Data.Yaml.Pretty as Pretty
27+import Data.Yaml (object, array, (.=))
28+import Data.Maybe
29+import qualified Data.HashMap.Strict as M
30+import qualified Data.Text as T
31+import Data.Aeson.TH
32+import Data.Text (Text)
33+import Data.Vector (Vector)
34+import qualified Data.Vector as V
35+import Data.HashMap.Strict (HashMap)
36+import qualified Data.HashMap.Strict as HM
37+import System.IO (hClose)
38+import System.IO.Temp (withSystemTempFile)
39+
40+data TestJSON = TestJSON
41+ { string :: Text
42+ , number :: Int
43+ , anArray :: Vector Text
44+ , hash :: HashMap Text Text
45+ , extrastring :: Text
46+ } deriving (Show, Eq)
47+
48+deriveJSON defaultOptions ''TestJSON
49+
50+main :: IO ()
51+main = hspec spec
52+
53+spec :: Spec
54+spec = do
55+ describe "streaming" $ do
56+ it "count scalars with anchor" caseCountScalarsWithAnchor
57+ it "count sequences with anchor" caseCountSequencesWithAnchor
58+ it "count mappings with anchor" caseCountMappingsWithAnchor
59+ it "count aliases" caseCountAliases
60+ it "count scalars" caseCountScalars
61+ it "largest string" caseLargestString
62+ it "encode/decode" caseEncodeDecode
63+ it "encode/decode file" caseEncodeDecodeFile
64+ it "interleaved encode/decode" caseInterleave
65+ it "decode invalid document (without segfault)" caseDecodeInvalidDocument
66+ describe "Data.Yaml" $ do
67+ it "encode/decode" caseEncodeDecodeData
68+ it "encode/decode file" caseEncodeDecodeFileData
69+ it "encode/decode files with non-ASCII names" caseEncodeDecodeNonAsciiFileData
70+ it "encode/decode strings" caseEncodeDecodeStrings
71+ it "decode invalid file" caseDecodeInvalid
72+ it "processes datatypes" caseDataTypes
73+ describe "Data.Yaml.Pretty" $ do
74+ it "encode/decode" caseEncodeDecodeDataPretty
75+ it "encode/decode strings" caseEncodeDecodeStringsPretty
76+ it "processes datatypes" caseDataTypesPretty
77+ describe "Data.Yaml aliases" $ do
78+ it "simple scalar alias" caseSimpleScalarAlias
79+ it "simple sequence alias" caseSimpleSequenceAlias
80+ it "simple mapping alias" caseSimpleMappingAlias
81+ it "mapping alias before anchor" caseMappingAliasBeforeAnchor
82+ it "mapping alias inside anchor" caseMappingAliasInsideAnchor
83+ it "scalar alias overriding" caseScalarAliasOverriding
84+ describe "Data.Yaml merge keys" $ do
85+ it "test uniqueness of keys" caseAllKeysShouldBeUnique
86+ it "test mapping merge" caseSimpleMappingMerge
87+ it "test sequence of mappings merging" caseMergeSequence
88+ describe "numbers" $ do
89+ it "parses as string when quoted" caseQuotedNumber
90+ it "parses as number when unquoted" caseUnquotedNumber
91+ it "parses as number !!str is present" caseAttribNumber
92+ it "integers have no decimals" caseIntegerDecimals
93+ describe "booleans" $ do
94+ it "parses when all lowercase" caseLowercaseBool
95+ it "parses when all uppercase" caseUppercaseBool
96+ it "parses when titlecase" caseTitlecaseBool
97+ describe "empty input" $ do
98+ it "doesn't crash" caseEmptyInput
99+ describe "alias stripping" $ do
100+ it "works" caseStripAlias
101+ describe "nulls" $ do
102+ checkNull "null"
103+ checkNull "Null"
104+ checkNull "NULL"
105+ checkNull "~"
106+ checkNull ""
107+
108+ describe "pretty output" $ do
109+ it "simple nulls" $ D.encode (object ["foo" .= D.Null]) `shouldBe` "foo: null\n"
110+ it "simple numbers" $ D.encode (object ["foo" .= (4 :: Int)]) `shouldBe` "foo: 4\n"
111+ it "True" $ D.encode (object ["foo" .= True]) `shouldBe` "foo: true\n"
112+ it "False" $ D.encode (object ["foo" .= False]) `shouldBe` "foo: false\n"
113+ it "simple string" $ D.encode (object ["foo" .= ("bar" :: T.Text)]) `shouldBe` "foo: bar\n"
114+
115+ describe "special keys" $ do
116+ let tester key = it (T.unpack key) $
117+ let value = object [key .= True]
118+ in D.decode (D.encode value) `shouldBe` Just value
119+ mapM_ tester specialStrings
120+
121+ describe "special values" $ do
122+ let tester value = it (T.unpack value) $
123+ let value' = object ["foo" .= value]
124+ in D.decode (D.encode value') `shouldBe` Just value'
125+ mapM_ tester specialStrings
126+
127+ describe "decodeFileEither" $ do
128+ it "loads YAML through JSON into Haskell data" $ do
129+ tj <- either (error . show) id `fmap` D.decodeFileEither "test/json.yaml"
130+ tj `shouldBe` TestJSON
131+ { string = "str"
132+ , number = 2
133+ , anArray = V.fromList ["a", "b"]
134+ , hash = HM.fromList [("key1", "value1"), ("key2", "value2")]
135+ , extrastring = "1234-foo"
136+ }
137+
138+ context "when file does not exist" $ do
139+ it "returns Left" $ do
140+ (D.decodeFileEither "./does_not_exist.yaml" :: IO (Either D.ParseException D.Value)) >>= (`shouldSatisfy` isLeft)
141+
142+
143+ describe "round-tripping of special scalars" $ do
144+ let special = words "y Y On ON false 12345 12345.0 12345a 12e3"
145+ forM_ special $ \w -> it w $
146+ let v = object ["word" .= w]
147+ in D.decode (D.encode v) `shouldBe` Just v
148+ it "no tags" $ D.encode (object ["word" .= ("true" :: String)]) `shouldBe` "word: 'true'\n"
149+
150+ it "aliases in keys #49" caseIssue49
151+
152+ it "serialization of +123 #64" $ do
153+ D.decode (D.encode ("+123" :: String)) `shouldBe` Just ("+123" :: String)
154+
155+ it "preserves Scientific precision" casePreservesScientificPrecision
156+
157+ it "truncates files" caseTruncatesFiles
158+
159+
160+specialStrings :: [T.Text]
161+specialStrings =
162+ [ "fo\"o"
163+ , "fo\'o"
164+ , "fo\\'o"
165+ , "fo: o"
166+ , "foo\nbar\nbaz\n"
167+ ]
168+
169+counter :: Monad m => (Y.Event -> Bool) -> C.Sink Y.Event m Int
170+counter pred' =
171+ CL.fold (\cnt e -> (if pred' e then 1 else 0) + cnt) 0
172+
173+caseHelper :: String
174+ -> (Y.Event -> Bool)
175+ -> Int
176+ -> Assertion
177+caseHelper yamlString pred' expRes = do
178+ res <- C.runResourceT $ Y.decode (B8.pack yamlString) C.$$ counter pred'
179+ res @?= expRes
180+
181+caseCountScalarsWithAnchor :: Assertion
182+caseCountScalarsWithAnchor =
183+ caseHelper yamlString isScalarA 1
184+ where
185+ yamlString = "foo:\n - &anchor bin1\n - bin2\n - bin3"
186+ isScalarA (Y.EventScalar _ _ _ (Just _)) = True
187+ isScalarA _ = False
188+
189+caseCountSequencesWithAnchor :: Assertion
190+caseCountSequencesWithAnchor =
191+ caseHelper yamlString isSequenceStartA 1
192+ where
193+ yamlString = "foo: &anchor\n - bin1\n - bin2\n - bin3"
194+ isSequenceStartA (Y.EventSequenceStart (Just _)) = True
195+ isSequenceStartA _ = False
196+
197+caseCountMappingsWithAnchor :: Assertion
198+caseCountMappingsWithAnchor =
199+ caseHelper yamlString isMappingA 1
200+ where
201+ yamlString = "foo: &anchor\n key1: bin1\n key2: bin2\n key3: bin3"
202+ isMappingA (Y.EventMappingStart (Just _)) = True
203+ isMappingA _ = False
204+
205+caseCountAliases :: Assertion
206+caseCountAliases =
207+ caseHelper yamlString isAlias 1
208+ where
209+ yamlString = "foo: &anchor\n key1: bin1\n key2: bin2\n key3: bin3\nboo: *anchor"
210+ isAlias Y.EventAlias{} = True
211+ isAlias _ = False
212+
213+caseCountScalars :: Assertion
214+caseCountScalars = do
215+ res <- C.runResourceT $ Y.decode yamlBS C.$$ CL.fold adder accum
216+ res @?= (7, 1, 2)
217+ where
218+ yamlString = "foo:\n baz: [bin1, bin2, bin3]\nbaz: bazval"
219+ yamlBS = B8.pack yamlString
220+ adder (s, l, m) (Y.EventScalar{}) = (s + 1, l, m)
221+ adder (s, l, m) (Y.EventSequenceStart{}) = (s, l + 1, m)
222+ adder (s, l, m) (Y.EventMappingStart{}) = (s, l, m + 1)
223+ adder a _ = a
224+ accum = (0, 0, 0) :: (Int, Int, Int)
225+
226+caseLargestString :: Assertion
227+caseLargestString = do
228+ res <- C.runResourceT $ Y.decodeFile filePath C.$$ CL.fold adder accum
229+ res @?= (length expected, expected)
230+ where
231+ expected = "this one is just a little bit bigger than the others"
232+ filePath = "test/largest-string.yaml"
233+ adder (i, s) (Y.EventScalar bs _ _ _) =
234+ let s' = B8.unpack bs
235+ i' = length s'
236+ in if i' > i then (i', s') else (i, s)
237+ adder acc _ = acc
238+ accum = (0, "no strings found")
239+
240+newtype MyEvent = MyEvent Y.Event deriving Show
241+instance Eq MyEvent where
242+ (MyEvent (Y.EventScalar s t _ _)) == (MyEvent (Y.EventScalar s' t' _ _)) =
243+ s == s' && t == t'
244+ MyEvent e1 == MyEvent e2 = e1 == e2
245+
246+caseEncodeDecode :: Assertion
247+caseEncodeDecode = do
248+ eList <- C.runResourceT $ Y.decode yamlBS C.$$ CL.consume
249+ bs <- C.runResourceT $ CL.sourceList eList C.$$ Y.encode
250+ eList2 <- C.runResourceT $ Y.decode bs C.$$ CL.consume
251+ map MyEvent eList @=? map MyEvent eList2
252+ where
253+ yamlString = "foo: bar\nbaz:\n - bin1\n - bin2\n"
254+ yamlBS = B8.pack yamlString
255+
256+caseEncodeDecodeFile :: Assertion
257+caseEncodeDecodeFile = withFile "" $ \tmpPath -> do
258+ eList <- C.runResourceT $ Y.decodeFile filePath C.$$ CL.consume
259+ C.runResourceT $ CL.sourceList eList C.$$ Y.encodeFile tmpPath
260+ eList2 <- C.runResourceT $ Y.decodeFile filePath C.$$ CL.consume
261+ map MyEvent eList @=? map MyEvent eList2
262+ where
263+ filePath = "test/largest-string.yaml"
264+
265+caseInterleave :: Assertion
266+caseInterleave = withFile "" $ \tmpPath -> withFile "" $ \tmpPath2 -> do
267+ () <- C.runResourceT $ Y.decodeFile filePath C.$$ Y.encodeFile tmpPath
268+ () <- C.runResourceT $ Y.decodeFile tmpPath C.$$ Y.encodeFile tmpPath2
269+ f1 <- readFile tmpPath
270+ f2 <- readFile tmpPath2
271+ f1 @=? f2
272+ where
273+ filePath = "test/largest-string.yaml"
274+
275+caseDecodeInvalidDocument :: Assertion
276+caseDecodeInvalidDocument = do
277+ x <- try $ C.runResourceT $ Y.decode yamlBS C.$$ CL.sinkNull
278+ case x of
279+ Left (_ :: SomeException) -> return ()
280+ Right y -> do
281+ putStrLn $ "bad return value: " ++ show y
282+ assertFailure "expected parsing exception, but got no errors"
283+ where
284+ yamlString = " - foo\n - baz\nbuz"
285+ yamlBS = B8.pack yamlString
286+
287+mkScalar :: String -> D.Value
288+mkScalar = mkStrScalar
289+
290+mkStrScalar :: String -> D.Value
291+mkStrScalar = D.String . T.pack
292+
293+mappingKey :: D.Value-> String -> D.Value
294+mappingKey (D.Object m) k = (fromJust . M.lookup (T.pack k) $ m)
295+mappingKey _ _ = error "expected Object"
296+
297+decodeYaml :: String -> Maybe D.Value
298+decodeYaml s = D.decode $ B8.pack s
299+
300+sample :: D.Value
301+sample = array
302+ [ D.String "foo"
303+ , object
304+ [ ("bar1", D.String "bar2")
305+ , ("bar3", D.String "")
306+ ]
307+ , D.String ""
308+ ]
309+
310+caseEncodeDecodeData :: Assertion
311+caseEncodeDecodeData = do
312+ let out = D.decode $ D.encode sample
313+ out @?= Just sample
314+
315+caseEncodeDecodeDataPretty :: Assertion
316+caseEncodeDecodeDataPretty = do
317+ let out = D.decode $ Pretty.encodePretty Pretty.defConfig sample
318+ out @?= Just sample
319+
320+caseEncodeDecodeFileData :: Assertion
321+caseEncodeDecodeFileData = withFile "" $ \fp -> do
322+ D.encodeFile fp sample
323+ out <- D.decodeFile fp
324+ out @?= Just sample
325+
326+caseEncodeDecodeNonAsciiFileData :: Assertion
327+caseEncodeDecodeNonAsciiFileData = do
328+ let mySample = (object ["foo" .= True])
329+ inTempDirectory $ do
330+ createDirectory "accenté"
331+ D.encodeFile "accenté/bar.yaml" mySample
332+ out1 <- D.decodeFile "accenté/bar.yaml"
333+ out1 @?= Just mySample
334+
335+ createDirectoryIfMissing True "test/resources/accenté/"
336+
337+ readFile "test/resources/accent/foo.yaml" >>=
338+ writeFile "test/resources/accenté/foo.yaml"
339+ out2 <- D.decodeFile "test/resources/accenté/foo.yaml"
340+ out2 @?= Just mySample
341+
342+caseEncodeDecodeStrings :: Assertion
343+caseEncodeDecodeStrings = do
344+ let out = D.decode $ D.encode sample
345+ out @?= Just sample
346+
347+caseEncodeDecodeStringsPretty :: Assertion
348+caseEncodeDecodeStringsPretty = do
349+ let out = D.decode $ Pretty.encodePretty Pretty.defConfig sample
350+ out @?= Just sample
351+
352+caseDecodeInvalid :: Assertion
353+caseDecodeInvalid = do
354+ let invalid = B8.pack "\tthis is 'not' valid :-)"
355+ Nothing @=? (D.decode invalid :: Maybe D.Value)
356+
357+caseSimpleScalarAlias :: Assertion
358+caseSimpleScalarAlias = do
359+ let maybeRes = decodeYaml "- &anch foo\n- baz\n- *anch"
360+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
361+ let res = fromJust maybeRes
362+ res @?= array [(mkScalar "foo"), (mkScalar "baz"), (mkScalar "foo")]
363+
364+caseSimpleSequenceAlias :: Assertion
365+caseSimpleSequenceAlias = do
366+ let maybeRes = decodeYaml "seq: &anch\n - foo\n - baz\nseq2: *anch"
367+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
368+ let res = fromJust maybeRes
369+ res @?= object [("seq", array [(mkScalar "foo"), (mkScalar "baz")]), ("seq2", array [(mkScalar "foo"), (mkScalar "baz")])]
370+
371+caseSimpleMappingAlias :: Assertion
372+caseSimpleMappingAlias = do
373+ let maybeRes = decodeYaml "map: &anch\n key1: foo\n key2: baz\nmap2: *anch"
374+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
375+ let res = fromJust maybeRes
376+ res @?= object [(T.pack "map", object [("key1", mkScalar "foo"), ("key2", (mkScalar "baz"))]), (T.pack "map2", object [("key1", (mkScalar "foo")), ("key2", mkScalar "baz")])]
377+
378+caseMappingAliasBeforeAnchor :: Assertion
379+caseMappingAliasBeforeAnchor = do
380+ let res = decodeYaml "map: *anch\nmap2: &anch\n key1: foo\n key2: baz"
381+ isNothing res @? "decode should return Nothing due to unknown alias"
382+
383+caseMappingAliasInsideAnchor :: Assertion
384+caseMappingAliasInsideAnchor = do
385+ let res = decodeYaml "map: &anch\n key1: foo\n key2: *anch"
386+ isNothing res @? "decode should return Nothing due to unknown alias"
387+
388+caseScalarAliasOverriding :: Assertion
389+caseScalarAliasOverriding = do
390+ let maybeRes = decodeYaml "- &anch foo\n- baz\n- *anch\n- &anch boo\n- buz\n- *anch"
391+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
392+ let res = fromJust maybeRes
393+ res @?= array [(mkScalar "foo"), (mkScalar "baz"), (mkScalar "foo"), (mkScalar "boo"), (mkScalar "buz"), (mkScalar "boo")]
394+
395+caseAllKeysShouldBeUnique :: Assertion
396+caseAllKeysShouldBeUnique = do
397+ let maybeRes = decodeYaml "foo1: foo\nfoo2: baz\nfoo1: buz"
398+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
399+ let res = fromJust maybeRes
400+ mappingKey res "foo1" @?= (mkScalar "buz")
401+
402+caseSimpleMappingMerge :: Assertion
403+caseSimpleMappingMerge = do
404+ let maybeRes = decodeYaml "foo1: foo\nfoo2: baz\n<<:\n foo1: buz\n foo3: fuz"
405+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
406+ let res = fromJust maybeRes
407+ mappingKey res "foo1" @?= (mkScalar "foo")
408+ mappingKey res "foo3" @?= (mkScalar "fuz")
409+
410+caseMergeSequence :: Assertion
411+caseMergeSequence = do
412+ let maybeRes = decodeYaml "m1: &m1\n k1: !!str 1\n k2: !!str 2\nm2: &m2\n k1: !!str 3\n k3: !!str 4\nfoo1: foo\n<<: [ *m1, *m2 ]"
413+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
414+ let res = fromJust maybeRes
415+ mappingKey res "foo1" @?= (mkScalar "foo")
416+ mappingKey res "k1" @?= (D.String "1")
417+ mappingKey res "k2" @?= (D.String "2")
418+ mappingKey res "k3" @?= (D.String "4")
419+
420+caseDataTypes :: Assertion
421+caseDataTypes =
422+ D.decode (D.encode val) @?= Just val
423+ where
424+ val = object
425+ [ ("string", D.String "foo")
426+ , ("int", D.Number 5)
427+ , ("float", D.Number 4.3)
428+ , ("true", D.Bool True)
429+ , ("false", D.Bool False)
430+ , ("null", D.Null)
431+ ]
432+
433+caseDataTypesPretty :: Assertion
434+caseDataTypesPretty =
435+ D.decode (Pretty.encodePretty Pretty.defConfig val) @?= Just val
436+ where
437+ val = object
438+ [ ("string", D.String "foo")
439+ , ("int", D.Number 5)
440+ , ("float", D.Number 4.3)
441+ , ("true", D.Bool True)
442+ , ("false", D.Bool False)
443+ , ("null", D.Null)
444+ ]
445+caseQuotedNumber, caseUnquotedNumber, caseAttribNumber, caseIntegerDecimals :: Assertion
446+caseQuotedNumber = D.decode "foo: \"1234\"" @?= Just (object [("foo", D.String "1234")])
447+caseUnquotedNumber = D.decode "foo: 1234" @?= Just (object [("foo", D.Number 1234)])
448+caseAttribNumber = D.decode "foo: !!str 1234" @?= Just (object [("foo", D.String "1234")])
449+caseIntegerDecimals = D.encode (1 :: Int) @?= "1\n...\n"
450+
451+obj :: Maybe D.Value
452+obj = Just (object [("foo", D.Bool False), ("bar", D.Bool True), ("baz", D.Bool True)])
453+
454+caseLowercaseBool, caseUppercaseBool, caseTitlecaseBool :: Assertion
455+caseLowercaseBool = D.decode "foo: off\nbar: y\nbaz: true" @?= obj
456+caseUppercaseBool = D.decode "foo: FALSE\nbar: Y\nbaz: ON" @?= obj
457+caseTitlecaseBool = D.decode "foo: No\nbar: Yes\nbaz: True" @?= obj
458+
459+caseEmptyInput :: Assertion
460+caseEmptyInput = D.decode B8.empty @?= (Nothing :: Maybe D.Value)
461+
462+checkNull :: T.Text -> Spec
463+checkNull x =
464+ it ("null recognized: " ++ show x) assertion
465+ where
466+ assertion = Just (object [("foo", D.Null)]) @=? D.decode (B8.pack $ "foo: " ++ T.unpack x)
467+
468+caseStripAlias :: Assertion
469+caseStripAlias =
470+ D.decode src @?= Just (object
471+ [ "Default" .= object
472+ [ "foo" .= (1 :: Int)
473+ , "bar" .= (2 :: Int)
474+ ]
475+ , "Obj" .= object
476+ [ "foo" .= (1 :: Int)
477+ , "bar" .= (2 :: Int)
478+ , "key" .= (3 :: Int)
479+ ]
480+ ])
481+ where
482+ src = "Default: &def\n foo: 1\n bar: 2\nObj:\n <<: *def\n key: 3\n"
483+
484+caseIssue49 :: Assertion
485+caseIssue49 =
486+ D.decodeEither src @?= Right (object
487+ [ "a" .= object [ "value" .= (1.0 :: Double) ]
488+ , "b" .= object [ "value" .= (1.2 :: Double) ]
489+ ])
490+ where
491+ src = "---\na:\n &id5 value: 1.0\nb:\n *id5: 1.2"
492+
493+-- | We cannot guarantee this before aeson started using 'Scientific'.
494+casePreservesScientificPrecision :: Assertion
495+casePreservesScientificPrecision = do
496+ D.decodeEither "x: 1e-100000" @?= Right (object
497+ [ "x" .= D.Number (read "1e-100000") ])
498+ -- Note that this ought to work also without 'Scientific', given
499+ -- that @read (show "9.78159610558926e-5") == 9.78159610558926e-5@.
500+ -- However, it didn't work (and still doesn't work with aeson < 0.7)
501+ -- for two reasons:
502+ --
503+ -- * We use 'Data.Text.Read.double', which is not as accurate as it
504+ -- can be;
505+ -- * Even if we used 'Data.Text.Read.rational' we would not get good
506+ -- results, because of <https://github.com/bos/text/issues/34>.
507+ D.decodeEither "x: 9.78159610558926e-5" @?= Right (object
508+ [ "x" .= D.Number (read "9.78159610558926e-5") ])
509+
510+caseTruncatesFiles :: Assertion
511+caseTruncatesFiles = withSystemTempFile "truncate.yaml" $ \fp h -> do
512+ replicateM_ 500 $ B8.hPut h "HELLO WORLD!!!!!\n"
513+ hClose h
514+ let val = object ["hello" .= ("world" :: String)]
515+ D.encodeFile fp val
516+ res <- D.decodeFileEither fp
517+ either (Left . show) Right res `shouldBe` Right val
yaml/test/Spec.hs → test/Spec.hsrenamed

The content is the same.

yaml/test/json.yaml → test/json.yamlrenamed

The content is the same.

yaml/test/largest-string.yaml → test/largest-string.yamlrenamed

The content is the same.

yaml/test/resources/accent/foo.yaml → test/resources/accent/foo.yamlrenamed

The content is the same.

yaml/test/resources/bar.yaml → test/resources/bar.yamlrenamed

The content is the same.

yaml/test/resources/baz.yaml → test/resources/baz.yamlrenamed

The content is the same.

yaml/test/resources/foo.yaml → test/resources/foo.yamlrenamed

The content is the same.

yaml/test/resources/loop/bar.yaml → test/resources/loop/bar.yamlrenamed

The content is the same.

yaml/test/resources/loop/foo.yaml → test/resources/loop/foo.yamlrenamed

The content is the same.

yaml.cabalnew file+166
@@ -0,0 +1,166 @@
1+name: yaml
2+version: 0.8.19.0
3+license: BSD3
4+license-file: LICENSE
5+author: Michael Snoyman <michael@snoyman.com>, Anton Ageev <antage@gmail.com>,Kirill Simonov
6+maintainer: Michael Snoyman <michael@snoyman.com>
7+synopsis: Support for parsing and rendering YAML documents.
8+description: Please see the README.md file.
9+category: Web
10+stability: stable
11+cabal-version: >= 1.8
12+build-type: Simple
13+homepage: http://github.com/snoyberg/yaml/
14+extra-source-files: c/helper.h
15+ libyaml/yaml_private.h
16+ libyaml/yaml.h
17+ libyaml/LICENSE
18+ test/largest-string.yaml
19+ test/json.yaml
20+ test/resources/foo.yaml
21+ test/resources/bar.yaml
22+ test/resources/baz.yaml
23+ test/resources/accent/foo.yaml
24+ test/resources/loop/foo.yaml
25+ test/resources/loop/bar.yaml
26+ README.md
27+ ChangeLog.md
28+
29+flag no-exe
30+ description: don't install the yaml2json or json2yaml executables
31+ default: False
32+
33+flag no-examples
34+ description: don't build the examples
35+ default: True
36+
37+flag system-libyaml
38+ description: Use the system-wide libyaml instead of the bundled copy
39+ default: False
40+
41+flag no-unicode
42+ description: Don't enable unicode output. Instead, unicode characters will be escaped.
43+ default: False
44+
45+library
46+ build-depends: base >= 4 && < 5
47+ , transformers >= 0.1
48+ , bytestring >= 0.9.1.4
49+ , conduit >= 1.1.0 && < 1.3
50+ , resourcet >= 0.3 && < 1.2
51+ , aeson >= 0.7
52+ , containers
53+ , unordered-containers
54+ , vector
55+ , text
56+ , attoparsec >= 0.11.3.0
57+ , scientific
58+ , filepath
59+ , directory
60+ , enclosed-exceptions
61+ , semigroups
62+ exposed-modules: Text.Libyaml
63+ Data.Yaml
64+ Data.Yaml.Aeson
65+ Data.Yaml.Builder
66+ Data.Yaml.Config
67+ Data.Yaml.Include
68+ Data.Yaml.Parser
69+ Data.Yaml.Pretty
70+ if impl(ghc >= 7.8.1)
71+ build-depends: template-haskell >= 2.8.0.0
72+ exposed-modules: Data.Yaml.TH
73+ other-modules:
74+ Data.Yaml.Internal
75+ ghc-options: -Wall
76+ c-sources: c/helper.c
77+ include-dirs: c
78+ if flag(no-unicode)
79+ cpp-options: -D__NO_UNICODE__
80+ if flag(system-libyaml)
81+ pkgconfig-depends: yaml-0.1
82+ else
83+ c-sources: libyaml/api.c,
84+ libyaml/dumper.c,
85+ libyaml/emitter.c,
86+ libyaml/loader.c,
87+ libyaml/parser.c,
88+ libyaml/reader.c,
89+ libyaml/scanner.c,
90+ libyaml/writer.c
91+ include-dirs: libyaml
92+ if os(windows)
93+ cpp-options: -DWINDOWS
94+
95+executable yaml2json
96+ if flag(no-exe)
97+ Buildable: False
98+ else
99+ Buildable: True
100+
101+ hs-source-dirs: exe
102+ main-is: yaml2json.hs
103+ build-depends: base >= 4 && < 5
104+ , yaml
105+ , bytestring >= 0.9.1.4
106+ , aeson >= 0.7
107+
108+executable json2yaml
109+ if flag(no-exe)
110+ Buildable: False
111+ else
112+ Buildable: True
113+
114+ hs-source-dirs: exe
115+ main-is: json2yaml.hs
116+ build-depends: base >= 4 && < 5
117+ , yaml
118+ , bytestring >= 0.9.1.4
119+ , aeson >= 0.7
120+
121+
122+test-suite spec
123+ type: exitcode-stdio-1.0
124+ hs-source-dirs: test
125+ main-is: Spec.hs
126+ other-modules: Data.YamlSpec
127+ Data.Yaml.IncludeSpec
128+ cpp-options: -DTEST
129+ build-depends: hspec >= 1.3
130+ , HUnit
131+ , base >= 4 && < 5
132+ , transformers >= 0.1
133+ , bytestring >= 0.9.1.4
134+ , conduit
135+ , yaml
136+ , text
137+ , aeson >= 0.7
138+ , unordered-containers
139+ , directory
140+ , vector
141+ , resourcet
142+ , aeson-qq
143+ , mockery
144+ , base-compat
145+ , temporary
146+ ghc-options: -Wall
147+
148+executable examples
149+ if flag(no-examples)
150+ Buildable: False
151+ else
152+ Buildable: True
153+ build-depends: base
154+ , bytestring
155+ , raw-strings-qq
156+ , text
157+ , yaml
158+ hs-source-dirs: examples
159+ main-is: Main.hs
160+ other-modules: Config
161+ Simple
162+ ghc-options: -Wall
163+
164+source-repository head
165+ type: git
166+ location: https://github.com/snoyberg/yaml
yaml/ChangeLog.mddeleted−303
@@ -1,303 +0,0 @@
1−# ChangeLog for yaml
2−
3−## 0.11.11.2
4−
5−* Compat with aeson 2.2
6−
7−## 0.11.11.1
8−
9−* For optparse-applicative-0.18: use `pretty` instead of `text` [#216](https://github.com/snoyberg/yaml/pull/216)
10−
11−## 0.11.11.0
12−
13−* Fix ambiguous occurrence `AesonException`
14−
15−## 0.11.10.0
16−
17−* Undo previous change (breakage with aeson 2)
18−
19−## 0.11.9.0
20−
21−* Data.Yaml.Pretty: provide key-sorting function with path to parent object [#206](https://github.com/snoyberg/yaml/pull/206)
22−
23−## 0.11.8.0
24−
25−* Export `Parse` and `StringStyle` [#204](https://github.com/snoyberg/yaml/pull/204)
26−
27−## 0.11.7.0
28−
29−* Support `aeson` 2 [#202](https://github.com/snoyberg/yaml/pull/202)
30−
31−## 0.11.6.0
32−
33−* `yaml2json`: add `--help` and `--version` options [#197](https://github.com/snoyberg/yaml/pull/197)
34−* `json2yaml`: add `--help` and `--version` options [#198](https://github.com/snoyberg/yaml/pull/198)
35−* Add the `-o` options to both `yaml2json` and `json2yaml` [#200](https://github.com/snoyberg/yaml/pull/200)
36−
37−## 0.11.5.0
38−
39−* New functions capable of parsing YAML streams containing multiple documents into a list of results:
40− * `decodeAllEither'`
41− * `decodeAllFileEither`
42− * `decodeAllFileWithWarnings`
43− * `decodeAllThrow`
44− * `decodeAllFileThrow`
45−
46−## 0.11.4.0
47−
48−* add `ToYaml` instance for `String` [#186](https://github.com/snoyberg/yaml/pull/186)
49−
50−## 0.11.3.0
51−
52−* Don't wrap up async exceptions [#185](https://github.com/snoyberg/yaml/issues/185)
53−
54−## 0.11.2.0
55−
56−* Reduces some of the code duplication between the `encode` and `encodePretty` functions
57−* The output of `encodePretty` has been improved:
58− - Multiline strings now use `Literal` style instead of `SingleQuoted`
59− - Special keys are now quoted in mappings [#179](https://github.com/snoyberg/yaml/issues/179)
60−* Support for complex keys in mappings: [#182](https://github.com/snoyberg/yaml/issues/182)
61− - Adds `complexMapping` function to `Data.Yaml.Builder`
62− - Decode functions now return a `NonStringKey` error when attempting to decode a mapping with a complex key as it is not possible to decode these to an Aeson `Value`
63−* Adds missing `ToYaml` instances
64−
65−## 0.11.1.2
66−
67−* Compiles with GHC 8.8.1 (`MonadFail` split)
68−
69−## 0.11.1.1
70−
71−* Use the appropriate `Scientific` rendering function to avoid a memory overflow when rendering. The previously used function from `aeson` would not use scientific notation, and could use large amounts of memory for values such as `1e9999999999999`.
72−
73−## 0.11.1.0
74−
75−* Better error messages in the `Data.Yaml.Config` module [#168](https://github.com/snoyberg/yaml/issues/168)
76−* Add `LoadSettingsException` exception and remove error printing from `loadYamlSettings` [#172](https://github.com/snoyberg/yaml/pull/172)
77−
78−## 0.11.0.0
79−
80−* Split out the `libyaml` and `Text.Libyaml` code into its own package. [#145](https://github.com/snoyberg/yaml/issues/145)
81−
82−## 0.10.4.0
83−
84−* Add `decodeMarked` and `decodeFileMarked` functions to `Text.Libyaml`, and
85− extend native bindings to extract mark information. [#157](https://github.com/snoyberg/yaml/issues/157)
86−
87−## 0.10.3.0
88−
89−* Add support for anchors and aliases to Data.Yaml.Builder [#155](https://github.com/snoyberg/yaml/pull/155)
90−* Fix test suite for 32 bit machines [#158](https://github.com/snoyberg/yaml/issues/158)
91−
92−## 0.10.2.0
93−
94−* Add `EncodeOptions` and `FormatOptions` to control the style of the encoded YAML. [#153](https://github.com/snoyberg/yaml/pull/153)
95−* Default to using literal style for multiline strings [#152](https://github.com/snoyberg/yaml/issues/152)
96−
97−## 0.10.1.1
98−
99−* Correctly declare libyaml dependency on system-libyaml flag [#151](https://github.com/snoyberg/yaml/pull/151)
100−
101−## 0.10.1
102−
103−* Avoid incurring a `semigroups` dependency on recent GHCs.
104−* Fix a space leak that was introduced with `0.10.0` [#147](https://github.com/snoyberg/yaml/issues/147)
105−
106−## 0.10.0
107−
108−* Add `decodeFileWithWarnings` which returns warnings for duplicate fields
109−
110−## 0.9.0
111−
112−* Expose style and tags on mappings and sequences in Text.Libyaml [#141](https://github.com/snoyberg/yaml/pull/141)
113−
114−## 0.8.32
115−
116−* Escape keys as necessary [#137](https://github.com/snoyberg/yaml/issues/137)
117−* Support hexadecimal and octal number values [#135](https://github.com/snoyberg/yaml/issues/135)
118−* More resilient `isNumeric` (should reduce cases of unneeded quoting)
119−* hpackify
120−* src subdir
121−
122−## 0.8.31.1
123−
124−* Add a workaround for a cabal bug [haskell-infra/hackage-trustees#165](https://github.com/haskell-infra/hackage-trustees/issues/165)
125−
126−## 0.8.31
127−
128−* Add `decodeThrow` and `decodeFileThrow` convenience functions.
129−* Upgrade libyaml versions
130−* Deprecate `decode` and `decodeEither`
131−
132−## 0.8.30
133−
134−* Removed `AppSettings` mentioned in `loadYamlSettings` error message.
135−
136−## 0.8.29
137−
138−* Deprecated `decodeFile` [#129](https://github.com/snoyberg/yaml/issues/129)
139−* Turn off executables by default [#103](https://github.com/snoyberg/yaml/issues/103)
140−
141−## 0.8.28
142−
143−* Add `Data.Yaml.TH.yamlQQ`
144−
145−## 0.8.27
146−
147−* Support conduit 1.3
148−
149−## 0.8.26
150−
151−* Add `Semigroup` instance [#123](https://github.com/snoyberg/yaml/pull/123)
152−
153−## 0.8.25.2
154−
155−* Use `throwM` instead of `monadThrow`
156−
157−## 0.8.25.1
158−
159−* Drop aeson-qq dep (incompatible with Stackage Nightly)
160−
161−## 0.8.25
162−
163−* Tweaks to the executable `yaml2json` [#119](https://github.com/snoyberg/yaml/pull/119):
164− - Add command-line option `-h` and `--help` to show help message
165− - Error messages are now written to `stderr` instead of `stdout`
166−
167−## 0.8.24
168−
169−* New encodePretty option `setConfDropNull` to drop null values from objects [#116](https://github.com/snoyberg/yaml/issues/116)
170−
171−## 0.8.23.3
172−
173−* Avoid over-escaping `*` [#113](https://github.com/snoyberg/yaml/issues/113)
174−
175−## 0.8.23.2
176−
177−* Update libyaml [#110](https://github.com/snoyberg/yaml/issues/110)
178−
179−## 0.8.23.1
180−
181−* Update CPP `MIN_VERSION_*` checks [#109](https://github.com/snoyberg/yaml/pull/109)
182−
183−## 0.8.23
184−
185−* Re-export the with helpers from aeson
186−
187−## 0.8.22.1
188−
189−* Make numeric string detection slightly smarter so, e.g., `.` does
190− not get quoted
191−
192−## 0.8.22
193−
194−* Update to libyaml hosted on Github [#105](https://github.com/snoyberg/yaml/issues/105)
195−
196−## 0.8.21.2
197−
198−* Fix wrong file not found exception in `Data.Yaml.Include` with pre-1.2.3.0 `directory` [#104](https://github.com/snoyberg/yaml/pull/104)
199−
200−## 0.8.21.1
201−
202−* Add missing test files [#102](https://github.com/snoyberg/yaml/pull/102)
203−
204−## 0.8.21
205−
206−* Decode empty inputs as Null [#101](https://github.com/snoyberg/yaml/pull/101)
207−
208−## 0.8.20
209−
210−* Upgrade to libyaml 0.1.7
211−
212−## 0.8.19.0
213−
214−* Add `Data.Yaml.TH` module
215−
216−## 0.8.18.7
217−
218−* Add `O_TRUNC` when opening files
219−
220−## 0.8.18.6
221−
222−* s/fdopen/_fdopen on Windows [#96](https://github.com/snoyberg/yaml/issues/96)
223−
224−## 0.8.18.5
225−
226−* Properly fix previous bug (fixes #94)
227−
228−## 0.8.18.4
229−
230−* Remove file with non-ASCII name due to Stack/cabal-install/Hackage
231− restrictions (see [#92](https://github.com/snoyberg/yaml/issues/92))
232−
233−## 0.8.18.2
234−
235−* Handle non-ASCII filenames correctly on Windows [#91](https://github.com/snoyberg/yaml/pull/91)
236−
237−## 0.8.18.1
238−
239−* Improve prettyPrintParseException when context is empty [#89](https://github.com/snoyberg/yaml/pull/89)
240−
241−## 0.8.18
242−
243−* Switched yaml decode function for config file readers in `Data.Yaml.Config` to
244− the one from `Data.Yaml.Include` that supports `!include` syntax.
245−
246−## 0.8.17.2
247−
248−* Fix pretty-printing order of UnexpectedEvent's fields (fixes [#84](https://github.com/snoyberg/yaml/issues/84)) [#85](https://github.com/snoyberg/yaml/pull/85)
249−
250−## 0.8.17.1
251−
252−* Avoid bug in Cabal [#83](https://github.com/snoyberg/yaml/pull/83)
253−
254−## 0.8.17
255−
256−* `loadYamlSettingsArgs`
257−
258−## 0.8.16.1
259−
260−* Slight doc improvement
261−
262−## 0.8.16
263−
264−Add env variable parsing. `loadYamlSettings` can read config values from the environment with Yaml that specifies an env var.
265−The syntax is
266−
267−`var: _env:ENV_VAR:default`
268−
269−## 0.8.15.3
270−
271−* Give a warning when compiling with GHCJS
272−
273−## 0.8.15.2
274−
275−* Canonicalise Monad instances [#76](https://github.com/snoyberg/yaml/pull/76)
276−
277−## 0.8.15.1
278−
279−* Compile with aeson below 0.7 [#70](https://github.com/snoyberg/yaml/pull/70)
280−
281−## 0.8.15
282−
283−* Parse `Scientific` directly, avoiding loss in precision. [#68](https://github.com/snoyberg/yaml/pull/68)
284−
285−## 0.8.14
286−
287−* Pretty print improvements for exceptions [#67](https://github.com/snoyberg/yaml/pull/67)
288−
289−## 0.8.13
290−
291−* Pretty module [#66](https://github.com/snoyberg/yaml/pull/66)
292−
293−## 0.8.12
294−
295−* Proper handling of `String "+123"` [#64](https://github.com/snoyberg/yaml/issues/64)
296−
297−## 0.8.11
298−
299−* Function to print prettier parse exceptions [#59](https://github.com/snoyberg/yaml/pull/59)
300−
301−## 0.8.10
302−
303−Add the Data.Yaml.Include module
yaml/README.mddeleted−26
@@ -1,26 +0,0 @@
1−## yaml
2−
3−[![GitHub build and test status](https://github.com/snoyberg/yaml/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/snoyberg/yaml/actions/workflows/tests.yml)
4−[![Appveyor build status](https://ci.appveyor.com/api/projects/status/hqy2jketp8m502so/branch/master?svg=true)](https://ci.appveyor.com/project/snoyberg/yaml/branch/master)
5−
6−Provides support for parsing and emitting Yaml documents.
7−
8−`Data.Yaml` provides a high-level interface based around the JSON datatypes provided by the `aeson` package. It uses `Text.Libyaml` from `libyaml` in its implementation of the low-level yaml encoder/decoder.
9−
10−### Examples
11−
12−Usage examples can be found in the `Data.Yaml` documentation or in the [examples](https://github.com/snoyberg/yaml/tree/master/yaml/examples) directory.
13−
14−### Additional `yaml` modules
15−
16−* `Data.Yaml.Include` supports adding `!include` directives to your YAML files.
17−* `Data.Yaml.Builder` and `Data.Yaml.Parser` allow more fine-grained control of parsing an rendering, as opposed to just using the aeson typeclass and datatype system for parsing and rendering.
18−* `Data.Yaml.Aeson` is currently a re-export of `Data.Yaml` to explicitly choose to use the aeson-compatible API.
19−
20−### Executables
21−
22−Converters `json2yaml` and `yaml2json` can be built by disabling flag `no-exe`, e.g., one of:
23−```
24−cabal install yaml -f-no-exe
25−stack install yaml --flag yaml:-no-exe
26−```
yaml/exe/Common.hsdeleted−68
@@ -1,68 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE LambdaCase #-}
3−
4−-- | Code shared between @yaml2json@ and @json2yaml@.
5−
6−module Common where
7−
8−import Data.List ( intercalate )
9−#if !MIN_VERSION_base(4,11,0)
10−import Data.Semigroup ( Semigroup(..) )
11−#endif
12−import Data.Version ( Version(versionBranch) )
13−
14−import Options.Applicative ( Parser, help, hidden, infoOption, long, short )
15−
16−import qualified Paths_yaml as Paths
17−
18−-- * Version info and option
19−---------------------------------------------------------------------------
20−
21−-- | Homepage for @yaml2json@ and @json2yaml@.
22−
23−homepage :: String
24−homepage = "https://github.com/snoyberg/yaml/"
25−
26−-- | Version in @x.y.z@ format.
27−
28−version :: String
29−version = intercalate "." $ map show $ versionBranch Paths.version
30−
31−-- | The version header including given program name and 'homepage'.
32−
33−versionText :: String -> String
34−versionText self = unwords
35− [ self
36− , "version"
37− , version
38− , homepage -- concat [ "<", homepage, ">" ]
39− ]
40−
41−-- | Option @--numeric-version@.
42−
43−numericVersionOption :: Parser (a -> a)
44−numericVersionOption =
45− infoOption version
46− $ long "numeric-version"
47− <> hidden
48− <> help "Show just version number."
49−
50−-- | Option @--version@.
51−
52−versionOption :: String -> Parser (a -> a)
53−versionOption self =
54− infoOption (versionText self)
55− $ long "version"
56− <> short 'V'
57− <> hidden
58− <> help "Show version info."
59−
60−-- * Misc
61−---------------------------------------------------------------------------
62−
63−-- | @Just@ unless argument is @"-"@ (denoting @stdin@ or @stdout@).
64−
65−dashToNothing :: FilePath -> Maybe FilePath
66−dashToNothing = \case
67− "-" -> Nothing
68− file -> Just file
yaml/exe/json2yaml.hsdeleted−106
@@ -1,106 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE NamedFieldPuns #-}
3−
4−import qualified Data.Aeson as J
5−import qualified Data.ByteString as S
6−import qualified Data.ByteString.Lazy as L
7−import qualified Data.Yaml as Y
8−#if !MIN_VERSION_base(4,11,0)
9−import Data.Semigroup ( Semigroup(..) )
10−#endif
11−
12−import Options.Applicative
13− ( Parser, (<|>)
14− , action, execParser, footerDoc, headerDoc, help, helper, hidden, info
15− , long, metavar, short, strArgument, strOption, value
16− )
17−import Options.Applicative.Help.Pretty
18− ( vcat, pretty )
19−
20−import System.Exit ( die )
21−
22−import Common ( dashToNothing, versionText, versionOption, numericVersionOption )
23−
24−data Options = Options
25− { optInput :: Maybe FilePath
26− -- ^ 'Nothing' means @stdin@.
27− , optOutput :: Maybe FilePath
28− -- ^ 'Nothing' means @stdout@.
29− }
30−
31−-- | Name of the executable.
32−
33−self :: String
34−self = "json2yaml"
35−
36−-- | Parse options; handle parse errors, @--help@, @--version@.
37−
38−options :: IO Options
39−options =
40− execParser $
41− info (helper <*> versionOption self <*> numericVersionOption <*> programOptions)
42− $ headerDoc hdoc
43− <> footerDoc fdoc
44−
45− where
46− hdoc = Just $ vcat $ map pretty
47− [ versionText self
48− , "Convert JSON to YAML."
49− ]
50− fdoc = Just $ pretty $ concat
51− [ "The old call pattern '"
52− , self
53− , " IN OUT' is also accepted, but deprecated."
54− ]
55−
56− programOptions :: Parser Options
57− programOptions = Options <$> oInput <*> oOutput
58−
59− oInput :: Parser (Maybe FilePath)
60− oInput = dashToNothing <$> do
61− strArgument
62− $ metavar "IN"
63− <> value "-"
64− <> action "file"
65− <> help "The input file containing the JSON document; use '-' for stdin (default)."
66−
67− oOutput :: Parser (Maybe FilePath)
68− oOutput = dashToNothing <$> do
69− oOutputExplicit <|> oOutputImplicit
70−
71− oOutputExplicit :: Parser FilePath
72− oOutputExplicit =
73− strOption
74− $ long "output"
75− <> short 'o'
76− <> metavar "OUT"
77− <> action "file"
78− -- <> help "The file to hold the produced YAML document; use '-' for stdout (default)."
79−
80− oOutputImplicit :: Parser FilePath
81− oOutputImplicit =
82− strArgument
83− $ metavar "OUT"
84− <> value "-"
85− <> action "file"
86− <> hidden
87− <> help "The file to hold the produced YAML document; use '-' for stdout (default)."
88−
89−-- | Exit with 'self'-stamped error message.
90−
91−abort :: String -> IO a
92−abort msg = die $ concat [ self, ": ", msg ]
93−
94−main :: IO ()
95−main = do
96− Options{ optInput, optOutput } <- options
97−
98− -- Read JSON.
99− mval <- J.decode <$> maybe L.getContents L.readFile optInput
100−
101− -- Write YAML.
102− case mval of
103− Nothing -> abort "Invalid input JSON"
104− Just val -> case optOutput of
105− Nothing -> S.putStr $ Y.encode (val :: Y.Value)
106− Just f -> Y.encodeFile f val
yaml/exe/yaml2json.hsdeleted−87
@@ -1,87 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE LambdaCase #-}
3−{-# LANGUAGE NamedFieldPuns #-}
4−
5−import Data.Aeson (encode, Value)
6−import qualified Data.ByteString as S (getContents)
7−import qualified Data.ByteString.Lazy as L (putStr, writeFile)
8−#if !MIN_VERSION_base(4,11,0)
9−import Data.Semigroup (Semigroup(..))
10−#endif
11−import Data.Yaml (decodeFileEither, decodeEither')
12−import System.Exit (die)
13−
14−import Options.Applicative
15− ( Parser
16− , action, execParser, headerDoc, help, helper, info
17− , long, metavar, short, strArgument, strOption, value
18− )
19−import Options.Applicative.Help.Pretty
20− ( vcat, pretty )
21−
22−import Common
23− ( versionText, versionOption, numericVersionOption, dashToNothing )
24−
25−data Options = Options
26− { optInput :: Maybe FilePath
27− -- ^ 'Nothing' means @stdin@.
28− , optOutput :: Maybe FilePath
29− -- ^ 'Nothing' means @stdout@.
30− }
31−
32−-- | Name of the executable.
33−
34−self :: String
35−self = "yaml2json"
36−
37−-- | Parse options; handle parse errors, @--help@, @--version@.
38−
39−options :: IO Options
40−options =
41− execParser $
42− info (helper <*> versionOption self <*> numericVersionOption <*> programOptions)
43− (headerDoc hdoc)
44−
45− where
46− hdoc = Just $ vcat $ map pretty
47− [ versionText self
48− , "Convert YAML to JSON."
49− ]
50−
51− programOptions = Options <$> oInput <*> oOutput
52−
53− oInput :: Parser (Maybe FilePath)
54− oInput = dashToNothing <$> do
55− strArgument
56− $ metavar "IN"
57− <> value "-"
58− <> action "file"
59− <> help "The input file containing the YAML document; use '-' for stdin (default)."
60−
61− oOutput :: Parser (Maybe FilePath)
62− oOutput = dashToNothing <$> do
63− strOption
64− $ long "output"
65− <> short 'o'
66− <> value "-"
67− <> metavar "OUT"
68− <> action "file"
69− <> help "The file to hold the produced JSON document; use '-' for stdout (default)."
70−
71−
72−main :: IO ()
73−main = do
74− Options{ optInput, optOutput } <- options
75−
76− -- Input YAML.
77− result <- case optInput of
78− -- strict getContents will read in all of stdin at once
79− Nothing -> decodeEither' <$> S.getContents
80− Just f -> decodeFileEither f
81−
82− -- Output JSON.
83− case result of
84− Left err -> die $ show err
85− Right val -> do
86− let json = encode (val :: Value)
87− maybe L.putStr L.writeFile optOutput json
yaml/package.yamldeleted−113
@@ -1,113 +0,0 @@
1−name: yaml
2−version: 0.11.11.2
3−synopsis: Support for parsing and rendering YAML documents.
4−description: README and API documentation are available at <https://www.stackage.org/package/yaml>
5−category: Data
6−author: Michael Snoyman <michael@snoyman.com>, Anton Ageev <antage@gmail.com>,Kirill Simonov
7−maintainer: Michael Snoyman <michael@snoyman.com>
8−license: BSD3
9−github: snoyberg/yaml
10−stability: stable
11−
12−extra-source-files:
13−- test/largest-string.yaml
14−- test/json.yaml
15−- test/resources/foo.yaml
16−- test/resources/bar.yaml
17−- test/resources/baz.yaml
18−- test/resources/accent/foo.yaml
19−- test/resources/loop/foo.yaml
20−- test/resources/loop/bar.yaml
21−- test/resources/empty.yaml
22−- test/resources/empty2.yaml
23−- README.md
24−- ChangeLog.md
25−
26−flags:
27− no-exe:
28− description: don't install the yaml2json or json2yaml executables
29− manual: false
30− default: true
31− no-examples:
32− description: don't build the examples
33− manual: false
34− default: true
35−
36−dependencies:
37−- base >=4.14 && <5 # GHC 8.10.1 and later
38−- bytestring >=0.9.1.4
39−- transformers >=0.1
40−- mtl
41−- conduit >=1.2.8 && <1.4
42−- resourcet >=0.3 && <1.4
43−- aeson >=0.11
44−- containers
45−- unordered-containers
46−- vector
47−- text
48−- attoparsec >=0.11.3.0
49−- scientific >= 0.3 # for Data.ByteString.Builder.Scientific
50−- filepath
51−- directory
52−- template-haskell
53−- libyaml >=0.1 && <0.2
54−
55−ghc-options: -Wall -Wcompat
56−
57−library:
58− other-extensions:
59− - LambdaCase
60− source-dirs: src
61−
62−executables:
63− json2yaml:
64− main: json2yaml.hs
65− source-dirs: exe
66− dependencies:
67− - optparse-applicative
68− - yaml
69− when:
70− - condition: flag(no-exe)
71− buildable: false
72− yaml2json:
73− main: yaml2json.hs
74− source-dirs: exe
75− dependencies:
76− - optparse-applicative
77− - yaml
78− when:
79− - condition: flag(no-exe)
80− buildable: false
81− other-extensions:
82− - CPP
83− - LambdaCase
84− - NamedFieldPuns
85− examples:
86− main: Main.hs
87− source-dirs: examples
88− when:
89− - condition: flag(no-examples)
90− then:
91− buildable: false
92− else:
93− dependencies:
94− - raw-strings-qq
95− - yaml
96−
97−tests:
98− spec:
99− main: Spec.hs
100− source-dirs: test
101− ghc-options: "-with-rtsopts=-K1K"
102− cpp-options: -DTEST
103− dependencies:
104− - hspec >=1.3
105− - HUnit
106− - yaml
107− - directory
108− - mockery
109− - base-compat
110− - temporary
111− - raw-strings-qq
112− build-tools:
113− - hspec-discover
yaml/src/Data/Yaml.hsdeleted−292
@@ -1,292 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE ScopedTypeVariables #-}
3−{-# LANGUAGE OverloadedStrings #-}
4−
5−-- | Provides a high-level interface for processing YAML files.
6−--
7−-- This module reuses most of the infrastructure from the @aeson@ package.
8−-- This means that you can use all of the existing tools for JSON
9−-- processing for processing YAML files. As a result, much of the
10−-- documentation below mentions JSON; do not let that confuse you, it's
11−-- intentional.
12−--
13−-- For the most part, YAML content translates directly into JSON, and
14−-- therefore there is very little data loss. If you need to deal with YAML
15−-- more directly (e.g., directly deal with aliases), you should use the
16−-- "Text.Libyaml" module instead.
17−--
18−-- For documentation on the @aeson@ types, functions, classes, and
19−-- operators, please see the @Data.Aeson@ module of the @aeson@ package.
20−--
21−-- Look in the examples directory of the source repository for some initial
22−-- pointers on how to use this library.
23−
24−#if (defined (ghcjs_HOST_OS))
25−module Data.Yaml {-# WARNING "GHCJS is not supported yet (will break at runtime once called)." #-}
26−#else
27−module Data.Yaml
28−#endif
29− ( -- * Encoding
30− encode
31− , encodeWith
32− , encodeFile
33− , encodeFileWith
34− -- * Decoding
35− , decodeEither'
36− , decodeFileEither
37− , decodeFileWithWarnings
38− , decodeThrow
39− , decodeFileThrow
40− -- ** Decoding multiple documents
41− --
42− -- | For situations where we need to be able to parse multiple documents
43− -- separated by `---` in a YAML stream, these functions decode a list of
44− -- values rather than a single value.
45− , decodeAllEither'
46− , decodeAllFileEither
47− , decodeAllFileWithWarnings
48− , decodeAllThrow
49− , decodeAllFileThrow
50− -- ** More control over decoding
51− , decodeHelper
52− -- * Types
53− , Value (..)
54− , Parser
55− , Object
56− , Array
57− , ParseException(..)
58− , prettyPrintParseException
59− , YamlException (..)
60− , YamlMark (..)
61− -- * Constructors and accessors
62− , object
63− , array
64− , (.=)
65− , (.:)
66− , (.:?)
67− , (.!=)
68− -- ** With helpers (since 0.8.23)
69− , withObject
70− , withText
71− , withArray
72− , withScientific
73− , withBool
74− -- * Parsing
75− , parseMonad
76− , parseEither
77− , parseMaybe
78− -- * Classes
79− , ToJSON (..)
80− , FromJSON (..)
81− -- * Custom encoding
82− , isSpecialString
83− , EncodeOptions
84− , defaultEncodeOptions
85− , defaultStringStyle
86− , setStringStyle
87− , setFormat
88− , FormatOptions
89− , defaultFormatOptions
90− , setWidth
91− -- * Deprecated
92− , decode
93− , decodeFile
94− , decodeEither
95− ) where
96−#if !MIN_VERSION_base(4,8,0)
97−import Control.Applicative((<$>))
98−#endif
99−import Control.Exception
100−import Control.Monad.IO.Class (MonadIO, liftIO)
101−import Control.Monad.Trans.Resource (MonadThrow, throwM)
102−import Data.Aeson
103− ( Value (..), ToJSON (..), FromJSON (..), object
104− , (.=) , (.:) , (.:?) , (.!=)
105− , Object, Array
106− , withObject, withText, withArray, withScientific, withBool
107− )
108−import Data.Aeson.Types (parseMaybe, parseEither, Parser)
109−import Data.ByteString (ByteString)
110−import Data.Conduit ((.|), runConduitRes)
111−import qualified Data.Conduit.List as CL
112−import qualified Data.Vector as V
113−import System.IO.Unsafe (unsafePerformIO)
114−import Data.Text (Text)
115−
116−import Data.Yaml.Internal
117−import Text.Libyaml hiding (encode, decode, encodeFile, decodeFile, encodeWith, encodeFileWith)
118−import qualified Text.Libyaml as Y
119−
120−-- | Set the string style in the encoded YAML. This is a function that decides
121−-- for each string the type of YAML string to output.
122−--
123−-- __WARNING__: You must ensure that special strings (like @"yes"@\/@"no"@\/@"null"@\/@"1234"@) are not encoded with the 'Plain' style, because
124−-- then they will be decoded as boolean, null or numeric values. You can use 'isSpecialString' to detect them.
125−--
126−-- By default, strings are encoded as follows:
127−--
128−-- * Any string containing a newline character uses the 'Literal' style
129−--
130−-- * Otherwise, any special string (see 'isSpecialString') uses 'SingleQuoted'
131−--
132−-- * Otherwise, use 'Plain'
133−--
134−-- @since 0.10.2.0
135−setStringStyle :: (Text -> ( Tag, Style )) -> EncodeOptions -> EncodeOptions
136−setStringStyle s opts = opts { encodeOptionsStringStyle = s }
137−
138−-- | Set the encoding formatting for the encoded YAML. By default, this is `defaultFormatOptions`.
139−--
140−-- @since 0.10.2.0
141−setFormat :: FormatOptions -> EncodeOptions -> EncodeOptions
142−setFormat f opts = opts { encodeOptionsFormat = f }
143−
144−-- |
145−-- @since 0.10.2.0
146−data EncodeOptions = EncodeOptions
147− { encodeOptionsStringStyle :: Text -> ( Tag, Style )
148− , encodeOptionsFormat :: FormatOptions
149− }
150−
151−-- |
152−-- @since 0.10.2.0
153−defaultEncodeOptions :: EncodeOptions
154−defaultEncodeOptions = EncodeOptions
155− { encodeOptionsStringStyle = defaultStringStyle
156− , encodeOptionsFormat = defaultFormatOptions
157− }
158−
159−-- | Encode a value into its YAML representation.
160−encode :: ToJSON a => a -> ByteString
161−encode = encodeWith defaultEncodeOptions
162−
163−-- | Encode a value into its YAML representation with custom styling.
164−--
165−-- @since 0.10.2.0
166−encodeWith :: ToJSON a => EncodeOptions -> a -> ByteString
167−encodeWith opts obj = unsafePerformIO $ runConduitRes
168− $ CL.sourceList (objToStream (encodeOptionsStringStyle opts) $ toJSON obj)
169− .| Y.encodeWith (encodeOptionsFormat opts)
170−
171−-- | Encode a value into its YAML representation and save to the given file.
172−encodeFile :: ToJSON a => FilePath -> a -> IO ()
173−encodeFile = encodeFileWith defaultEncodeOptions
174−
175−-- | Encode a value into its YAML representation with custom styling and save to the given file.
176−--
177−-- @since 0.10.2.0
178−encodeFileWith :: ToJSON a => EncodeOptions -> FilePath -> a -> IO ()
179−encodeFileWith opts fp obj = runConduitRes
180− $ CL.sourceList (objToStream (encodeOptionsStringStyle opts) $ toJSON obj)
181− .| Y.encodeFileWith (encodeOptionsFormat opts) fp
182−
183−decode :: FromJSON a
184− => ByteString
185− -> Maybe a
186−decode bs = unsafePerformIO
187− $ either (const Nothing) snd
188− <$> decodeHelper_ (Y.decode bs)
189−{-# DEPRECATED decode "Please use decodeEither or decodeThrow, which provide information on how the decode failed" #-}
190−
191−decodeFile :: FromJSON a
192− => FilePath
193− -> IO (Maybe a)
194−decodeFile fp = (fmap snd <$> decodeHelper (Y.decodeFile fp)) >>= either throwIO (return . either (const Nothing) id)
195−{-# DEPRECATED decodeFile "Please use decodeFileEither, which does not confused type-directed and runtime exceptions." #-}
196−
197−-- | A version of 'decodeFile' which should not throw runtime exceptions.
198−--
199−-- @since 0.8.4
200−decodeFileEither
201− :: FromJSON a
202− => FilePath
203− -> IO (Either ParseException a)
204−decodeFileEither = fmap (fmap snd) . decodeFileWithWarnings
205−
206−-- | Like `decodeFileEither`, but decode multiple documents.
207−--
208−-- @since 0.11.5.0
209−decodeAllFileEither
210− :: FromJSON a
211− => FilePath
212− -> IO (Either ParseException [a])
213−decodeAllFileEither = fmap (fmap snd) . decodeAllFileWithWarnings
214−
215−-- | A version of `decodeFileEither` that returns warnings along with the parse
216−-- result.
217−--
218−-- @since 0.10.0
219−decodeFileWithWarnings
220− :: FromJSON a
221− => FilePath
222− -> IO (Either ParseException ([Warning], a))
223−decodeFileWithWarnings = decodeHelper_ . Y.decodeFile
224−
225−-- | Like `decodeFileWithWarnings`, but decode multiple documents.
226−--
227−-- @since 0.11.5.0
228−decodeAllFileWithWarnings
229− :: FromJSON a
230− => FilePath
231− -> IO (Either ParseException ([Warning], [a]))
232−decodeAllFileWithWarnings = decodeAllHelper_ . Y.decodeFile
233−
234−decodeEither :: FromJSON a => ByteString -> Either String a
235−decodeEither bs = unsafePerformIO
236− $ either (Left . prettyPrintParseException) id
237− <$> (fmap snd <$> decodeHelper (Y.decode bs))
238−{-# DEPRECATED decodeEither "Please use decodeEither' or decodeThrow, which provide more useful failures" #-}
239−
240−-- | More helpful version of 'decodeEither' which returns the 'YamlException'.
241−--
242−-- @since 0.8.3
243−decodeEither' :: FromJSON a => ByteString -> Either ParseException a
244−decodeEither' = either Left (either (Left . AesonException) Right)
245− . unsafePerformIO
246− . fmap (fmap snd) . decodeHelper
247− . Y.decode
248−
249−-- | Like 'decodeEither'', but decode multiple documents.
250−--
251−-- @since 0.11.5.0
252−decodeAllEither' :: FromJSON a => ByteString -> Either ParseException [a]
253−decodeAllEither' = either Left (either (Left . AesonException) Right)
254− . unsafePerformIO
255− . fmap (fmap snd) . decodeAllHelper
256− . Y.decode
257−
258−-- | A version of 'decodeEither'' lifted to MonadThrow
259−--
260−-- @since 0.8.31
261−decodeThrow :: (MonadThrow m, FromJSON a) => ByteString -> m a
262−decodeThrow = either throwM return . decodeEither'
263−
264−-- | Like `decodeThrow`, but decode multiple documents.
265−--
266−-- @since 0.11.5.0
267−decodeAllThrow :: (MonadThrow m, FromJSON a) => ByteString -> m [a]
268−decodeAllThrow = either throwM return . decodeAllEither'
269−
270−-- | A version of 'decodeFileEither' lifted to MonadIO
271−--
272−-- @since 0.8.31
273−decodeFileThrow :: (MonadIO m, FromJSON a) => FilePath -> m a
274−decodeFileThrow f = liftIO $ decodeFileEither f >>= either throwIO return
275−
276−-- | Like `decodeFileThrow`, but decode multiple documents.
277−--
278−-- @since 0.11.5.0
279−decodeAllFileThrow :: (MonadIO m, FromJSON a) => FilePath -> m [a]
280−decodeAllFileThrow f = liftIO $ decodeAllFileEither f >>= either throwIO return
281−
282−-- | Construct a new 'Value' from a list of 'Value's.
283−array :: [Value] -> Value
284−array = Array . V.fromList
285−
286−#if MIN_VERSION_base(4, 13, 0)
287−parseMonad :: MonadFail m => (a -> Parser b) -> a -> m b
288−#else
289−parseMonad :: Monad m => (a -> Parser b) -> a -> m b
290−#endif
291−parseMonad p = either fail return . parseEither p
292−{-# DEPRECATED parseMonad "With the MonadFail split, this function is going to be removed in the future. Please migrate to parseEither." #-}
yaml/src/Data/Yaml/Builder.hsdeleted−240
@@ -1,240 +0,0 @@
1−{-# LANGUAGE FlexibleInstances #-}
2−{-# LANGUAGE OverloadedStrings #-}
3−{-# LANGUAGE CPP #-}
4−-- | NOTE: This module is a highly experimental preview release. It may change
5−-- drastically, or be entirely removed, in a future release.
6−module Data.Yaml.Builder
7− ( YamlBuilder (..)
8− , ToYaml (..)
9− , mapping
10− , namedMapping
11− , maybeNamedMapping
12− , mappingComplex
13− , namedMappingComplex
14− , maybeNamedMappingComplex
15− , array
16− , namedArray
17− , maybeNamedArray
18− , string
19− , namedString
20− , maybeNamedString
21− , bool
22− , namedBool
23− , maybeNamedBool
24− , null
25− , namedNull
26− , maybeNamedNull
27− , scientific
28− , namedScientific
29− , maybeNamedScientific
30− , alias
31− , number
32− , toByteString
33− , toByteStringWith
34− , writeYamlFile
35− , writeYamlFileWith
36− , (.=)
37− , FormatOptions
38− , setWidth
39− ) where
40−
41−import Prelude hiding (null)
42−
43−#if MIN_VERSION_aeson(1,0,0)
44−import Data.Aeson.Text (encodeToTextBuilder)
45−#else
46−import Data.Aeson.Encode (encodeToTextBuilder)
47−#endif
48−import Data.Aeson.Types (Value(..))
49−import Data.ByteString (ByteString)
50−import qualified Data.ByteString.Char8 as S8
51−import Data.Conduit
52−import Data.Scientific (Scientific)
53−import Data.Text (Text, unpack)
54−import qualified Data.Text as T
55−import qualified Data.Text.Encoding as TE
56−import qualified Data.Text.Lazy as TL
57−import Data.Text.Lazy.Builder (toLazyText)
58−import System.IO.Unsafe (unsafePerformIO)
59−
60−import Data.Yaml.Internal
61−import Text.Libyaml
62−
63−(.=) :: ToYaml a => Text -> a -> (Text, YamlBuilder)
64−k .= v = (k, toYaml v)
65−
66−newtype YamlBuilder = YamlBuilder { unYamlBuilder :: [Event] -> [Event] }
67−
68−class ToYaml a where
69− toYaml :: a -> YamlBuilder
70−instance ToYaml YamlBuilder where
71− toYaml = id
72−instance (ToYaml a, ToYaml b) => ToYaml [(a, b)] where
73− toYaml = mappingComplex . map (\(k, v) -> (toYaml k, toYaml v))
74−instance ToYaml a => ToYaml [a] where
75− toYaml = array . map toYaml
76−instance ToYaml Text where
77− toYaml = string
78−instance {-# OVERLAPPING #-} ToYaml String where
79− toYaml = string . T.pack
80−instance ToYaml Int where
81− toYaml i = YamlBuilder (EventScalar (S8.pack $ show i) NoTag PlainNoTag Nothing:)
82−instance ToYaml Double where
83− toYaml i = YamlBuilder (EventScalar (S8.pack $ show i) NoTag PlainNoTag Nothing:)
84−instance ToYaml Scientific where
85− toYaml = scientific
86−instance ToYaml Bool where
87− toYaml = bool
88−instance ToYaml a => ToYaml (Maybe a) where
89− toYaml = maybe null toYaml
90−
91−-- |
92−-- @since 0.10.3.0
93−maybeNamedMapping :: Maybe Text -> [(Text, YamlBuilder)] -> YamlBuilder
94−maybeNamedMapping anchor pairs = maybeNamedMappingComplex anchor complexPairs
95− where
96− complexPairs = map (\(k, v) -> (string k, v)) pairs
97−
98−-- |
99−-- @since 0.8.7
100−mapping :: [(Text, YamlBuilder)] -> YamlBuilder
101−mapping = maybeNamedMapping Nothing
102−
103−-- |
104−-- @since 0.10.3.0
105−namedMapping :: Text -> [(Text, YamlBuilder)] -> YamlBuilder
106−namedMapping name = maybeNamedMapping $ Just name
107−
108−-- |
109−-- @since 0.11.2.0
110−maybeNamedMappingComplex :: Maybe Text -> [(YamlBuilder, YamlBuilder)] -> YamlBuilder
111−maybeNamedMappingComplex anchor pairs = YamlBuilder $ \rest ->
112− EventMappingStart NoTag AnyMapping (unpack <$> anchor) : foldr addPair (EventMappingEnd : rest) pairs
113− where
114− addPair (YamlBuilder key, YamlBuilder value) after = key $ value after
115−
116−-- |
117−-- @since 0.11.2.0
118−mappingComplex :: [(YamlBuilder, YamlBuilder)] -> YamlBuilder
119−mappingComplex = maybeNamedMappingComplex Nothing
120−
121−-- |
122−-- @since 0.11.2.0
123−namedMappingComplex :: Text -> [(YamlBuilder, YamlBuilder)] -> YamlBuilder
124−namedMappingComplex name = maybeNamedMappingComplex $ Just name
125−
126−-- |
127−-- @since 0.10.3.0
128−maybeNamedArray :: Maybe Text -> [YamlBuilder] -> YamlBuilder
129−maybeNamedArray anchor bs =
130− YamlBuilder $ (EventSequenceStart NoTag AnySequence (unpack <$> anchor):) . flip (foldr go) bs . (EventSequenceEnd:)
131− where
132− go (YamlBuilder b) = b
133−
134−-- |
135−-- @since 0.8.7
136−array :: [YamlBuilder] -> YamlBuilder
137−array = maybeNamedArray Nothing
138−
139−-- |
140−-- @since 0.10.3.0
141−namedArray :: Text -> [YamlBuilder] -> YamlBuilder
142−namedArray name = maybeNamedArray $ Just name
143−
144−-- |
145−-- @since 0.10.3.0
146−maybeNamedString :: Maybe Text -> Text -> YamlBuilder
147−maybeNamedString anchor s = YamlBuilder (stringScalar defaultStringStyle anchor s :)
148−
149−-- |
150−-- @since 0.8.7
151−string :: Text -> YamlBuilder
152−string = maybeNamedString Nothing
153−
154−-- |
155−-- @since 0.10.3.0
156−namedString :: Text -> Text -> YamlBuilder
157−namedString name = maybeNamedString $ Just name
158−
159−-- Use aeson's implementation which gets rid of annoying decimal points
160−-- |
161−-- @since 0.10.3.0
162−maybeNamedScientific :: Maybe Text -> Scientific -> YamlBuilder
163−maybeNamedScientific anchor n = YamlBuilder (EventScalar (TE.encodeUtf8 $ TL.toStrict $ toLazyText $ encodeToTextBuilder (Number n)) NoTag PlainNoTag (unpack <$> anchor) :)
164−
165−-- |
166−-- @since 0.8.13
167−scientific :: Scientific -> YamlBuilder
168−scientific = maybeNamedScientific Nothing
169−
170−-- |
171−-- @since 0.10.3.0
172−namedScientific :: Text -> Scientific -> YamlBuilder
173−namedScientific name = maybeNamedScientific $ Just name
174−
175−-- |
176−-- @since 0.8.13
177−{-# DEPRECATED number "Use scientific" #-}
178−number :: Scientific -> YamlBuilder
179−number = scientific
180−
181−-- |
182−-- @since 0.10.3.0
183−maybeNamedBool :: Maybe Text -> Bool -> YamlBuilder
184−maybeNamedBool anchor True = YamlBuilder (EventScalar "true" NoTag PlainNoTag (unpack <$> anchor) :)
185−maybeNamedBool anchor False = YamlBuilder (EventScalar "false" NoTag PlainNoTag (unpack <$> anchor) :)
186−
187−-- |
188−-- @since 0.8.13
189−bool :: Bool -> YamlBuilder
190−bool = maybeNamedBool Nothing
191−
192−-- |
193−-- @since 0.10.3.0
194−namedBool :: Text -> Bool -> YamlBuilder
195−namedBool name = maybeNamedBool $ Just name
196−
197−-- |
198−-- @since 0.10.3.0
199−maybeNamedNull :: Maybe Text -> YamlBuilder
200−maybeNamedNull anchor = YamlBuilder (EventScalar "null" NoTag PlainNoTag (unpack <$> anchor) :)
201−
202−-- |
203−-- @since 0.8.13
204−null :: YamlBuilder
205−null = maybeNamedNull Nothing
206−
207−-- |
208−-- @since 0.10.3.0
209−namedNull :: Text -> YamlBuilder
210−namedNull name = maybeNamedNull $ Just name
211−
212−-- |
213−-- @since 0.10.3.0
214−alias :: Text -> YamlBuilder
215−alias anchor = YamlBuilder (EventAlias (unpack anchor) :)
216−
217−toEvents :: YamlBuilder -> [Event]
218−toEvents (YamlBuilder front) =
219− EventStreamStart : EventDocumentStart : front [EventDocumentEnd, EventStreamEnd]
220−
221−toSource :: (Monad m, ToYaml a) => a -> ConduitM i Event m ()
222−toSource = mapM_ yield . toEvents . toYaml
223−
224−-- |
225−-- @since 0.8.7
226−toByteString :: ToYaml a => a -> ByteString
227−toByteString = toByteStringWith defaultFormatOptions
228−
229−-- |
230−-- @since 0.10.2.0
231−toByteStringWith :: ToYaml a => FormatOptions -> a -> ByteString
232−toByteStringWith opts yb = unsafePerformIO $ runConduitRes $ toSource yb .| encodeWith opts
233−
234−writeYamlFile :: ToYaml a => FilePath -> a -> IO ()
235−writeYamlFile = writeYamlFileWith defaultFormatOptions
236−
237−-- |
238−-- @since 0.10.2.0
239−writeYamlFileWith :: ToYaml a => FormatOptions -> FilePath -> a -> IO ()
240−writeYamlFileWith opts fp yb = runConduitRes $ toSource yb .| encodeFileWith opts fp
yaml/src/Data/Yaml/Internal.hsdeleted−469
@@ -1,469 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE DeriveDataTypeable #-}
3−{-# LANGUAGE PatternGuards #-}
4−{-# LANGUAGE OverloadedStrings #-}
5−{-# LANGUAGE BangPatterns #-}
6−module Data.Yaml.Internal
7− (
8− ParseException(..)
9− , prettyPrintParseException
10− , Warning(..)
11− , parse
12− , Parse
13− , decodeHelper
14− , decodeHelper_
15− , decodeAllHelper
16− , decodeAllHelper_
17− , textToScientific
18− , stringScalar
19− , StringStyle
20− , defaultStringStyle
21− , isSpecialString
22− , specialStrings
23− , isNumeric
24− , objToStream
25− , objToEvents
26− ) where
27−
28−#if !MIN_VERSION_base(4,8,0)
29−import Control.Applicative ((<$>), Applicative(..))
30−#endif
31−import Control.Applicative ((<|>))
32−import Control.Exception
33−import Control.Monad (when, unless)
34−import Control.Monad.Trans.Resource (ResourceT, runResourceT)
35−import Control.Monad.State.Strict
36−import Control.Monad.Reader
37−#if MIN_VERSION_aeson(2,1,2)
38−import Data.Aeson hiding (AesonException)
39−#else
40−import Data.Aeson
41−#endif
42−#if MIN_VERSION_aeson(2,0,0)
43−import qualified Data.Aeson.Key as K
44−import qualified Data.Aeson.KeyMap as M
45−import Data.Aeson.KeyMap (KeyMap)
46−#else
47−import qualified Data.HashMap.Strict as M
48−#endif
49−#if MIN_VERSION_aeson(2,2,0)
50−import Data.Aeson.Types hiding (AesonException, parse)
51−#else
52−import Data.Aeson.Types hiding (parse)
53−import Data.Aeson.Internal (JSONPath, JSONPathElement(..), formatError)
54−#endif
55−import qualified Data.Attoparsec.Text as Atto
56−import Data.Bits (shiftL, (.|.))
57−import Data.ByteString (ByteString)
58−import qualified Data.ByteString.Builder as BB
59−import qualified Data.ByteString.Lazy as BL
60−import Data.ByteString.Builder.Scientific (scientificBuilder)
61−import Data.Char (toUpper, ord)
62−import qualified Data.List as List
63−import Data.Conduit ((.|), ConduitM, runConduit)
64−import qualified Data.Conduit.List as CL
65−import qualified Data.HashSet as HashSet
66−import Data.Map (Map)
67−import qualified Data.Map as Map
68−import Data.Set (Set)
69−import qualified Data.Set as Set
70−import Data.Scientific (Scientific, base10Exponent, coefficient)
71−import Data.Text (Text)
72−import qualified Data.Text as T
73−import Data.Text.Encoding (decodeUtf8With, encodeUtf8)
74−import Data.Text.Encoding.Error (lenientDecode)
75−import Data.Typeable
76−import qualified Data.Vector as V
77−import Data.Void (Void)
78−
79−import qualified Text.Libyaml as Y
80−import Text.Libyaml hiding (encode, decode, encodeFile, decodeFile)
81−
82−#if MIN_VERSION_aeson(2,0,0)
83−fromText :: T.Text -> K.Key
84−fromText = K.fromText
85−
86−toText :: K.Key -> T.Text
87−toText = K.toText
88−#else
89−fromText :: T.Text -> T.Text
90−fromText = id
91−
92−toText :: Key -> T.Text
93−toText = id
94−
95−type KeyMap a = M.HashMap Text a
96−type Key = Text
97−#endif
98−
99−data ParseException = NonScalarKey
100− | UnknownAlias { _anchorName :: Y.AnchorName }
101− | UnexpectedEvent { _received :: Maybe Event
102− , _expected :: Maybe Event
103− }
104− | InvalidYaml (Maybe YamlException)
105− | MultipleDocuments
106− | AesonException String
107− | OtherParseException SomeException
108− | NonStringKey JSONPath
109− | NonStringKeyAlias Y.AnchorName Value
110− | CyclicIncludes
111− | LoadSettingsException FilePath ParseException
112− deriving (Show, Typeable)
113−
114−instance Exception ParseException where
115−#if MIN_VERSION_base(4, 8, 0)
116− displayException = prettyPrintParseException
117−#endif
118−
119−-- | Alternative to 'show' to display a 'ParseException' on the screen.
120−-- Instead of displaying the data constructors applied to their arguments,
121−-- a more textual output is returned. For example, instead of printing:
122−--
123−-- > InvalidYaml (Just (YamlParseException {yamlProblem = "did not find expected ',' or '}'", yamlContext = "while parsing a flow mapping", yamlProblemMark = YamlMark {yamlIndex = 42, yamlLine = 2, yamlColumn = 12}})))
124−--
125−-- It looks more pleasant to print:
126−--
127−-- > YAML parse exception at line 2, column 12,
128−-- > while parsing a flow mapping:
129−-- > did not find expected ',' or '}'
130−--
131−-- Since 0.8.11
132−prettyPrintParseException :: ParseException -> String
133−prettyPrintParseException pe = case pe of
134− NonScalarKey -> "Non scalar key"
135− UnknownAlias anchor -> "Unknown alias `" ++ anchor ++ "`"
136− UnexpectedEvent { _expected = mbExpected, _received = mbUnexpected } -> unlines
137− [ "Unexpected event: expected"
138− , " " ++ show mbExpected
139− , "but received"
140− , " " ++ show mbUnexpected
141− ]
142− InvalidYaml mbYamlError -> case mbYamlError of
143− Nothing -> "Unspecified YAML error"
144− Just yamlError -> case yamlError of
145− YamlException s -> "YAML exception:\n" ++ s
146− YamlParseException problem context mark -> concat
147− [ "YAML parse exception at line " ++ show (yamlLine mark) ++
148− ", column " ++ show (yamlColumn mark)
149− , case context of
150− "" -> ":\n"
151− -- The context seems to include a leading "while" or similar.
152− _ -> ",\n" ++ context ++ ":\n"
153− , problem
154− ]
155− MultipleDocuments -> "Multiple YAML documents encountered"
156− AesonException s -> "Aeson exception:\n" ++ s
157− OtherParseException exc -> "Generic parse exception:\n" ++ show exc
158− NonStringKey path -> formatError path "Non-string keys are not supported"
159− NonStringKeyAlias anchor value -> unlines
160− [ "Non-string key alias:"
161− , " Anchor name: " ++ anchor
162− , " Value: " ++ show value
163− ]
164− CyclicIncludes -> "Cyclic includes"
165− LoadSettingsException fp exc -> "Could not parse file as YAML: " ++ fp ++ "\n" ++ prettyPrintParseException exc
166−
167−defineAnchor :: Value -> String -> ReaderT JSONPath (ConduitM e o Parse) ()
168−defineAnchor value name = modify (modifyAnchors $ Map.insert name value)
169− where
170− modifyAnchors :: (Map String Value -> Map String Value) -> ParseState -> ParseState
171− modifyAnchors f st = st {parseStateAnchors = f (parseStateAnchors st)}
172−
173−lookupAnchor :: String -> ReaderT JSONPath (ConduitM e o Parse) (Maybe Value)
174−lookupAnchor name = gets (Map.lookup name . parseStateAnchors)
175−
176−data Warning = DuplicateKey JSONPath
177− deriving (Eq, Show)
178−
179−addWarning :: Warning -> ReaderT JSONPath (ConduitM e o Parse) ()
180−addWarning w = modify (modifyWarnings (w :))
181− where
182− modifyWarnings :: ([Warning] -> [Warning]) -> ParseState -> ParseState
183− modifyWarnings f st = st {parseStateWarnings = f (parseStateWarnings st)}
184−
185−data ParseState = ParseState {
186− parseStateAnchors :: Map String Value
187−, parseStateWarnings :: [Warning]
188−}
189−
190−type Parse = StateT ParseState (ResourceT IO)
191−
192−requireEvent :: Event -> ReaderT JSONPath (ConduitM Event o Parse) ()
193−requireEvent e = do
194− f <- lift CL.head
195− unless (f == Just e) $ liftIO $ throwIO $ UnexpectedEvent f $ Just e
196−
197−parse :: ReaderT JSONPath (ConduitM Event o Parse) Value
198−parse = do
199− docs <- parseAll
200− case docs of
201− [] -> return Null
202− [doc] -> return doc
203− _ -> liftIO $ throwIO MultipleDocuments
204−
205−parseAll :: ReaderT JSONPath (ConduitM Event o Parse) [Value]
206−parseAll = do
207− streamStart <- lift CL.head
208− case streamStart of
209− Nothing ->
210− -- empty string input
211− return []
212− Just EventStreamStart ->
213− -- empty file input, comment only string/file input
214− parseDocs
215− _ -> missed streamStart
216− where
217− parseDocs = do
218− documentStart <- lift CL.head
219− case documentStart of
220− Just EventStreamEnd -> return []
221− Just EventDocumentStart -> do
222− res <- parseO
223− requireEvent EventDocumentEnd
224− (res :) <$> parseDocs
225− _ -> missed documentStart
226− missed event = liftIO $ throwIO $ UnexpectedEvent event Nothing
227−
228−parseScalar :: ByteString -> Anchor -> Style -> Tag
229− -> ReaderT JSONPath (ConduitM Event o Parse) Text
230−parseScalar v a style tag = do
231− let res = decodeUtf8With lenientDecode v
232− mapM_ (defineAnchor (textToValue style tag res)) a
233− return res
234−
235−textToValue :: Style -> Tag -> Text -> Value
236−textToValue SingleQuoted _ t = String t
237−textToValue DoubleQuoted _ t = String t
238−textToValue _ StrTag t = String t
239−textToValue Folded _ t = String t
240−textToValue _ _ t
241− | t `elem` ["null", "Null", "NULL", "~", ""] = Null
242− | any (t `isLike`) ["y", "yes", "on", "true"] = Bool True
243− | any (t `isLike`) ["n", "no", "off", "false"] = Bool False
244− | Right x <- textToScientific t = Number x
245− | otherwise = String t
246− where x `isLike` ref = x `elem` [ref, T.toUpper ref, titleCased]
247− where titleCased = toUpper (T.head ref) `T.cons` T.tail ref
248−
249−textToScientific :: Text -> Either String Scientific
250−textToScientific = Atto.parseOnly (num <* Atto.endOfInput)
251− where
252− num = (fromInteger <$> ("0x" *> Atto.hexadecimal))
253− <|> (fromInteger <$> ("0o" *> octal))
254− <|> Atto.scientific
255−
256− octal = T.foldl' step 0 <$> Atto.takeWhile1 isOctalDigit
257− where
258− isOctalDigit c = (c >= '0' && c <= '7')
259− step a c = (a `shiftL` 3) .|. fromIntegral (ord c - 48)
260−
261−parseO :: ReaderT JSONPath (ConduitM Event o Parse) Value
262−parseO = do
263− me <- lift CL.head
264− case me of
265− Just (EventScalar v tag style a) -> textToValue style tag <$> parseScalar v a style tag
266− Just (EventSequenceStart _ _ a) -> parseS 0 a id
267− Just (EventMappingStart _ _ a) -> parseM mempty a M.empty
268− Just (EventAlias an) -> do
269− m <- lookupAnchor an
270− case m of
271− Nothing -> liftIO $ throwIO $ UnknownAlias an
272− Just v -> return v
273− _ -> liftIO $ throwIO $ UnexpectedEvent me Nothing
274−
275−parseS :: Int
276− -> Y.Anchor
277− -> ([Value] -> [Value])
278− -> ReaderT JSONPath (ConduitM Event o Parse) Value
279−parseS !n a front = do
280− me <- lift CL.peek
281− case me of
282− Just EventSequenceEnd -> do
283− lift $ CL.drop 1
284− let res = Array $ V.fromList $ front []
285− mapM_ (defineAnchor res) a
286− return res
287− _ -> do
288− o <- local (Index n :) parseO
289− parseS (succ n) a $ front . (:) o
290−
291−parseM :: Set Key
292− -> Y.Anchor
293− -> KeyMap Value
294− -> ReaderT JSONPath (ConduitM Event o Parse) Value
295−parseM mergedKeys a front = do
296− me <- lift CL.head
297− case me of
298− Just EventMappingEnd -> do
299− let res = Object front
300− mapM_ (defineAnchor res) a
301− return res
302− _ -> do
303− s <- case me of
304− Just (EventScalar v tag style a') -> fromText <$> parseScalar v a' style tag
305− Just (EventAlias an) -> do
306− m <- lookupAnchor an
307− case m of
308− Nothing -> liftIO $ throwIO $ UnknownAlias an
309− Just (String t) -> return $ fromText t
310− Just v -> liftIO $ throwIO $ NonStringKeyAlias an v
311− _ -> do
312− path <- ask
313− liftIO $ throwIO $ NonStringKey path
314−
315− (mergedKeys', al') <- local (Key s :) $ do
316− o <- parseO
317− let al = do
318− when (M.member s front && Set.notMember s mergedKeys) $ do
319− path <- reverse <$> ask
320− addWarning (DuplicateKey path)
321− return (Set.delete s mergedKeys, M.insert s o front)
322− if s == "<<"
323− then case o of
324− Object l -> return (merge l)
325− Array l -> return $ merge $ List.foldl' mergeObjects M.empty $ V.toList l
326− _ -> al
327− else al
328− parseM mergedKeys' a al'
329− where mergeObjects al (Object om) = M.union al om
330− mergeObjects al _ = al
331−
332− merge xs = (Set.fromList (M.keys xs List.\\ M.keys front), M.union front xs)
333−
334−parseSrc :: ReaderT JSONPath (ConduitM Event Void Parse) val
335− -> ConduitM () Event Parse ()
336− -> IO (val, ParseState)
337−parseSrc eventParser src = runResourceT $ runStateT
338− (runConduit $ src .| runReaderT eventParser [])
339− (ParseState Map.empty [])
340−
341−mkHelper :: ReaderT JSONPath (ConduitM Event Void Parse) val -- ^ parse libyaml events as Value or [Value]
342− -> (SomeException -> IO (Either ParseException a)) -- ^ what to do with unhandled exceptions
343− -> ((val, ParseState) -> Either ParseException a) -- ^ further transform and parse results
344− -> ConduitM () Event Parse () -- ^ the libyaml event (string/file) source
345− -> IO (Either ParseException a)
346−mkHelper eventParser onOtherExc extractResults src = catches
347− (extractResults <$> parseSrc eventParser src)
348− [ Handler $ \pe -> return $ Left (pe :: ParseException)
349− , Handler $ \ye -> return $ Left $ InvalidYaml $ Just (ye :: YamlException)
350− , Handler $ \sae -> throwIO (sae :: SomeAsyncException)
351− , Handler onOtherExc
352− ]
353−
354−decodeHelper :: FromJSON a
355− => ConduitM () Y.Event Parse ()
356− -> IO (Either ParseException ([Warning], Either String a))
357−decodeHelper = mkHelper parse throwIO $ \(v, st) ->
358− Right (parseStateWarnings st, parseEither parseJSON v)
359−
360−decodeAllHelper :: FromJSON a
361− => ConduitM () Event Parse ()
362− -> IO (Either ParseException ([Warning], Either String [a]))
363−decodeAllHelper = mkHelper parseAll throwIO $ \(vs, st) ->
364− Right (parseStateWarnings st, mapM (parseEither parseJSON) vs)
365−
366−catchLeft :: SomeException -> IO (Either ParseException a)
367−catchLeft = return . Left . OtherParseException
368−
369−decodeHelper_ :: FromJSON a
370− => ConduitM () Event Parse ()
371− -> IO (Either ParseException ([Warning], a))
372−decodeHelper_ = mkHelper parse catchLeft $ \(v, st) ->
373− case parseEither parseJSON v of
374− Left e -> Left $ AesonException e
375− Right x -> Right (parseStateWarnings st, x)
376−
377−decodeAllHelper_ :: FromJSON a
378− => ConduitM () Event Parse ()
379− -> IO (Either ParseException ([Warning], [a]))
380−decodeAllHelper_ = mkHelper parseAll catchLeft $ \(vs, st) ->
381− case mapM (parseEither parseJSON) vs of
382− Left e -> Left $ AesonException e
383− Right xs -> Right (parseStateWarnings st, xs)
384−
385−type StringStyle = Text -> ( Tag, Style )
386−
387−-- | Encodes a string with the supplied style. This function handles the empty
388−-- string case properly to avoid https://github.com/snoyberg/yaml/issues/24
389−--
390−-- @since 0.11.2.0
391−stringScalar :: StringStyle -> Maybe Text -> Text -> Event
392−stringScalar _ anchor "" = EventScalar "" NoTag SingleQuoted (T.unpack <$> anchor)
393−stringScalar stringStyle anchor s = EventScalar (encodeUtf8 s) tag style (T.unpack <$> anchor)
394− where
395− ( tag, style ) = stringStyle s
396−
397−-- |
398−-- @since 0.11.2.0
399−defaultStringStyle :: StringStyle
400−defaultStringStyle = \s ->
401− case () of
402− ()
403− | "\n" `T.isInfixOf` s -> ( NoTag, Literal )
404− | isSpecialString s -> ( NoTag, SingleQuoted )
405− | otherwise -> ( NoTag, PlainNoTag )
406−
407−-- | Determine whether a string must be quoted in YAML and can't appear as plain text.
408−-- Useful if you want to use 'setStringStyle'.
409−--
410−-- @since 0.10.2.0
411−isSpecialString :: Text -> Bool
412−isSpecialString s = s `HashSet.member` specialStrings || isNumeric s
413−
414−-- | Strings which must be escaped so as not to be treated as non-string scalars.
415−--
416−-- @since 0.8.32
417−specialStrings :: HashSet.HashSet Text
418−specialStrings = HashSet.fromList $ T.words
419− "y Y yes Yes YES n N no No NO true True TRUE false False FALSE on On ON off Off OFF null Null NULL ~ *"
420−
421−-- |
422−-- @since 0.8.32
423−isNumeric :: Text -> Bool
424−isNumeric = either (const False) (const True) . textToScientific
425−
426−-- | Encode a value as a YAML document stream.
427−--
428−-- @since 0.11.2.0
429−objToStream :: ToJSON a => StringStyle -> a -> [Y.Event]
430−objToStream stringStyle o =
431− (:) EventStreamStart
432− . (:) EventDocumentStart
433− $ objToEvents stringStyle o
434− [ EventDocumentEnd
435− , EventStreamEnd
436− ]
437−
438−-- | Encode a value as a list of 'Event's.
439−--
440−-- @since 0.11.2.0
441−objToEvents :: ToJSON a => StringStyle -> a -> [Y.Event] -> [Y.Event]
442−objToEvents stringStyle = objToEvents' . toJSON
443− where
444− objToEvents' (Array list) rest =
445− EventSequenceStart NoTag AnySequence Nothing
446− : foldr objToEvents' (EventSequenceEnd : rest) (V.toList list)
447−
448− objToEvents' (Object o) rest =
449− EventMappingStart NoTag AnyMapping Nothing
450− : foldr pairToEvents (EventMappingEnd : rest) (M.toList o)
451− where
452− pairToEvents :: Pair -> [Y.Event] -> [Y.Event]
453− pairToEvents (k, v) = objToEvents' (String $ toText k) . objToEvents' v
454−
455− objToEvents' (String s) rest = stringScalar stringStyle Nothing s : rest
456−
457− objToEvents' Null rest = EventScalar "null" NullTag PlainNoTag Nothing : rest
458−
459− objToEvents' (Bool True) rest = EventScalar "true" BoolTag PlainNoTag Nothing : rest
460− objToEvents' (Bool False) rest = EventScalar "false" BoolTag PlainNoTag Nothing : rest
461−
462− objToEvents' (Number s) rest =
463− let builder
464− -- Special case the 0 exponent to remove the trailing .0
465− | base10Exponent s == 0 = BB.integerDec $ coefficient s
466− | otherwise = scientificBuilder s
467− lbs = BB.toLazyByteString builder
468− bs = BL.toStrict lbs
469− in EventScalar bs IntTag PlainNoTag Nothing : rest
yaml/src/Data/Yaml/TH.hsdeleted−80
@@ -1,80 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE LambdaCase #-}
3−{-# LANGUAGE ScopedTypeVariables #-}
4−
5−module Data.Yaml.TH
6− ( -- * Decoding
7− yamlQQ
8−#if MIN_VERSION_template_haskell(2,9,0)
9− , decodeFile
10−#endif
11− -- * Re-exports from "Data.Yaml"
12− , Value (..)
13− , Parser
14− , Object
15− , Array
16− , object
17− , array
18− , (.=)
19− , (.:)
20− , (.:?)
21− , (.!=)
22− , FromJSON (..)
23− ) where
24−
25−import Data.Text.Encoding
26−import qualified Data.Text as T
27−import Language.Haskell.TH
28−import Language.Haskell.TH.Syntax
29−import Language.Haskell.TH.Quote
30−
31−import Data.Yaml hiding (decodeFile)
32−
33−-- | Decode a YAML file at compile time. Only available on GHC version @7.8.1@
34−-- or higher.
35−--
36−-- @since 0.8.19.0
37−--
38−-- ==== __Examples__
39−--
40−-- @
41−-- {-\# LANGUAGE TemplateHaskell \#-}
42−--
43−-- config :: Config
44−-- config = $$('decodeFile' "config.yaml")
45−-- @
46−decodeFile :: forall a. (Lift a, FromJSON a) => FilePath -> Q (TExp a)
47−decodeFile path = do
48− addDependentFile path
49− x <- runIO $ decodeFileThrow path
50− fmap TExp (lift (x :: a))
51−
52−yamlExp :: String -> Q Exp
53−yamlExp input = do
54− val <- runIO $ decodeThrow $ encodeUtf8 $ T.pack input
55− lift (val :: Value)
56−
57−-- | A @QuasiQuoter@ for YAML.
58−--
59−-- @since 0.8.28.0
60−--
61−-- ==== __Examples__
62−--
63−-- @
64−-- {-\# LANGUAGE QuasiQuotes \#-}
65−-- import Data.Yaml.TH
66−--
67−-- value :: Value
68−-- value = [yamlQQ|
69−-- name: John Doe
70−-- age: 23
71−-- |]
72−-- @
73−yamlQQ :: QuasiQuoter
74−yamlQQ = QuasiQuoter {
75− quoteExp = yamlExp
76−, quotePat = notDefined "quotePat"
77−, quoteType = notDefined "quoteType"
78−, quoteDec = notDefined "quoteDec"
79−} where
80− notDefined name _ = fail (name ++ " is not defined for yamlQQ")
yaml/test/Data/Yaml/IncludeSpec.hsdeleted−139
@@ -1,139 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE QuasiQuotes #-}
3−{-# LANGUAGE OverloadedStrings #-}
4−module Data.Yaml.IncludeSpec (main, spec) where
5−
6−import Test.Hspec
7−import Data.List (isPrefixOf)
8−import qualified Data.ByteString.Lazy as LB
9−import Data.Aeson
10−#if MIN_VERSION_aeson(2,2,0)
11−import Data.Aeson.Types (JSONPathElement(..))
12−#else
13−import Data.Aeson.Internal (JSONPathElement(..))
14−#endif
15−import Data.Yaml (ParseException(InvalidYaml))
16−import Data.Yaml.Include
17−import Data.Yaml.Internal
18−import Text.Libyaml (YamlException(YamlException))
19−import Test.Mockery.Directory
20−import Text.RawString.QQ
21−import Data.Yaml.TH (yamlQQ)
22−
23−main :: IO ()
24−main = hspec spec
25−
26−asInt :: Int -> Int
27−asInt = id
28−
29−spec :: Spec
30−spec = do
31− describe "decodeFile" $ do
32− it "supports includes" $ do
33− decodeFile "test/resources/foo.yaml" `shouldReturn` Just (object
34− [ "foo" .= asInt 23
35− , "bar" .= object
36− [ "one" .= asInt 1
37− , "two" .= asInt 2
38− ]
39− , "baz" .= asInt 42
40− ])
41−
42− it "supports recursive includes" $ do
43− decodeFile "test/resources/baz.yaml" `shouldReturn` Just (object
44− [ "foo" .= object
45− [ "foo" .= asInt 23
46− , "bar" .= object
47− [ "one" .= asInt 1
48− , "two" .= asInt 2
49− ]
50− , "baz" .= asInt 42
51− ]
52− ])
53−
54− it "aborts on cyclic includes" $ do
55− (decodeFile "test/resources/loop/foo.yaml" :: IO (Maybe Value)) `shouldThrow` anyException
56−
57− context "when file does not exist" $ do
58− it "throws Left (InvalidYaml (Just (YamlException \"Yaml file not found: ...\")))" $ do
59− (decodeFile "./does_not_exist.yaml" :: IO (Maybe Value)) `shouldThrow` isYamlFileNotFoundException
60−
61− context "with a 1K stack size limit" $ around_ inTempDirectory $ do
62− context "with a large list" $ do
63− it "succeeds" $ do
64− let
65− xs :: [Value]
66− xs = replicate 5000 (Number 23)
67− LB.writeFile "foo.yaml" (encode xs)
68− decodeFile "foo.yaml" `shouldReturn` Just xs
69−
70− describe "decodeFileEither" $ do
71− context "when file does not exist" $ do
72− it "returns Left (InvalidYaml (Just (YamlException \"Yaml file not found: ...\")))" $ do
73− (decodeFileEither "./does_not_exist.yaml" :: IO (Either ParseException Value)) >>=
74− (`shouldSatisfy` either isYamlFileNotFoundException (const False))
75−
76− describe "decodeFileWithWarnings" $ around_ inTempDirectory $ do
77− it "warns on duplicate keys" $ do
78− writeFile "foo.yaml" [r|
79− foo: 23
80− foo: bar
81− |]
82− Right result <- decodeFileWithWarnings "foo.yaml"
83− result `shouldBe` ([DuplicateKey [Key "foo"]], [yamlQQ|
84− foo: bar
85− |])
86−
87− it "warns on nested duplicate keys" $ do
88− writeFile "foo.yaml" [r|
89− foo:
90− - 42
91− - bar: 23
92− bar: baz
93− |]
94− Right result <- decodeFileWithWarnings "foo.yaml"
95− result `shouldBe` ([DuplicateKey [Key "foo", Index 1, Key "bar"]], [yamlQQ|
96− foo:
97− - 42
98− - bar: baz
99− |])
100−
101− context "when overriding a merged key" $ do
102− it "does not warn" $ do
103− writeFile "foo.yaml" [r|
104− foo-1: &my-ref
105− bar: 23
106− foo-2:
107− <<: *my-ref
108− bar: 42
109− |]
110− Right result <- decodeFileWithWarnings "foo.yaml"
111− result `shouldBe` ([], [yamlQQ|
112− foo-1:
113− bar: 23
114− foo-2:
115− bar: 42
116− |])
117−
118− context "when overriding twice" $ do
119− it "warns" $ do
120− writeFile "foo.yaml" [r|
121− foo-1: &my-ref
122− bar: 23
123− foo-2:
124− <<: *my-ref
125− bar: 42
126− bar: 65
127− |]
128− Right result <- decodeFileWithWarnings "foo.yaml"
129− result `shouldBe` ([DuplicateKey [Key "foo-2", Key "bar"]], [yamlQQ|
130− foo-1:
131− bar: 23
132− foo-2:
133− bar: 65
134− |])
135−
136−isYamlFileNotFoundException :: ParseException -> Bool
137−isYamlFileNotFoundException (InvalidYaml (Just (YamlException msg)))
138− | "Yaml file not found: " `isPrefixOf` msg = True
139−isYamlFileNotFoundException _ = False
yaml/test/Data/Yaml/THSpec.hsdeleted−17
@@ -1,17 +0,0 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE QuasiQuotes #-}
3−module Data.Yaml.THSpec (spec) where
4−
5−import Test.Hspec
6−import Data.Aeson
7−
8−import Data.Yaml.TH
9−
10−spec :: Spec
11−spec = do
12− describe "yamlQQ" $ do
13− it "parses yaml" $ do
14− [yamlQQ|
15− name: John Doe
16− age: 23
17− |] `shouldBe` object ["name" .= String "John Doe", "age" .= Number 23]
yaml/test/Data/YamlSpec.hsdeleted−899
@@ -1,899 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE PackageImports #-}
3−{-# LANGUAGE ScopedTypeVariables #-}
4−{-# LANGUAGE OverloadedStrings #-}
5−{-# LANGUAGE TemplateHaskell #-}
6−{-# LANGUAGE TupleSections #-}
7−
8−module Data.YamlSpec (main, spec) where
9−
10−import qualified Text.Libyaml as Y
11−import qualified Data.ByteString as BS
12−import qualified Data.ByteString.Char8 as B8
13−import Data.Int (Int64)
14−import qualified Data.Scientific as S
15−
16−import Test.HUnit hiding (Test, path)
17−
18−import Data.Conduit (runConduitRes, (.|), ConduitM)
19−import qualified Data.Conduit.List as CL
20−
21−import Control.Monad
22−import Control.Exception (try, SomeException)
23−import Test.Hspec
24−import Test.Hspec.QuickCheck
25−import Data.Either.Compat
26−import System.Directory (createDirectory, createDirectoryIfMissing)
27−import Test.Mockery.Directory
28−
29−import qualified Data.Yaml as D
30−import qualified Data.Yaml.Builder as B
31−import qualified Data.Yaml.Internal as Internal
32−import qualified Data.Yaml.Pretty as Pretty
33−import Data.Yaml (object, array, (.=))
34−import Data.Maybe
35−import qualified Data.HashMap.Strict as HM
36−#if MIN_VERSION_aeson(2,0,0)
37−import qualified Data.Aeson.KeyMap as M
38−import qualified Data.Aeson.Key as K
39−import Data.Aeson.KeyMap (KeyMap)
40−#else
41−import qualified Data.HashMap.Strict as M
42−#endif
43−import qualified Data.Text as T
44−import Data.Aeson.TH
45−import Data.Scientific (Scientific)
46−import Data.String (fromString)
47−import Data.Text (Text)
48−import Data.Text.Encoding (decodeUtf8, encodeUtf8)
49−import Data.Vector (Vector)
50−import qualified Data.Vector as V
51−import Data.HashMap.Strict (HashMap)
52−import qualified Data.HashMap.Strict as HM
53−import System.IO (hClose)
54−import System.IO.Temp (withSystemTempFile)
55−
56−#if MIN_VERSION_aeson(2,0,0)
57−fromText :: T.Text -> K.Key
58−fromText = K.fromText
59−
60−toText :: K.Key -> T.Text
61−toText = K.toText
62−#else
63−fromText :: T.Text -> T.Text
64−fromText = id
65−
66−toText :: Key -> T.Text
67−toText = id
68−
69−type KeyMap a = M.HashMap Text a
70−type Key = Text
71−#endif
72−
73−data TestJSON = TestJSON
74− { string :: Text
75− , number :: Int
76− , anArray :: Vector Text
77− , hash :: HashMap Text Text
78− , extrastring :: Text
79− } deriving (Show, Eq)
80−
81−deriveJSON defaultOptions ''TestJSON
82−
83−testJSON :: TestJSON
84−testJSON = TestJSON
85− { string = "str"
86− , number = 2
87− , anArray = V.fromList ["a", "b"]
88− , hash = HM.fromList [("key1", "value1"), ("key2", "value2")]
89− , extrastring = "1234-foo"
90− }
91−
92−shouldDecode :: (Show a, D.FromJSON a, Eq a) => B8.ByteString -> a -> IO ()
93−shouldDecode bs expected = do
94− actual <- D.decodeThrow bs
95− actual `shouldBe` expected
96−
97−shouldDecodeAll :: (Show a, D.FromJSON a, Eq a) => B8.ByteString -> [a] -> IO ()
98−shouldDecodeAll bs expected = do
99− actual <- D.decodeAllThrow bs
100− actual `shouldBe` expected
101−
102−shouldDecodeEvents :: B8.ByteString -> [Y.Event] -> IO ()
103−shouldDecodeEvents bs expected = do
104− actual <- runConduitRes $ Y.decode bs .| CL.consume
105− map anyStyle actual `shouldBe` map anyStyle expected
106−
107−anyStyle :: Y.Event -> Y.Event
108−anyStyle (Y.EventScalar bs tag _ anchor) = Y.EventScalar bs tag Y.Any anchor
109−anyStyle (Y.EventSequenceStart tag _ anchor) = Y.EventSequenceStart tag Y.AnySequence anchor
110−anyStyle (Y.EventMappingStart tag _ anchor) = Y.EventMappingStart tag Y.AnyMapping anchor
111−anyStyle event = event
112−
113−testEncodeWith :: Y.FormatOptions -> [Y.Event] -> IO BS.ByteString
114−testEncodeWith opts es = runConduitRes $ CL.sourceList (eventStream es) .| Y.encodeWith opts
115−
116−eventStream :: [Y.Event] -> [Y.Event]
117−eventStream events =
118− [Y.EventStreamStart, Y.EventDocumentStart]
119− ++ events
120− ++ [Y.EventDocumentEnd, Y.EventStreamEnd]
121−
122−main :: IO ()
123−main = hspec spec
124−
125−spec :: Spec
126−spec = do
127− describe "streaming" $ do
128− it "count scalars with anchor" caseCountScalarsWithAnchor
129− it "count sequences with anchor" caseCountSequencesWithAnchor
130− it "count mappings with anchor" caseCountMappingsWithAnchor
131− it "count sequences with custom tag" caseCountSequenceTags
132− it "count mappings with custom tag" caseCountMappingTags
133− it "count count sequences with ! tag" caseCountEmptySequenceTags
134− it "count count mappings with ! tag" caseCountEmptyMappingTags
135− it "count block style sequences" caseCountBlockStyleSequences
136− it "count flow style sequences" caseCountFlowStyleSequences
137− it "count block style mappings" caseCountBlockStyleMappings
138− it "count flow style mappings" caseCountFlowStyleMappings
139− it "count aliases" caseCountAliases
140− it "count scalars" caseCountScalars
141− it "largest string" caseLargestString
142− it "encode/decode" caseEncodeDecode
143− it "encode/decode events" caseEncodeDecodeEvents
144− it "encode/decode file" caseEncodeDecodeFile
145− it "interleaved encode/decode" caseInterleave
146− it "decode invalid document (without segfault)" caseDecodeInvalidDocument
147− describe "Data.Yaml" $ do
148− it "encode/decode" caseEncodeDecodeData
149− it "encode/decode file" caseEncodeDecodeFileData
150− it "encode/decode files with non-ASCII names" caseEncodeDecodeNonAsciiFileData
151− it "encode/decode strings" caseEncodeDecodeStrings
152− it "decode invalid file" caseDecodeInvalid
153− it "processes datatypes" caseDataTypes
154− it "encode invalid numbers" caseEncodeInvalidNumbers
155− describe "Data.Yaml.Pretty" $ do
156− it "encode/decode" caseEncodeDecodeDataPretty
157− it "encode/decode strings" caseEncodeDecodeStringsPretty
158− it "processes datatypes" caseDataTypesPretty
159− describe "Data.Yaml.Builder" $ do
160− it "encode/decode" caseEncodeDecodeDataBuilder
161− it "encode/decode complex mapping" caseEncodeDecodeComplexMappingBuilder
162− describe "Data.Yaml aliases" $ do
163− it "simple scalar alias" caseSimpleScalarAlias
164− it "simple sequence alias" caseSimpleSequenceAlias
165− it "simple mapping alias" caseSimpleMappingAlias
166− it "mapping alias before anchor" caseMappingAliasBeforeAnchor
167− it "mapping alias inside anchor" caseMappingAliasInsideAnchor
168− it "scalar alias overriding" caseScalarAliasOverriding
169− describe "Data.Yaml merge keys" $ do
170− it "test uniqueness of keys" caseAllKeysShouldBeUnique
171− it "test mapping merge" caseSimpleMappingMerge
172− it "test sequence of mappings merging" caseMergeSequence
173− describe "numbers" $ do
174− it "parses as string when quoted" caseQuotedNumber
175− it "parses as number when unquoted" caseUnquotedNumber
176− it "parses as number !!str is present" caseAttribNumber
177− it "integers have no decimals" caseIntegerDecimals
178− describe "booleans" $ do
179− it "parses when all lowercase" caseLowercaseBool
180− it "parses when all uppercase" caseUppercaseBool
181− it "parses when titlecase" caseTitlecaseBool
182− describe "empty input" $ do
183− it "parses as Null" caseEmptyInput
184− it "parses as Null from file" caseEmptyInputFile
185− describe "comment only input" $ do
186− it "parses as Null" caseCommentOnlyInput
187− it "parses as Null from file" caseCommentOnlyInputFile
188− describe "alias stripping" $ do
189− it "works" caseStripAlias
190− describe "nulls" $ do
191− checkNull "null"
192− checkNull "Null"
193− checkNull "NULL"
194− checkNull "~"
195− checkNull ""
196−
197− describe "pretty output" $ do
198− it "simple nulls" $ D.encode (object ["foo" .= D.Null]) `shouldBe` "foo: null\n"
199− it "simple numbers" $ D.encode (object ["foo" .= (4 :: Int)]) `shouldBe` "foo: 4\n"
200− it "True" $ D.encode (object ["foo" .= True]) `shouldBe` "foo: true\n"
201− it "False" $ D.encode (object ["foo" .= False]) `shouldBe` "foo: false\n"
202− it "simple string" $ D.encode (object ["foo" .= ("bar" :: T.Text)]) `shouldBe` "foo: bar\n"
203− it "*" $ D.encode (object ["foo" .= ("*" :: T.Text)]) `shouldBe` "foo: '*'\n"
204−
205− describe "special keys" $ do
206− let tester key = it (T.unpack key) $
207− let value = object [fromText key .= True]
208− in D.encode value `shouldDecode` value
209− mapM_ tester specialStrings
210−
211− describe "special values" $ do
212− let tester value = it (T.unpack value) $
213− let value' = object ["foo" .= value]
214− in D.encode value' `shouldDecode` value'
215− mapM_ tester specialStrings
216−
217− describe "decodeFileEither" $ do
218− it "loads YAML through JSON into Haskell data" $ do
219− tj <- either (error . show) id `fmap` D.decodeFileEither "test/json.yaml"
220− tj `shouldBe` testJSON
221−
222− context "when file does not exist" $ do
223− it "returns Left" $ do
224− (D.decodeFileEither "./does_not_exist.yaml" :: IO (Either D.ParseException D.Value)) >>= (`shouldSatisfy` isLeft)
225−
226− describe "multiple document support" $ do
227− it "decodes zero-length input" $
228− "" `shouldDecodeAll` ([] :: [D.Value])
229− it "decodes comment-only input" $
230− "# foo\n# bar" `shouldDecodeAll` ([] :: [D.Value])
231− it "decodes a single document stream" $
232− "foo: true" `shouldDecodeAll` [object ["foo" .= True]]
233− it "decodes multiple documents" $
234− "--- 1\n--- 2" `shouldDecodeAll` [D.Number 1, D.Number 2]
235−
236− describe "round-tripping of special scalars" $ do
237− let special = words "y Y On ON false 12345 12345.0 12345a 12e3"
238− forM_ special $ \w -> it w $
239− let v = object ["word" .= w]
240− in D.encode v `shouldDecode` v
241− it "no tags" $ D.encode (object ["word" .= ("true" :: String)]) `shouldBe` "word: 'true'\n"
242−
243− it "aliases in keys #49" caseIssue49
244−
245− it "serialization of +123 #64" $ do
246− D.encode ("+123" :: String) `shouldDecode` ("+123" :: String)
247−
248− it "preserves Scientific precision" casePreservesScientificPrecision
249−
250− it "truncates files" caseTruncatesFiles
251−
252− it "encode quotes special keys #137" $ caseSpecialKeys D.encode
253−
254− it "encodePretty quotes special keys #179" $ caseSpecialKeys (Pretty.encodePretty Pretty.defConfig)
255−
256− describe "non-decimal numbers #135" $ do
257− let go str val = it str $ encodeUtf8 (T.pack str) `shouldDecode` val
258− go "12345" (12345 :: Int)
259− go "+12345" (12345 :: Int)
260− go "0o14" (12 :: Int)
261− go "0o123" (83 :: Int)
262− go "0xC" (12 :: Int)
263− go "0xc" (12 :: Int)
264− go "0xdeadBEEF" (3735928559 :: Int64)
265− go "0xDEADBEEF" (3735928559 :: Int64)
266− go "1.23015e+3" (1230.15 :: Scientific)
267− go "12.3015e+02" (1230.15 :: Scientific)
268− go "1230.15" (1230.15 :: Scientific)
269−
270− describe "Text.Libyaml with default tag rendering" $ do
271− let enc = testEncodeWith Y.defaultFormatOptions
272− it "elides custom sequence tags" $
273− enc taggedSequence `shouldReturn` "[]\n"
274− it "elides custom mapping tags" $
275− enc taggedMapping `shouldReturn` "{}\n"
276− it "elides default sequence tags" $
277− enc defaultTaggedSequence `shouldReturn` "[]\n"
278− it "elides default mapping tags" $
279− enc defaultTaggedMapping `shouldReturn` "{}\n"
280− it "handles NoTag on sequences" $
281− enc untaggedSequence `shouldReturn` "[]\n"
282− it "handles NoTag on mappings" $
283− enc untaggedMapping `shouldReturn` "{}\n"
284− it "handles mixed tag usages but elides all mapping and sequence tags" $
285− enc mixedTagSampleA `shouldReturn` "- {}\n"
286− it "in combination of tags, anchors and styles, outputs only the scalar tags" $
287− enc mixedTagSampleB `shouldReturn` "&a\n&b !<bar> foo: &c [&d !!null '']\n"
288− it "outputs tags when double quoted" $
289− enc [Y.EventScalar "foo" Y.StrTag Y.DoubleQuoted Nothing] `shouldReturn` "!!str \"foo\"\n"
290− it "outputs tags when single quoted" $
291− enc [Y.EventScalar "foo" Y.StrTag Y.SingleQuoted Nothing] `shouldReturn` "!!str 'foo'\n"
292− it "outputs tags on literal text" $
293− enc [Y.EventScalar "foo" Y.StrTag Y.Literal Nothing] `shouldReturn` "!!str |-\n foo\n"
294− it "outputs tags on folded text" $
295− enc [Y.EventScalar "foo" Y.StrTag Y.Folded Nothing] `shouldReturn` "!!str >-\n foo\n"
296− describe "Text.Libyaml with all tags on" $ do
297− let enc = testEncodeWith $ Y.setTagRendering Y.renderAllTags Y.defaultFormatOptions
298− it "will output custom sequence tags" $
299− enc taggedSequence `shouldReturn` "!foo []\n"
300− it "will output custom mapping tags" $
301− enc taggedMapping `shouldReturn` "!foo {}\n"
302− it "will output default sequence tags" $
303− enc defaultTaggedSequence `shouldReturn` "!!seq []\n"
304− it "will output default mapping tags" $
305− enc defaultTaggedMapping `shouldReturn` "!!map {}\n"
306− it "handles NoTag on sequences" $
307− enc untaggedSequence `shouldReturn` "[]\n"
308− it "handles NoTag on mappings" $
309− enc untaggedMapping `shouldReturn` "{}\n"
310− it "handles mixed tag usages outputting all mapping and sequence tags" $
311− enc mixedTagSampleA `shouldReturn` "- !foo {}\n"
312− it "in combination of tags, anchors and styles, outputs all the tags" $
313− enc mixedTagSampleB `shouldReturn` "&a\n&b !<bar> foo: &c !baz [&d !!null '']\n"
314− it "outputs plain tags" $
315− enc [Y.EventScalar "foo" Y.StrTag Y.Plain Nothing] `shouldReturn` "!!str foo\n"
316− it "respects PlainNoTag tags" $
317− enc [Y.EventScalar "foo" Y.StrTag Y.PlainNoTag Nothing] `shouldReturn` "foo\n"
318− describe "Text.Libyaml with uri tags on" $ do
319− let enc = testEncodeWith $ Y.setTagRendering Y.renderUriTags Y.defaultFormatOptions
320− it "will output custom sequence tags" $
321− enc taggedSequence `shouldReturn` "!foo []\n"
322− it "will output custom mapping tags" $
323− enc taggedMapping `shouldReturn` "!foo {}\n"
324− it "will output default sequence tags" $
325− enc defaultTaggedSequence `shouldReturn` "[]\n"
326− it "will output default mapping tags" $
327− enc defaultTaggedMapping `shouldReturn` "{}\n"
328− it "handles NoTag on sequences" $
329− enc untaggedSequence `shouldReturn` "[]\n"
330− it "handles NoTag on mappings" $
331− enc untaggedMapping `shouldReturn` "{}\n"
332− it "handles mixed tag usages outputting all mapping and sequence tags" $
333− enc mixedTagSampleA `shouldReturn` "- !foo {}\n"
334− it "in combination of tags, anchors and styles, outputs all the tags" $
335− enc mixedTagSampleB `shouldReturn` "&a\n&b !<bar> foo: &c !baz [&d '']\n"
336− describe "Text.Libyaml with tags off" $ do
337− let enc = testEncodeWith $ Y.setTagRendering Y.renderNoTags Y.defaultFormatOptions
338− it "outputs plain tags" $
339− enc [Y.EventScalar "foo" Y.StrTag Y.Plain Nothing] `shouldReturn` "foo\n"
340− it "respects PlainNoTag tags" $
341− enc [Y.EventScalar "foo" Y.StrTag Y.PlainNoTag Nothing] `shouldReturn` "foo\n"
342− it "elides tags when double quoted" $
343− enc [Y.EventScalar "foo" Y.StrTag Y.DoubleQuoted Nothing] `shouldReturn` "\"foo\"\n"
344− it "elides tags when single quoted" $
345− enc [Y.EventScalar "foo" Y.StrTag Y.SingleQuoted Nothing] `shouldReturn` "'foo'\n"
346− it "elides tags on literal text" $
347− enc [Y.EventScalar "foo" Y.StrTag Y.Literal Nothing] `shouldReturn` "|-\n foo\n"
348− it "elides tags on folded text" $
349− enc [Y.EventScalar "foo" Y.StrTag Y.Folded Nothing] `shouldReturn` ">-\n foo\n"
350− describe "Text.Libyaml with only UriTags set to render " $ do
351− let enc =
352− testEncodeWith $
353− Y.setTagRendering Y.renderUriTags $ Y.defaultFormatOptions
354− it "outputs only UriTags" $
355− enc
356− [ Y.EventSequenceStart Y.NoTag Y.FlowSequence Nothing
357− , Y.EventScalar "foo" Y.StrTag Y.DoubleQuoted Nothing
358− , Y.EventScalar "99" Y.IntTag Y.Plain Nothing
359− , Y.EventScalar "99.99" Y.FloatTag Y.Plain Nothing
360− , Y.EventScalar "bar" Y.NoTag Y.Plain Nothing
361− , Y.EventScalar "foo" (Y.UriTag "!foo") Y.DoubleQuoted Nothing
362− , Y.EventScalar "foo" (Y.UriTag "!foo") Y.Plain Nothing
363− , Y.EventSequenceEnd
364− ] `shouldReturn`
365− "[\"foo\", 99, 99.99, bar, !foo \"foo\", !foo foo]\n"
366−
367− prop "Scientific values round-trip" $ \coeff expon -> do
368− let val = D.Number $ S.scientific coeff expon
369− let rendered = D.encode val
370− case D.decodeEither' rendered of
371− Left e -> error $ show (coeff, expon, e)
372− Right val' -> val' `shouldBe` val
373−
374−specialStrings :: [T.Text]
375−specialStrings =
376− [ "fo\"o"
377− , "fo\'o"
378− , "fo\\'o"
379− , "fo: o"
380− , "foo\nbar\nbaz\n"
381− ]
382−
383−counter :: Monad m => (Y.Event -> Bool) -> ConduitM Y.Event o m Int
384−counter pred' =
385− CL.fold (\cnt e -> (if pred' e then 1 else 0) + cnt) 0
386−
387−caseHelper :: String
388− -> (Y.Event -> Bool)
389− -> Int
390− -> Assertion
391−caseHelper yamlString pred' expRes = do
392− res <- runConduitRes $ Y.decode (B8.pack yamlString) .| counter pred'
393− res @?= expRes
394−
395−caseCountScalarsWithAnchor :: Assertion
396−caseCountScalarsWithAnchor =
397− caseHelper yamlString isScalarA 1
398− where
399− yamlString = "foo:\n - &anchor bin1\n - bin2\n - bin3"
400− isScalarA (Y.EventScalar _ _ _ (Just _)) = True
401− isScalarA _ = False
402−
403−caseCountSequencesWithAnchor :: Assertion
404−caseCountSequencesWithAnchor =
405− caseHelper yamlString isSequenceStartA 1
406− where
407− yamlString = "foo: &anchor\n - bin1\n - bin2\n - bin3"
408− isSequenceStartA (Y.EventSequenceStart Y.NoTag _ (Just _)) = True
409− isSequenceStartA _ = False
410−
411−caseCountMappingsWithAnchor :: Assertion
412−caseCountMappingsWithAnchor =
413− caseHelper yamlString isMappingA 1
414− where
415− yamlString = "foo: &anchor\n key1: bin1\n key2: bin2\n key3: bin3"
416− isMappingA (Y.EventMappingStart _ _ (Just _)) = True
417− isMappingA _ = False
418−
419−caseCountAliases :: Assertion
420−caseCountAliases =
421− caseHelper yamlString isAlias 1
422− where
423− yamlString = "foo: &anchor\n key1: bin1\n key2: bin2\n key3: bin3\nboo: *anchor"
424− isAlias Y.EventAlias{} = True
425− isAlias _ = False
426−
427−caseCountMappingTags :: Assertion
428−caseCountMappingTags =
429− caseHelper yamlString isCustomTaggedMapping 1
430− where
431− yamlString = "foo: !bar\n k: v\n k2: v2"
432− isCustomTaggedMapping (Y.EventMappingStart (Y.UriTag "!bar") _ _) = True
433− isCustomTaggedMapping _ = False
434−
435−caseCountEmptyMappingTags :: Assertion
436−caseCountEmptyMappingTags =
437− caseHelper yamlString isCustomTaggedMapping 1
438− where
439− yamlString = "foo: !\n k: v\n k2: v2"
440− isCustomTaggedMapping (Y.EventMappingStart (Y.UriTag "!") _ _) = True
441− isCustomTaggedMapping _ = False
442−
443−caseCountSequenceTags :: Assertion
444−caseCountSequenceTags =
445− caseHelper yamlString isCustomTaggedSequence 1
446− where
447− yamlString = "foo: !bar [x, y, z]"
448− isCustomTaggedSequence (Y.EventSequenceStart (Y.UriTag "!bar") _ _) = True
449− isCustomTaggedSequence _ = False
450−
451−caseCountEmptySequenceTags :: Assertion
452−caseCountEmptySequenceTags =
453− caseHelper yamlString isCustomTaggedSequence 1
454− where
455− yamlString = "foo: ! [x, y, z]"
456− isCustomTaggedSequence (Y.EventSequenceStart (Y.UriTag "!") _ _) = True
457− isCustomTaggedSequence _ = False
458−
459−caseCountFlowStyleSequences :: Assertion
460−caseCountFlowStyleSequences =
461− caseHelper yamlString isFlowStyleSequence 1
462− where
463− yamlString = "foo: [x, y, z]"
464− isFlowStyleSequence (Y.EventSequenceStart _ Y.FlowSequence _) = True
465− isFlowStyleSequence _ = False
466−
467−caseCountBlockStyleSequences :: Assertion
468−caseCountBlockStyleSequences =
469− caseHelper yamlString isBlockStyleSequence 1
470− where
471− yamlString = "foo:\n- x\n- y\n- z\n"
472− isBlockStyleSequence (Y.EventSequenceStart _ Y.BlockSequence _) = True
473− isBlockStyleSequence _ = False
474−
475−caseCountFlowStyleMappings :: Assertion
476−caseCountFlowStyleMappings =
477− caseHelper yamlString isFlowStyleMapping 1
478− where
479− yamlString = "foo: { bar: 1, baz: 2 }"
480− isFlowStyleMapping (Y.EventMappingStart _ Y.FlowMapping _) = True
481− isFlowStyleMapping _ = False
482−
483−caseCountBlockStyleMappings :: Assertion
484−caseCountBlockStyleMappings =
485− caseHelper yamlString isBlockStyleMapping 1
486− where
487− yamlString = "foo: bar\nbaz: quux"
488− isBlockStyleMapping (Y.EventMappingStart _ Y.BlockMapping _) = True
489− isBlockStyleMapping _ = False
490−
491−caseCountScalars :: Assertion
492−caseCountScalars = do
493− res <- runConduitRes $ Y.decode yamlBS .| CL.fold adder accum
494− res @?= (7, 1, 2)
495− where
496− yamlString = "foo:\n baz: [bin1, bin2, bin3]\nbaz: bazval"
497− yamlBS = B8.pack yamlString
498− adder (s, l, m) (Y.EventScalar{}) = (s + 1, l, m)
499− adder (s, l, m) (Y.EventSequenceStart{}) = (s, l + 1, m)
500− adder (s, l, m) (Y.EventMappingStart{}) = (s, l, m + 1)
501− adder a _ = a
502− accum = (0, 0, 0) :: (Int, Int, Int)
503−
504−caseLargestString :: Assertion
505−caseLargestString = do
506− res <- runConduitRes $ Y.decodeFile filePath .| CL.fold adder accum
507− res @?= (length expected, expected)
508− where
509− expected = "this one is just a little bit bigger than the others"
510− filePath = "test/largest-string.yaml"
511− adder (i, s) (Y.EventScalar bs _ _ _) =
512− let s' = B8.unpack bs
513− i' = length s'
514− in if i' > i then (i', s') else (i, s)
515− adder acc _ = acc
516− accum = (0, "no strings found")
517−
518−newtype MyEvent = MyEvent Y.Event deriving Show
519−instance Eq MyEvent where
520− (MyEvent (Y.EventScalar s t _ _)) == (MyEvent (Y.EventScalar s' t' _ _)) =
521− s == s' && t == t'
522− MyEvent e1 == MyEvent e2 = e1 == e2
523−
524−caseEncodeDecode :: Assertion
525−caseEncodeDecode = do
526− eList <- runConduitRes $ Y.decode yamlBS .| CL.consume
527− bs <- runConduitRes $ CL.sourceList eList .| Y.encode
528− eList2 <- runConduitRes $ Y.decode bs .| CL.consume
529− map MyEvent eList @=? map MyEvent eList2
530− where
531− yamlString = "foo: bar\nbaz:\n - bin1\n - bin2\n"
532− yamlBS = B8.pack yamlString
533−
534−caseEncodeDecodeEvents :: Assertion
535−caseEncodeDecodeEvents = do
536− let events = Internal.objToEvents D.defaultStringStyle testJSON []
537− result <- Internal.decodeHelper_ . CL.sourceList $ eventStream events
538− let (_, value) = either (error . show) id result
539− value @?= testJSON
540−
541−caseEncodeDecodeFile :: Assertion
542−caseEncodeDecodeFile = withFile "" $ \tmpPath -> do
543− eList <- runConduitRes $ Y.decodeFile filePath .| CL.consume
544− runConduitRes $ CL.sourceList eList .| Y.encodeFile tmpPath
545− eList2 <- runConduitRes $ Y.decodeFile filePath .| CL.consume
546− map MyEvent eList @=? map MyEvent eList2
547− where
548− filePath = "test/largest-string.yaml"
549−
550−caseInterleave :: Assertion
551−caseInterleave = withFile "" $ \tmpPath -> withFile "" $ \tmpPath2 -> do
552− () <- runConduitRes $ Y.decodeFile filePath .| Y.encodeFile tmpPath
553− () <- runConduitRes $ Y.decodeFile tmpPath .| Y.encodeFile tmpPath2
554− f1 <- readFile tmpPath
555− f2 <- readFile tmpPath2
556− f1 @=? f2
557− where
558− filePath = "test/largest-string.yaml"
559−
560−caseDecodeInvalidDocument :: Assertion
561−caseDecodeInvalidDocument = do
562− x <- try $ runConduitRes $ Y.decode yamlBS .| CL.sinkNull
563− case x of
564− Left (_ :: SomeException) -> return ()
565− Right y -> do
566− putStrLn $ "bad return value: " ++ show y
567− assertFailure "expected parsing exception, but got no errors"
568− where
569− yamlString = " - foo\n - baz\nbuz"
570− yamlBS = B8.pack yamlString
571−
572−mkScalar :: String -> D.Value
573−mkScalar = mkStrScalar
574−
575−mkStrScalar :: String -> D.Value
576−mkStrScalar = D.String . T.pack
577−
578−mappingKey :: D.Value-> String -> D.Value
579−mappingKey (D.Object m) k = (fromJust . M.lookup (fromText $ T.pack k) $ m)
580−mappingKey _ _ = error "expected Object"
581−
582−sample :: D.Value
583−sample = array
584− [ D.String "foo"
585− , object
586− [ ("bar1", D.String "bar2")
587− , ("bar3", D.String "")
588− ]
589− , D.String ""
590− , D.Number 1
591− , D.Number 0.1
592− , D.Bool True
593− , D.Null
594− ]
595−
596−sampleBuilder :: B.YamlBuilder
597−sampleBuilder = B.array
598− [ B.string "foo"
599− , B.mapping
600− [ ("bar1", B.string "bar2")
601− , ("bar3", B.string "")
602− ]
603− , B.string ""
604− , B.scientific 1
605− , B.scientific 0.1
606− , B.bool True
607− , B.null
608− ]
609−
610−caseEncodeDecodeData :: Assertion
611−caseEncodeDecodeData = D.encode sample `shouldDecode` sample
612−
613−caseEncodeDecodeDataPretty :: Assertion
614−caseEncodeDecodeDataPretty =
615− Pretty.encodePretty Pretty.defConfig sample `shouldDecode` sample
616−
617−caseEncodeDecodeDataBuilder :: Assertion
618−caseEncodeDecodeDataBuilder = do
619− let events = B.unYamlBuilder sampleBuilder []
620− bs <- testEncodeWith Y.defaultFormatOptions events
621− bs `shouldDecodeEvents` eventStream events
622−
623−caseEncodeDecodeComplexMappingBuilder :: Assertion
624−caseEncodeDecodeComplexMappingBuilder = do
625− let events = B.unYamlBuilder builder []
626− bs <- testEncodeWith Y.defaultFormatOptions events
627− bs `shouldDecodeEvents` eventStream events
628− where
629− builder :: B.YamlBuilder
630− builder = B.mappingComplex
631− [ ( B.mapping
632− [ ("foo", B.scientific 1)
633− , ("bar", B.scientific 2)
634− ]
635− , B.bool True
636− )
637− ]
638−
639−caseEncodeDecodeFileData :: Assertion
640−caseEncodeDecodeFileData = withFile "" $ \fp -> do
641− D.encodeFile fp sample
642− out <- D.decodeFileThrow fp
643− out @?= sample
644−
645−caseEncodeDecodeNonAsciiFileData :: Assertion
646−caseEncodeDecodeNonAsciiFileData = do
647− let mySample = (object ["foo" .= True])
648− inTempDirectory $ do
649− createDirectory "accenté"
650− D.encodeFile "accenté/bar.yaml" mySample
651− out1 <- D.decodeFileThrow "accenté/bar.yaml"
652− out1 @?= mySample
653−
654− c <- readFile "test/resources/accent/foo.yaml"
655− inTempDirectory $ do
656− createDirectoryIfMissing True "test/resources/unicode/accenté/"
657− writeFile "test/resources/unicode/accenté/foo.yaml" c
658− out2 <- D.decodeFileThrow "test/resources/unicode/accenté/foo.yaml"
659− out2 @?= mySample
660−
661−caseEncodeDecodeStrings :: Assertion
662−caseEncodeDecodeStrings = D.encode sample `shouldDecode` sample
663−
664−caseEncodeDecodeStringsPretty :: Assertion
665−caseEncodeDecodeStringsPretty =
666− Pretty.encodePretty Pretty.defConfig sample `shouldDecode` sample
667−
668−caseDecodeInvalid :: Assertion
669−caseDecodeInvalid =
670− D.decodeThrow "\tthis is 'not' valid :-)" `shouldBe`
671− (Nothing :: Maybe D.Value)
672−
673−caseSimpleScalarAlias :: Assertion
674−caseSimpleScalarAlias =
675− "- &anch foo\n- baz\n- *anch" `shouldDecode`
676− array [(mkScalar "foo"), (mkScalar "baz"), (mkScalar "foo")]
677−
678−caseSimpleSequenceAlias :: Assertion
679−caseSimpleSequenceAlias =
680− "seq: &anch\n - foo\n - baz\nseq2: *anch" `shouldDecode`
681− object [("seq", array [(mkScalar "foo"), (mkScalar "baz")]), ("seq2", array [(mkScalar "foo"), (mkScalar "baz")])]
682−
683−caseSimpleMappingAlias :: Assertion
684−caseSimpleMappingAlias =
685− "map: &anch\n key1: foo\n key2: baz\nmap2: *anch" `shouldDecode`
686− object [(packStr "map", object [("key1", mkScalar "foo"), ("key2", (mkScalar "baz"))]), (packStr "map2", object [("key1", (mkScalar "foo")), ("key2", mkScalar "baz")])]
687− where
688− packStr = fromText . T.pack
689−
690−caseMappingAliasBeforeAnchor :: Assertion
691−caseMappingAliasBeforeAnchor =
692− case D.decodeThrow "map: *anch\nmap2: &anch\n key1: foo\n key2: baz" of
693− Nothing -> pure ()
694− Just (_ :: D.Value) -> error "decode should return Nothing due to unknown alias"
695−
696−caseMappingAliasInsideAnchor :: Assertion
697−caseMappingAliasInsideAnchor = do
698− case D.decodeThrow "map: &anch\n key1: foo\n key2: *anch" of
699− Nothing -> pure ()
700− Just (_ :: D.Value) -> error "decode should return Nothing due to unknown alias"
701−
702−caseScalarAliasOverriding :: Assertion
703−caseScalarAliasOverriding =
704− "- &anch foo\n- baz\n- *anch\n- &anch boo\n- buz\n- *anch" `shouldDecode`
705− array [(mkScalar "foo"), (mkScalar "baz"), (mkScalar "foo"), (mkScalar "boo"), (mkScalar "buz"), (mkScalar "boo")]
706−
707−caseAllKeysShouldBeUnique :: Assertion
708−caseAllKeysShouldBeUnique = do
709− res <- D.decodeThrow "foo1: foo\nfoo2: baz\nfoo1: buz"
710− mappingKey res "foo1" `shouldBe` mkScalar "buz"
711−
712−caseSimpleMappingMerge :: Assertion
713−caseSimpleMappingMerge = do
714− res <- D.decodeThrow "foo1: foo\nfoo2: baz\n<<:\n foo1: buz\n foo3: fuz"
715− mappingKey res "foo1" `shouldBe` mkScalar "foo"
716− mappingKey res "foo3" `shouldBe` mkScalar "fuz"
717−
718−caseMergeSequence :: Assertion
719−caseMergeSequence = do
720− res <- D.decodeThrow "m1: &m1\n k1: !!str 1\n k2: !!str 2\nm2: &m2\n k1: !!str 3\n k3: !!str 4\nfoo1: foo\n<<: [ *m1, *m2 ]"
721− mappingKey res "foo1" @?= (mkScalar "foo")
722− mappingKey res "k1" @?= (D.String "1")
723− mappingKey res "k2" @?= (D.String "2")
724− mappingKey res "k3" @?= (D.String "4")
725−
726−caseDataTypes :: Assertion
727−caseDataTypes =
728− D.encode val `shouldDecode` val
729− where
730− val = object
731− [ ("string", D.String "foo")
732− , ("int", D.Number 5)
733− , ("float", D.Number 4.3)
734− , ("true", D.Bool True)
735− , ("false", D.Bool False)
736− , ("null", D.Null)
737− ]
738−
739−caseEncodeInvalidNumbers :: Assertion
740−caseEncodeInvalidNumbers =
741− D.encode (D.String ".") `shouldBe` ".\n"
742−
743−caseDataTypesPretty :: Assertion
744−caseDataTypesPretty =
745− Pretty.encodePretty Pretty.defConfig val `shouldDecode` val
746− where
747− val = object
748− [ ("string", D.String "foo")
749− , ("int", D.Number 5)
750− , ("float", D.Number 4.3)
751− , ("true", D.Bool True)
752− , ("false", D.Bool False)
753− , ("null", D.Null)
754− ]
755−caseQuotedNumber, caseUnquotedNumber, caseAttribNumber, caseIntegerDecimals :: Assertion
756−caseQuotedNumber = "foo: \"1234\"" `shouldDecode` object [("foo", D.String "1234")]
757−caseUnquotedNumber = "foo: 1234" `shouldDecode` object [("foo", D.Number 1234)]
758−caseAttribNumber = "foo: !!str 1234" `shouldDecode` object [("foo", D.String "1234")]
759−caseIntegerDecimals = "1\n" `shouldDecode` (1 :: Int)
760−
761−obj :: D.Value
762−obj = object [("foo", D.Bool False), ("bar", D.Bool True), ("baz", D.Bool True)]
763−
764−caseLowercaseBool, caseUppercaseBool, caseTitlecaseBool :: Assertion
765−caseLowercaseBool = "foo: off\nbar: y\nbaz: true" `shouldDecode` obj
766−caseUppercaseBool = "foo: FALSE\nbar: Y\nbaz: ON" `shouldDecode` obj
767−caseTitlecaseBool = "foo: No\nbar: Yes\nbaz: True" `shouldDecode` obj
768−
769−caseEmptyInput :: Assertion
770−caseEmptyInput = B8.empty `shouldDecode` D.Null
771−
772−caseEmptyInputFile :: Assertion
773−caseEmptyInputFile = do
774− out <- D.decodeFileEither "test/resources/empty.yaml"
775− either (Left . D.prettyPrintParseException) Right out @?= Right D.Null
776−
777−caseCommentOnlyInput :: Assertion
778−caseCommentOnlyInput = "# comment\n" `shouldDecode` D.Null
779−
780−caseCommentOnlyInputFile :: Assertion
781−caseCommentOnlyInputFile = do
782− out <- D.decodeFileEither "test/resources/empty2.yaml"
783− either (Left . D.prettyPrintParseException) Right out @?= Right D.Null
784−
785−checkNull :: T.Text -> Spec
786−checkNull x =
787− it ("null recognized: " ++ show x) $
788− B8.pack ("foo: " ++ T.unpack x) `shouldDecode` object [("foo", D.Null)]
789−
790−caseStripAlias :: Assertion
791−caseStripAlias =
792− src `shouldDecode` object
793− [ "Default" .= object
794− [ "foo" .= (1 :: Int)
795− , "bar" .= (2 :: Int)
796− ]
797− , "Obj" .= object
798− [ "foo" .= (1 :: Int)
799− , "bar" .= (2 :: Int)
800− , "key" .= (3 :: Int)
801− ]
802− ]
803− where
804− src = "Default: &def\n foo: 1\n bar: 2\nObj:\n <<: *def\n key: 3\n"
805−
806−caseIssue49 :: Assertion
807−caseIssue49 =
808− src `shouldDecode` object
809− [ "a" .= object [ "value" .= (1.0 :: Double) ]
810− , "b" .= object [ "value" .= (1.2 :: Double) ]
811− ]
812− where
813− src = "---\na:\n &id5 value: 1.0\nb:\n *id5: 1.2"
814−
815−-- | We cannot guarantee this before aeson started using 'Scientific'.
816−casePreservesScientificPrecision :: Assertion
817−casePreservesScientificPrecision = do
818− "x: 1e-100000" `shouldDecode` object
819− [ "x" .= D.Number (read "1e-100000") ]
820− -- Note that this ought to work also without 'Scientific', given
821− -- that @read (show "9.78159610558926e-5") == 9.78159610558926e-5@.
822− -- However, it didn't work (and still doesn't work with aeson < 0.7)
823− -- for two reasons:
824− --
825− -- - We use 'Data.Text.Read.double', which is not as accurate as it
826− -- can be;
827− -- - Even if we used 'Data.Text.Read.rational' we would not get good
828− -- results, because of <https://github.com/bos/text/issues/34>.
829− "x: 9.78159610558926e-5" `shouldDecode` object
830− [ "x" .= D.Number (read "9.78159610558926e-5") ]
831−
832−caseTruncatesFiles :: Assertion
833−caseTruncatesFiles = withSystemTempFile "truncate.yaml" $ \fp h -> do
834− replicateM_ 500 $ B8.hPut h "HELLO WORLD!!!!!\n"
835− hClose h
836− let val = object ["hello" .= ("world" :: String)]
837− D.encodeFile fp val
838− res <- D.decodeFileEither fp
839− either (Left . show) Right res `shouldBe` Right val
840−
841−caseSpecialKeys :: (KeyMap () -> B8.ByteString) -> Assertion
842−caseSpecialKeys encoder = do
843− let keys = T.words "true false NO YES 1.2 1e5 null"
844− bs = encoder $ M.fromList $ map (, ()) $ fmap fromText keys
845− text = decodeUtf8 bs
846− forM_ keys $ \key -> do
847− let quoted = T.concat ["'", key, "'"]
848− unless (quoted `T.isInfixOf` text) $ error $ concat
849− [ "Could not find quoted key: "
850− , T.unpack quoted
851− , "\n\n"
852− , T.unpack text
853− ] :: IO ()
854−
855−taggedSequence :: [Y.Event]
856−taggedSequence =
857− [ Y.EventSequenceStart (Y.UriTag "!foo") Y.FlowSequence Nothing
858− , Y.EventSequenceEnd
859− ]
860−
861−taggedMapping :: [Y.Event]
862−taggedMapping =
863− [ Y.EventMappingStart (Y.UriTag "!foo") Y.FlowMapping Nothing
864− , Y.EventMappingEnd
865− ]
866−
867−defaultTaggedSequence :: [Y.Event]
868−defaultTaggedSequence =
869− [Y.EventSequenceStart Y.SeqTag Y.FlowSequence Nothing, Y.EventSequenceEnd]
870−
871−defaultTaggedMapping :: [Y.Event]
872−defaultTaggedMapping =
873− [Y.EventMappingStart Y.MapTag Y.FlowMapping Nothing, Y.EventMappingEnd]
874−
875−untaggedSequence :: [Y.Event]
876−untaggedSequence =
877− [Y.EventSequenceStart Y.NoTag Y.FlowSequence Nothing, Y.EventSequenceEnd]
878−
879−untaggedMapping :: [Y.Event]
880−untaggedMapping =
881− [Y.EventMappingStart Y.NoTag Y.FlowMapping Nothing, Y.EventMappingEnd]
882−
883−mixedTagSampleA :: [Y.Event]
884−mixedTagSampleA =
885− [ Y.EventSequenceStart Y.NoTag Y.BlockSequence Nothing
886− , Y.EventMappingStart (Y.UriTag "!foo") Y.FlowMapping Nothing
887− , Y.EventMappingEnd
888− , Y.EventSequenceEnd
889− ]
890−
891−mixedTagSampleB :: [Y.Event]
892−mixedTagSampleB =
893− [ Y.EventMappingStart Y.NoTag Y.BlockMapping (Just "a")
894− , Y.EventScalar "foo" (Y.UriTag "bar") Y.Plain (Just "b")
895− , Y.EventSequenceStart (Y.UriTag "!baz") Y.FlowSequence (Just "c")
896− , Y.EventScalar "" Y.NullTag Y.Plain (Just "d")
897− , Y.EventSequenceEnd
898− , Y.EventMappingEnd
899− ]
yaml/test/resources/empty.yamldeleted

No changes to the content.

yaml/test/resources/empty2.yamldeleted−1
@@ -1 +0,0 @@
1−# comment
yaml/yaml.cabaldeleted−228
@@ -1,228 +0,0 @@
1−cabal-version: 1.12
2−
3−-- This file has been generated from package.yaml by hpack version 0.35.1.
4−--
5−-- see: https://github.com/sol/hpack
6−
7−name: yaml
8−version: 0.11.11.2
9−synopsis: Support for parsing and rendering YAML documents.
10−description: README and API documentation are available at <https://www.stackage.org/package/yaml>
11−category: Data
12−stability: stable
13−homepage: https://github.com/snoyberg/yaml#readme
14−bug-reports: https://github.com/snoyberg/yaml/issues
15−author: Michael Snoyman <michael@snoyman.com>, Anton Ageev <antage@gmail.com>,Kirill Simonov
16−maintainer: Michael Snoyman <michael@snoyman.com>
17−license: BSD3
18−license-file: LICENSE
19−build-type: Simple
20−extra-source-files:
21− test/largest-string.yaml
22− test/json.yaml
23− test/resources/foo.yaml
24− test/resources/bar.yaml
25− test/resources/baz.yaml
26− test/resources/accent/foo.yaml
27− test/resources/loop/foo.yaml
28− test/resources/loop/bar.yaml
29− test/resources/empty.yaml
30− test/resources/empty2.yaml
31− README.md
32− ChangeLog.md
33−
34−source-repository head
35− type: git
36− location: https://github.com/snoyberg/yaml
37−
38−flag no-examples
39− description: don't build the examples
40− manual: False
41− default: True
42−
43−flag no-exe
44− description: don't install the yaml2json or json2yaml executables
45− manual: False
46− default: True
47−
48−library
49− exposed-modules:
50− Data.Yaml
51− Data.Yaml.Aeson
52− Data.Yaml.Builder
53− Data.Yaml.Config
54− Data.Yaml.Include
55− Data.Yaml.Internal
56− Data.Yaml.Parser
57− Data.Yaml.Pretty
58− Data.Yaml.TH
59− other-modules:
60− Paths_yaml
61− hs-source-dirs:
62− src
63− other-extensions:
64− LambdaCase
65− ghc-options: -Wall -Wcompat
66− build-depends:
67− aeson >=0.11
68− , attoparsec >=0.11.3.0
69− , base >=4.9.1 && <5
70− , bytestring >=0.9.1.4
71− , conduit >=1.2.8 && <1.4
72− , containers
73− , directory
74− , filepath
75− , libyaml ==0.1.*
76− , mtl
77− , resourcet >=0.3 && <1.4
78− , scientific >=0.3
79− , template-haskell
80− , text
81− , transformers >=0.1
82− , unordered-containers
83− , vector
84− default-language: Haskell2010
85−
86−executable examples
87− main-is: Main.hs
88− other-modules:
89− Config
90− Simple
91− Paths_yaml
92− hs-source-dirs:
93− examples
94− ghc-options: -Wall -Wcompat
95− build-depends:
96− aeson >=0.11
97− , attoparsec >=0.11.3.0
98− , base >=4.9.1 && <5
99− , bytestring >=0.9.1.4
100− , conduit >=1.2.8 && <1.4
101− , containers
102− , directory
103− , filepath
104− , libyaml ==0.1.*
105− , mtl
106− , resourcet >=0.3 && <1.4
107− , scientific >=0.3
108− , template-haskell
109− , text
110− , transformers >=0.1
111− , unordered-containers
112− , vector
113− default-language: Haskell2010
114− if flag(no-examples)
115− buildable: False
116− else
117− build-depends:
118− raw-strings-qq
119− , yaml
120−
121−executable json2yaml
122− main-is: json2yaml.hs
123− other-modules:
124− Common
125− Paths_yaml
126− hs-source-dirs:
127− exe
128− ghc-options: -Wall -Wcompat
129− build-depends:
130− aeson >=0.11
131− , attoparsec >=0.11.3.0
132− , base >=4.9.1 && <5
133− , bytestring >=0.9.1.4
134− , conduit >=1.2.8 && <1.4
135− , containers
136− , directory
137− , filepath
138− , libyaml ==0.1.*
139− , mtl
140− , optparse-applicative
141− , resourcet >=0.3 && <1.4
142− , scientific >=0.3
143− , template-haskell
144− , text
145− , transformers >=0.1
146− , unordered-containers
147− , vector
148− , yaml
149− default-language: Haskell2010
150− if flag(no-exe)
151− buildable: False
152−
153−executable yaml2json
154− main-is: yaml2json.hs
155− other-modules:
156− Common
157− Paths_yaml
158− hs-source-dirs:
159− exe
160− other-extensions:
161− CPP
162− LambdaCase
163− NamedFieldPuns
164− ghc-options: -Wall -Wcompat
165− build-depends:
166− aeson >=0.11
167− , attoparsec >=0.11.3.0
168− , base >=4.9.1 && <5
169− , bytestring >=0.9.1.4
170− , conduit >=1.2.8 && <1.4
171− , containers
172− , directory
173− , filepath
174− , libyaml ==0.1.*
175− , mtl
176− , optparse-applicative
177− , resourcet >=0.3 && <1.4
178− , scientific >=0.3
179− , template-haskell
180− , text
181− , transformers >=0.1
182− , unordered-containers
183− , vector
184− , yaml
185− default-language: Haskell2010
186− if flag(no-exe)
187− buildable: False
188−
189−test-suite spec
190− type: exitcode-stdio-1.0
191− main-is: Spec.hs
192− other-modules:
193− Data.Yaml.IncludeSpec
194− Data.Yaml.THSpec
195− Data.YamlSpec
196− Paths_yaml
197− hs-source-dirs:
198− test
199− ghc-options: -Wall -Wcompat -with-rtsopts=-K1K
200− cpp-options: -DTEST
201− build-tool-depends:
202− hspec-discover:hspec-discover
203− build-depends:
204− HUnit
205− , aeson >=0.11
206− , attoparsec >=0.11.3.0
207− , base >=4.9.1 && <5
208− , base-compat
209− , bytestring >=0.9.1.4
210− , conduit >=1.2.8 && <1.4
211− , containers
212− , directory
213− , filepath
214− , hspec >=1.3
215− , libyaml ==0.1.*
216− , mockery
217− , mtl
218− , raw-strings-qq
219− , resourcet >=0.3 && <1.4
220− , scientific >=0.3
221− , template-haskell
222− , temporary
223− , text
224− , transformers >=0.1
225− , unordered-containers
226− , vector
227− , yaml
228− default-language: Haskell2010