Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 29 Nov 2014 00:45:10 +0000 (UTC)
From:      Baptiste Daroussin <bapt@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r275223 - in head: contrib/libucl contrib/libucl/cmake contrib/libucl/doc contrib/libucl/include contrib/libucl/lua contrib/libucl/m4 contrib/libucl/src contrib/libucl/tests contrib/lib...
Message-ID:  <201411290045.sAT0jAwd031798@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bapt
Date: Sat Nov 29 00:45:09 2014
New Revision: 275223
URL: https://svnweb.freebsd.org/changeset/base/275223

Log:
  Update libucl to latest version
  
  While here correctly link libucl to libm and register the dependency on libm
  for static building

Added:
  head/contrib/libucl/COPYING
     - copied unchanged from r275222, vendor/libucl/dist/COPYING
  head/contrib/libucl/doc/lua_api.md
     - copied unchanged from r275222, vendor/libucl/dist/doc/lua_api.md
  head/contrib/libucl/include/lua_ucl.h
     - copied unchanged from r275222, vendor/libucl/dist/include/lua_ucl.h
  head/contrib/libucl/lua/
     - copied from r275222, vendor/libucl/dist/lua/
  head/contrib/libucl/m4/
     - copied from r275222, vendor/libucl/dist/m4/
  head/contrib/libucl/tests/basic/12.in
     - copied unchanged from r275222, vendor/libucl/dist/tests/basic/12.in
  head/contrib/libucl/tests/basic/12.res
     - copied unchanged from r275222, vendor/libucl/dist/tests/basic/12.res
  head/contrib/libucl/tests/basic/13.in
     - copied unchanged from r275222, vendor/libucl/dist/tests/basic/13.in
  head/contrib/libucl/tests/basic/13.res
     - copied unchanged from r275222, vendor/libucl/dist/tests/basic/13.res
  head/contrib/libucl/tests/basic/comments.in
     - copied unchanged from r275222, vendor/libucl/dist/tests/basic/comments.in
  head/contrib/libucl/tests/basic/comments.res
     - copied unchanged from r275222, vendor/libucl/dist/tests/basic/comments.res
  head/contrib/libucl/tests/basic/include_dir/
     - copied from r275222, vendor/libucl/dist/tests/basic/include_dir/
Modified:
  head/contrib/libucl/ChangeLog.md
  head/contrib/libucl/Makefile.am
  head/contrib/libucl/Makefile.w32
  head/contrib/libucl/README.md
  head/contrib/libucl/cmake/CMakeLists.txt
  head/contrib/libucl/configure.ac
  head/contrib/libucl/include/ucl.h
  head/contrib/libucl/libucl.pc.in
  head/contrib/libucl/src/ucl_emitter.c
  head/contrib/libucl/src/ucl_emitter_streamline.c
  head/contrib/libucl/src/ucl_emitter_utils.c
  head/contrib/libucl/src/ucl_hash.c
  head/contrib/libucl/src/ucl_hash.h
  head/contrib/libucl/src/ucl_internal.h
  head/contrib/libucl/src/ucl_parser.c
  head/contrib/libucl/src/ucl_util.c
  head/contrib/libucl/tests/Makefile.am
  head/contrib/libucl/tests/basic/4.res
  head/contrib/libucl/tests/generate.res
  head/contrib/libucl/tests/test_basic.c
  head/contrib/libucl/tests/test_generate.c
  head/contrib/libucl/tests/test_schema.c
  head/contrib/libucl/utils/objdump.c
  head/lib/libucl/Makefile
  head/share/mk/src.libnames.mk
Directory Properties:
  head/contrib/libucl/   (props changed)

Copied: head/contrib/libucl/COPYING (from r275222, vendor/libucl/dist/COPYING)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/contrib/libucl/COPYING	Sat Nov 29 00:45:09 2014	(r275223, copy of r275222, vendor/libucl/dist/COPYING)
@@ -0,0 +1,23 @@
+Copyright (c) 2013-2014, Vsevolod Stakhov <vsevolod@highsecure.ru>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Modified: head/contrib/libucl/ChangeLog.md
==============================================================================
--- head/contrib/libucl/ChangeLog.md	Sat Nov 29 00:34:47 2014	(r275222)
+++ head/contrib/libucl/ChangeLog.md	Sat Nov 29 00:45:09 2014	(r275223)
@@ -4,3 +4,19 @@
 
 - Streamline emitter has been added, so it is now possible to output partial `ucl` objects
 - Emitter now is more flexible due to emitter_context structure
+
+### 0.5.1
+- Fixed number of bugs and memory leaks
+
+### 0.5.2
+
+- Allow userdata objects to be emitted and destructed
+- Use userdata objects to store lua function references
+
+### Libucl 0.6
+
+- Reworked macro interface
+
+### Libucl 0.6.1
+
+- Various utilities fixes

Modified: head/contrib/libucl/Makefile.am
==============================================================================
--- head/contrib/libucl/Makefile.am	Sat Nov 29 00:34:47 2014	(r275222)
+++ head/contrib/libucl/Makefile.am	Sat Nov 29 00:45:09 2014	(r275223)
@@ -4,4 +4,8 @@ EXTRA_DIST = uthash README.md
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libucl.pc
 
-SUBDIRS = src tests utils doc
+if LUA_SUB
+  LUA_SUBDIR = lua
+endif
+
+SUBDIRS = src tests utils doc $(LUA_SUBDIR)
\ No newline at end of file

Modified: head/contrib/libucl/Makefile.w32
==============================================================================
--- head/contrib/libucl/Makefile.w32	Sat Nov 29 00:34:47 2014	(r275222)
+++ head/contrib/libucl/Makefile.w32	Sat Nov 29 00:45:09 2014	(r275223)
@@ -33,6 +33,7 @@ OBJECTS = $(OBJDIR)/ucl_hash.o \
 		$(OBJDIR)/ucl_util.o \
 		$(OBJDIR)/ucl_parser.o \
 		$(OBJDIR)/ucl_emitter.o \
+		$(OBJDIR)/ucl_emitter_utils.o \
 		$(OBJDIR)/ucl_schema.o \
 		$(OBJDIR)/xxhash.o
 
@@ -51,6 +52,8 @@ $(OBJDIR)/ucl_parser.o: $(SRCDIR)/ucl_pa
 	$(CC) -o $(OBJDIR)/ucl_parser.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_parser.c
 $(OBJDIR)/ucl_emitter.o: $(SRCDIR)/ucl_emitter.c $(HDEPS)
 	$(CC) -o $(OBJDIR)/ucl_emitter.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_emitter.c
+$(OBJDIR)/ucl_emitter_utils.o: $(SRCDIR)/ucl_emitter_utils.c $(HDEPS)
+	$(CC) -o $(OBJDIR)/ucl_emitter_utils.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_emitter_utils.c
 $(OBJDIR)/ucl_hash.o: $(SRCDIR)/ucl_hash.c $(HDEPS)
 	$(CC) -o $(OBJDIR)/ucl_hash.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_hash.c
 $(OBJDIR)/ucl_schema.o: $(SRCDIR)/ucl_schema.c $(HDEPS)
@@ -61,7 +64,7 @@ $(OBJDIR)/xxhash.o: $(SRCDIR)/xxhash.c $
 clean:
 	$(RM) $(OBJDIR)/*.o $(OBJDIR)/$(SONAME) $(OBJDIR)/$(SONAME) $(OBJDIR)/chargen $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/objdump $(OBJDIR)/test_generate
 	$(RMDIR) $(OBJDIR)
-	
+
 # Utils
 
 chargen: utils/chargen.c $(OBJDIR)/$(SONAME)
@@ -75,7 +78,7 @@ test: $(OBJDIR) $(OBJDIR)/$(SONAME) $(OB
 
 run-test: test
 	TEST_DIR=$(TESTDIR) $(TESTDIR)/run_tests.sh $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/test_generate
-	
+
 $(OBJDIR)/test_basic: $(TESTDIR)/test_basic.c $(OBJDIR)/$(SONAME)
 	$(CC) -o $(OBJDIR)/test_basic $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_basic.c $(LD_UCL_FLAGS)
 $(OBJDIR)/test_speed: $(TESTDIR)/test_speed.c $(OBJDIR)/$(SONAME)

Modified: head/contrib/libucl/README.md
==============================================================================
--- head/contrib/libucl/README.md	Sat Nov 29 00:34:47 2014	(r275222)
+++ head/contrib/libucl/README.md	Sat Nov 29 00:45:09 2014	(r275223)
@@ -223,15 +223,57 @@ UCL supports external macros both multil
      ....
 };
 ```
-There are two internal macros provided by UCL:
 
-* `include` - read a file `/path/to/file` or an url `http://example.com/file` and include it to the current place of
-UCL configuration;
-* `try\_include` - try to read a file or url and include it but do not create a fatal error if a file or url is not accessible;
-* `includes` - read a file or an url like the previous macro, but fetch and check the signature file (which is obtained
-by `.sig` suffix appending).
-
-Public keys which are used for the last command are specified by the concrete UCL user.
+Moreover, each macro can accept an optional list of arguments in braces. These
+arguments themselves are the UCL object that is parsed and passed to a macro as
+options:
+
+```nginx
+.macro(param=value) "something";
+.macro(param={key=value}) "something";
+.macro(.include "params.conf") "something";
+.macro(#this is multiline macro
+param = [value1, value2]) "something";
+.macro(key="()") "something";
+```
+
+UCL also provide a convenient `include` macro to load content from another files
+to the current UCL object. This macro accepts either path to file:
+
+```nginx
+.include "/full/path.conf"
+.include "./relative/path.conf"
+.include "${CURDIR}/path.conf"
+```
+
+or URL (if ucl is built with url support provided by either `libcurl` or `libfetch`):
+
+	.include "http://example.com/file.conf"
+
+`.include` macro supports a set of options:
+
+* `try` (default: **false**) - if this option is `true` than UCL treats errors on loading of
+this file as non-fatal. For example, such a file can be absent but it won't stop the parsing
+of the top-level document.
+* `sign` (default: **false**) - if this option is `true` UCL loads and checks the signature for
+a file from path named `<FILEPATH>.sig`. Trusted public keys should be provided for UCL API after
+parser is created but before any configurations are parsed.
+* `glob` (default: **false**) - if this option is `true` UCL treats the filename as GLOB pattern and load
+all files that matches the specified pattern (normally the format of patterns is defined in `glob` manual page
+for your operating system). This option is meaningless for URL includes.
+* `url` (default: **true**) - allow URL includes.
+* `priority` (default: 0) - specify priority for the include (see below).
+
+Priorities are used by UCL parser to manage the policy of objects rewriting during including other files
+as following:
+
+* If we have two objects with the same priority then we form an implicit array
+* If a new object has bigger priority then we overwrite an old one
+* If a new object has lower priority then we ignore it
+
+By default, the priority of top-level object is set to zero (lowest priority). Currently,
+you can define up to 16 priorities (from 0 to 15). Includes with bigger priorities will
+rewrite keys from the objects with lower priorities as specified by the policy.
 
 ### Variables support
 
@@ -317,7 +359,7 @@ ucl: emitted compact json in 0.0991 seco
 ucl: emitted yaml in 0.1354 seconds
 ```
 
-You can do your own benchmarks by running `make test` in libucl top directory.
+You can do your own benchmarks by running `make check` in libucl top directory.
 
 ## Conclusion
 

Modified: head/contrib/libucl/cmake/CMakeLists.txt
==============================================================================
--- head/contrib/libucl/cmake/CMakeLists.txt	Sat Nov 29 00:34:47 2014	(r275222)
+++ head/contrib/libucl/cmake/CMakeLists.txt	Sat Nov 29 00:45:09 2014	(r275223)
@@ -1,8 +1,8 @@
 PROJECT(libucl C)
 
 SET(LIBUCL_VERSION_MAJOR 0)
-SET(LIBUCL_VERSION_MINOR 2)
-SET(LIBUCL_VERSION_PATCH 9)
+SET(LIBUCL_VERSION_MINOR 5)
+SET(LIBUCL_VERSION_PATCH 0)
 
 SET(LIBUCL_VERSION         "${LIBUCL_VERSION_MAJOR}.${LIBUCL_VERSION_MINOR}.${LIBUCL_VERSION_PATCH}")
 
@@ -86,6 +86,8 @@ INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOU
 SET(UCLSRC            ../src/ucl_util.c
                       ../src/ucl_parser.c
                       ../src/ucl_emitter.c
+                      ../src/ucl_emitter_streamline.c
+                      ../src/ucl_emitter_utils.c
                       ../src/ucl_hash.c
                       ../src/ucl_schema.c
                       ../src/xxhash.c)
@@ -98,6 +100,18 @@ ENDIF (BUILD_SHARED_LIBS)
 ADD_LIBRARY(ucl ${LIB_TYPE} ${UCLSRC})
 SET_TARGET_PROPERTIES(ucl PROPERTIES VERSION ${LIBUCL_VERSION} SOVERSION ${LIBUCL_VERSION_MAJOR})
 
+IF(WITH_LUA)
+	SET(UCL_LUA_SRC ../lua/lua_ucl.c)
+	ADD_LIBRARY(lua-ucl ${LIB_TYPE} ${UCL_LUA_SRC})
+	IF(ENABLE_LUAJIT MATCHES "ON")
+		TARGET_LINK_LIBRARIES(lua-ucl "${LUAJIT_LIBRARY}")
+	ELSE(ENABLE_LUAJIT MATCHES "ON")
+		TARGET_LINK_LIBRARIES(lua-ucl "${LUA_LIBRARY}")
+	ENDIF(ENABLE_LUAJIT MATCHES "ON")
+	TARGET_LINK_LIBRARIES(lua-ucl ucl)
+	SET_TARGET_PROPERTIES(lua-ucl PROPERTIES VERSION ${LIBUCL_VERSION} SOVERSION ${LIBUCL_VERSION_MAJOR})
+ENDIF(WITH_LUA)
+
 IF(HAVE_FETCH_H)
     TARGET_LINK_LIBRARIES(ucl fetch)
 ELSE(HAVE_FETCH_H)

Modified: head/contrib/libucl/configure.ac
==============================================================================
--- head/contrib/libucl/configure.ac	Sat Nov 29 00:34:47 2014	(r275222)
+++ head/contrib/libucl/configure.ac	Sat Nov 29 00:45:09 2014	(r275223)
@@ -1,12 +1,13 @@
 m4_define([maj_ver], [0])
-m4_define([med_ver], [5])
-m4_define([min_ver], [0])
-m4_define([so_version], [2:0:0])
+m4_define([med_ver], [6])
+m4_define([min_ver], [1])
+m4_define([so_version], [3:0:1])
 m4_define([ucl_version], [maj_ver.med_ver.min_ver])
 
 AC_INIT([libucl],[ucl_version],[https://github.com/vstakhov/libucl],[libucl])
 AC_CONFIG_SRCDIR([configure.ac])
-AM_INIT_AUTOMAKE([1.11 foreign silent-rules -Wall -Wportability no-dist-gzip dist-xz])
+AM_INIT_AUTOMAKE([1.11 foreign -Wall -Wportability no-dist-gzip dist-xz])
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
 
 UCL_VERSION=ucl_version
 SO_VERSION=so_version
@@ -57,6 +58,9 @@ AC_ARG_ENABLE([regex], AS_HELP_STRING([-
 AC_ARG_ENABLE([signatures], AS_HELP_STRING([--enable-signatures],
 	[Enable signatures check (requires openssl) @<:@default=no@:>@]), [],
 	[enable_signatures=no])
+AC_ARG_ENABLE([lua], AS_HELP_STRING([--enable-lua],
+	[Enable lua API build (requires lua libraries and headers) @<:@default=no@:>@]), [],
+	[enable_lua=no])
 AC_ARG_ENABLE([utils],
 	AS_HELP_STRING([--enable-utils], [Build and install utils @<:@default=no@:>@]),
 	[case "${enableval}" in
@@ -99,6 +103,21 @@ AS_IF([test "x$enable_regex" = "xyes"], 
 ])
 AC_SUBST(LIBREGEX_LIB)
 
+AS_IF([test "x$enable_lua" = "xyes"], [
+	AX_PROG_LUA([5.1], [], [
+		AX_LUA_HEADERS([
+			AX_LUA_LIBS([
+				AC_DEFINE(HAVE_LUA, 1, [Define to 1 for lua support.])
+				with_lua="yes"
+			], [AC_MSG_ERROR([unable to find the lua libraries])
+			])
+		], [AC_MSG_ERROR([unable to find the lua header files])
+		])
+	], [AC_MSG_ERROR([unable to find the lua interpreter])])
+], [with_lua="no"])
+
+AM_CONDITIONAL([LUA_SUB], [test "$with_lua" = "yes"])
+
 AS_IF([test "x$enable_urls" = "xyes"], [
 	AC_CHECK_HEADER([fetch.h], [
 		AC_DEFINE(HAVE_FETCH_H, 1, [Define to 1 if you have the <fetch.h> header file.])
@@ -155,9 +174,11 @@ AC_LINK_IFELSE([
 
 AC_CONFIG_FILES(Makefile \
 	src/Makefile \
+	lua/Makefile
 	tests/Makefile \
 	utils/Makefile \
 	doc/Makefile \
+	lua/libucl.rockspec \
 	libucl.pc)
 AC_CONFIG_FILES([stamp-h], [echo timestamp > stamp-h])
 AC_OUTPUT

Copied: head/contrib/libucl/doc/lua_api.md (from r275222, vendor/libucl/dist/doc/lua_api.md)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/contrib/libucl/doc/lua_api.md	Sat Nov 29 00:45:09 2014	(r275223, copy of r275222, vendor/libucl/dist/doc/lua_api.md)
@@ -0,0 +1,194 @@
+## Module `ucl`
+
+This lua module allows to parse objects from strings and to store data into
+ucl objects. It uses `libucl` C library to parse and manipulate with ucl objects.
+
+Example:
+
+~~~lua
+local ucl = require("ucl")
+
+local parser = ucl.parser()
+local res,err = parser:parse_string('{key=value}')
+
+if not res then
+	print('parser error: ' .. err)
+else
+	local obj = parser:get_object()
+	local got = ucl.to_format(obj, 'json')
+endif
+
+local table = {
+  str = 'value',
+  num = 100500,
+  null = ucl.null,
+  func = function ()
+    return 'huh'
+  end
+
+
+print(ucl.to_format(table, 'ucl'))
+-- Output:
+--[[
+num = 100500;
+str = "value";
+null = null;
+func = "huh";
+--]]
+~~~
+
+###Brief content:
+
+**Functions**:
+
+> [`ucl_object_push_lua(L, obj, allow_array)`](#function-ucl_object_push_lual-obj-allow_array)
+
+> [`ucl.to_format(var, format)`](#function-uclto_formatvar-format)
+
+
+
+**Methods**:
+
+> [`parser:parse_file(name)`](#method-parserparse_filename)
+
+> [`parser:parse_string(input)`](#method-parserparse_stringinput)
+
+> [`parser:get_object()`](#method-parserget_object)
+
+
+## Functions
+
+The module `ucl` defines the following functions.
+
+### Function `ucl_object_push_lua(L, obj, allow_array)`
+
+This is a `C` function to push `UCL` object as lua variable. This function
+converts `obj` to lua representation using the following conversions:
+
+- *scalar* values are directly presented by lua objects
+- *userdata* values are converted to lua function objects using `LUA_REGISTRYINDEX`,
+this can be used to pass functions from lua to c and vice-versa
+- *arrays* are converted to lua tables with numeric indicies suitable for `ipairs` iterations
+- *objects* are converted to lua tables with string indicies
+
+**Parameters:**
+
+- `L {lua_State}`: lua state pointer
+- `obj {ucl_object_t}`: object to push
+- `allow_array {bool}`: expand implicit arrays (should be true for all but partial arrays)
+
+**Returns:**
+
+- `{int}`: `1` if an object is pushed to lua
+
+Back to [module description](#module-ucl).
+
+### Function `ucl.to_format(var, format)`
+
+Converts lua variable `var` to the specified `format`. Formats supported are:
+
+- `json` - fine printed json
+- `json-compact` - compacted json
+- `config` - fine printed configuration
+- `ucl` - same as `config`
+- `yaml` - embedded yaml
+
+If `var` contains function, they are called during output formatting and if
+they return string value, then this value is used for ouptut.
+
+**Parameters:**
+
+- `var {variant}`: any sort of lua variable (if userdata then metafield `__to_ucl` is searched for output)
+- `format {string}`: any available format
+
+**Returns:**
+
+- `{string}`: string representation of `var` in the specific `format`.
+
+Example:
+
+~~~lua
+local table = {
+  str = 'value',
+  num = 100500,
+  null = ucl.null,
+  func = function ()
+    return 'huh'
+  end
+
+
+print(ucl.to_format(table, 'ucl'))
+-- Output:
+--[[
+num = 100500;
+str = "value";
+null = null;
+func = "huh";
+--]]
+~~~
+
+Back to [module description](#module-ucl).
+
+
+## Methods
+
+The module `ucl` defines the following methods.
+
+### Method `parser:parse_file(name)`
+
+Parse UCL object from file.
+
+**Parameters:**
+
+- `name {string}`: filename to parse
+
+**Returns:**
+
+- `{bool[, string]}`: if res is `true` then file has been parsed successfully, otherwise an error string is also returned
+
+Example:
+
+~~~lua
+local parser = ucl.parser()
+local res,err = parser:parse_file('/some/file.conf')
+
+if not res then
+	print('parser error: ' .. err)
+else
+	-- Do something with object
+end
+~~~
+
+Back to [module description](#module-ucl).
+
+### Method `parser:parse_string(input)`
+
+Parse UCL object from file.
+
+**Parameters:**
+
+- `input {string}`: string to parse
+
+**Returns:**
+
+- `{bool[, string]}`: if res is `true` then file has been parsed successfully, otherwise an error string is also returned
+
+Back to [module description](#module-ucl).
+
+### Method `parser:get_object()`
+
+Get top object from parser and export it to lua representation.
+
+**Parameters:**
+
+	nothing
+
+**Returns:**
+
+- `{variant or nil}`: ucl object as lua native variable
+
+Back to [module description](#module-ucl).
+
+
+Back to [top](#).
+

Copied: head/contrib/libucl/include/lua_ucl.h (from r275222, vendor/libucl/dist/include/lua_ucl.h)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/contrib/libucl/include/lua_ucl.h	Sat Nov 29 00:45:09 2014	(r275223, copy of r275222, vendor/libucl/dist/include/lua_ucl.h)
@@ -0,0 +1,69 @@
+/* Copyright (c) 2014, Vsevolod Stakhov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *       * Redistributions of source code must retain the above copyright
+ *         notice, this list of conditions and the following disclaimer.
+ *       * Redistributions in binary form must reproduce the above copyright
+ *         notice, this list of conditions and the following disclaimer in the
+ *         documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef LUA_UCL_H_
+#define LUA_UCL_H_
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+#include "ucl.h"
+
+/**
+ * Closure structure for lua function storing inside UCL
+ */
+struct ucl_lua_funcdata {
+	lua_State *L;
+	int idx;
+	char *ret;
+};
+
+/**
+ * Initialize lua UCL API
+ */
+UCL_EXTERN int luaopen_ucl (lua_State *L);
+
+/**
+ * Import UCL object from lua state
+ * @param L lua state
+ * @param idx index of object at the lua stack to convert to UCL
+ * @return new UCL object or NULL, the caller should unref object after using
+ */
+UCL_EXTERN ucl_object_t* ucl_object_lua_import (lua_State *L, int idx);
+
+/**
+ * Push an object to lua
+ * @param L lua state
+ * @param obj object to push
+ * @param allow_array traverse over implicit arrays
+ */
+UCL_EXTERN int ucl_object_push_lua (lua_State *L,
+		const ucl_object_t *obj, bool allow_array);
+
+UCL_EXTERN struct ucl_lua_funcdata* ucl_object_toclosure (
+		const ucl_object_t *obj);
+
+#endif /* LUA_UCL_H_ */

Modified: head/contrib/libucl/include/ucl.h
==============================================================================
--- head/contrib/libucl/include/ucl.h	Sat Nov 29 00:34:47 2014	(r275222)
+++ head/contrib/libucl/include/ucl.h	Sat Nov 29 00:45:09 2014	(r275223)
@@ -147,7 +147,8 @@ typedef enum ucl_emitter {
 typedef enum ucl_parser_flags {
 	UCL_PARSER_KEY_LOWERCASE = 0x1, /**< Convert all keys to lower case */
 	UCL_PARSER_ZEROCOPY = 0x2, /**< Parse input in zero-copy mode if possible */
-	UCL_PARSER_NO_TIME = 0x4 /**< Do not parse time and treat time values as strings */
+	UCL_PARSER_NO_TIME = 0x4, /**< Do not parse time and treat time values as strings */
+	UCL_PARSER_NO_IMPLICIT_ARRAYS = 0x8 /** Create explicit arrays instead of implicit ones */
 } ucl_parser_flags_t;
 
 /**
@@ -171,9 +172,12 @@ typedef enum ucl_string_flags {
  * Basic flags for an object
  */
 typedef enum ucl_object_flags {
-	UCL_OBJECT_ALLOCATED_KEY = 1, /**< An object has key allocated internally */
-	UCL_OBJECT_ALLOCATED_VALUE = 2, /**< An object has a string value allocated internally */
-	UCL_OBJECT_NEED_KEY_ESCAPE = 4 /**< The key of an object need to be escaped on output */
+	UCL_OBJECT_ALLOCATED_KEY = 0x1, /**< An object has key allocated internally */
+	UCL_OBJECT_ALLOCATED_VALUE = 0x2, /**< An object has a string value allocated internally */
+	UCL_OBJECT_NEED_KEY_ESCAPE = 0x4, /**< The key of an object need to be escaped on output */
+	UCL_OBJECT_EPHEMERAL = 0x8, /**< Temporary object that does not need to be freed really */
+	UCL_OBJECT_MULTILINE = 0x10, /**< String should be displayed as multiline string */
+	UCL_OBJECT_MULTIVALUE = 0x20 /**< Object is a key with multiple values */
 } ucl_object_flags_t;
 
 /**
@@ -195,14 +199,21 @@ typedef struct ucl_object_s {
 	const char *key;						/**< Key of an object		*/
 	struct ucl_object_s *next;				/**< Array handle			*/
 	struct ucl_object_s *prev;				/**< Array handle			*/
-	unsigned char* trash_stack[2];			/**< Pointer to allocated chunks */
-	unsigned keylen;						/**< Lenght of a key		*/
-	unsigned len;							/**< Size of an object		*/
-	enum ucl_type type;						/**< Real type				*/
-	uint16_t ref;							/**< Reference count		*/
+	uint32_t keylen;						/**< Lenght of a key		*/
+	uint32_t len;							/**< Size of an object		*/
+	uint32_t ref;							/**< Reference count		*/
 	uint16_t flags;							/**< Object flags			*/
+	uint16_t type;							/**< Real type				*/
+	unsigned char* trash_stack[2];			/**< Pointer to allocated chunks */
 } ucl_object_t;
 
+/**
+ * Destructor type for userdata objects
+ * @param ud user specified data pointer
+ */
+typedef void (*ucl_userdata_dtor)(void *ud);
+typedef const char* (*ucl_userdata_emitter)(void *ud);
+
 /** @} */
 
 /**
@@ -239,6 +250,31 @@ UCL_EXTERN ucl_object_t* ucl_object_new 
 UCL_EXTERN ucl_object_t* ucl_object_typed_new (ucl_type_t type) UCL_WARN_UNUSED_RESULT;
 
 /**
+ * Create new object with type and priority specified
+ * @param type type of a new object
+ * @param priority priority of an object
+ * @return new object
+ */
+UCL_EXTERN ucl_object_t* ucl_object_new_full (ucl_type_t type, unsigned priority)
+	UCL_WARN_UNUSED_RESULT;
+
+/**
+ * Create new object with userdata dtor
+ * @param dtor destructor function
+ * @return new object
+ */
+UCL_EXTERN ucl_object_t* ucl_object_new_userdata (ucl_userdata_dtor dtor,
+		ucl_userdata_emitter emitter) UCL_WARN_UNUSED_RESULT;
+
+/**
+ * Perform deep copy of an object copying everything
+ * @param other object to copy
+ * @return new object with refcount equal to 1
+ */
+UCL_EXTERN ucl_object_t * ucl_object_copy (const ucl_object_t *other)
+	UCL_WARN_UNUSED_RESULT;
+
+/**
  * Return the type of an object
  * @return the object type
  */
@@ -293,7 +329,7 @@ UCL_EXTERN ucl_object_t* ucl_object_from
 
 /**
  * Insert a object 'elt' to the hash 'top' and associate it with key 'key'
- * @param top destination object (will be created automatically if top is NULL)
+ * @param top destination object (must be of type UCL_OBJECT)
  * @param elt element to insert (must NOT be NULL)
  * @param key key to associate with this object (either const or preallocated)
  * @param keylen length of the key (or 0 for NULL terminated keys)
@@ -306,7 +342,7 @@ UCL_EXTERN bool ucl_object_insert_key (u
 /**
  * Replace a object 'elt' to the hash 'top' and associate it with key 'key', old object will be unrefed,
  * if no object has been found this function works like ucl_object_insert_key()
- * @param top destination object (will be created automatically if top is NULL)
+ * @param top destination object (must be of type UCL_OBJECT)
  * @param elt element to insert (must NOT be NULL)
  * @param key key to associate with this object (either const or preallocated)
  * @param keylen length of the key (or 0 for NULL terminated keys)
@@ -317,6 +353,15 @@ UCL_EXTERN bool ucl_object_replace_key (
 		const char *key, size_t keylen, bool copy_key);
 
 /**
+ * Merge the keys from one object to another object. Overwrite on conflict
+ * @param top destination object (must be of type UCL_OBJECT)
+ * @param elt element to insert (must be of type UCL_OBJECT)
+ * @param copy copy rather than reference the elements
+ * @return true if all keys have been merged
+ */
+UCL_EXTERN bool ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy);
+
+/**
  * Delete a object associated with key 'key', old object will be unrefered,
  * @param top object
  * @param key key associated to the object to remove
@@ -335,8 +380,9 @@ UCL_EXTERN bool ucl_object_delete_key (u
 
 
 /**
- * Delete key from `top` object returning the object deleted. This object is not
- * released
+ * Removes `key` from `top` object, returning the object that was removed. This
+ * object is not released, caller must unref the returned object when it is no
+ * longer needed.
  * @param top object
  * @param key key to remove
  * @param keylen length of the key (or 0 for NULL terminated keys)
@@ -346,8 +392,9 @@ UCL_EXTERN ucl_object_t* ucl_object_pop_
 		size_t keylen) UCL_WARN_UNUSED_RESULT;
 
 /**
- * Delete key from `top` object returning the object deleted. This object is not
- * released
+ * Removes `key` from `top` object returning the object that was removed. This
+ * object is not released, caller must unref the returned object when it is no
+ * longer needed.
  * @param top object
  * @param key key to remove
  * @return removed object or NULL if object has not been found
@@ -356,9 +403,9 @@ UCL_EXTERN ucl_object_t* ucl_object_pop_
 	UCL_WARN_UNUSED_RESULT;
 
 /**
- * Insert a object 'elt' to the hash 'top' and associate it with key 'key', if the specified key exist,
- * try to merge its content
- * @param top destination object (will be created automatically if top is NULL)
+ * Insert a object 'elt' to the hash 'top' and associate it with key 'key', if
+ * the specified key exist, try to merge its content
+ * @param top destination object (must be of type UCL_OBJECT)
  * @param elt element to insert (must NOT be NULL)
  * @param key key to associate with this object (either const or preallocated)
  * @param keylen length of the key (or 0 for NULL terminated keys)
@@ -369,8 +416,8 @@ UCL_EXTERN bool ucl_object_insert_key_me
 		const char *key, size_t keylen, bool copy_key);
 
 /**
- * Append an element to the front of array object
- * @param top destination object (will be created automatically if top is NULL)
+ * Append an element to the end of array object
+ * @param top destination object (must NOT be NULL)
  * @param elt element to append (must NOT be NULL)
  * @return true if value has been inserted
  */
@@ -379,7 +426,7 @@ UCL_EXTERN bool ucl_array_append (ucl_ob
 
 /**
  * Append an element to the start of array object
- * @param top destination object (will be created automatically if top is NULL)
+ * @param top destination object (must NOT be NULL)
  * @param elt element to append (must NOT be NULL)
  * @return true if value has been inserted
  */
@@ -387,8 +434,19 @@ UCL_EXTERN bool ucl_array_prepend (ucl_o
 		ucl_object_t *elt);
 
 /**
- * Removes an element `elt` from the array `top`. Caller must unref the returned object when it is not
- * needed.
+ * Merge all elements of second array into the first array
+ * @param top destination array (must be of type UCL_ARRAY)
+ * @param elt array to copy elements from (must be of type UCL_ARRAY)
+ * @param copy copy elements instead of referencing them
+ * @return true if arrays were merged
+ */
+UCL_EXTERN bool ucl_array_merge (ucl_object_t *top, ucl_object_t *elt,
+		bool copy);
+
+/**
+ * Removes an element `elt` from the array `top`, returning the object that was
+ * removed. This object is not released, caller must unref the returned object
+ * when it is no longer needed.
  * @param top array ucl object
  * @param elt element to remove
  * @return removed element or NULL if `top` is NULL or not an array
@@ -411,35 +469,50 @@ UCL_EXTERN const ucl_object_t* ucl_array
 UCL_EXTERN const ucl_object_t* ucl_array_tail (const ucl_object_t *top);
 
 /**
- * Removes the last element from the array `top`. Caller must unref the returned object when it is not
- * needed.
+ * Removes the last element from the array `top`, returning the object that was
+ * removed. This object is not released, caller must unref the returned object
+ * when it is no longer needed.
  * @param top array ucl object
  * @return removed element or NULL if `top` is NULL or not an array
  */
 UCL_EXTERN ucl_object_t* ucl_array_pop_last (ucl_object_t *top);
 
 /**
- * Return object identified by an index of the array `top`
- * @param obj object to get a key from (must be of type UCL_ARRAY)
- * @param index index to return
+ * Removes the first element from the array `top`, returning the object that was
+ * removed. This object is not released, caller must unref the returned object
+ * when it is no longer needed.
+ * @param top array ucl object
+ * @return removed element or NULL if `top` is NULL or not an array
+ */
+UCL_EXTERN ucl_object_t* ucl_array_pop_first (ucl_object_t *top);
+
+/**
+ * Return object identified by index of the array `top`
+ * @param top object to get a key from (must be of type UCL_ARRAY)
+ * @param index array index to return
  * @return object at the specified index or NULL if index is not found
  */
 UCL_EXTERN const ucl_object_t* ucl_array_find_index (const ucl_object_t *top,
 		unsigned int index);
 
 /**
- * Removes the first element from the array `top`. Caller must unref the returned object when it is not
- * needed.
- * @param top array ucl object
- * @return removed element or NULL if `top` is NULL or not an array
+ * Replace an element in an array with a different element, returning the object
+ * that was replaced. This object is not released, caller must unref the
+ * returned object when it is no longer needed.
+ * @param top destination object (must be of type UCL_ARRAY)
+ * @param elt element to append (must NOT be NULL)
+ * @param index array index in destination to overwrite with elt
+ * @return object that was replaced or NULL if index is not found
  */
-UCL_EXTERN ucl_object_t* ucl_array_pop_first (ucl_object_t *top);
+ucl_object_t *
+ucl_array_replace_index (ucl_object_t *top, ucl_object_t *elt,
+	unsigned int index);
 
 /**
  * Append a element to another element forming an implicit array
  * @param head head to append (may be NULL)
  * @param elt new element
- * @return true if element has been inserted
+ * @return the new implicit array
  */
 UCL_EXTERN ucl_object_t * ucl_elt_append (ucl_object_t *head,
 		ucl_object_t *elt);
@@ -533,7 +606,7 @@ UCL_EXTERN const char* ucl_object_tolstr
  * Return object identified by a key in the specified object
  * @param obj object to get a key from (must be of type UCL_OBJECT)
  * @param key key to search
- * @return object matched the specified key or NULL if key is not found
+ * @return object matching the specified key or NULL if key was not found
  */
 UCL_EXTERN const ucl_object_t* ucl_object_find_key (const ucl_object_t *obj,
 		const char *key);
@@ -543,7 +616,7 @@ UCL_EXTERN const ucl_object_t* ucl_objec
  * @param obj object to get a key from (must be of type UCL_OBJECT)
  * @param key key to search
  * @param klen length of a key
- * @return object matched the specified key or NULL if key is not found
+ * @return object matching the specified key or NULL if key was not found
  */
 UCL_EXTERN const ucl_object_t* ucl_object_find_keyl (const ucl_object_t *obj,
 		const char *key, size_t klen);
@@ -575,6 +648,7 @@ UCL_EXTERN const char* ucl_object_keyl (
 /**
  * Increase reference count for an object
  * @param obj object to ref
+ * @return the referenced object
  */
 UCL_EXTERN ucl_object_t* ucl_object_ref (const ucl_object_t *obj);
 
@@ -612,6 +686,21 @@ UCL_EXTERN void ucl_object_array_sort (u
 		int (*cmp)(const ucl_object_t *o1, const ucl_object_t *o2));
 
 /**
+ * Get the priority for specific UCL object
+ * @param obj any ucl object
+ * @return priority of an object
+ */
+UCL_EXTERN unsigned int ucl_object_get_priority (const ucl_object_t *obj);
+
+/**
+ * Set explicit priority of an object.
+ * @param obj any ucl object
+ * @param priority new priroity value (only 4 least significant bits are considred)
+ */
+UCL_EXTERN void ucl_object_set_priority (ucl_object_t *obj,
+		unsigned int priority);
+
+/**
  * Opaque iterator object
  */
 typedef void* ucl_object_iter_t;
@@ -640,11 +729,14 @@ UCL_EXTERN const ucl_object_t* ucl_itera
  * Macro handler for a parser
  * @param data the content of macro
  * @param len the length of content
+ * @param arguments arguments object
  * @param ud opaque user data
  * @param err error pointer
  * @return true if macro has been parsed
  */
-typedef bool (*ucl_macro_handler) (const unsigned char *data, size_t len, void* ud);
+typedef bool (*ucl_macro_handler) (const unsigned char *data, size_t len,
+		const ucl_object_t *arguments,
+		void* ud);
 
 /* Opaque parser */
 struct ucl_parser;
@@ -702,13 +794,24 @@ UCL_EXTERN void ucl_parser_set_variables
  * @param parser parser structure
  * @param data the pointer to the beginning of a chunk
  * @param len the length of a chunk
- * @param err if *err is NULL it is set to parser error
  * @return true if chunk has been added and false in case of error
  */
 UCL_EXTERN bool ucl_parser_add_chunk (struct ucl_parser *parser,
 		const unsigned char *data, size_t len);
 
 /**
+ * Load new chunk to a parser with the specified priority
+ * @param parser parser structure
+ * @param data the pointer to the beginning of a chunk
+ * @param len the length of a chunk
+ * @param priority the desired priority of a chunk (only 4 least significant bits
+ * are considered for this parameter)
+ * @return true if chunk has been added and false in case of error
+ */
+UCL_EXTERN bool ucl_parser_add_chunk_priority (struct ucl_parser *parser,
+		const unsigned char *data, size_t len, unsigned priority);
+
+/**
  * Load ucl object from a string
  * @param parser parser structure
  * @param data the pointer to the string
@@ -835,7 +938,7 @@ struct ucl_emitter_context {
 	/** A set of output operations */
 	const struct ucl_emitter_operations *ops;
 	/** Current amount of indent tabs */
-	unsigned int ident;
+	unsigned int indent;
 	/** Top level object */
 	const ucl_object_t *top;
 	/** The rest of context */

Modified: head/contrib/libucl/libucl.pc.in
==============================================================================
--- head/contrib/libucl/libucl.pc.in	Sat Nov 29 00:34:47 2014	(r275222)
+++ head/contrib/libucl/libucl.pc.in	Sat Nov 29 00:45:09 2014	(r275223)
@@ -7,5 +7,5 @@ Name: LibUCL
 Description: Universal configuration library
 Version: @UCL_VERSION@
 Libs: -L${libdir} -lucl
-Libs.private: @LIBS_EXTRA@
+Libs.private: @LIBS_EXTRA@ @LUA_LIB@
 Cflags: -I${includedir}/

Modified: head/contrib/libucl/src/ucl_emitter.c
==============================================================================
--- head/contrib/libucl/src/ucl_emitter.c	Sat Nov 29 00:34:47 2014	(r275222)
+++ head/contrib/libucl/src/ucl_emitter.c	Sat Nov 29 00:45:09 2014	(r275223)
@@ -130,6 +130,19 @@ ucl_emitter_print_key (bool print_key, s
 			func->ucl_emitter_append_character (' ', 1, func->ud);
 		}
 	}
+	else if (ctx->id == UCL_EMIT_YAML) {
+		if (obj->keylen > 0 && (obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE)) {
+			ucl_elt_string_write_json (obj->key, obj->keylen, ctx);
+		}
+		else if (obj->keylen > 0) {
+			func->ucl_emitter_append_len (obj->key, obj->keylen, func->ud);
+		}
+		else {
+			func->ucl_emitter_append_len ("null", 4, func->ud);
+		}
+
+		func->ucl_emitter_append_len (": ", 2, func->ud);
+	}
 	else {
 		if (obj->keylen > 0) {
 			ucl_elt_string_write_json (obj->key, obj->keylen, ctx);
@@ -182,7 +195,7 @@ ucl_emitter_common_end_object (struct uc
 	const struct ucl_emitter_functions *func = ctx->func;
 
 	if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) {
-		ctx->ident --;
+		ctx->indent --;
 		if (compact) {
 			func->ucl_emitter_append_character ('}', 1, func->ud);
 		}
@@ -191,7 +204,7 @@ ucl_emitter_common_end_object (struct uc
 				/* newline is already added for this format */
 				func->ucl_emitter_append_character ('\n', 1, func->ud);
 			}
-			ucl_add_tabs (func, ctx->ident, compact);
+			ucl_add_tabs (func, ctx->indent, compact);
 			func->ucl_emitter_append_character ('}', 1, func->ud);
 		}
 	}
@@ -210,7 +223,7 @@ ucl_emitter_common_end_array (struct ucl
 {
 	const struct ucl_emitter_functions *func = ctx->func;
 
-	ctx->ident --;
+	ctx->indent --;
 	if (compact) {
 		func->ucl_emitter_append_character (']', 1, func->ud);
 	}
@@ -219,7 +232,7 @@ ucl_emitter_common_end_array (struct ucl
 			/* newline is already added for this format */
 			func->ucl_emitter_append_character ('\n', 1, func->ud);
 		}
-		ucl_add_tabs (func, ctx->ident, compact);
+		ucl_add_tabs (func, ctx->indent, compact);
 		func->ucl_emitter_append_character (']', 1, func->ud);
 	}
 
@@ -249,7 +262,7 @@ ucl_emitter_common_start_array (struct u
 		func->ucl_emitter_append_len ("[\n", 2, func->ud);
 	}
 
-	ctx->ident ++;
+	ctx->indent ++;
 
 	if (obj->type == UCL_ARRAY) {
 		/* explicit array */
@@ -294,7 +307,7 @@ ucl_emitter_common_start_object (struct 
 		else {
 			func->ucl_emitter_append_len ("{\n", 2, func->ud);
 		}
-		ctx->ident ++;
+		ctx->indent ++;
 	}
 
 	while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
@@ -315,7 +328,7 @@ ucl_emitter_common_start_object (struct 
 						func->ucl_emitter_append_len (",\n", 2, func->ud);
 					}
 				}
-				ucl_add_tabs (func, ctx->ident, compact);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201411290045.sAT0jAwd031798>