浏览代码

- Added `libconfig` (configuration file library: http://www.hyperrealm.com/libconfig/):
- Updated VS9/10 project files.
- Updated `configure` & `Makefile`s.
- New GM, Commands & Permissions system:
- '''This is a backwards compatibility breaking update''', please read tid:58877
- Replaced GM levels with Player Groups.
- Commands permissions & other privileges now depend on group, not GM level.
- `@help` command improvements: requires "commandname" param and shows more detailed info about commands.
- Modified GM whisper system to deliver messages basing on permissions, not GM level.
- Remote trade request is now possible only if player is allowed to use `@trade` command as well.
- Added a proper permission to use `/changemaptype` command.
- `clif_displaymessage` is now capable of displaying multiline messages.
- All `ACMD_FUNC`s are static now, and the only way to invoke them is with `is_atcommand()`; all client commands (starting with `/`) are now translated into corresponding atcommands (with exception of `/kick` used on monster, as there is no atcommand to kill single monster).
- Removed nonsense "bot check" triggering when player blocked (`/ex`) Server.
- Merged `@monster`, `@monsterbig` and `@monstersmall`.
- Improved flow of atcommand execution to avoid revealing info about online players or existing commands to non-privileged players.
- Merged `atcommand` and `charcommand` script functions (`charcommand` is aliased to `atcommand`).
- Fixed `atcommand` script function reading unknown memory area (possible access violation).

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@15572 54d463be-8e91-2dee-dedb-b68131a5f0ec

gepard1984 13 年之前
父节点
当前提交
22f0714c07
共有 79 个文件被更改,包括 10747 次插入2334 次删除
  1. 674 0
      3rdparty/libconfig/LICENSE
  2. 24 0
      3rdparty/libconfig/Makefile.in
  3. 2001 0
      3rdparty/libconfig/grammar.c
  4. 113 0
      3rdparty/libconfig/grammar.h
  5. 0 0
      3rdparty/libconfig/libconfig-1.4.8
  6. 1615 0
      3rdparty/libconfig/libconfig.c
  7. 320 0
      3rdparty/libconfig/libconfig.h
  8. 47 0
      3rdparty/libconfig/parsectx.h
  9. 170 0
      3rdparty/libconfig/scanctx.c
  10. 61 0
      3rdparty/libconfig/scanctx.h
  11. 2362 0
      3rdparty/libconfig/scanner.c
  12. 326 0
      3rdparty/libconfig/scanner.h
  13. 57 0
      3rdparty/libconfig/strbuf.c
  14. 39 0
      3rdparty/libconfig/strbuf.h
  15. 89 0
      3rdparty/libconfig/wincompat.h
  16. 9 4
      Makefile.in
  17. 60 753
      conf/atcommand_athena.conf
  18. 0 87
      conf/battle/gm.conf
  19. 4 2
      conf/char_athena.conf
  20. 274 0
      conf/groups.conf
  21. 230 172
      conf/help.txt
  22. 0 94
      conf/help2.txt
  23. 4 2
      conf/log_athena.conf
  24. 4 3
      conf/login_athena.conf
  25. 1 11
      conf/msg_athena.conf
  26. 286 2
      configure
  27. 5 1
      configure.in
  28. 213 0
      doc/atcommands.txt
  29. 21 0
      doc/permissions.txt
  30. 3 0
      sql-files/upgrade_svn15572.sql
  31. 15 5
      src/char/Makefile.in
  32. 10 12
      src/char/char.c
  33. 21 9
      src/common/Makefile.in
  34. 109 0
      src/common/conf.c
  35. 13 0
      src/common/conf.h
  36. 16 0
      src/common/showmsg.c
  37. 3 0
      src/common/showmsg.h
  38. 16 5
      src/login/Makefile.in
  39. 1 1
      src/login/account.h
  40. 6 6
      src/login/account_sql.c
  41. 10 14
      src/login/login.c
  42. 2 2
      src/login/login.h
  43. 17 7
      src/map/Makefile.in
  44. 174 408
      src/map/atcommand.c
  45. 9 21
      src/map/atcommand.h
  46. 0 26
      src/map/battle.c
  47. 0 27
      src/map/battle.h
  48. 5 5
      src/map/buyingstore.c
  49. 2 2
      src/map/chat.c
  50. 4 4
      src/map/chrif.c
  51. 152 347
      src/map/clif.c
  52. 0 2
      src/map/clif.h
  53. 18 16
      src/map/intif.c
  54. 1 1
      src/map/intif.h
  55. 8 7
      src/map/log.c
  56. 2 2
      src/map/log.h
  57. 4 4
      src/map/mail.c
  58. 2 6
      src/map/party.c
  59. 71 73
      src/map/pc.c
  60. 31 6
      src/map/pc.h
  61. 459 0
      src/map/pc_groups.c
  62. 20 0
      src/map/pc_groups.h
  63. 9 50
      src/map/script.c
  64. 6 7
      src/map/skill.c
  65. 4 4
      src/map/storage.c
  66. 13 17
      src/map/trade.c
  67. 2 2
      src/map/vending.c
  68. 12 2
      src/tool/Makefile.in
  69. 16 4
      vcproj-10/char-server_sql.vcxproj
  70. 48 6
      vcproj-10/char-server_sql.vcxproj.filters
  71. 16 4
      vcproj-10/login-server_sql.vcxproj
  72. 48 6
      vcproj-10/login-server_sql.vcxproj.filters
  73. 20 4
      vcproj-10/map-server_sql.vcxproj
  74. 73 12
      vcproj-10/map-server_sql.vcxproj.filters
  75. 4 4
      vcproj-10/mapcache.vcxproj
  76. 75 11
      vcproj-9/char-server_sql.vcproj
  77. 76 12
      vcproj-9/login-server_sql.vcproj
  78. 106 34
      vcproj-9/map-server_sql.vcproj
  79. 6 6
      vcproj-9/mapcache.vcproj

+ 674 - 0
3rdparty/libconfig/LICENSE

@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.

+ 24 - 0
3rdparty/libconfig/Makefile.in

@@ -0,0 +1,24 @@
+
+LIBCONFIG_OBJ = libconfig.o grammar.o scanctx.o scanner.o strbuf.o
+LIBCONFIG_H = libconfig.h grammar.h parsectx.h scanctx.h scanner.h strbuf.h wincompat.h
+
+@SET_MAKE@
+
+#####################################################################
+.PHONY : all clean help
+
+all: $(LIBCONFIG_OBJ)
+
+clean:
+	rm -rf *.o
+
+help:
+	@echo "possible targets are 'all' 'clean' 'help'"
+	@echo "'all'    - builds $(LIBCONFIG_OBJ)"
+	@echo "'clean'  - deletes $(LIBCONFIG_OBJ)"
+	@echo "'help'   - outputs this message"
+
+#####################################################################
+
+%.o: %.c $(LIBCONFIG_H)
+	@CC@ @CFLAGS@ @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<

+ 2001 - 0
3rdparty/libconfig/grammar.c

@@ -0,0 +1,2001 @@
+
+/* A Bison parser, made by GNU Bison 2.4.1.  */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+   
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+   
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.4.1"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 1
+
+/* Push parsers.  */
+#define YYPUSH 0
+
+/* Pull parsers.  */
+#define YYPULL 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names.  */
+#define yyparse         libconfig_yyparse
+#define yylex           libconfig_yylex
+#define yyerror         libconfig_yyerror
+#define yylval          libconfig_yylval
+#define yychar          libconfig_yychar
+#define yydebug         libconfig_yydebug
+#define yynerrs         libconfig_yynerrs
+
+
+/* Copy the first part of user declarations.  */
+
+/* Line 189 of yacc.c  */
+#line 32 "grammar.y"
+
+#include <string.h>
+#include <stdlib.h>
+#include "libconfig.h"
+#ifdef WIN32
+#include "wincompat.h"
+
+/* prevent warnings about redefined malloc/free in generated code: */
+#ifndef _STDLIB_H
+#define _STDLIB_H
+#endif
+
+#include <malloc.h>
+#endif
+#include "parsectx.h"
+#include "scanctx.h"
+
+/* these delcarations are provided to suppress compiler warnings */
+extern int libconfig_yylex();
+extern int libconfig_yyget_lineno();
+
+static const char *err_array_elem_type = "mismatched element type in array";
+static const char *err_duplicate_setting = "duplicate setting name";
+
+#define _delete(P) free((void *)(P))
+
+#define IN_ARRAY() \
+  (ctx->parent && (ctx->parent->type == CONFIG_TYPE_ARRAY))
+
+#define IN_LIST() \
+  (ctx->parent && (ctx->parent->type == CONFIG_TYPE_LIST))
+
+static void capture_parse_pos(void *scanner, struct scan_context *scan_ctx,
+                              config_setting_t *setting)
+{
+  setting->line = (unsigned int)libconfig_yyget_lineno(scanner);
+  setting->file = scanctx_current_filename(scan_ctx);
+}
+
+#define CAPTURE_PARSE_POS(S) \
+  capture_parse_pos(scanner, scan_ctx, (S))
+
+void libconfig_yyerror(void *scanner, struct parse_context *ctx,
+                       struct scan_context *scan_ctx, char const *s)
+{
+  if(ctx->config->error_text) return;
+  ctx->config->error_line = libconfig_yyget_lineno(scanner);
+  ctx->config->error_text = s;
+}
+
+
+
+/* Line 189 of yacc.c  */
+#line 134 "grammar.c"
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     TOK_BOOLEAN = 258,
+     TOK_INTEGER = 259,
+     TOK_HEX = 260,
+     TOK_INTEGER64 = 261,
+     TOK_HEX64 = 262,
+     TOK_FLOAT = 263,
+     TOK_STRING = 264,
+     TOK_NAME = 265,
+     TOK_EQUALS = 266,
+     TOK_NEWLINE = 267,
+     TOK_ARRAY_START = 268,
+     TOK_ARRAY_END = 269,
+     TOK_LIST_START = 270,
+     TOK_LIST_END = 271,
+     TOK_COMMA = 272,
+     TOK_GROUP_START = 273,
+     TOK_GROUP_END = 274,
+     TOK_SEMICOLON = 275,
+     TOK_GARBAGE = 276,
+     TOK_ERROR = 277
+   };
+#endif
+/* Tokens.  */
+#define TOK_BOOLEAN 258
+#define TOK_INTEGER 259
+#define TOK_HEX 260
+#define TOK_INTEGER64 261
+#define TOK_HEX64 262
+#define TOK_FLOAT 263
+#define TOK_STRING 264
+#define TOK_NAME 265
+#define TOK_EQUALS 266
+#define TOK_NEWLINE 267
+#define TOK_ARRAY_START 268
+#define TOK_ARRAY_END 269
+#define TOK_LIST_START 270
+#define TOK_LIST_END 271
+#define TOK_COMMA 272
+#define TOK_GROUP_START 273
+#define TOK_GROUP_END 274
+#define TOK_SEMICOLON 275
+#define TOK_GARBAGE 276
+#define TOK_ERROR 277
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 214 of yacc.c  */
+#line 85 "grammar.y"
+
+  int ival;
+  long long llval;
+  double fval;
+  char *sval;
+
+
+
+/* Line 214 of yacc.c  */
+#line 223 "grammar.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 264 of yacc.c  */
+#line 235 "grammar.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+    int yyi;
+#endif
+{
+  return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     ifndef _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss_alloc;
+  YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack)				\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack_alloc, Stack, yysize);			\
+	Stack = &yyptr->Stack_alloc;					\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  6
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   35
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  23
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  20
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  39
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  47
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   277
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint8 yyprhs[] =
+{
+       0,     0,     3,     4,     6,     8,    11,    12,    14,    15,
+      17,    19,    20,    26,    27,    32,    33,    38,    40,    42,
+      44,    46,    48,    51,    53,    55,    57,    59,    61,    63,
+      65,    67,    71,    72,    74,    76,    80,    81,    83,    84
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      24,     0,    -1,    -1,    25,    -1,    28,    -1,    25,    28,
+      -1,    -1,    25,    -1,    -1,    20,    -1,    17,    -1,    -1,
+      10,    29,    11,    34,    27,    -1,    -1,    13,    31,    40,
+      14,    -1,    -1,    15,    33,    38,    16,    -1,    36,    -1,
+      30,    -1,    32,    -1,    41,    -1,     9,    -1,    35,     9,
+      -1,     3,    -1,     4,    -1,     6,    -1,     5,    -1,     7,
+      -1,     8,    -1,    35,    -1,    34,    -1,    37,    17,    34,
+      -1,    -1,    37,    -1,    36,    -1,    39,    17,    36,    -1,
+      -1,    39,    -1,    -1,    18,    42,    26,    19,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,   100,   100,   102,   106,   107,   110,   112,   115,   117,
+     118,   123,   122,   142,   141,   165,   164,   187,   188,   189,
+     190,   194,   195,   199,   219,   241,   263,   285,   307,   325,
+     353,   354,   357,   359,   363,   364,   367,   369,   374,   373
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "TOK_BOOLEAN", "TOK_INTEGER", "TOK_HEX",
+  "TOK_INTEGER64", "TOK_HEX64", "TOK_FLOAT", "TOK_STRING", "TOK_NAME",
+  "TOK_EQUALS", "TOK_NEWLINE", "TOK_ARRAY_START", "TOK_ARRAY_END",
+  "TOK_LIST_START", "TOK_LIST_END", "TOK_COMMA", "TOK_GROUP_START",
+  "TOK_GROUP_END", "TOK_SEMICOLON", "TOK_GARBAGE", "TOK_ERROR", "$accept",
+  "configuration", "setting_list", "setting_list_optional",
+  "setting_terminator", "setting", "$@1", "array", "$@2", "list", "$@3",
+  "value", "string", "simple_value", "value_list", "value_list_optional",
+  "simple_value_list", "simple_value_list_optional", "group", "$@4", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    23,    24,    24,    25,    25,    26,    26,    27,    27,
+      27,    29,    28,    31,    30,    33,    32,    34,    34,    34,
+      34,    35,    35,    36,    36,    36,    36,    36,    36,    36,
+      37,    37,    38,    38,    39,    39,    40,    40,    42,    41
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     0,     1,     1,     2,     0,     1,     0,     1,
+       1,     0,     5,     0,     4,     0,     4,     1,     1,     1,
+       1,     1,     2,     1,     1,     1,     1,     1,     1,     1,
+       1,     3,     0,     1,     1,     3,     0,     1,     0,     4
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       2,    11,     0,     3,     4,     0,     1,     5,     0,    23,
+      24,    26,    25,    27,    28,    21,    13,    15,    38,    18,
+      19,     8,    29,    17,    20,    36,    32,     6,    10,     9,
+      12,    22,    34,    37,     0,    30,    33,     0,     7,     0,
+       0,    14,     0,    16,    39,    35,    31
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int8 yydefgoto[] =
+{
+      -1,     2,     3,    39,    30,     4,     5,    19,    25,    20,
+      26,    21,    22,    23,    36,    37,    33,    34,    24,    27
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -26
+static const yytype_int8 yypact[] =
+{
+      -8,   -26,    12,    -8,   -26,     5,   -26,   -26,     0,   -26,
+     -26,   -26,   -26,   -26,   -26,   -26,   -26,   -26,   -26,   -26,
+     -26,    -6,    10,   -26,   -26,    23,     0,    -8,   -26,   -26,
+     -26,   -26,   -26,     3,     7,   -26,     6,     8,    -8,    14,
+      23,   -26,     0,   -26,   -26,   -26,   -26
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int8 yypgoto[] =
+{
+     -26,   -26,    -5,   -26,   -26,    -3,   -26,   -26,   -26,   -26,
+     -26,   -25,   -26,   -15,   -26,   -26,   -26,   -26,   -26,   -26
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+       7,    35,     1,     9,    10,    11,    12,    13,    14,    15,
+      32,    28,     6,    16,    29,    17,     8,    46,    18,    31,
+      40,    41,    38,    42,    43,    45,     9,    10,    11,    12,
+      13,    14,    15,    44,     0,     7
+};
+
+static const yytype_int8 yycheck[] =
+{
+       3,    26,    10,     3,     4,     5,     6,     7,     8,     9,
+      25,    17,     0,    13,    20,    15,    11,    42,    18,     9,
+      17,    14,    27,    17,    16,    40,     3,     4,     5,     6,
+       7,     8,     9,    19,    -1,    38
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,    10,    24,    25,    28,    29,     0,    28,    11,     3,
+       4,     5,     6,     7,     8,     9,    13,    15,    18,    30,
+      32,    34,    35,    36,    41,    31,    33,    42,    17,    20,
+      27,     9,    36,    39,    40,    34,    37,    38,    25,    26,
+      17,    14,    17,    16,    19,    36,    34
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+
+#define YYFAIL		goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (scanner, ctx, scan_ctx, YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)				\
+    do									\
+      if (YYID (N))                                                    \
+	{								\
+	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
+	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
+	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
+	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+	}								\
+      else								\
+	{								\
+	  (Current).first_line   = (Current).last_line   =		\
+	    YYRHSLOC (Rhs, 0).last_line;				\
+	  (Current).first_column = (Current).last_column =		\
+	    YYRHSLOC (Rhs, 0).last_column;				\
+	}								\
+    while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)			\
+     fprintf (File, "%d.%d-%d.%d",			\
+	      (Loc).first_line, (Loc).first_column,	\
+	      (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval, scanner)
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value, scanner, ctx, scan_ctx); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void *scanner, struct parse_context *ctx, struct scan_context *scan_ctx)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, scanner, ctx, scan_ctx)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    void *scanner;
+    struct parse_context *ctx;
+    struct scan_context *scan_ctx;
+#endif
+{
+  if (!yyvaluep)
+    return;
+  YYUSE (scanner);
+  YYUSE (ctx);
+  YYUSE (scan_ctx);
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void *scanner, struct parse_context *ctx, struct scan_context *scan_ctx)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, scanner, ctx, scan_ctx)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    void *scanner;
+    struct parse_context *ctx;
+    struct scan_context *scan_ctx;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep, scanner, ctx, scan_ctx);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+    yytype_int16 *yybottom;
+    yytype_int16 *yytop;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; yybottom <= yytop; yybottom++)
+    {
+      int yybot = *yybottom;
+      YYFPRINTF (stderr, " %d", yybot);
+    }
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule, void *scanner, struct parse_context *ctx, struct scan_context *scan_ctx)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule, scanner, ctx, scan_ctx)
+    YYSTYPE *yyvsp;
+    int yyrule;
+    void *scanner;
+    struct parse_context *ctx;
+    struct scan_context *scan_ctx;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       		       , scanner, ctx, scan_ctx);
+      YYFPRINTF (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, Rule, scanner, ctx, scan_ctx); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
+   including the terminating null byte.  If YYRESULT is null, do not
+   copy anything; just return the number of bytes that would be
+   copied.  As a special case, return 0 if an ordinary "syntax error"
+   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
+   size calculation.  */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+  int yyn = yypact[yystate];
+
+  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+    return 0;
+  else
+    {
+      int yytype = YYTRANSLATE (yychar);
+      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+      YYSIZE_T yysize = yysize0;
+      YYSIZE_T yysize1;
+      int yysize_overflow = 0;
+      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+      int yyx;
+
+# if 0
+      /* This is so xgettext sees the translatable formats that are
+	 constructed on the fly.  */
+      YY_("syntax error, unexpected %s");
+      YY_("syntax error, unexpected %s, expecting %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+      char *yyfmt;
+      char const *yyf;
+      static char const yyunexpected[] = "syntax error, unexpected %s";
+      static char const yyexpecting[] = ", expecting %s";
+      static char const yyor[] = " or %s";
+      char yyformat[sizeof yyunexpected
+		    + sizeof yyexpecting - 1
+		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+		       * (sizeof yyor - 1))];
+      char const *yyprefix = yyexpecting;
+
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+	 YYCHECK.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yycount = 1;
+
+      yyarg[0] = yytname[yytype];
+      yyfmt = yystpcpy (yyformat, yyunexpected);
+
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+	  {
+	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+	      {
+		yycount = 1;
+		yysize = yysize0;
+		yyformat[sizeof yyunexpected - 1] = '\0';
+		break;
+	      }
+	    yyarg[yycount++] = yytname[yyx];
+	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+	    yysize_overflow |= (yysize1 < yysize);
+	    yysize = yysize1;
+	    yyfmt = yystpcpy (yyfmt, yyprefix);
+	    yyprefix = yyor;
+	  }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+	return YYSIZE_MAXIMUM;
+
+      if (yyresult)
+	{
+	  /* Avoid sprintf, as that infringes on the user's name space.
+	     Don't have undefined behavior even if the translation
+	     produced a string with the wrong number of "%s"s.  */
+	  char *yyp = yyresult;
+	  int yyi = 0;
+	  while ((*yyp = *yyf) != '\0')
+	    {
+	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+		{
+		  yyp += yytnamerr (yyp, yyarg[yyi++]);
+		  yyf += 2;
+		}
+	      else
+		{
+		  yyp++;
+		  yyf++;
+		}
+	    }
+	}
+      return yysize;
+    }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, void *scanner, struct parse_context *ctx, struct scan_context *scan_ctx)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, scanner, ctx, scan_ctx)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+    void *scanner;
+    struct parse_context *ctx;
+    struct scan_context *scan_ctx;
+#endif
+{
+  YYUSE (yyvaluep);
+  YYUSE (scanner);
+  YYUSE (ctx);
+  YYUSE (scan_ctx);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+	break;
+    }
+}
+
+/* Prevent warnings from -Wmissing-prototypes.  */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *scanner, struct parse_context *ctx, struct scan_context *scan_ctx);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+/*-------------------------.
+| yyparse or yypush_parse.  |
+`-------------------------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *scanner, struct parse_context *ctx, struct scan_context *scan_ctx)
+#else
+int
+yyparse (scanner, ctx, scan_ctx)
+    void *scanner;
+    struct parse_context *ctx;
+    struct scan_context *scan_ctx;
+#endif
+#endif
+{
+/* The lookahead symbol.  */
+int yychar;
+
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval;
+
+    /* Number of syntax errors so far.  */
+    int yynerrs;
+
+    int yystate;
+    /* Number of tokens to shift before error messages enabled.  */
+    int yyerrstatus;
+
+    /* The stacks and their tools:
+       `yyss': related to states.
+       `yyvs': related to semantic values.
+
+       Refer to the stacks thru separate pointers, to allow yyoverflow
+       to reallocate them elsewhere.  */
+
+    /* The state stack.  */
+    yytype_int16 yyssa[YYINITDEPTH];
+    yytype_int16 *yyss;
+    yytype_int16 *yyssp;
+
+    /* The semantic value stack.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs;
+    YYSTYPE *yyvsp;
+
+    YYSIZE_T yystacksize;
+
+  int yyn;
+  int yyresult;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yytoken;
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  yytoken = 0;
+  yyss = yyssa;
+  yyvs = yyvsa;
+  yystacksize = YYINITDEPTH;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY; /* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+  yyssp = yyss;
+  yyvsp = yyvs;
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	yytype_int16 *yyss1 = yyss;
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+		    &yystacksize);
+
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss_alloc, yyss);
+	YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  if (yystate == YYFINAL)
+    YYACCEPT;
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     lookahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the lookahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 11:
+
+/* Line 1455 of yacc.c  */
+#line 123 "grammar.y"
+    {
+    ctx->setting = config_setting_add(ctx->parent, (yyvsp[(1) - (1)].sval), CONFIG_TYPE_NONE);
+
+    if(ctx->setting == NULL)
+    {
+      libconfig_yyerror(scanner, ctx, scan_ctx, err_duplicate_setting);
+      YYABORT;
+    }
+    else
+    {
+      CAPTURE_PARSE_POS(ctx->setting);
+    }
+  }
+    break;
+
+  case 13:
+
+/* Line 1455 of yacc.c  */
+#line 142 "grammar.y"
+    {
+    if(IN_LIST())
+    {
+      ctx->parent = config_setting_add(ctx->parent, NULL, CONFIG_TYPE_ARRAY);
+      CAPTURE_PARSE_POS(ctx->parent);
+    }
+    else
+    {
+      ctx->setting->type = CONFIG_TYPE_ARRAY;
+      ctx->parent = ctx->setting;
+      ctx->setting = NULL;
+    }
+  }
+    break;
+
+  case 14:
+
+/* Line 1455 of yacc.c  */
+#line 157 "grammar.y"
+    {
+    if(ctx->parent)
+      ctx->parent = ctx->parent->parent;
+  }
+    break;
+
+  case 15:
+
+/* Line 1455 of yacc.c  */
+#line 165 "grammar.y"
+    {
+    if(IN_LIST())
+    {
+      ctx->parent = config_setting_add(ctx->parent, NULL, CONFIG_TYPE_LIST);
+      CAPTURE_PARSE_POS(ctx->parent);
+    }
+    else
+    {
+      ctx->setting->type = CONFIG_TYPE_LIST;
+      ctx->parent = ctx->setting;
+      ctx->setting = NULL;
+    }
+  }
+    break;
+
+  case 16:
+
+/* Line 1455 of yacc.c  */
+#line 180 "grammar.y"
+    {
+    if(ctx->parent)
+      ctx->parent = ctx->parent->parent;
+  }
+    break;
+
+  case 21:
+
+/* Line 1455 of yacc.c  */
+#line 194 "grammar.y"
+    { parsectx_append_string(ctx, (yyvsp[(1) - (1)].sval)); free((yyvsp[(1) - (1)].sval)); }
+    break;
+
+  case 22:
+
+/* Line 1455 of yacc.c  */
+#line 195 "grammar.y"
+    { parsectx_append_string(ctx, (yyvsp[(2) - (2)].sval)); free((yyvsp[(2) - (2)].sval)); }
+    break;
+
+  case 23:
+
+/* Line 1455 of yacc.c  */
+#line 200 "grammar.y"
+    {
+    if(IN_ARRAY() || IN_LIST())
+    {
+      config_setting_t *e = config_setting_set_bool_elem(ctx->parent, -1,
+                                                         (int)(yyvsp[(1) - (1)].ival));
+
+      if(! e)
+      {
+        libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type);
+        YYABORT;
+      }
+      else
+      {
+        CAPTURE_PARSE_POS(e);
+      }
+    }
+    else
+      config_setting_set_bool(ctx->setting, (int)(yyvsp[(1) - (1)].ival));
+  }
+    break;
+
+  case 24:
+
+/* Line 1455 of yacc.c  */
+#line 220 "grammar.y"
+    {
+    if(IN_ARRAY() || IN_LIST())
+    {
+      config_setting_t *e = config_setting_set_int_elem(ctx->parent, -1, (yyvsp[(1) - (1)].ival));
+      if(! e)
+      {
+        libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type);
+        YYABORT;
+      }
+      else
+      {
+        config_setting_set_format(e, CONFIG_FORMAT_DEFAULT);
+        CAPTURE_PARSE_POS(e);
+      }
+    }
+    else
+    {
+      config_setting_set_int(ctx->setting, (yyvsp[(1) - (1)].ival));
+      config_setting_set_format(ctx->setting, CONFIG_FORMAT_DEFAULT);
+    }
+  }
+    break;
+
+  case 25:
+
+/* Line 1455 of yacc.c  */
+#line 242 "grammar.y"
+    {
+    if(IN_ARRAY() || IN_LIST())
+    {
+      config_setting_t *e = config_setting_set_int64_elem(ctx->parent, -1, (yyvsp[(1) - (1)].llval));
+      if(! e)
+      {
+        libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type);
+        YYABORT;
+      }
+      else
+      {
+        config_setting_set_format(e, CONFIG_FORMAT_DEFAULT);
+        CAPTURE_PARSE_POS(e);
+      }
+    }
+    else
+    {
+      config_setting_set_int64(ctx->setting, (yyvsp[(1) - (1)].llval));
+      config_setting_set_format(ctx->setting, CONFIG_FORMAT_DEFAULT);
+    }
+  }
+    break;
+
+  case 26:
+
+/* Line 1455 of yacc.c  */
+#line 264 "grammar.y"
+    {
+    if(IN_ARRAY() || IN_LIST())
+    {
+      config_setting_t *e = config_setting_set_int_elem(ctx->parent, -1, (yyvsp[(1) - (1)].ival));
+      if(! e)
+      {
+        libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type);
+        YYABORT;
+      }
+      else
+      {
+        config_setting_set_format(e, CONFIG_FORMAT_HEX);
+        CAPTURE_PARSE_POS(e);
+      }
+    }
+    else
+    {
+      config_setting_set_int(ctx->setting, (yyvsp[(1) - (1)].ival));
+      config_setting_set_format(ctx->setting, CONFIG_FORMAT_HEX);
+    }
+  }
+    break;
+
+  case 27:
+
+/* Line 1455 of yacc.c  */
+#line 286 "grammar.y"
+    {
+    if(IN_ARRAY() || IN_LIST())
+    {
+      config_setting_t *e = config_setting_set_int64_elem(ctx->parent, -1, (yyvsp[(1) - (1)].llval));
+      if(! e)
+      {
+        libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type);
+        YYABORT;
+      }
+      else
+      {
+        config_setting_set_format(e, CONFIG_FORMAT_HEX);
+        CAPTURE_PARSE_POS(e);
+      }
+    }
+    else
+    {
+      config_setting_set_int64(ctx->setting, (yyvsp[(1) - (1)].llval));
+      config_setting_set_format(ctx->setting, CONFIG_FORMAT_HEX);
+    }
+  }
+    break;
+
+  case 28:
+
+/* Line 1455 of yacc.c  */
+#line 308 "grammar.y"
+    {
+    if(IN_ARRAY() || IN_LIST())
+    {
+      config_setting_t *e = config_setting_set_float_elem(ctx->parent, -1, (yyvsp[(1) - (1)].fval));
+      if(! e)
+      {
+        libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type);
+        YYABORT;
+      }
+      else
+      {
+        CAPTURE_PARSE_POS(e);
+      }
+    }
+    else
+      config_setting_set_float(ctx->setting, (yyvsp[(1) - (1)].fval));
+  }
+    break;
+
+  case 29:
+
+/* Line 1455 of yacc.c  */
+#line 326 "grammar.y"
+    {
+    if(IN_ARRAY() || IN_LIST())
+    {
+      const char *s = parsectx_take_string(ctx);
+      config_setting_t *e = config_setting_set_string_elem(ctx->parent, -1, s);
+      _delete(s);
+
+      if(! e)
+      {
+        libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type);
+        YYABORT;
+      }
+      else
+      {
+        CAPTURE_PARSE_POS(e);
+      }
+    }
+    else
+    {
+      const char *s = parsectx_take_string(ctx);
+      config_setting_set_string(ctx->setting, s);
+      _delete(s);
+    }
+  }
+    break;
+
+  case 38:
+
+/* Line 1455 of yacc.c  */
+#line 374 "grammar.y"
+    {
+    if(IN_LIST())
+    {
+      ctx->parent = config_setting_add(ctx->parent, NULL, CONFIG_TYPE_GROUP);
+      CAPTURE_PARSE_POS(ctx->parent);
+    }
+    else
+    {
+      ctx->setting->type = CONFIG_TYPE_GROUP;
+      ctx->parent = ctx->setting;
+      ctx->setting = NULL;
+    }
+  }
+    break;
+
+  case 39:
+
+/* Line 1455 of yacc.c  */
+#line 389 "grammar.y"
+    {
+    if(ctx->parent)
+      ctx->parent = ctx->parent->parent;
+  }
+    break;
+
+
+
+/* Line 1455 of yacc.c  */
+#line 1788 "grammar.c"
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (scanner, ctx, scan_ctx, YY_("syntax error"));
+#else
+      {
+	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+	  {
+	    YYSIZE_T yyalloc = 2 * yysize;
+	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
+	    if (yymsg != yymsgbuf)
+	      YYSTACK_FREE (yymsg);
+	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+	    if (yymsg)
+	      yymsg_alloc = yyalloc;
+	    else
+	      {
+		yymsg = yymsgbuf;
+		yymsg_alloc = sizeof yymsgbuf;
+	      }
+	  }
+
+	if (0 < yysize && yysize <= yymsg_alloc)
+	  {
+	    (void) yysyntax_error (yymsg, yystate, yychar);
+	    yyerror (scanner, ctx, scan_ctx, yymsg);
+	  }
+	else
+	  {
+	    yyerror (scanner, ctx, scan_ctx, YY_("syntax error"));
+	    if (yysize != 0)
+	      goto yyexhaustedlab;
+	  }
+      }
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval, scanner, ctx, scan_ctx);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp, scanner, ctx, scan_ctx);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  *++yyvsp = yylval;
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (scanner, ctx, scan_ctx, YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+		 yytoken, &yylval, scanner, ctx, scan_ctx);
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp, scanner, ctx, scan_ctx);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+
+/* Line 1675 of yacc.c  */
+#line 395 "grammar.y"
+
+

+ 113 - 0
3rdparty/libconfig/grammar.h

@@ -0,0 +1,113 @@
+
+/* A Bison parser, made by GNU Bison 2.4.1.  */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+   
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+   
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     TOK_BOOLEAN = 258,
+     TOK_INTEGER = 259,
+     TOK_HEX = 260,
+     TOK_INTEGER64 = 261,
+     TOK_HEX64 = 262,
+     TOK_FLOAT = 263,
+     TOK_STRING = 264,
+     TOK_NAME = 265,
+     TOK_EQUALS = 266,
+     TOK_NEWLINE = 267,
+     TOK_ARRAY_START = 268,
+     TOK_ARRAY_END = 269,
+     TOK_LIST_START = 270,
+     TOK_LIST_END = 271,
+     TOK_COMMA = 272,
+     TOK_GROUP_START = 273,
+     TOK_GROUP_END = 274,
+     TOK_SEMICOLON = 275,
+     TOK_GARBAGE = 276,
+     TOK_ERROR = 277
+   };
+#endif
+/* Tokens.  */
+#define TOK_BOOLEAN 258
+#define TOK_INTEGER 259
+#define TOK_HEX 260
+#define TOK_INTEGER64 261
+#define TOK_HEX64 262
+#define TOK_FLOAT 263
+#define TOK_STRING 264
+#define TOK_NAME 265
+#define TOK_EQUALS 266
+#define TOK_NEWLINE 267
+#define TOK_ARRAY_START 268
+#define TOK_ARRAY_END 269
+#define TOK_LIST_START 270
+#define TOK_LIST_END 271
+#define TOK_COMMA 272
+#define TOK_GROUP_START 273
+#define TOK_GROUP_END 274
+#define TOK_SEMICOLON 275
+#define TOK_GARBAGE 276
+#define TOK_ERROR 277
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 1676 of yacc.c  */
+#line 85 "grammar.y"
+
+  int ival;
+  long long llval;
+  double fval;
+  char *sval;
+
+
+
+/* Line 1676 of yacc.c  */
+#line 105 "grammar.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+
+

+ 0 - 0
conf/import-tmpl/atcommand_conf.txt → 3rdparty/libconfig/libconfig-1.4.8


+ 1615 - 0
3rdparty/libconfig/libconfig.c

@@ -0,0 +1,1615 @@
+/* ----------------------------------------------------------------------------
+   libconfig - A library for processing structured configuration files
+   Copyright (C) 2005-2010  Mark A Lindner
+
+   This file is part of libconfig.
+
+   This library is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this library.  If not, see <http://www.gnu.org/licenses/>.
+   ----------------------------------------------------------------------------
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "ac_config.h"
+#endif
+
+#include "libconfig.h"
+#include "grammar.h"
+#include "scanner.h"
+#include "scanctx.h"
+#include "parsectx.h"
+#include "wincompat.h"
+
+#include <locale.h>
+
+#ifdef HAVE_XLOCALE_H
+#include <xlocale.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define PATH_TOKENS ":./"
+#define CHUNK_SIZE 16
+#define FLOAT_PRECISION 10
+
+#define _new(T) (T *)calloc(sizeof(T), 1) /* zeroed */
+#define _delete(P) free((void *)(P))
+
+/* ------------------------------------------------------------------------- */
+
+#ifndef LIBCONFIG_STATIC
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+  return(TRUE);
+}
+
+#endif /* WIN32 */
+#endif /* LIBCONFIG_STATIC */
+
+/* ------------------------------------------------------------------------- */
+
+static const char *__io_error = "file I/O error";
+
+static void __config_list_destroy(config_list_t *list);
+static void __config_write_setting(const config_setting_t *setting,
+                                   FILE *stream, int depth,
+                                   unsigned short tab_width);
+
+extern int libconfig_yyparse(void *scanner, struct parse_context *ctx,
+                             struct scan_context *scan_ctx);
+extern int libconfig_yylex_init_extra(struct scan_context *scan_ctx,
+                                      yyscan_t *scanner);
+
+/* ------------------------------------------------------------------------- */
+
+static void __config_locale_override(void)
+{
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \
+  && ! defined(__MINGW32__)
+
+  _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
+  setlocale(LC_NUMERIC, "C");
+
+#elif defined(__APPLE__)
+
+  locale_t loc = newlocale(LC_NUMERIC_MASK, "C", NULL);
+  uselocale(loc);
+
+#elif ((defined HAVE_NEWLOCALE) && (defined HAVE_USELOCALE))
+
+  locale_t loc = newlocale(LC_NUMERIC, "C", NULL);
+  uselocale(loc);
+
+#else
+
+#warning "No way to modify calling thread's locale!"
+
+#endif
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void __config_locale_restore(void)
+{
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \
+  && ! defined(__MINGW32__)
+
+    _configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
+
+#elif ((defined HAVE_USELOCALE) && (defined HAVE_FREELOCALE))
+
+  locale_t loc = uselocale(LC_GLOBAL_LOCALE);
+  freelocale(loc);
+
+#else
+
+#warning "No way to modify calling thread's locale!"
+
+#endif
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __config_name_compare(const char *a, const char *b)
+{
+  const char *p, *q;
+
+  for(p = a, q = b; ; p++, q++)
+  {
+    int pd = ((! *p) || strchr(PATH_TOKENS, *p));
+    int qd = ((! *q) || strchr(PATH_TOKENS, *q));
+
+    if(pd && qd)
+      break;
+    else if(pd)
+      return(-1);
+    else if(qd)
+      return(1);
+    else if(*p < *q)
+      return(-1);
+    else if(*p > *q)
+      return(1);
+  }
+
+  return(0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void __config_indent(FILE *stream, int depth, unsigned short w)
+{
+  if(w)
+    fprintf(stream, "%*s", (depth - 1) * w, " ");
+  else
+  {
+    int i;
+    for(i = 0; i < (depth - 1); ++i)
+      fputc('\t', stream);
+  }
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void __config_write_value(const config_value_t *value, int type,
+                                 int format, int depth,
+                                 unsigned short tab_width, FILE *stream)
+{
+  char fbuf[64];
+
+  switch(type)
+  {
+    /* boolean */
+    case CONFIG_TYPE_BOOL:
+      fputs(value->ival ? "true" : "false", stream);
+      break;
+
+    /* int */
+    case CONFIG_TYPE_INT:
+      switch(format)
+      {
+        case CONFIG_FORMAT_HEX:
+          fprintf(stream, "0x%X", value->ival);
+          break;
+
+        case CONFIG_FORMAT_DEFAULT:
+        default:
+          fprintf(stream, "%d", value->ival);
+          break;
+      }
+      break;
+
+    /* 64-bit int */
+    case CONFIG_TYPE_INT64:
+      switch(format)
+      {
+        case CONFIG_FORMAT_HEX:
+          fprintf(stream, "0x" INT64_HEX_FMT "L", value->llval);
+          break;
+
+        case CONFIG_FORMAT_DEFAULT:
+        default:
+          fprintf(stream, INT64_FMT "L", value->llval);
+          break;
+      }
+      break;
+
+    /* float */
+    case CONFIG_TYPE_FLOAT:
+    {
+      char *q;
+
+      snprintf(fbuf, sizeof(fbuf) - 3, "%.*g", FLOAT_PRECISION, value->fval);
+
+      /* check for exponent */
+      q = strchr(fbuf, 'e');
+      if(! q)
+      {
+        /* no exponent */
+        if(! strchr(fbuf, '.')) /* no decimal point */
+          strcat(fbuf, ".0");
+        else
+        {
+          /* has decimal point */
+          char *p;
+
+          for(p = fbuf + strlen(fbuf) - 1; p > fbuf; --p)
+          {
+            if(*p != '0')
+            {
+              *(++p) = '\0';
+              break;
+            }
+          }
+        }
+      }
+
+      fputs(fbuf, stream);
+      break;
+    }
+
+    /* string */
+    case CONFIG_TYPE_STRING:
+    {
+      char *p;
+
+      fputc('\"', stream);
+
+      if(value->sval)
+      {
+        for(p = value->sval; *p; p++)
+        {
+          int c = (int)*p & 0xFF;
+          switch(c)
+          {
+            case '\"':
+            case '\\':
+              fputc('\\', stream);
+              fputc(c, stream);
+              break;
+
+            case '\n':
+              fputs("\\n", stream);
+              break;
+
+            case '\r':
+              fputs("\\r", stream);
+              break;
+
+            case '\f':
+              fputs("\\f", stream);
+              break;
+
+            case '\t':
+              fputs("\\t", stream);
+              break;
+
+            default:
+              if(c >= ' ')
+                fputc(c, stream);
+              else
+                fprintf(stream, "\\x%02X", c);
+          }
+        }
+      }
+      fputc('\"', stream);
+      break;
+    }
+
+    /* list */
+    case CONFIG_TYPE_LIST:
+    {
+      config_list_t *list = value->list;
+
+      fprintf(stream, "( ");
+
+      if(list)
+      {
+        int len = list->length;
+        config_setting_t **s;
+
+        for(s = list->elements; len--; s++)
+        {
+          __config_write_value(&((*s)->value), (*s)->type,
+                               config_setting_get_format(*s),
+                               depth + 1, tab_width, stream);
+
+          if(len)
+            fputc(',', stream);
+
+          fputc(' ', stream);
+        }
+      }
+
+      fputc(')', stream);
+      break;
+    }
+
+    /* array */
+    case CONFIG_TYPE_ARRAY:
+    {
+      config_list_t *list = value->list;
+
+      fprintf(stream, "[ ");
+
+      if(list)
+      {
+        int len = list->length;
+        config_setting_t **s;
+
+        for(s = list->elements; len--; s++)
+        {
+          __config_write_value(&((*s)->value), (*s)->type,
+                               config_setting_get_format(*s),
+                               depth + 1, tab_width, stream);
+
+          if(len)
+            fputc(',', stream);
+
+          fputc(' ', stream);
+        }
+      }
+
+      fputc(']', stream);
+      break;
+    }
+
+    /* group */
+    case CONFIG_TYPE_GROUP:
+    {
+      config_list_t *list = value->list;
+
+      if(depth > 0)
+      {
+#ifdef K_AND_R_STYLE /* Horrendous, but many people like it. */
+        fputc(' ', stream);
+#else
+        fputc('\n', stream);
+
+        if(depth > 1)
+          __config_indent(stream, depth, tab_width);
+#endif
+        fprintf(stream, "{\n");
+      }
+
+      if(list)
+      {
+        int len = list->length;
+        config_setting_t **s;
+
+        for(s = list->elements; len--; s++)
+          __config_write_setting(*s, stream, depth + 1, tab_width);
+      }
+
+      if(depth > 1)
+        __config_indent(stream, depth, tab_width);
+
+      if(depth > 0)
+        fputc('}', stream);
+
+      break;
+    }
+
+    default:
+      /* this shouldn't happen, but handle it gracefully... */
+      fputs("???", stream);
+      break;
+  }
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void __config_list_add(config_list_t *list, config_setting_t *setting)
+{
+  if((list->length % CHUNK_SIZE) == 0)
+  {
+    list->elements = (config_setting_t **)realloc(
+      list->elements,
+      (list->length + CHUNK_SIZE) * sizeof(config_setting_t *));
+  }
+
+  list->elements[list->length] = setting;
+  list->length++;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static config_setting_t *__config_list_search(config_list_t *list,
+                                              const char *name,
+                                              unsigned int *idx)
+{
+  config_setting_t **found = NULL;
+  unsigned int i;
+
+  if(! list)
+    return(NULL);
+
+  for(i = 0, found = list->elements; i < list->length; i++, found++)
+  {
+    if(! (*found)->name)
+      continue;
+
+    if(! __config_name_compare(name, (*found)->name))
+    {
+      if(idx)
+        *idx = i;
+
+      return(*found);
+    }
+  }
+
+  return(NULL);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static config_setting_t *__config_list_remove(config_list_t *list, int idx)
+{
+  config_setting_t *removed = *(list->elements + idx);
+  int offset = (idx * sizeof(config_setting_t *));
+  int len = list->length - 1 - idx;
+  char *base = (char *)list->elements + offset;
+
+  memmove(base, base + sizeof(config_setting_t *),
+          len * sizeof(config_setting_t *));
+
+  list->length--;
+
+  /* possibly realloc smaller? */
+
+  return(removed);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void __config_setting_destroy(config_setting_t *setting)
+{
+  if(setting)
+  {
+    if(setting->name)
+      _delete(setting->name);
+
+    if(setting->type == CONFIG_TYPE_STRING)
+      _delete(setting->value.sval);
+
+    else if((setting->type == CONFIG_TYPE_GROUP)
+            || (setting->type == CONFIG_TYPE_ARRAY)
+            || (setting->type == CONFIG_TYPE_LIST))
+    {
+      if(setting->value.list)
+        __config_list_destroy(setting->value.list);
+    }
+
+    if(setting->hook && setting->config->destructor)
+      setting->config->destructor(setting->hook);
+
+    _delete(setting);
+  }
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void __config_list_destroy(config_list_t *list)
+{
+  config_setting_t **p;
+  unsigned int i;
+
+  if(! list)
+    return;
+
+  if(list->elements)
+  {
+    for(p = list->elements, i = 0; i < list->length; p++, i++)
+      __config_setting_destroy(*p);
+
+    _delete(list->elements);
+  }
+
+  _delete(list);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __config_vector_checktype(const config_setting_t *vector, int type)
+{
+  /* if the array is empty, then it has no type yet */
+
+  if(! vector->value.list)
+    return(CONFIG_TRUE);
+
+  if(vector->value.list->length == 0)
+    return(CONFIG_TRUE);
+
+  /* if it's a list, any type is allowed */
+
+  if(vector->type == CONFIG_TYPE_LIST)
+    return(CONFIG_TRUE);
+
+  /* otherwise the first element added determines the type of the array */
+
+  return((vector->value.list->elements[0]->type == type)
+         ? CONFIG_TRUE : CONFIG_FALSE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __config_validate_name(const char *name)
+{
+  const char *p = name;
+
+  if(*p == '\0')
+    return(CONFIG_FALSE);
+
+  if(! isalpha(*p) && (*p != '*'))
+    return(CONFIG_FALSE);
+
+  for(++p; *p; ++p)
+  {
+    if(! (isalpha(*p) || isdigit(*p) || strchr("*_-", (int)*p)))
+      return(CONFIG_FALSE);
+  }
+
+  return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __config_read(config_t *config, FILE *stream, const char *filename,
+                         const char *str)
+{
+  yyscan_t scanner;
+  struct scan_context scan_ctx;
+  struct parse_context parse_ctx;
+  YY_BUFFER_STATE buffer = NULL;
+  int r;
+
+  /* Reinitialize the config */
+  void (*destructor)(void *) = config->destructor;
+  const char *include_dir = config->include_dir;
+  unsigned short tab_width = config->tab_width;
+  unsigned short flags = config->flags;
+
+  config->include_dir = NULL;
+  config_destroy(config);
+  config_init(config);
+
+  config->destructor = destructor;
+  config->include_dir = include_dir;
+  config->tab_width = tab_width;
+  config->flags = flags;
+
+  parsectx_init(&parse_ctx);
+  parse_ctx.config = config;
+  parse_ctx.parent = config->root;
+  parse_ctx.setting = config->root;
+
+  __config_locale_override();
+
+  scanctx_init(&scan_ctx, filename);
+  scan_ctx.config = config;
+  libconfig_yylex_init_extra(&scan_ctx, &scanner);
+
+  if(stream)
+    libconfig_yyrestart(stream, scanner);
+  else /* read from string */
+    buffer = libconfig_yy_scan_string(str, scanner);
+
+  libconfig_yyset_lineno(1, scanner);
+  r = libconfig_yyparse(scanner, &parse_ctx, &scan_ctx);
+
+  if(r != 0)
+  {
+    YY_BUFFER_STATE buf;
+
+    config->error_file = scanctx_current_filename(&scan_ctx);
+    config->error_type = CONFIG_ERR_PARSE;
+
+    /* Unwind the include stack, freeing the buffers and closing the files. */
+    while((buf = (YY_BUFFER_STATE)scanctx_pop_include(&scan_ctx)) != NULL)
+      libconfig_yy_delete_buffer(buf, scanner);
+  }
+
+  libconfig_yylex_destroy(scanner);
+  config->filenames = scanctx_cleanup(&scan_ctx, &(config->num_filenames));
+  parsectx_cleanup(&parse_ctx);
+
+  __config_locale_restore();
+
+  return(r == 0 ? CONFIG_TRUE : CONFIG_FALSE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_read(config_t *config, FILE *stream)
+{
+  return(__config_read(config, stream, NULL, NULL));
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_read_string(config_t *config, const char *str)
+{
+  return(__config_read(config, NULL, NULL, str));
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void __config_write_setting(const config_setting_t *setting,
+                                   FILE *stream, int depth,
+                                   unsigned short tab_width)
+{
+  if(depth > 1)
+    __config_indent(stream, depth, tab_width);
+
+  if(setting->name)
+  {
+    fputs(setting->name, stream);
+    fprintf(stream, " %c ", (setting->type == CONFIG_TYPE_GROUP ? ':' : '='));
+  }
+
+  __config_write_value(&(setting->value), setting->type,
+                       config_setting_get_format(setting),
+                       depth, tab_width, stream);
+
+  if(depth > 0)
+  {
+    fputc(';', stream);
+    fputc('\n', stream);
+  }
+}
+
+/* ------------------------------------------------------------------------- */
+
+void config_write(const config_t *config, FILE *stream)
+{
+  __config_locale_override();
+
+  __config_write_setting(config->root, stream, 0, config->tab_width);
+
+  __config_locale_restore();
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_read_file(config_t *config, const char *filename)
+{
+  int ret;
+  FILE *stream = fopen(filename, "rt");
+  if(! stream)
+  {
+    config->error_text = __io_error;
+    config->error_type = CONFIG_ERR_FILE_IO;
+    return(CONFIG_FALSE);
+  }
+
+  ret = __config_read(config, stream, filename, NULL);
+  fclose(stream);
+
+  return(ret);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_write_file(config_t *config, const char *filename)
+{
+  FILE *f = fopen(filename, "wt");
+  if(! f)
+  {
+    config->error_text = __io_error;
+    config->error_type = CONFIG_ERR_FILE_IO;
+    return(CONFIG_FALSE);
+  }
+
+  config_write(config, f);
+  fclose(f);
+  config->error_type = CONFIG_ERR_NONE;
+  return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void config_destroy(config_t *config)
+{
+  unsigned int count = config->num_filenames;
+  const char **f;
+
+  __config_setting_destroy(config->root);
+
+  for(f = config->filenames; count > 0; ++f, --count)
+    _delete(*f);
+
+  _delete(config->filenames);
+  _delete(config->include_dir);
+
+  memset((void *)config, 0, sizeof(config_t));
+}
+
+/* ------------------------------------------------------------------------- */
+
+void config_init(config_t *config)
+{
+  memset((void *)config, 0, sizeof(config_t));
+
+  config->root = _new(config_setting_t);
+  config->root->type = CONFIG_TYPE_GROUP;
+  config->root->config = config;
+  config->tab_width = 2;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void config_set_auto_convert(config_t *config, int flag)
+{
+  if(flag)
+    config->flags |= CONFIG_OPTION_AUTOCONVERT;
+  else
+    config->flags &= ~CONFIG_OPTION_AUTOCONVERT;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_get_auto_convert(const config_t *config)
+{
+  return((config->flags & CONFIG_OPTION_AUTOCONVERT) != 0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static config_setting_t *config_setting_create(config_setting_t *parent,
+                                               const char *name, int type)
+{
+  config_setting_t *setting;
+  config_list_t *list;
+
+  if((parent->type != CONFIG_TYPE_GROUP)
+     && (parent->type != CONFIG_TYPE_ARRAY)
+     && (parent->type != CONFIG_TYPE_LIST))
+    return(NULL);
+
+  setting = _new(config_setting_t);
+  setting->parent = parent;
+  setting->name = (name == NULL) ? NULL : strdup(name);
+  setting->type = type;
+  setting->config = parent->config;
+  setting->hook = NULL;
+  setting->line = 0;
+
+  list = parent->value.list;
+
+  if(! list)
+    list = parent->value.list = _new(config_list_t);
+
+  __config_list_add(list, setting);
+
+  return(setting);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __config_setting_get_int(const config_setting_t *setting,
+                                    int *value)
+{
+  switch(setting->type)
+  {
+    case CONFIG_TYPE_INT:
+      *value = setting->value.ival;
+      return(CONFIG_TRUE);
+
+    case CONFIG_TYPE_INT64:
+      if((setting->value.llval > INT32_MAX)
+         || (setting->value.llval < INT32_MIN))
+        *value = 0;
+      else
+        *value = (int)(setting->value.llval);
+      return(CONFIG_TRUE);
+
+    case CONFIG_TYPE_FLOAT:
+      if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
+      {
+        *value = (int)(setting->value.fval);
+        return(CONFIG_TRUE);
+      }
+      else
+      { /* fall through */ }
+
+    default:
+      return(CONFIG_FALSE);
+  }
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_get_int(const config_setting_t *setting)
+{
+  int value = 0;
+  __config_setting_get_int(setting, &value);
+  return(value);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __config_setting_get_int64(const config_setting_t *setting,
+                                      long long *value)
+{
+  switch(setting->type)
+  {
+    case CONFIG_TYPE_INT64:
+      *value = setting->value.llval;
+      return(CONFIG_TRUE);
+
+    case CONFIG_TYPE_INT:
+      *value = (long long)(setting->value.ival);
+      return(CONFIG_TRUE);
+
+    case CONFIG_TYPE_FLOAT:
+      if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
+      {
+        *value = (long long)(setting->value.fval);
+        return(CONFIG_TRUE);
+      }
+      else
+      { /* fall through */ }
+
+    default:
+      return(CONFIG_FALSE);
+  }
+}
+
+/* ------------------------------------------------------------------------- */
+
+long long config_setting_get_int64(const config_setting_t *setting)
+{
+  long long value = 0;
+  __config_setting_get_int64(setting, &value);
+  return(value);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_lookup_int(const config_setting_t *setting,
+                              const char *name, int *value)
+{
+  config_setting_t *member = config_setting_get_member(setting, name);
+  if(! member)
+    return(CONFIG_FALSE);
+
+  return(__config_setting_get_int(member, value));
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_lookup_int64(const config_setting_t *setting,
+                                const char *name, long long *value)
+{
+  config_setting_t *member = config_setting_get_member(setting, name);
+  if(! member)
+    return(CONFIG_FALSE);
+
+  return(__config_setting_get_int64(member, value));
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __config_setting_get_float(const config_setting_t *setting,
+                                      double *value)
+{
+  switch(setting->type)
+  {
+    case CONFIG_TYPE_FLOAT:
+      *value = setting->value.fval;
+      return(CONFIG_TRUE);
+
+    case CONFIG_TYPE_INT:
+      if(config_get_auto_convert(setting->config))
+      {
+        *value = (double)(setting->value.ival);
+        return(CONFIG_TRUE);
+      }
+      else
+        return(CONFIG_FALSE);
+
+    case CONFIG_TYPE_INT64:
+      if(config_get_auto_convert(setting->config))
+      {
+        *value = (double)(setting->value.llval);
+        return(CONFIG_TRUE);
+      }
+      else
+      { /* fall through */ }
+
+    default:
+      return(CONFIG_FALSE);
+  }
+}
+
+/* ------------------------------------------------------------------------- */
+
+double config_setting_get_float(const config_setting_t *setting)
+{
+  double value = 0.0;
+  __config_setting_get_float(setting, &value);
+  return(value);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_lookup_float(const config_setting_t *setting,
+                                const char *name, double *value)
+{
+  config_setting_t *member = config_setting_get_member(setting, name);
+  if(! member)
+    return(CONFIG_FALSE);
+
+  return(__config_setting_get_float(member, value));
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_lookup_string(const config_setting_t *setting,
+                                 const char *name, const char **value)
+{
+  config_setting_t *member = config_setting_get_member(setting, name);
+  if(! member)
+    return(CONFIG_FALSE);
+
+  if(config_setting_type(member) != CONFIG_TYPE_STRING)
+    return(CONFIG_FALSE);
+
+  *value = config_setting_get_string(member);
+  return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_lookup_bool(const config_setting_t *setting,
+                               const char *name, int *value)
+{
+  config_setting_t *member = config_setting_get_member(setting, name);
+  if(! member)
+    return(CONFIG_FALSE);
+
+  if(config_setting_type(member) != CONFIG_TYPE_BOOL)
+    return(CONFIG_FALSE);
+
+  *value = config_setting_get_bool(member);
+  return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_set_int(config_setting_t *setting, int value)
+{
+  switch(setting->type)
+  {
+    case CONFIG_TYPE_NONE:
+      setting->type = CONFIG_TYPE_INT;
+      /* fall through */
+
+    case CONFIG_TYPE_INT:
+      setting->value.ival = value;
+      return(CONFIG_TRUE);
+
+    case CONFIG_TYPE_FLOAT:
+      if(config_get_auto_convert(setting->config))
+      {
+        setting->value.fval = (float)value;
+        return(CONFIG_TRUE);
+      }
+      else
+        return(CONFIG_FALSE);
+
+    default:
+      return(CONFIG_FALSE);
+  }
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_set_int64(config_setting_t *setting, long long value)
+{
+  switch(setting->type)
+  {
+    case CONFIG_TYPE_NONE:
+      setting->type = CONFIG_TYPE_INT64;
+      /* fall through */
+
+    case CONFIG_TYPE_INT64:
+      setting->value.llval = value;
+      return(CONFIG_TRUE);
+
+    case CONFIG_TYPE_INT:
+      if((value > INT32_MAX) || (value < INT32_MIN))
+        setting->value.ival = 0;
+      else
+        setting->value.ival = (int)value;
+      return(CONFIG_TRUE);
+
+    case CONFIG_TYPE_FLOAT:
+      if(config_get_auto_convert(setting->config))
+      {
+        setting->value.fval = (float)value;
+        return(CONFIG_TRUE);
+      }
+      else
+        return(CONFIG_FALSE);
+
+    default:
+      return(CONFIG_FALSE);
+  }
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_set_float(config_setting_t *setting, double value)
+{
+  switch(setting->type)
+  {
+    case CONFIG_TYPE_NONE:
+      setting->type = CONFIG_TYPE_FLOAT;
+      /* fall through */
+
+    case CONFIG_TYPE_FLOAT:
+      setting->value.fval = value;
+      return(CONFIG_TRUE);
+
+    case CONFIG_TYPE_INT:
+      if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
+      {
+        setting->value.ival = (int)value;
+        return(CONFIG_TRUE);
+      }
+      else
+        return(CONFIG_FALSE);
+
+    case CONFIG_TYPE_INT64:
+      if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
+      {
+        setting->value.llval = (long long)value;
+        return(CONFIG_TRUE);
+      }
+      else
+        return(CONFIG_FALSE);
+
+    default:
+      return(CONFIG_FALSE);
+  }
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_get_bool(const config_setting_t *setting)
+{
+  return((setting->type == CONFIG_TYPE_BOOL) ? setting->value.ival : 0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_set_bool(config_setting_t *setting, int value)
+{
+  if(setting->type == CONFIG_TYPE_NONE)
+    setting->type = CONFIG_TYPE_BOOL;
+  else if(setting->type != CONFIG_TYPE_BOOL)
+    return(CONFIG_FALSE);
+
+  setting->value.ival = value;
+  return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+const char *config_setting_get_string(const config_setting_t *setting)
+{
+  return((setting->type == CONFIG_TYPE_STRING) ? setting->value.sval : NULL);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_set_string(config_setting_t *setting, const char *value)
+{
+  if(setting->type == CONFIG_TYPE_NONE)
+    setting->type = CONFIG_TYPE_STRING;
+  else if(setting->type != CONFIG_TYPE_STRING)
+    return(CONFIG_FALSE);
+
+  if(setting->value.sval)
+    _delete(setting->value.sval);
+
+  setting->value.sval = (value == NULL) ? NULL : strdup(value);
+  return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_set_format(config_setting_t *setting, short format)
+{
+  if(((setting->type != CONFIG_TYPE_INT)
+      && (setting->type != CONFIG_TYPE_INT64))
+     || ((format != CONFIG_FORMAT_DEFAULT) && (format != CONFIG_FORMAT_HEX)))
+    return(CONFIG_FALSE);
+
+  setting->format = format;
+
+  return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+short config_setting_get_format(const config_setting_t *setting)
+{
+  return(setting->format != 0 ? setting->format
+         : setting->config->default_format);
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_lookup_from(config_setting_t *setting,
+                                     const char *path)
+{
+  const char *p = path;
+  config_setting_t *found;
+
+  for(;;)
+  {
+    while(*p && strchr(PATH_TOKENS, *p))
+      p++;
+
+    if(! *p)
+      break;
+
+    if(*p == '[')
+      found = config_setting_get_elem(setting, atoi(++p));
+    else
+      found = config_setting_get_member(setting, p);
+
+    if(! found)
+      break;
+
+    setting = found;
+
+    while(! strchr(PATH_TOKENS, *p))
+      p++;
+  }
+
+  return(*p ? NULL : setting);
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_lookup(const config_t *config, const char *path)
+{
+  return(config_lookup_from(config->root, path));
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_lookup_string(const config_t *config, const char *path,
+                         const char **value)
+{
+  const config_setting_t *s = config_lookup(config, path);
+  if(! s)
+    return(CONFIG_FALSE);
+
+  if(config_setting_type(s) != CONFIG_TYPE_STRING)
+    return(CONFIG_FALSE);
+
+  *value = config_setting_get_string(s);
+
+  return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_lookup_int(const config_t *config, const char *path,
+                      int *value)
+{
+  const config_setting_t *s = config_lookup(config, path);
+  if(! s)
+    return(CONFIG_FALSE);
+
+  return(__config_setting_get_int(s, value));
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_lookup_int64(const config_t *config, const char *path,
+                        long long *value)
+{
+  const config_setting_t *s = config_lookup(config, path);
+  if(! s)
+    return(CONFIG_FALSE);
+
+  return(__config_setting_get_int64(s, value));
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_lookup_float(const config_t *config, const char *path,
+                        double *value)
+{
+  const config_setting_t *s = config_lookup(config, path);
+  if(! s)
+    return(CONFIG_FALSE);
+
+  return(__config_setting_get_float(s, value));
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_lookup_bool(const config_t *config, const char *path, int *value)
+{
+  const config_setting_t *s = config_lookup(config, path);
+  if(! s)
+    return(CONFIG_FALSE);
+
+  if(config_setting_type(s) != CONFIG_TYPE_BOOL)
+    return(CONFIG_FALSE);
+
+  *value = config_setting_get_bool(s);
+  return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_get_int_elem(const config_setting_t *vector, int idx)
+{
+  const config_setting_t *element = config_setting_get_elem(vector, idx);
+
+  return(element ? config_setting_get_int(element) : 0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_setting_set_int_elem(config_setting_t *vector,
+                                              int idx, int value)
+{
+  config_setting_t *element = NULL;
+
+  if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
+    return(NULL);
+
+  if(idx < 0)
+  {
+    if(! __config_vector_checktype(vector, CONFIG_TYPE_INT))
+      return(NULL);
+
+    element = config_setting_create(vector, NULL, CONFIG_TYPE_INT);
+  }
+  else
+  {
+    element = config_setting_get_elem(vector, idx);
+
+    if(! element)
+      return(NULL);
+  }
+
+  if(! config_setting_set_int(element, value))
+    return(NULL);
+
+  return(element);
+}
+
+/* ------------------------------------------------------------------------- */
+
+long long config_setting_get_int64_elem(const config_setting_t *vector,
+                                        int idx)
+{
+  const config_setting_t *element = config_setting_get_elem(vector, idx);
+
+  return(element ? config_setting_get_int64(element) : 0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_setting_set_int64_elem(config_setting_t *vector,
+                                                int idx, long long value)
+{
+  config_setting_t *element = NULL;
+
+  if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
+    return(NULL);
+
+  if(idx < 0)
+  {
+    if(! __config_vector_checktype(vector, CONFIG_TYPE_INT64))
+      return(NULL);
+
+    element = config_setting_create(vector, NULL, CONFIG_TYPE_INT64);
+  }
+  else
+  {
+    element = config_setting_get_elem(vector, idx);
+
+    if(! element)
+      return(NULL);
+  }
+
+  if(! config_setting_set_int64(element, value))
+    return(NULL);
+
+  return(element);
+}
+
+/* ------------------------------------------------------------------------- */
+
+double config_setting_get_float_elem(const config_setting_t *vector, int idx)
+{
+  config_setting_t *element = config_setting_get_elem(vector, idx);
+
+  return(element ? config_setting_get_float(element) : 0.0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_setting_set_float_elem(config_setting_t *vector,
+                                                int idx, double value)
+{
+  config_setting_t *element = NULL;
+
+  if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
+    return(NULL);
+
+  if(idx < 0)
+  {
+    if(! __config_vector_checktype(vector, CONFIG_TYPE_FLOAT))
+      return(NULL);
+
+    element = config_setting_create(vector, NULL, CONFIG_TYPE_FLOAT);
+  }
+  else
+    element = config_setting_get_elem(vector, idx);
+
+  if(! element)
+    return(NULL);
+
+  if(! config_setting_set_float(element, value))
+    return(NULL);
+
+  return(element);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_get_bool_elem(const config_setting_t *vector, int idx)
+{
+  config_setting_t *element = config_setting_get_elem(vector, idx);
+
+  if(! element)
+    return(CONFIG_FALSE);
+
+  if(element->type != CONFIG_TYPE_BOOL)
+    return(CONFIG_FALSE);
+
+  return(element->value.ival);
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_setting_set_bool_elem(config_setting_t *vector,
+                                               int idx, int value)
+{
+  config_setting_t *element = NULL;
+
+  if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
+    return(NULL);
+
+  if(idx < 0)
+  {
+    if(! __config_vector_checktype(vector, CONFIG_TYPE_BOOL))
+      return(NULL);
+
+    element = config_setting_create(vector, NULL, CONFIG_TYPE_BOOL);
+  }
+  else
+    element = config_setting_get_elem(vector, idx);
+
+  if(! element)
+    return(NULL);
+
+  if(! config_setting_set_bool(element, value))
+    return(NULL);
+
+  return(element);
+}
+
+/* ------------------------------------------------------------------------- */
+
+const char *config_setting_get_string_elem(const config_setting_t *vector,
+                                           int idx)
+{
+  config_setting_t *element = config_setting_get_elem(vector, idx);
+
+  if(! element)
+    return(NULL);
+
+  if(element->type != CONFIG_TYPE_STRING)
+    return(NULL);
+
+  return(element->value.sval);
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_setting_set_string_elem(config_setting_t *vector,
+                                                 int idx, const char *value)
+{
+  config_setting_t *element = NULL;
+
+  if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
+    return(NULL);
+
+  if(idx < 0)
+  {
+    if(! __config_vector_checktype(vector, CONFIG_TYPE_STRING))
+      return(NULL);
+
+    element = config_setting_create(vector, NULL, CONFIG_TYPE_STRING);
+  }
+  else
+    element = config_setting_get_elem(vector, idx);
+
+  if(! element)
+    return(NULL);
+
+  if(! config_setting_set_string(element, value))
+    return(NULL);
+
+  return(element);
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_setting_get_elem(const config_setting_t *vector,
+                                          unsigned int idx)
+{
+  config_list_t *list = vector->value.list;
+
+  if(((vector->type != CONFIG_TYPE_ARRAY)
+      && (vector->type != CONFIG_TYPE_LIST)
+      && (vector->type != CONFIG_TYPE_GROUP)) || ! list)
+    return(NULL);
+
+  if(idx >= list->length)
+    return(NULL);
+
+  return(list->elements[idx]);
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_setting_get_member(const config_setting_t *setting,
+                                            const char *name)
+{
+  if(setting->type != CONFIG_TYPE_GROUP)
+    return(NULL);
+
+  return(__config_list_search(setting->value.list, name, NULL));
+}
+
+/* ------------------------------------------------------------------------- */
+
+void config_set_destructor(config_t *config, void (*destructor)(void *))
+{
+  config->destructor = destructor;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void config_set_include_dir(config_t *config, const char *include_dir)
+{
+  _delete(config->include_dir);
+  config->include_dir = strdup(include_dir);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_length(const config_setting_t *setting)
+{
+  if((setting->type != CONFIG_TYPE_GROUP)
+     && (setting->type != CONFIG_TYPE_ARRAY)
+     && (setting->type != CONFIG_TYPE_LIST))
+    return(0);
+
+  if(! setting->value.list)
+    return(0);
+
+  return(setting->value.list->length);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void config_setting_set_hook(config_setting_t *setting, void *hook)
+{
+  setting->hook = hook;
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_setting_add(config_setting_t *parent,
+                                     const char *name, int type)
+{
+  if((type < CONFIG_TYPE_NONE) || (type > CONFIG_TYPE_LIST))
+    return(NULL);
+
+  if(! parent)
+    return(NULL);
+
+  if((parent->type == CONFIG_TYPE_ARRAY) || (parent->type == CONFIG_TYPE_LIST))
+    name = NULL;
+
+  if(name)
+  {
+    if(! __config_validate_name(name))
+      return(NULL);
+  }
+
+  if(config_setting_get_member(parent, name) != NULL)
+    return(NULL); /* already exists */
+
+  return(config_setting_create(parent, name, type));
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_remove(config_setting_t *parent, const char *name)
+{
+  unsigned int idx;
+  config_setting_t *setting;
+
+  if(! parent)
+    return(CONFIG_FALSE);
+
+  if(parent->type != CONFIG_TYPE_GROUP)
+    return(CONFIG_FALSE);
+
+  if(! (setting = __config_list_search(parent->value.list, name, &idx)))
+    return(CONFIG_FALSE);
+
+  __config_list_remove(parent->value.list, idx);
+  __config_setting_destroy(setting);
+
+  return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_remove_elem(config_setting_t *parent, unsigned int idx)
+{
+  config_list_t *list;
+  config_setting_t *removed = NULL;
+
+  if(! parent)
+    return(CONFIG_FALSE);
+
+  list = parent->value.list;
+
+  if(((parent->type != CONFIG_TYPE_ARRAY)
+      && (parent->type != CONFIG_TYPE_LIST)
+      && (parent->type != CONFIG_TYPE_GROUP)) || ! list)
+    return(CONFIG_FALSE);
+
+  if(idx >= list->length)
+    return(CONFIG_FALSE);
+
+  removed = __config_list_remove(list, idx);
+  __config_setting_destroy(removed);
+
+  return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_index(const config_setting_t *setting)
+{
+  config_setting_t **found = NULL;
+  config_list_t *list;
+  int i;
+
+  if(! setting->parent)
+    return(-1);
+
+  list = setting->parent->value.list;
+
+  for(i = 0, found = list->elements; i < (int)list->length; ++i, ++found)
+  {
+    if(*found == setting)
+      return(i);
+  }
+
+  return(-1);
+}
+
+/* ------------------------------------------------------------------------- */
+/* eof */

+ 320 - 0
3rdparty/libconfig/libconfig.h

@@ -0,0 +1,320 @@
+/* ----------------------------------------------------------------------------
+   libconfig - A library for processing structured configuration files
+   Copyright (C) 2005-2010  Mark A Lindner
+
+   This file is part of libconfig.
+
+   This library is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this library.  If not, see <http://www.gnu.org/licenses/>.
+   ----------------------------------------------------------------------------
+*/
+
+#ifndef __libconfig_h
+#define __libconfig_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
+#if defined(LIBCONFIG_STATIC)
+#define LIBCONFIG_API
+#elif defined(LIBCONFIG_EXPORTS)
+#define LIBCONFIG_API __declspec(dllexport)
+#else /* ! LIBCONFIG_EXPORTS */
+#define LIBCONFIG_API __declspec(dllimport)
+#endif /* LIBCONFIG_STATIC */
+#else /* ! WIN32 */
+#define LIBCONFIG_API
+#endif /* WIN32 */
+
+#define LIBCONFIG_VER_MAJOR    1
+#define LIBCONFIG_VER_MINOR    4
+#define LIBCONFIG_VER_REVISION 8
+
+#include <stdio.h>
+
+#define CONFIG_TYPE_NONE    0
+#define CONFIG_TYPE_GROUP   1
+#define CONFIG_TYPE_INT     2
+#define CONFIG_TYPE_INT64   3
+#define CONFIG_TYPE_FLOAT   4
+#define CONFIG_TYPE_STRING  5
+#define CONFIG_TYPE_BOOL    6
+#define CONFIG_TYPE_ARRAY   7
+#define CONFIG_TYPE_LIST    8
+
+#define CONFIG_FORMAT_DEFAULT  0
+#define CONFIG_FORMAT_HEX      1
+
+#define CONFIG_OPTION_AUTOCONVERT 0x01
+
+#define CONFIG_TRUE  (1)
+#define CONFIG_FALSE (0)
+
+typedef union config_value_t
+{
+  int ival;
+  long long llval;
+  double fval;
+  char *sval;
+  struct config_list_t *list;
+} config_value_t;
+
+typedef struct config_setting_t
+{
+  char *name;
+  short type;
+  short format;
+  config_value_t value;
+  struct config_setting_t *parent;
+  struct config_t *config;
+  void *hook;
+  unsigned int line;
+  const char *file;
+} config_setting_t;
+
+typedef enum
+{
+  CONFIG_ERR_NONE = 0,
+  CONFIG_ERR_FILE_IO = 1,
+  CONFIG_ERR_PARSE = 2
+} config_error_t;
+
+typedef struct config_list_t
+{
+  unsigned int length;
+  config_setting_t **elements;
+} config_list_t;
+
+typedef struct config_t
+{
+  config_setting_t *root;
+  void (*destructor)(void *);
+  unsigned short flags;
+  unsigned short tab_width;
+  short default_format;
+  const char *include_dir;
+  const char *error_text;
+  const char *error_file;
+  int error_line;
+  config_error_t error_type;
+  const char **filenames;
+  unsigned int num_filenames;
+} config_t;
+
+extern LIBCONFIG_API int config_read(config_t *config, FILE *stream);
+extern LIBCONFIG_API void config_write(const config_t *config, FILE *stream);
+
+extern LIBCONFIG_API void config_set_default_format(config_t *config,
+                                                    short format);
+
+extern LIBCONFIG_API void config_set_auto_convert(config_t *config, int flag);
+extern LIBCONFIG_API int config_get_auto_convert(const config_t *config);
+
+extern LIBCONFIG_API int config_read_string(config_t *config, const char *str);
+
+extern LIBCONFIG_API int config_read_file(config_t *config,
+                                          const char *filename);
+extern LIBCONFIG_API int config_write_file(config_t *config,
+                                           const char *filename);
+
+extern LIBCONFIG_API void config_set_destructor(config_t *config,
+                                                void (*destructor)(void *));
+extern LIBCONFIG_API void config_set_include_dir(config_t *config,
+                                                 const char *include_dir);
+
+extern LIBCONFIG_API void config_init(config_t *config);
+extern LIBCONFIG_API void config_destroy(config_t *config);
+
+extern LIBCONFIG_API int config_setting_get_int(
+  const config_setting_t *setting);
+extern LIBCONFIG_API long long config_setting_get_int64(
+  const config_setting_t *setting);
+extern LIBCONFIG_API double config_setting_get_float(
+  const config_setting_t *setting);
+extern LIBCONFIG_API int config_setting_get_bool(
+  const config_setting_t *setting);
+extern LIBCONFIG_API const char *config_setting_get_string(
+  const config_setting_t *setting);
+
+extern LIBCONFIG_API int config_setting_lookup_int(
+  const config_setting_t *setting, const char *name, int *value);
+extern LIBCONFIG_API int config_setting_lookup_int64(
+  const config_setting_t *setting, const char *name, long long *value);
+extern LIBCONFIG_API int config_setting_lookup_float(
+  const config_setting_t *setting, const char *name, double *value);
+extern LIBCONFIG_API int config_setting_lookup_bool(
+  const config_setting_t *setting, const char *name, int *value);
+extern LIBCONFIG_API int config_setting_lookup_string(
+  const config_setting_t *setting, const char *name, const char **value);
+
+extern LIBCONFIG_API int config_setting_set_int(config_setting_t *setting,
+                                                int value);
+extern LIBCONFIG_API int config_setting_set_int64(config_setting_t *setting,
+                                                  long long value);
+extern LIBCONFIG_API int config_setting_set_float(config_setting_t *setting,
+                                                  double value);
+extern LIBCONFIG_API int config_setting_set_bool(config_setting_t *setting,
+                                                 int value);
+extern LIBCONFIG_API int config_setting_set_string(config_setting_t *setting,
+                                                   const char *value);
+
+extern LIBCONFIG_API int config_setting_set_format(config_setting_t *setting,
+                                                   short format);
+extern LIBCONFIG_API short config_setting_get_format(
+  const config_setting_t *setting);
+
+extern LIBCONFIG_API int config_setting_get_int_elem(
+  const config_setting_t *setting, int idx);
+extern LIBCONFIG_API long long config_setting_get_int64_elem(
+  const config_setting_t *setting, int idx);
+extern LIBCONFIG_API double config_setting_get_float_elem(
+  const config_setting_t *setting, int idx);
+extern LIBCONFIG_API int config_setting_get_bool_elem(
+  const config_setting_t *setting, int idx);
+extern LIBCONFIG_API const char *config_setting_get_string_elem(
+  const config_setting_t *setting, int idx);
+
+extern LIBCONFIG_API config_setting_t *config_setting_set_int_elem(
+  config_setting_t *setting, int idx, int value);
+extern LIBCONFIG_API config_setting_t *config_setting_set_int64_elem(
+  config_setting_t *setting, int idx, long long value);
+extern LIBCONFIG_API config_setting_t *config_setting_set_float_elem(
+  config_setting_t *setting, int idx, double value);
+extern LIBCONFIG_API config_setting_t *config_setting_set_bool_elem(
+  config_setting_t *setting, int idx, int value);
+extern LIBCONFIG_API config_setting_t *config_setting_set_string_elem(
+  config_setting_t *setting, int idx, const char *value);
+
+#define /* const char * */ config_get_include_dir(/* const config_t * */ C) \
+  ((C)->include_dir)
+
+#define /* int */ config_setting_type(/* const config_setting_t * */ S) \
+  ((S)->type)
+
+#define /* int */ config_setting_is_group(/* const config_setting_t * */ S) \
+  ((S)->type == CONFIG_TYPE_GROUP)
+#define /* int */ config_setting_is_array(/* const config_setting_t * */ S) \
+  ((S)->type == CONFIG_TYPE_ARRAY)
+#define /* int */ config_setting_is_list(/* const config_setting_t * */ S) \
+  ((S)->type == CONFIG_TYPE_LIST)
+
+#define /* int */ config_setting_is_aggregate( \
+  /* const config_setting_t * */ S)                                     \
+  (((S)->type == CONFIG_TYPE_GROUP) || ((S)->type == CONFIG_TYPE_LIST)  \
+   || ((S)->type == CONFIG_TYPE_ARRAY))
+
+#define /* int */ config_setting_is_number(/* const config_setting_t * */ S) \
+  (((S)->type == CONFIG_TYPE_INT)                                       \
+   || ((S)->type == CONFIG_TYPE_INT64)                                  \
+   || ((S)->type == CONFIG_TYPE_FLOAT))
+
+#define /* int */ config_setting_is_scalar(/* const config_setting_t * */ S) \
+  (((S)->type == CONFIG_TYPE_BOOL) || ((S)->type == CONFIG_TYPE_STRING) \
+   || config_setting_is_number(S))
+
+#define /* const char * */ config_setting_name( \
+  /* const config_setting_t * */ S)             \
+  ((S)->name)
+
+#define /* config_setting_t * */ config_setting_parent( \
+  /* const config_setting_t * */ S)                     \
+  ((S)->parent)
+
+#define /* int */ config_setting_is_root(       \
+  /* const config_setting_t * */ S)             \
+  ((S)->parent ? CONFIG_FALSE : CONFIG_TRUE)
+
+extern LIBCONFIG_API int config_setting_index(const config_setting_t *setting);
+
+extern LIBCONFIG_API int config_setting_length(
+  const config_setting_t *setting);
+extern LIBCONFIG_API config_setting_t *config_setting_get_elem(
+  const config_setting_t *setting, unsigned int idx);
+
+extern LIBCONFIG_API config_setting_t *config_setting_get_member(
+  const config_setting_t *setting, const char *name);
+
+extern LIBCONFIG_API config_setting_t *config_setting_add(
+  config_setting_t *parent, const char *name, int type);
+extern LIBCONFIG_API int config_setting_remove(config_setting_t *parent,
+                                               const char *name);
+extern LIBCONFIG_API int config_setting_remove_elem(config_setting_t *parent,
+                                                    unsigned int idx);
+extern LIBCONFIG_API void config_setting_set_hook(config_setting_t *setting,
+                                                  void *hook);
+
+#define config_setting_get_hook(S) ((S)->hook)
+
+extern LIBCONFIG_API config_setting_t *config_lookup(const config_t *config,
+                                                     const char *path);
+extern LIBCONFIG_API config_setting_t *config_lookup_from(
+  config_setting_t *setting, const char *path);
+
+extern LIBCONFIG_API int config_lookup_int(const config_t *config,
+                                           const char *path, int *value);
+extern LIBCONFIG_API int config_lookup_int64(const config_t *config,
+                                             const char *path,
+                                             long long *value);
+extern LIBCONFIG_API int config_lookup_float(const config_t *config,
+                                             const char *path, double *value);
+extern LIBCONFIG_API int config_lookup_bool(const config_t *config,
+                                            const char *path, int *value);
+extern LIBCONFIG_API int config_lookup_string(const config_t *config,
+                                              const char *path,
+                                              const char **value);
+
+#define /* config_setting_t * */ config_root_setting( \
+  /* const config_t * */ C)                           \
+  ((C)->root)
+
+#define  /* void */ config_set_default_format(/* config_t * */ C,       \
+                                              /* short */ F)            \
+  (C)->default_format = (F)
+
+#define /* short */ config_get_default_format(/* config_t * */ C)       \
+  ((C)->default_format)
+
+#define /* void */ config_set_tab_width(/* config_t * */ C,     \
+                                        /* unsigned short */ W) \
+  (C)->tab_width = ((W) & 0x0F)
+
+#define /* unsigned char */ config_get_tab_width(/* const config_t * */ C) \
+  ((C)->tab_width)
+
+#define /* unsigned short */ config_setting_source_line(   \
+  /* const config_setting_t * */ S)                        \
+  ((S)->line)
+
+#define /* const char */ config_setting_source_file(    \
+  /* const config_setting_t * */ S)                     \
+  ((S)->file)
+
+#define /* const char * */ config_error_text(/* const config_t * */ C)  \
+  ((C)->error_text)
+
+#define /* const char * */ config_error_file(/* const config_t * */ C)  \
+  ((C)->error_file)
+
+#define /* int */ config_error_line(/* const config_t * */ C)   \
+  ((C)->error_line)
+
+#define /* config_error_t */ config_error_type(/* const config_t * */ C) \
+  ((C)->error_type)
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __libconfig_h */

+ 47 - 0
3rdparty/libconfig/parsectx.h

@@ -0,0 +1,47 @@
+/* ----------------------------------------------------------------------------
+   libconfig - A library for processing structured configuration files
+   Copyright (C) 2005-2010  Mark A Lindner
+
+   This file is part of libconfig.
+
+   This library is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this library.  If not, see <http://www.gnu.org/licenses/>.
+   ----------------------------------------------------------------------------
+*/
+
+#ifndef __libconfig_parsectx_h
+#define __libconfig_parsectx_h
+
+#include "libconfig.h"
+#include "strbuf.h"
+
+struct parse_context
+{
+  config_t *config;
+  config_setting_t *parent;
+  config_setting_t *setting;
+  char *name;
+  strbuf_t string;
+};
+
+#define parsectx_init(C)                        \
+  memset((C), 0, sizeof(struct parse_context))
+#define parsectx_cleanup(C)                             \
+  free((void *)(strbuf_release(&((C)->string))))
+
+#define parsectx_append_string(C, S)            \
+  strbuf_append(&((C)->string), (S))
+#define parsectx_take_string(C)                 \
+  strbuf_release(&((C)->string))
+
+#endif /* __libconfig_parsectx_h */

+ 170 - 0
3rdparty/libconfig/scanctx.c

@@ -0,0 +1,170 @@
+/* ----------------------------------------------------------------------------
+   libconfig - A library for processing structured configuration files
+   Copyright (C) 2005-2010  Mark A Lindner
+
+   This file is part of libconfig.
+
+   This library is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this library.  If not, see <http://www.gnu.org/licenses/>.
+   ----------------------------------------------------------------------------
+*/
+
+#include "scanctx.h"
+#include "wincompat.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define STRING_BLOCK_SIZE 64
+#define CHUNK_SIZE 32
+
+/* ------------------------------------------------------------------------- */
+
+static const char *err_bad_include = "cannot open include file";
+static const char *err_include_too_deep = "include file nesting too deep";
+
+/* ------------------------------------------------------------------------- */
+
+static const char *__scanctx_add_filename(struct scan_context *ctx,
+                                          const char *filename)
+{
+  unsigned int count = ctx->num_filenames;
+  const char **f;
+
+  for(f = ctx->filenames; count > 0; ++f, --count)
+  {
+    if(!strcmp(*f, filename))
+    {
+      free((void *)filename);
+      return(*f); /* already in list */
+    }
+  }
+
+  if((ctx->num_filenames % CHUNK_SIZE) == 0)
+  {
+    ctx->filenames = (const char **)realloc(
+      (void *)ctx->filenames,
+      (ctx->num_filenames + CHUNK_SIZE) * sizeof(const char *));
+  }
+
+  ctx->filenames[ctx->num_filenames] = filename;
+  ++ctx->num_filenames;
+  return(filename);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void scanctx_init(struct scan_context *ctx, const char *top_filename)
+{
+  memset(ctx, 0, sizeof(struct scan_context));
+  if(top_filename)
+    ctx->top_filename = __scanctx_add_filename(ctx, strdup(top_filename));
+}
+
+/* ------------------------------------------------------------------------- */
+
+const char **scanctx_cleanup(struct scan_context *ctx,
+                             unsigned int *num_filenames)
+{
+  int i;
+
+  for(i = 0; i < ctx->depth; ++i)
+    fclose(ctx->streams[i]);
+
+  free((void *)(strbuf_release(&(ctx->string))));
+
+  *num_filenames = ctx->num_filenames;
+  return(ctx->filenames);
+}
+
+/* ------------------------------------------------------------------------- */
+
+FILE *scanctx_push_include(struct scan_context *ctx, void *buffer,
+                           const char **error)
+{
+  FILE *fp = NULL;
+  const char *file;
+  char *full_file = NULL;
+
+  *error = NULL;
+
+  if(ctx->depth == MAX_INCLUDE_DEPTH)
+  {
+    *error = err_include_too_deep;
+    return(NULL);
+  }
+
+  file = scanctx_take_string(ctx);
+  if(ctx->config->include_dir)
+  {
+    full_file = (char *)malloc(strlen(ctx->config->include_dir) + strlen(file)
+                               + 2);
+    strcpy(full_file, ctx->config->include_dir);
+    strcat(full_file, FILE_SEPARATOR);
+    strcat(full_file, file);
+  }
+
+  fp = fopen(full_file ? full_file : file, "rt");
+  free((void *)full_file);
+
+  if(fp)
+  {
+    ctx->streams[ctx->depth] = fp;
+    ctx->files[ctx->depth] = __scanctx_add_filename(ctx, file);
+    ctx->buffers[ctx->depth] = buffer;
+    ++(ctx->depth);
+  }
+  else
+  {
+    free((void *)file);
+    *error = err_bad_include;
+  }
+
+  return(fp);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void *scanctx_pop_include(struct scan_context *ctx)
+{
+  void *buffer;
+
+  if(ctx->depth == 0)
+    return(NULL); /* stack underflow */
+
+  --(ctx->depth);
+  buffer = ctx->buffers[ctx->depth];
+  fclose(ctx->streams[ctx->depth]);
+
+  return(buffer);
+}
+
+/* ------------------------------------------------------------------------- */
+
+char *scanctx_take_string(struct scan_context *ctx)
+{
+  char *r = strbuf_release(&(ctx->string));
+
+  return(r ? r : strdup(""));
+}
+
+/* ------------------------------------------------------------------------- */
+
+const char *scanctx_current_filename(struct scan_context *ctx)
+{
+  return((ctx->depth == 0) ? ctx->top_filename : ctx->files[ctx->depth - 1]);
+}
+
+/* ------------------------------------------------------------------------- */
+/* eof */

+ 61 - 0
3rdparty/libconfig/scanctx.h

@@ -0,0 +1,61 @@
+/* ----------------------------------------------------------------------------
+   libconfig - A library for processing structured configuration files
+   Copyright (C) 2005-2010  Mark A Lindner
+
+   This file is part of libconfig.
+
+   This library is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this library.  If not, see <http://www.gnu.org/licenses/>.
+   ----------------------------------------------------------------------------
+*/
+
+#ifndef __libconfig_scanctx_h
+#define __libconfig_scanctx_h
+
+#include "libconfig.h"
+#include "strbuf.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#define MAX_INCLUDE_DEPTH 10
+
+struct scan_context
+{
+  config_t *config;
+  const char *top_filename;
+  const char *files[MAX_INCLUDE_DEPTH];
+  void *buffers[MAX_INCLUDE_DEPTH];
+  FILE *streams[MAX_INCLUDE_DEPTH];
+  int depth;
+  strbuf_t string;
+  const char **filenames;
+  unsigned int num_filenames;
+};
+
+extern void scanctx_init(struct scan_context *ctx, const char *top_filename);
+extern const char **scanctx_cleanup(struct scan_context *ctx,
+                                    unsigned int *num_filenames);
+
+extern FILE *scanctx_push_include(struct scan_context *ctx, void *prev_buffer,
+                                  const char **error);
+extern void *scanctx_pop_include(struct scan_context *ctx);
+
+#define scanctx_append_string(C, S)             \
+  strbuf_append(&((C)->string), (S))
+
+extern char *scanctx_take_string(struct scan_context *ctx);
+
+extern const char *scanctx_current_filename(struct scan_context *ctx);
+
+#endif /* __libconfig_scanctx_h */

+ 2362 - 0
3rdparty/libconfig/scanner.c

@@ -0,0 +1,2362 @@
+#line 2 "scanner.c"
+
+#line 4 "scanner.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+   are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE libconfig_yyrestart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
+     *       access to the local variable yy_act. Since yyless() is a macro, it would break
+     *       existing scanners that call yyless() from OUTSIDE libconfig_yylex. 
+     *       One obvious solution it to make yy_act a global. I tried that, and saw
+     *       a 5% performance hit in a non-yylineno scanner, because yy_act is
+     *       normally declared as a register variable-- so it is not worth it.
+     */
+    #define  YY_LESS_LINENO(n) \
+            do { \
+                int yyl;\
+                for ( yyl = n; yyl < yyleng; ++yyl )\
+                    if ( yytext[yyl] == '\n' )\
+                        --yylineno;\
+            }while(0)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = yyg->yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via libconfig_yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+                          ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void libconfig_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void libconfig_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE libconfig_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void libconfig_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void libconfig_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void libconfig_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void libconfig_yypop_buffer_state (yyscan_t yyscanner );
+
+static void libconfig_yyensure_buffer_stack (yyscan_t yyscanner );
+static void libconfig_yy_load_buffer_state (yyscan_t yyscanner );
+static void libconfig_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER libconfig_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE libconfig_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE libconfig_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE libconfig_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
+
+void *libconfig_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *libconfig_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void libconfig_yyfree (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer libconfig_yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        libconfig_yyensure_buffer_stack (yyscanner); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            libconfig_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        libconfig_yyensure_buffer_stack (yyscanner); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            libconfig_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+#define libconfig_yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	yyg->yytext_ptr = yy_bp; \
+	yyleng = (size_t) (yy_cp - yy_bp); \
+	yyg->yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 41
+#define YY_END_OF_BUFFER 42
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_accept[103] =
+    {   0,
+        0,    0,    0,    0,    0,    0,    0,    0,   42,   40,
+       21,   20,   20,    5,   40,   36,   37,   28,   40,   23,
+       29,   40,   30,   30,   22,   38,   28,   28,   34,   35,
+       24,   25,   21,   40,    3,    4,    3,    6,   14,   41,
+       16,   19,   41,   21,    0,   39,   28,   29,   30,   29,
+        0,    1,    0,   29,    0,   31,    0,   28,   28,   21,
+        0,    0,    2,    6,   12,    0,   11,   10,    7,    8,
+        9,   16,   18,   17,    0,   29,   29,    0,    0,   29,
+       31,   32,   28,   28,    0,    0,    0,   29,   33,   28,
+       26,    0,   13,   33,   27,    0,    0,    0,    0,    0,
+
+       15,    0
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    4,    5,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    1,    6,    7,    1,    1,    1,    1,    8,
+        9,   10,   11,   12,   13,   14,   15,   16,   17,   17,
+       17,   17,   17,   17,   17,   17,   17,   18,   19,    1,
+       20,    1,    1,   21,   22,   23,   23,   23,   24,   25,
+       26,   26,   26,   26,   26,   27,   26,   26,   26,   26,
+       26,   28,   29,   30,   31,   26,   26,   32,   26,   26,
+       33,   34,   35,    1,   36,    1,   22,   23,   37,   38,
+
+       39,   40,   26,   26,   41,   26,   26,   42,   26,   43,
+       26,   26,   26,   44,   29,   45,   46,   26,   26,   32,
+       26,   26,   47,    1,   48,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst flex_int32_t yy_meta[49] =
+    {   0,
+        1,    1,    1,    1,    1,    2,    1,    1,    1,    3,
+        1,    1,    3,    1,    1,    4,    4,    1,    1,    1,
+        1,    4,    4,    4,    4,    3,    3,    3,    3,    3,
+        3,    3,    1,    2,    1,    3,    4,    4,    4,    4,
+        3,    3,    3,    3,    3,    3,    1,    1
+    } ;
+
+static yyconst flex_int16_t yy_base[113] =
+    {   0,
+        0,   47,   47,   48,   46,   47,   48,   49,  203,  204,
+      200,  204,  204,  204,  198,  204,  204,    0,   45,  204,
+       47,   50,   60,   74,  204,  204,  178,   28,  204,  204,
+      204,  204,   64,  158,  204,  204,  183,    0,  204,   63,
+        0,  204,   83,  195,  193,  204,    0,   88,  102,   98,
+       62,  204,  190,  104,  119,  162,    0,   67,   65,  121,
+      127,  124,  204,    0,  204,    0,  204,  204,  204,  204,
+      204,    0,  204,  204,  108,  117,  122,  134,  132,  136,
+      204,  139,  136,  116,  126,    0,  140,  142,  135,  130,
+        0,  102,  204,  204,    0,   85,   72,   63,   98,  158,
+
+      204,  204,  169,  173,  177,  181,  183,  187,  191,   89,
+       66,   63
+    } ;
+
+static yyconst flex_int16_t yy_def[113] =
+    {   0,
+      102,    1,  103,  103,  104,  104,  105,  105,  102,  102,
+      102,  102,  102,  102,  106,  102,  102,  107,  102,  102,
+      102,  102,  102,  102,  102,  102,  107,  107,  102,  102,
+      102,  102,  102,  102,  102,  102,  102,  108,  102,  102,
+      109,  102,  102,  102,  106,  102,  107,  102,  102,  102,
+      102,  102,  106,  102,  102,  102,  110,  107,  107,  102,
+      102,  102,  102,  108,  102,  111,  102,  102,  102,  102,
+      102,  109,  102,  102,  102,  102,  102,  102,  102,  102,
+      102,  110,  107,  107,  102,  112,  102,  102,  102,  107,
+      107,  102,  102,  102,  107,  102,  102,  102,  102,  102,
+
+      102,    0,  102,  102,  102,  102,  102,  102,  102,  102,
+      102,  102
+    } ;
+
+static yyconst flex_int16_t yy_nxt[253] =
+    {   0,
+       10,   11,   12,   13,   13,   14,   15,   16,   17,   18,
+       19,   20,   19,   21,   22,   23,   24,   25,   26,   25,
+       10,   18,   18,   18,   27,   18,   18,   18,   18,   28,
+       18,   18,   29,   10,   30,   10,   18,   18,   18,   27,
+       18,   18,   18,   18,   28,   18,   31,   32,   33,   36,
+       36,   39,   39,   42,   42,   59,   37,   37,   48,   52,
+       49,   49,   50,   50,   53,   60,   93,   34,   65,   86,
+       51,   59,   75,   54,   75,   49,   49,   76,   76,   40,
+       40,   43,   43,   55,   61,   51,   56,   54,   73,   49,
+       49,   57,   82,   83,   66,   84,   67,   55,   55,  100,
+
+       56,   99,   68,   50,   50,   69,   70,   71,   83,   98,
+       84,   51,   55,   50,   50,   54,   74,   49,   49,   77,
+       77,   51,   60,   76,   76,   55,   51,   78,   56,   79,
+       97,   79,   76,   76,   80,   80,   51,   77,   77,   91,
+       55,   61,   78,   96,   87,   78,   87,   80,   80,   88,
+       88,   80,   80,   95,   91,   88,   88,   88,   88,  100,
+       78,   94,   92,  101,   90,   89,   85,   62,   95,   35,
+       35,   35,   35,   38,   38,   38,   38,   41,   41,   41,
+       41,   45,   45,   45,   45,   47,   47,   64,   81,   64,
+       64,   72,   46,   72,   72,   46,   44,   63,   62,   58,
+
+       46,   44,  102,    9,  102,  102,  102,  102,  102,  102,
+      102,  102,  102,  102,  102,  102,  102,  102,  102,  102,
+      102,  102,  102,  102,  102,  102,  102,  102,  102,  102,
+      102,  102,  102,  102,  102,  102,  102,  102,  102,  102,
+      102,  102,  102,  102,  102,  102,  102,  102,  102,  102,
+      102,  102
+    } ;
+
+static yyconst flex_int16_t yy_chk[253] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        4,    5,    6,    7,    8,   28,    3,    4,   19,   22,
+       19,   19,   21,   21,   22,   33,  112,    2,   40,  111,
+       21,   28,   51,   23,   51,   23,   23,   51,   51,    5,
+        6,    7,    8,   23,   33,   21,   23,   24,   43,   24,
+       24,   23,  110,   58,   40,   59,   40,   24,   23,   99,
+
+       24,   98,   40,   48,   48,   40,   40,   40,   58,   97,
+       59,   48,   24,   50,   50,   49,   43,   49,   49,   54,
+       54,   50,   60,   75,   75,   49,   48,   54,   49,   55,
+       96,   55,   76,   76,   55,   55,   50,   77,   77,   84,
+       49,   60,   54,   92,   78,   77,   78,   79,   79,   78,
+       78,   80,   80,   90,   84,   87,   87,   88,   88,  100,
+       77,   89,   85,  100,   83,   82,   62,   61,   90,  103,
+      103,  103,  103,  104,  104,  104,  104,  105,  105,  105,
+      105,  106,  106,  106,  106,  107,  107,  108,   56,  108,
+      108,  109,   53,  109,  109,   45,   44,   37,   34,   27,
+
+       15,   11,    9,  102,  102,  102,  102,  102,  102,  102,
+      102,  102,  102,  102,  102,  102,  102,  102,  102,  102,
+      102,  102,  102,  102,  102,  102,  102,  102,  102,  102,
+      102,  102,  102,  102,  102,  102,  102,  102,  102,  102,
+      102,  102,  102,  102,  102,  102,  102,  102,  102,  102,
+      102,  102
+    } ;
+
+/* Table of booleans, true if rule could match eol. */
+static yyconst flex_int32_t yy_rule_can_match_eol[42] =
+    {   0,
+0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 
+    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0,     };
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "scanner.l"
+/* -*- mode: C -*- */
+/* --------------------------------------------------------------------------
+   libconfig - A library for processing structured configuration files
+   Copyright (C) 2005-2010  Mark A Lindner
+
+   This file is part of libconfig.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, see
+   <http://www.gnu.org/licenses/>.
+   ----------------------------------------------------------------------------
+*/
+#define YY_NO_UNISTD_H 1
+#line 35 "scanner.l"
+
+#ifdef _MSC_VER
+#pragma warning (disable: 4996)
+#endif
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "grammar.h"
+#include "wincompat.h"
+#include "parsectx.h"
+#include "scanctx.h"
+
+#define YY_NO_INPUT // Suppress generation of useless input() function
+
+static unsigned long long fromhex(const char *s)
+{
+#ifdef __MINGW32__
+
+  /* MinGW's strtoull() seems to be broken; it only returns the lower
+   * 32 bits...
+   */
+
+  const char *p = s;
+  unsigned long long val = 0;
+
+  if(*p != '0')
+    return(0);
+
+  ++p;
+
+  if(*p != 'x' && *p != 'X')
+    return(0);
+
+  for(++p; isxdigit(*p); ++p)
+  {
+    val <<= 4;
+    val |= ((*p < 'A') ? (*p & 0xF) : (9 + (*p & 0x7)));
+  }
+
+  return(val);
+
+#else /* ! __MINGW32__ */
+
+  return(strtoull(s, NULL, 16));
+
+#endif /* __MINGW32__ */
+}
+
+
+#line 626 "scanner.c"
+
+#define INITIAL 0
+#define COMMENT 1
+#define STRING 2
+#define INCLUDE 3
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#define YY_EXTRA_TYPE struct scan_context *
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+    {
+
+    /* User-defined. Not touched by flex. */
+    YY_EXTRA_TYPE yyextra_r;
+
+    /* The rest are the same as the globals declared in the non-reentrant scanner. */
+    FILE *yyin_r, *yyout_r;
+    size_t yy_buffer_stack_top; /**< index of top of stack. */
+    size_t yy_buffer_stack_max; /**< capacity of stack. */
+    YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+    char yy_hold_char;
+    int yy_n_chars;
+    int yyleng_r;
+    char *yy_c_buf_p;
+    int yy_init;
+    int yy_start;
+    int yy_did_buffer_switch_on_eof;
+    int yy_start_stack_ptr;
+    int yy_start_stack_depth;
+    int *yy_start_stack;
+    yy_state_type yy_last_accepting_state;
+    char* yy_last_accepting_cpos;
+
+    int yylineno_r;
+    int yy_flex_debug_r;
+
+    char *yytext_r;
+    int yy_more_flag;
+    int yy_more_len;
+
+    YYSTYPE * yylval_r;
+
+    }; /* end struct yyguts_t */
+
+static int yy_init_globals (yyscan_t yyscanner );
+
+    /* This must go here because YYSTYPE and YYLTYPE are included
+     * from bison output in section 1.*/
+    #    define yylval yyg->yylval_r
+    
+int libconfig_yylex_init (yyscan_t* scanner);
+
+int libconfig_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int libconfig_yylex_destroy (yyscan_t yyscanner );
+
+int libconfig_yyget_debug (yyscan_t yyscanner );
+
+void libconfig_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE libconfig_yyget_extra (yyscan_t yyscanner );
+
+void libconfig_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *libconfig_yyget_in (yyscan_t yyscanner );
+
+void libconfig_yyset_in  (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *libconfig_yyget_out (yyscan_t yyscanner );
+
+void libconfig_yyset_out  (FILE * out_str ,yyscan_t yyscanner );
+
+int libconfig_yyget_leng (yyscan_t yyscanner );
+
+char *libconfig_yyget_text (yyscan_t yyscanner );
+
+int libconfig_yyget_lineno (yyscan_t yyscanner );
+
+void libconfig_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+YYSTYPE * libconfig_yyget_lval (yyscan_t yyscanner );
+
+void libconfig_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int libconfig_yywrap (yyscan_t yyscanner );
+#else
+extern int libconfig_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		size_t n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(yyin); \
+			} \
+		}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int libconfig_yylex \
+               (YYSTYPE * yylval_param ,yyscan_t yyscanner);
+
+#define YY_DECL int libconfig_yylex \
+               (YYSTYPE * yylval_param , yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	if ( yyleng > 0 ) \
+		YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \
+				(yytext[yyleng - 1] == '\n'); \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+#line 100 "scanner.l"
+
+
+#line 869 "scanner.c"
+
+    yylval = yylval_param;
+
+	if ( !yyg->yy_init )
+		{
+		yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! yyg->yy_start )
+			yyg->yy_start = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = stdin;
+
+		if ( ! yyout )
+			yyout = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			libconfig_yyensure_buffer_stack (yyscanner);
+			YY_CURRENT_BUFFER_LVALUE =
+				libconfig_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+		}
+
+		libconfig_yy_load_buffer_state(yyscanner );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = yyg->yy_c_buf_p;
+
+		/* Support of yytext. */
+		*yy_cp = yyg->yy_hold_char;
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yyg->yy_start;
+		yy_current_state += YY_AT_BOL();
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				yyg->yy_last_accepting_state = yy_current_state;
+				yyg->yy_last_accepting_cpos = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 103 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 204 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = yyg->yy_last_accepting_cpos;
+			yy_current_state = yyg->yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+		if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+			{
+			int yyl;
+			for ( yyl = 0; yyl < yyleng; ++yyl )
+				if ( yytext[yyl] == '\n' )
+					   
+    do{ yylineno++;
+        yycolumn=0;
+    }while(0)
+;
+			}
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = yyg->yy_hold_char;
+			yy_cp = yyg->yy_last_accepting_cpos;
+			yy_current_state = yyg->yy_last_accepting_state;
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 102 "scanner.l"
+{ BEGIN COMMENT; }
+	YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 103 "scanner.l"
+{ BEGIN INITIAL; }
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 104 "scanner.l"
+{ /* ignore */ }
+	YY_BREAK
+case 4:
+/* rule 4 can match eol */
+YY_RULE_SETUP
+#line 105 "scanner.l"
+{ /* ignore */ }
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 107 "scanner.l"
+{ BEGIN STRING; }
+	YY_BREAK
+case 6:
+/* rule 6 can match eol */
+YY_RULE_SETUP
+#line 108 "scanner.l"
+{ scanctx_append_string(yyextra, yytext); }
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 109 "scanner.l"
+{ scanctx_append_string(yyextra, "\n"); }
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 110 "scanner.l"
+{ scanctx_append_string(yyextra, "\r"); }
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 111 "scanner.l"
+{ scanctx_append_string(yyextra, "\t"); }
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 112 "scanner.l"
+{ scanctx_append_string(yyextra, "\f"); }
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 113 "scanner.l"
+{ scanctx_append_string(yyextra, "\\"); }
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 114 "scanner.l"
+{ scanctx_append_string(yyextra, "\""); }
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 115 "scanner.l"
+{
+                    char c[2] = { (char)(strtol(yytext + 2, NULL, 16) & 0xFF),
+                                  0 };
+                    scanctx_append_string(yyextra, c);
+                  }
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 120 "scanner.l"
+{
+                    yylval->sval = scanctx_take_string(yyextra);
+                    BEGIN INITIAL;
+                    return(TOK_STRING);
+                  }
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 126 "scanner.l"
+{ BEGIN INCLUDE; }
+	YY_BREAK
+case 16:
+/* rule 16 can match eol */
+YY_RULE_SETUP
+#line 127 "scanner.l"
+{ scanctx_append_string(yyextra, yytext); }
+	YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 128 "scanner.l"
+{ scanctx_append_string(yyextra, "\\"); }
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 129 "scanner.l"
+{ scanctx_append_string(yyextra, "\""); }
+	YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 130 "scanner.l"
+{
+                    const char *error;
+                    FILE *fp = scanctx_push_include(yyextra,
+                                                    (void *)YY_CURRENT_BUFFER,
+                                                    &error);
+                    if(fp)
+                    {
+                      yyin = fp;
+                      libconfig_yy_switch_to_buffer(libconfig_yy_create_buffer(yyin,YY_BUF_SIZE,yyscanner),yyscanner);
+                    }
+                    else
+                    {
+                      yyextra->config->error_text = error;
+                      yyextra->config->error_file = scanctx_current_filename(
+                        yyextra);
+                      yyextra->config->error_line = libconfig_yyget_lineno(
+                        yyscanner);
+                      return TOK_ERROR;
+                    }
+                    BEGIN INITIAL;
+                  }
+	YY_BREAK
+case 20:
+/* rule 20 can match eol */
+YY_RULE_SETUP
+#line 154 "scanner.l"
+{ /* ignore */ }
+	YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 155 "scanner.l"
+{ /* ignore */ }
+	YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 157 "scanner.l"
+{ return(TOK_EQUALS); }
+	YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 158 "scanner.l"
+{ return(TOK_COMMA); }
+	YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 159 "scanner.l"
+{ return(TOK_GROUP_START); }
+	YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 160 "scanner.l"
+{ return(TOK_GROUP_END); }
+	YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 161 "scanner.l"
+{ yylval->ival = 1; return(TOK_BOOLEAN); }
+	YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 162 "scanner.l"
+{ yylval->ival = 0; return(TOK_BOOLEAN); }
+	YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 163 "scanner.l"
+{ yylval->sval = yytext; return(TOK_NAME); }
+	YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 164 "scanner.l"
+{ yylval->fval = atof(yytext); return(TOK_FLOAT); }
+	YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 165 "scanner.l"
+{ yylval->ival = atoi(yytext); return(TOK_INTEGER); }
+	YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 166 "scanner.l"
+{ yylval->llval = atoll(yytext); return(TOK_INTEGER64); }
+	YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 167 "scanner.l"
+{
+                    yylval->ival = strtoul(yytext, NULL, 16);
+                    return(TOK_HEX);
+                  }
+	YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 171 "scanner.l"
+{ yylval->llval = fromhex(yytext); return(TOK_HEX64); }
+	YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 172 "scanner.l"
+{ return(TOK_ARRAY_START); }
+	YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 173 "scanner.l"
+{ return(TOK_ARRAY_END); }
+	YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 174 "scanner.l"
+{ return(TOK_LIST_START); }
+	YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 175 "scanner.l"
+{ return(TOK_LIST_END); }
+	YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 176 "scanner.l"
+{ return(TOK_SEMICOLON); }
+	YY_BREAK
+case 39:
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 177 "scanner.l"
+{ /* ignore */ }
+	YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 178 "scanner.l"
+{ return(TOK_GARBAGE); }
+	YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(COMMENT):
+case YY_STATE_EOF(STRING):
+case YY_STATE_EOF(INCLUDE):
+#line 180 "scanner.l"
+{
+                    YY_BUFFER_STATE buf = (YY_BUFFER_STATE)scanctx_pop_include(
+                      yyextra);
+                    if(buf)
+                    {
+                      libconfig_yy_delete_buffer(YY_CURRENT_BUFFER,yyscanner);
+                      libconfig_yy_switch_to_buffer(buf,yyscanner);
+                    }
+                    else
+                      yyterminate();
+                  }
+	YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 191 "scanner.l"
+ECHO;
+	YY_BREAK
+#line 1227 "scanner.c"
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = yyg->yy_hold_char;
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * libconfig_yylex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state( yyscanner );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+			yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++yyg->yy_c_buf_p;
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = yyg->yy_c_buf_p;
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer( yyscanner ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				yyg->yy_did_buffer_switch_on_eof = 0;
+
+				if ( libconfig_yywrap(yyscanner ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! yyg->yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yyg->yy_c_buf_p =
+					yyg->yytext_ptr + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state( yyscanner );
+
+				yy_cp = yyg->yy_c_buf_p;
+				yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				yyg->yy_c_buf_p =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+				yy_current_state = yy_get_previous_state( yyscanner );
+
+				yy_cp = yyg->yy_c_buf_p;
+				yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of libconfig_yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = yyg->yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+	else
+		{
+			int num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+			int yy_c_buf_p_offset =
+				(int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					libconfig_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			yyg->yy_n_chars, (size_t) num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	if ( yyg->yy_n_chars == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			libconfig_yyrestart(yyin  ,yyscanner);
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) libconfig_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	yyg->yy_n_chars += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	yy_current_state = yyg->yy_start;
+	yy_current_state += YY_AT_BOL();
+
+	for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			yyg->yy_last_accepting_state = yy_current_state;
+			yyg->yy_last_accepting_cpos = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 103 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+	register int yy_is_jam;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+	register char *yy_cp = yyg->yy_c_buf_p;
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		yyg->yy_last_accepting_state = yy_current_state;
+		yyg->yy_last_accepting_cpos = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 103 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 102);
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (yyscan_t yyscanner)
+#else
+    static int input  (yyscan_t yyscanner)
+#endif
+
+{
+	int c;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	*yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+	if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+			/* This was really a NUL. */
+			*yyg->yy_c_buf_p = '\0';
+
+		else
+			{ /* need more input */
+			int offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+			++yyg->yy_c_buf_p;
+
+			switch ( yy_get_next_buffer( yyscanner ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					libconfig_yyrestart(yyin ,yyscanner);
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( libconfig_yywrap(yyscanner ) )
+						return EOF;
+
+					if ( ! yyg->yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput(yyscanner);
+#else
+					return input(yyscanner);
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) yyg->yy_c_buf_p;	/* cast for 8-bit char's */
+	*yyg->yy_c_buf_p = '\0';	/* preserve yytext */
+	yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n');
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_at_bol )
+		   
+    do{ yylineno++;
+        yycolumn=0;
+    }while(0)
+;
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void libconfig_yyrestart  (FILE * input_file , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if ( ! YY_CURRENT_BUFFER ){
+        libconfig_yyensure_buffer_stack (yyscanner);
+		YY_CURRENT_BUFFER_LVALUE =
+            libconfig_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+	}
+
+	libconfig_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+	libconfig_yy_load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+    void libconfig_yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		libconfig_yypop_buffer_state();
+	 *		libconfig_yypush_buffer_state(new_buffer);
+     */
+	libconfig_yyensure_buffer_stack (yyscanner);
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*yyg->yy_c_buf_p = yyg->yy_hold_char;
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	libconfig_yy_load_buffer_state(yyscanner );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (libconfig_yywrap()) processing, but the only time this flag
+	 * is looked at is after libconfig_yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void libconfig_yy_load_buffer_state  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE libconfig_yy_create_buffer  (FILE * file, int  size , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) libconfig_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in libconfig_yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) libconfig_yyalloc(b->yy_buf_size + 2 ,yyscanner );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in libconfig_yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	libconfig_yy_init_buffer(b,file ,yyscanner);
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with libconfig_yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+    void libconfig_yy_delete_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		libconfig_yyfree((void *) b->yy_ch_buf ,yyscanner );
+
+	libconfig_yyfree((void *) b ,yyscanner );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+    
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a libconfig_yyrestart() or at EOF.
+ */
+    static void libconfig_yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file , yyscan_t yyscanner)
+
+{
+	int oerrno = errno;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	libconfig_yy_flush_buffer(b ,yyscanner);
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then libconfig_yy_init_buffer was _probably_
+     * called from libconfig_yyrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+    void libconfig_yy_flush_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		libconfig_yy_load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  @param yyscanner The scanner object.
+ */
+void libconfig_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if (new_buffer == NULL)
+		return;
+
+	libconfig_yyensure_buffer_stack(yyscanner);
+
+	/* This block is copied from libconfig_yy_switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*yyg->yy_c_buf_p = yyg->yy_hold_char;
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		yyg->yy_buffer_stack_top++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from libconfig_yy_switch_to_buffer. */
+	libconfig_yy_load_buffer_state(yyscanner );
+	yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  @param yyscanner The scanner object.
+ */
+void libconfig_yypop_buffer_state (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if (!YY_CURRENT_BUFFER)
+		return;
+
+	libconfig_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if (yyg->yy_buffer_stack_top > 0)
+		--yyg->yy_buffer_stack_top;
+
+	if (YY_CURRENT_BUFFER) {
+		libconfig_yy_load_buffer_state(yyscanner );
+		yyg->yy_did_buffer_switch_on_eof = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void libconfig_yyensure_buffer_stack (yyscan_t yyscanner)
+{
+	int num_to_alloc;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if (!yyg->yy_buffer_stack) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)libconfig_yyalloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								, yyscanner);
+		if ( ! yyg->yy_buffer_stack )
+			YY_FATAL_ERROR( "out of dynamic memory in libconfig_yyensure_buffer_stack()" );
+								  
+		memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		yyg->yy_buffer_stack_max = num_to_alloc;
+		yyg->yy_buffer_stack_top = 0;
+		return;
+	}
+
+	if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)libconfig_yyrealloc
+								(yyg->yy_buffer_stack,
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								, yyscanner);
+		if ( ! yyg->yy_buffer_stack )
+			YY_FATAL_ERROR( "out of dynamic memory in libconfig_yyensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+		yyg->yy_buffer_stack_max = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE libconfig_yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) libconfig_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in libconfig_yy_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	libconfig_yy_switch_to_buffer(b ,yyscanner );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to libconfig_yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       libconfig_yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE libconfig_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+{
+    
+	return libconfig_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to libconfig_yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE libconfig_yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) libconfig_yyalloc(n ,yyscanner );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in libconfig_yy_scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = libconfig_yy_scan_buffer(buf,n ,yyscanner);
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in libconfig_yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		yytext[yyleng] = yyg->yy_hold_char; \
+		yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+		yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+		*yyg->yy_c_buf_p = '\0'; \
+		yyleng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE libconfig_yyget_extra  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int libconfig_yyget_lineno  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    
+        if (! YY_CURRENT_BUFFER)
+            return 0;
+    
+    return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int libconfig_yyget_column  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    
+        if (! YY_CURRENT_BUFFER)
+            return 0;
+    
+    return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *libconfig_yyget_in  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *libconfig_yyget_out  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int libconfig_yyget_leng  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *libconfig_yyget_text  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void libconfig_yyset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void libconfig_yyset_lineno (int  line_number , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        /* lineno is only valid if an input buffer exists. */
+        if (! YY_CURRENT_BUFFER )
+           yy_fatal_error( "libconfig_yyset_lineno called with no buffer" , yyscanner); 
+    
+    yylineno = line_number;
+}
+
+/** Set the current column.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void libconfig_yyset_column (int  column_no , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        /* column is only valid if an input buffer exists. */
+        if (! YY_CURRENT_BUFFER )
+           yy_fatal_error( "libconfig_yyset_column called with no buffer" , yyscanner); 
+    
+    yycolumn = column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see libconfig_yy_switch_to_buffer
+ */
+void libconfig_yyset_in (FILE *  in_str , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyin = in_str ;
+}
+
+void libconfig_yyset_out (FILE *  out_str , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyout = out_str ;
+}
+
+int libconfig_yyget_debug  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yy_flex_debug;
+}
+
+void libconfig_yyset_debug (int  bdebug , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yy_flex_debug = bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+YYSTYPE * libconfig_yyget_lval  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yylval;
+}
+
+void libconfig_yyset_lval (YYSTYPE *  yylval_param , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yylval = yylval_param;
+}
+
+/* User-visible API */
+
+/* libconfig_yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int libconfig_yylex_init(yyscan_t* ptr_yy_globals)
+
+{
+    if (ptr_yy_globals == NULL){
+        errno = EINVAL;
+        return 1;
+    }
+
+    *ptr_yy_globals = (yyscan_t) libconfig_yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+    if (*ptr_yy_globals == NULL){
+        errno = ENOMEM;
+        return 1;
+    }
+
+    /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+    return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* libconfig_yylex_init_extra has the same functionality as libconfig_yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to libconfig_yyalloc in
+ * the yyextra field.
+ */
+
+int libconfig_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+
+{
+    struct yyguts_t dummy_yyguts;
+
+    libconfig_yyset_extra (yy_user_defined, &dummy_yyguts);
+
+    if (ptr_yy_globals == NULL){
+        errno = EINVAL;
+        return 1;
+    }
+	
+    *ptr_yy_globals = (yyscan_t) libconfig_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+	
+    if (*ptr_yy_globals == NULL){
+        errno = ENOMEM;
+        return 1;
+    }
+    
+    /* By setting to 0xAA, we expose bugs in
+    yy_init_globals. Leave at 0x00 for releases. */
+    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+    
+    libconfig_yyset_extra (yy_user_defined, *ptr_yy_globals);
+    
+    return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from libconfig_yylex_destroy(), so don't allocate here.
+     */
+
+    yyg->yy_buffer_stack = 0;
+    yyg->yy_buffer_stack_top = 0;
+    yyg->yy_buffer_stack_max = 0;
+    yyg->yy_c_buf_p = (char *) 0;
+    yyg->yy_init = 0;
+    yyg->yy_start = 0;
+
+    yyg->yy_start_stack_ptr = 0;
+    yyg->yy_start_stack_depth = 0;
+    yyg->yy_start_stack =  NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    yyin = stdin;
+    yyout = stdout;
+#else
+    yyin = (FILE *) 0;
+    yyout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * libconfig_yylex_init()
+     */
+    return 0;
+}
+
+/* libconfig_yylex_destroy is for both reentrant and non-reentrant scanners. */
+int libconfig_yylex_destroy  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		libconfig_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		libconfig_yypop_buffer_state(yyscanner);
+	}
+
+	/* Destroy the stack itself. */
+	libconfig_yyfree(yyg->yy_buffer_stack ,yyscanner);
+	yyg->yy_buffer_stack = NULL;
+
+    /* Destroy the start condition stack. */
+        libconfig_yyfree(yyg->yy_start_stack ,yyscanner );
+        yyg->yy_start_stack = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * libconfig_yylex() is called, initialization will occur. */
+    yy_init_globals( yyscanner);
+
+    /* Destroy the main struct (reentrant only). */
+    libconfig_yyfree ( yyscanner , yyscanner );
+    yyscanner = NULL;
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *libconfig_yyalloc (yy_size_t  size , yyscan_t yyscanner)
+{
+	return (void *) malloc( size );
+}
+
+void *libconfig_yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void libconfig_yyfree (void * ptr , yyscan_t yyscanner)
+{
+	free( (char *) ptr );	/* see libconfig_yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 191 "scanner.l"

+ 326 - 0
3rdparty/libconfig/scanner.h

@@ -0,0 +1,326 @@
+#ifndef libconfig_yyHEADER_H
+#define libconfig_yyHEADER_H 1
+#define libconfig_yyIN_HEADER 1
+
+#line 6 "scanner.h"
+
+#line 8 "scanner.h"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 33
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_CONST
+
+#endif	/* __STDC__ */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+   are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+int libconfig_yylex_init (yyscan_t* scanner);
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef unsigned int yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void libconfig_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void libconfig_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE libconfig_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void libconfig_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void libconfig_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void libconfig_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void libconfig_yypop_buffer_state (yyscan_t yyscanner );
+
+YY_BUFFER_STATE libconfig_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE libconfig_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE libconfig_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
+
+void *libconfig_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *libconfig_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void libconfig_yyfree (void * ,yyscan_t yyscanner );
+
+#define libconfig_yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+#define yytext_ptr yytext_r
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+#define COMMENT 1
+
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int libconfig_yylex_destroy (yyscan_t yyscanner );
+
+int libconfig_yyget_debug (yyscan_t yyscanner );
+
+void libconfig_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE libconfig_yyget_extra (yyscan_t yyscanner );
+
+void libconfig_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *libconfig_yyget_in (yyscan_t yyscanner );
+
+void libconfig_yyset_in  (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *libconfig_yyget_out (yyscan_t yyscanner );
+
+void libconfig_yyset_out  (FILE * out_str ,yyscan_t yyscanner );
+
+int libconfig_yyget_leng (yyscan_t yyscanner );
+
+char *libconfig_yyget_text (yyscan_t yyscanner );
+
+int libconfig_yyget_lineno (yyscan_t yyscanner );
+
+void libconfig_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+YYSTYPE * libconfig_yyget_lval (yyscan_t yyscanner );
+
+void libconfig_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int libconfig_yywrap (yyscan_t yyscanner );
+#else
+extern int libconfig_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int libconfig_yylex (YYSTYPE * yylval_param ,yyscan_t yyscanner);
+
+#define YY_DECL int libconfig_yylex (YYSTYPE * yylval_param , yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#line 130 "scanner.l"
+
+#line 325 "scanner.h"
+#undef libconfig_yyIN_HEADER
+#endif /* libconfig_yyHEADER_H */

+ 57 - 0
3rdparty/libconfig/strbuf.c

@@ -0,0 +1,57 @@
+/* ----------------------------------------------------------------------------
+   libconfig - A library for processing structured configuration files
+   Copyright (C) 2005-2010  Mark A Lindner
+
+   This file is part of libconfig.
+
+   This library is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this library.  If not, see <http://www.gnu.org/licenses/>.
+   ----------------------------------------------------------------------------
+*/
+
+#include "strbuf.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#define STRING_BLOCK_SIZE 64
+
+/* ------------------------------------------------------------------------- */
+
+char *strbuf_release(strbuf_t *buf)
+{
+  char *r = buf->string;
+  memset(buf, 0, sizeof(strbuf_t));
+  return(r);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void strbuf_append(strbuf_t *buf, const char *text)
+{
+  static const size_t mask = ~(STRING_BLOCK_SIZE - 1);
+  size_t len = strlen(text);
+  size_t newlen = buf->length + len + 1; /* add 1 for NUL */
+
+  if(newlen > buf->capacity)
+  {
+    buf->capacity = (newlen + (STRING_BLOCK_SIZE - 1)) & mask;
+    buf->string = (char *)realloc(buf->string, buf->capacity);
+  }
+
+  strcpy(buf->string + buf->length, text);
+  buf->length += len;
+}
+
+/* ------------------------------------------------------------------------- */
+/* eof */

+ 39 - 0
3rdparty/libconfig/strbuf.h

@@ -0,0 +1,39 @@
+/* ----------------------------------------------------------------------------
+   libconfig - A library for processing structured configuration files
+   Copyright (C) 2005-2010  Mark A Lindner
+
+   This file is part of libconfig.
+
+   This library is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this library.  If not, see <http://www.gnu.org/licenses/>.
+   ----------------------------------------------------------------------------
+*/
+
+#ifndef __libconfig_strbuf_h
+#define __libconfig_strbuf_h
+
+#include <string.h>
+#include <sys/types.h>
+
+typedef struct
+{
+  char *string;
+  size_t length;
+  size_t capacity;
+} strbuf_t;
+
+char *strbuf_release(strbuf_t *buf);
+
+void strbuf_append(strbuf_t *buf, const char *text);
+
+#endif /* __libconfig_strbuf_h */

+ 89 - 0
3rdparty/libconfig/wincompat.h

@@ -0,0 +1,89 @@
+/* ----------------------------------------------------------------------------
+   libconfig - A library for processing structured configuration files
+   Copyright (C) 2005-2010  Mark A Lindner
+
+   This file is part of libconfig.
+
+   This library is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this library.  If not, see <http://www.gnu.org/licenses/>.
+   ----------------------------------------------------------------------------
+*/
+
+#ifndef __wincompat_h
+#define __wincompat_h
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
+
+#ifdef _MSC_VER
+#pragma warning (disable: 4996)
+#endif
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#define snprintf  _snprintf
+
+#ifndef __MINGW32__
+#define atoll     _atoi64
+#define strtoull  _strtoui64
+#endif /* __MINGW32__ */
+
+#endif
+
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \
+     || defined(__MINGW32__))
+
+/* Why does gcc on MinGW use the Visual C++ style format directives
+ * for 64-bit integers? Inquiring minds want to know....
+ */
+
+#define INT64_FMT "%I64d"
+#define UINT64_FMT "%I64u"
+
+#define INT64_HEX_FMT "%I64X"
+
+#define FILE_SEPARATOR "\\"
+
+#else /* defined(WIN32) || defined(__MINGW32__) */
+
+#define INT64_FMT "%lld"
+#define UINT64_FMT "%llu"
+
+#define INT64_HEX_FMT "%llX"
+
+#define FILE_SEPARATOR "/"
+
+#endif /* defined(WIN32) || defined(__MINGW32__) */
+
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \
+  && ! defined(__MINGW32__)
+
+#define INT64_CONST(I)  (I ## i64)
+#define UINT64_CONST(I) (I ## Ui64)
+
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+
+#else /* defined(WIN32) && ! defined(__MINGW32__) */
+
+#define INT64_CONST(I)  (I ## LL)
+#define UINT64_CONST(I) (I ## ULL)
+
+#endif /* defined(WIN32) && ! defined(__MINGW32__) */
+
+#endif /* __wincompat_h */

+ 9 - 4
Makefile.in

@@ -4,10 +4,10 @@ HAVE_MYSQL=@HAVE_MYSQL@
 ifeq ($(HAVE_MYSQL),yes)
 	ALL_DEPENDS=common_sql login_sql char_sql map_sql tools import
 	SQL_DEPENDS=common_sql login_sql char_sql map_sql import
-	COMMON_SQL_DEPENDS=mt19937ar
-	LOGIN_SQL_DEPENDS=mt19937ar common_sql
-	CHAR_SQL_DEPENDS=mt19937ar common_sql
-	MAP_SQL_DEPENDS=mt19937ar common_sql
+	COMMON_SQL_DEPENDS=mt19937ar libconfig
+	LOGIN_SQL_DEPENDS=mt19937ar libconfig common_sql
+	CHAR_SQL_DEPENDS=mt19937ar libconfig common_sql
+	MAP_SQL_DEPENDS=mt19937ar libconfig common_sql
 	CONVERTERS_DEPENDS=common_sql
 else
 	ALL_DEPENDS=needs_mysql
@@ -47,6 +47,9 @@ common_sql: $(COMMON_SQL_DEPENDS)
 mt19937ar:
 	@$(MAKE) -C 3rdparty/mt19937ar
 
+libconfig:
+	@$(MAKE) -C 3rdparty/libconfig
+
 login_sql: $(LOGIN_SQL_DEPENDS)
 	@$(MAKE) -C src/login sql
 
@@ -74,6 +77,7 @@ import:
 clean:
 	@$(MAKE) -C src/common $@
 	@$(MAKE) -C 3rdparty/mt19937ar $@
+	@$(MAKE) -C 3rdparty/libconfig $@
 	@$(MAKE) -C src/login $@
 	@$(MAKE) -C src/char $@
 	@$(MAKE) -C src/map $@
@@ -85,6 +89,7 @@ help:
 	@echo "possible targets are:"
 	@echo "'common_sql'  - builds object files used in SQL servers"
 	@echo "'mt19937ar'   - builds object file of Mersenne Twister MT19937"
+	@echo "'libconfig'   - builds object files of libconfig
 	@echo "'login_sql'   - builds login server (SQL version)"
 	@echo "'char_sql'    - builds char server (SQL version)"
 	@echo "'map_sql'     - builds map server (SQL version)"

+ 60 - 753
conf/atcommand_athena.conf

@@ -1,753 +1,60 @@
-//--------------------------------------------------------------
-// rAthena atcommand/charcommand Configuration File
-//--------------------------------------------------------------
-
-// The symbol that will be used to recognize commands.
-// You can set any one character except control-characters (0x00-0x1f),
-// '%', '$' (party/guild chat speaking) and '/' (standard client commands).
-// command_symbol represents @commands used locally
-// char_symbol represents #commands used on other players.
-command_symbol:@
-char_symbol:#
-
-// The following settings in this file use the format "<command name>: level(@),level(#)".
-// They define the minimum GM level required to execute the associated command.
-// @ = atcommand. most work only on yourself.
-// # = charcommand. remote usage only. GMs will be able to use these on other players.
-// Adjust values as you like. Note that to activate commands for normal players,
-// (GM level 0), you also need to change the 'atcommand_gm_only' option to 'no'.
-// To completely disable a command, set its required GM level to 100.
-
-// Default levels were chosen so that they form the following hierarchy:
-// 0: Normal player
-//    -> no commands accessible
-// 1: Super player
-//    -> some minor advantage: storage, petrename, etc...
-// 10: Super player+
-//    -> more powerful commands, like mobsearch and changegm
-// 20: Mediator
-//    -> GM commands for finding players and moving to them (also kicking them)
-// 40: Sub-GM
-//    -> GM commands for basic tasks, no significant impact on other players
-// 50: Sub-GM+
-//    -> GM commands to spawn mobs and create guilds
-// 60: GM
-//    -> almost all commands available (except administration and mass commands)
-// 80: GM Chief
-//    -> can do anything, except administration commands
-// 99: Administrator
-//    -> can do anything!
-// 100: Disabled
-//    -> commands that will not be available to anyone
-
-// Syntax of file:
-// command: @level,#level [<alias commands seperated by commas>]
-
-// Syntax Example:
-// command: 40,40 [alias,alias2,alias3,alias4]
-// If it has more than 4 aliases you can keep adding, just like in the example below:
-
-// Example:
-// blvl: 60,60 [lvup,blevel,baselvl,baselvup,baselevel,baselvlup]
-
-//--------------------------
-// 0: normal player commands
-// None for security purposes.
-
-//-------------------------
-// 1: Super player commands
-
-// Displays a list of @ commands available to the player.
-commands: 1,1
-
-// Displays a list of # commands available to the player.
-charcommands: 1,1
-
-// Displays the server rates.
-rates: 1,1
-
-// Show server uptime since last map server restart
-uptime: 1,1
-
-// Shows/Hides the "there is a delay after a skill" message.
-showdelay: 1,1
-
-// Displays current levels and % progress.
-exp: 1,40
-
-// To change your (own) email
-// note: this command doesn't check email itself, but check structure of the email (xxx@xxx)
-//       if you want be sure of each e-mail disable this option (value: 100)
-email: 1,60
-
-// Show Monster info (rates, stats, drops, MVP stuff)
-monsterinfo: 1,1 [mobinfo, mi]
-
-// Show Item info (type, price, etc)
-iteminfo: 1,1 [ii]
-
-// Show who drops an item (mobs with highest drop rate)
-whodrops: 1,1
-
-// Syncs the player's position on the client with the one stored on the server.
-refresh: 1,40
-
-// Give server time. (4 same commands)
-time: 1,1 [date,serverdate,servertime]
-
-// Displays SVN version of the server.
-version: 1,1
-
-// Suicide your character.
-die: 1,1
-
-// Enables you to rename your pet.
-petrename: 1,50
-
-// Organize a new party, with you as the party leader
-party: 1,1
-
-// Opens your Kafra storage wherever you are
-storage: 1,1
-
-// Opens your mailbox
-mail: 1,1
-
-// Opens auctions window
-auction: 1,1
-
-// Locate someone on a map, returns your coordinates if the person isn't on.
-where: 1,1
-
-// Duel organizing commands
-duel: 1,1
-invite: 1,1
-accept: 1,1
-reject: 1,1
-leave: 1,1
-
-// Main chat
-main: 1,1
-
-// Autorejecting Deals/Invites
-noask: 1,1
-
-// Displays remaining jail time
-jailtime: 1,40
-
-// Homunculus commands for players
-hominfo: 1,40
-homstats: 1,40
-
-// Kill Steal Protection
-noks: 1,1
-
-// Set Font
-font: 1,1
-
-//---------------------------
-// 10: Super player+ commands
-
-// Displays/Hides Experience gained messages
-showexp: 10,10
-
-// Displays/Hides Zeny gained messages
-showzeny: 10,10
-
-// Warps you to predefined locations in major cities.
-go: 10,10
-
-// Enables/disables autolooting from killed mobs.
-autoloot: 10,10
-
-// Enables/disables autolooting an item.
-alootid: 10,10
-
-// Allows you continue vending offline.
-autotrade: 10,10 [at]
-
-// Change Guild Master of your Guild
-changegm: 10,10
-
-// Change the leader of your party.
-changeleader: 10,10
-
-// Change the party exp- and item share rules.
-partyoption: 10,10
-
-// Command what the player's pet will say.
-pettalk: 10,10
-
-// Command what the player's homunculus will say.
-homtalk: 10,10
-
-// Locates and displays the position of a certain mob on the current map.
-mobsearch: 10,10
-// Locates and displays the position of a certain mob on your mini-map
-showmobs: 10,10
-// Prints out in which maps a monster normally spawns at (does not count script-invoked mobs)
-whereis: 10,10
-
-// Resets a Star Gladiator's marked maps
-feelreset: 10,60
-
-//----------------------
-// 20: Mediator commands
-
-// Displays helpfile in rAthena base directory (2 same commands).
-help: 20,20 [h]
-help2: 20,20 [h2]
-
-// Warp yourself to a person (3 same commands + /shift).
-goto: 20,20 [jumpto,warpto]
-
-// Displays the motd file to all players
-gmotd: 20,20
-
-// Follow a player (including warping to them)
-follow: 20,20
-
-// Sends a request to all connected GMs (via the gm whisper system)
-request: 20,100
-
-// Disconnects a user from the server (1 command + right click menu for GM "(name) force to quit").
-kick: 20,20
-
-// Changes your appearance.
-model: 20,50
-
-// To get a peco to (un)ride (2 same commands).
-mount: 20,50 [mountpeco]
-
-// Returns list of logged in characters with their position (2 same commands).
-who: 20,20 [whois]
-
-// Returns list of logged in characters with their job.
-who2: 20,20
-
-// Returns list of logged in characters with their party/guild.
-who3: 20,20
-
-// Returns list of logged in characters with their position in a specifical map.
-whomap: 20,20
-
-// Returns list of logged in characters with their job in a specifical map.
-whomap2: 20,20
-
-// Returns list of logged in characters with their party/guild in a specifical map.
-whomap3: 20,20
-
-// Displays GMs online. For those who are higher GM level than yourself,
-// only the name is shown, for the rest, it displays the same info of
-// @who+@who2+who3
-whogm: 20,20
-
-// Change your appearence to other players to a mob.
-disguise: 20,60
-
-// Restore your normal appearance.
-undisguise: 20,20
-
-// Displays the text as a normal message with the format "*name message*" 
-// instead of "name : message" (Like the /me command in IRC)
-me: 20,20
-
-// Changes your name to your choice temporarily.
-fakename: 20,50
-
-// Changes your size.
-size: 20,50
-
-// Can command what other npcs (by name) can say.
-npctalk: 20,100 [npctalkc]
-
-//--------------------
-// 40: Sub-GM commands
-
-// Broadcast to the whole server. Using (1 command + /nb, /b).
-broadcast: 40,40
-
-// Broadcast to the map you are on (1 command + /lb, /nlb).
-localbroadcast: 40,40
-
-// Broadcast (with or without name)
-kami: 40,40
-// Same as kami but with blue color
-kamib: 40,40
-// Same as kami but you can choose the color (uses different packet)
-kamic: 40,40
-
-// Enables GvG on a map (2 same commands).
-gvgon: 40,100 [gpvpon]
-
-// Turns GvG (Guild vs. Guild) off on a map (2 same commands).
-gvgoff: 40,100 [gpvpoff]
-
-// Activate/Deactivate kill steal protection on a map
-allowks: 40,100
-
-// Modifies your HP/SP.
-heal: 40,60
-
-// GM Hide (total invisibility to characters and monsters) (1 command + /hide).
-hide: 40,60
-
-// Changes your job to one you specify (2 same commands).
-job: 40,60 [jobchange]
-
-// Enables you to to jump randomly on a map (that you are already on).
-jump: 40,40
-
-// Warps you to your last save point (2 same commands).
-load: 40,60 [return]
-
-// Warps you to a specific npc
-tonpc: 40,40
-
-// Saves a warp point.
-memo: 40,40
-
-// Set your character display options. (Visual effects of your character)
-option: 40,60
-
-// Sets the level of intemecy of your pet.
-petfriendly: 40,50
-
-// Sets hunger level of your pet.
-pethungry: 40,50
-
-// Turns PvP (Person vs. Person) off on a map.
-pvpoff: 40,100
-
-// Enables PvP on a map.
-pvpon: 40,100
-
-// Permanently adds a quest skill
-questskill: 40,60
-
-// Permanently removes a quest skill
-lostskill: 40,60
-
-// Sets the speed you can walk/attack at. Default is 150.
-speed: 40,60
-
-// Summons spirit spheres around you.
-spiritball: 40,60
-
-// Warp yourself to a certain map, at (x,y) coordinates (2 same commands) + also /mm or /mapmove.
-warp: 40,60 [rura,mapmove]
-
-// Changes GM clothes color (2 same commands)
-dye: 40,50 [ccolor]
-
-// Changes GM hair style (2 same commands)
-hairstyle: 40,40 [hstyle]
-
-// Changes GM hair color (2 same commands)
-haircolor: 40,50 [hcolor]
-
-// Deletes all your items.
-itemreset: 40,60
-
-// Does a skill/stat reset.
-reset: 40,60
-
-// Displays distribution of players on the server per map (% on each map which has players)
-users: 40,40
-
-// Deletes floor items in your range of sight
-cleanmap: 40,40
-
-// Kill all monsters in map (without drops)
-killmonster2: 40,40
-
-// Sets your spawn point (aka save point).
-save: 40,60
-
-// Do some visual effect on your character
-effect: 40,40
-
-// Do some visual effect on your character (misceffect)
-misceffect: 40,40
-
-// GM's magnifier
-identify: 40,40
-
-// Drop all your items
-dropall: 40,60
-
-// Store all your items
-storeall: 40,60
-
-// Allow other players to hit you out of PvP
-killable: 40,60
-
-// Look up a skill by name
-skillid: 40,40
-
-// Use a skill by id
-useskill: 40,40
-
-// What skills are required to get this skill
-skilltree: 40,40
-
-// Marriage commands
-marry: 40,40
-divorce: 40,40
-
-// Adopt a novice into a family
-adopt: 40,40
-
-// Play a Sound!
-sound: 40,40
-
-// Displays a player's storage
-storagelist: 40,40
-
-// Displays a player's cart contents
-cartlist: 40,40
-
-// Displays a player's items
-itemlist: 40,40
-
-// Displays a player's stats
-stats: 40,40
-
-//---------------------
-// 50: Sub-GM+ commands
-
-// Creates a new guild, with you as the guildmaster.
-guild: 50,50
-
-// Brings up your guild storage wherever you are.
-gstorage: 50,60
-
-// Spawns a monster, and a certain amount (2 same commands + /monster).
-monster: 50,50 [spawn]
-
-// Spawns a smaller sized version of a monster.
-monstersmall: 50,50
-
-// Spawns a larger sized version of a monster.
-monsterbig: 50,50
-
-// Spawns mobs that treat you as their master (they disappear after some time)
-summon: 50,50
-
-// It will spawn a supportive clone of the given player.
-clone: 50,50
-
-// It will spawn a supportive clone of the given player that follows the creator around.
-slaveclone: 50,50
-
-// It will spawn an aggresive clone of the given player.
-evilclone: 50,50
-
-//----------------
-// 60: GM commands
-
-// Add or Remove Cash Points to/from yourself
-cash: 60,60
-
-// Add or Remove Kafra Points to/from yourself
-points: 60,60
-
-// Starts Guild Wars
-agitstart: 60,100
-
-// Ends Guild Wars
-agitend: 60,100
-
-// Resurects yourself.
-alive: 60,60
-
-// Raises your base level by specified amount (7 same commands).
-blvl: 60,60 [lvup,blevel,baselvl,baselvup,baselevel,baselvlup]
-
-// Raises your job level by specified amount (6 same commands).
-jlvl: 60,60 [jlevel,joblvl,joblvup,joblevel,joblvlup]
-
-// Changes the sex of yourself
-changesex: 60,60
-
-// Raises your guild level by specified amount (6 same commands).
-glvl: 60,60 [glevel,guildlvl,guildlvup,guildlevel,guildlvlup]
-
-// Find an itemID based on item name
-idsearch: 60,60
-
-// Creates an item of your choosing, either Item ID or Name (1 command + /item).
-item: 60,60
-
-// Creates a complet item (card, etc...) of your choosing, either Item ID or Name.
-item2: 60,60
-
-// Deletes an item of your choosing, either Item ID or Name.
-delitem: 60,60
-
-// Kill another character without hitting them.
-kill: 60,60
-
-// Kill all monsters in map (with drops)
-killmonster: 60,60
-
-// Creates yourself a pet egg.
-makeegg: 60,60
-
-// Hatches an egg
-hatch: 60,60
-
-// Instantly kills player whose name is entered and deals insane damage to everything around
-nuke: 60,60
-
-// Enable hitting a player even when not in PvP
-killer: 60,60
-
-// Creates weapon of desired element.
-produce: 60,60
-
-// Warps a character to you (1 command + /recall).
-recall: 60,60
-
-// Refines all weapons in your items list.
-refine: 60,80
-
-// Will repair all broken items in inventory.
-repairall: 60,60
-
-// Change Status of your character
-str: 60,60
-agi: 60,60
-vit: 60,60
-int: 60,60
-dex: 60,60
-luk: 60,60
-
-// Gives all skills
-allskill: 60,60 [allskills,skillall,skillsall]
-
-// Sets GM stats to maximum
-allstats: 60,60 [allstat,statall,statsall]
-
-// Gives you stat points.
-stpoint: 60,60
-
-// Gives you skill points of desired amount.
-skpoint: 60,60
-
-// Warps all online character of a guild to you. (at least one member of that guild must be on.)
-guildrecall: 60,60
-
-// Warps all online character of a party to you. 
-// (at least one party member must be online.)
-partyrecall: 60,60
-
-// Allows you to spy on any Guilds Guild chat. 
-// (at least one member of that guild must be on.)
-// NOTE: map server needs to be configured to enable spying to use this command (enable_spy: yes)
-guildspy: 60,60
-
-// Allows you to spy on any party's party chat. 
-// (at least one party member must be online.)
-// NOTE: map server needs to be configured to enable spying to use this command (enable_spy: yes)
-partyspy: 60,60
-
-// Gives you zeny (or subtracts, if amount is negative)
-zeny: 60,80
-
-// Block a player indefinitely
-block: 60,100 [charblock]
-
-// Unblock a player
-unblock: 60,100 [charunblock]
-
-// Ban a player for a limited time
-ban: 60,100 [banish,charban,charbanish]
-
-// Unban a player
-unban: 60,100 [unbanish,charunban,charunbanish]
-
-// To send specified character in jails
-jail: 60,100
-
-// To discharge a jailed character (2 same commands)
-unjail: 60,100 [discharge]
-
-// Timed jailing
-jailfor: 60,60
-
-// Create a static warp portal that lasts until the next reboot
-addwarp: 60,60
-
-// Open a trade window with any player
-trade: 60,60
-
-// Changes the player's appearance (headgear)
-changelook: 60,60
-
-// Homunculus commands for GMs
-hlvl: 60,60 [homlevel,hlevel,homlvl,homlvup]
-homevolve: 60,60 [homevolution]
-makehomun: 60,60
-homfriendly: 60,60
-homhungry: 60,60
-// Re-calculates stats, as if the homun was sent back to level 1 and re-leveled
-homshuffle: 60,60
-
-// WoE 2 start/stop commands
-agitstart2: 60,100
-agitend2: 60,100
-
-// Resets player stats
-streset: 60,60
-
-// Resets player skills
-skreset: 60,60
-
-//----------------------
-// 80: GM Chief commands
-
-// Set the server to day.
-day: 80,100
-
-// Set the server to night.
-night: 80,100
-
-// Kills everyone on the server.
-doom: 80,100
-
-// Kills everyone on the map you are on.
-doommap: 80,80
-
-// Recalls Everyone To Your Coordinates
-recallall: 80,80
-
-// Revives all players on the map.
-raisemap: 80,80
-
-// Revives all players on the server.
-raise: 80,100
-
-// Hides a NPC.
-hidenpc: 80,100
-
-// Unhides a NPC.
-shownpc: 80,100
-
-// Loads an NPC script by path
-loadnpc: 80,100
-
-// Unloads a NPC
-unloadnpc: 80,100
-
-// Move a NPC
-npcmove: 80,100
-
-// turn skills on for a map
-skillon: 80,100
-
-// turn skills off for a map
-skilloff: 80,100
-
-// Mute a player (prevents talking, usage of skills and commands)
-mute: 80,100
-
-// Unmute a player
-unmute: 80,100
-
-//---------------------------
-// 99: Administrator commands
-
-// Disconnect all users from the server
-kickall: 99,100
-
-// Closes Map-Server
-mapexit: 99,100
-
-// Used for testing packet sends from the client (debug function)
-send: 99,100
-
-// Give information about terrain/area (debug function)
-gat: 99,100
-
-// Displays a status change without really applying it (debug function)
-displaystatus: 99,100
-
-// Displays the animation of a skill without really using it (debug function)
-displayskill: 99,100
-
-// Shows information about the map
-mapinfo: 99,100
-
-// Set Map Flags
-mapflag: 99,100
-
-// Re-load item database (admin command)
-reloaditemdb: 99,100
-
-// Re-load monsters database (admin command)
-reloadmobdb: 99,100
-
-// Re-load skills database (admin command)
-reloadskilldb: 99,100
-
-// Re-load scripts (admin command)
-reloadscript: 99,100
-
-// Change a battle_config flag without rebooting server
-setbattleflag: 99,100
-
-// Re-load gm command config (admin command)
-reloadatcommand: 99,100
-
-// Re-load battle config (admin command)
-// Note that some player config settings won't take effect until relog
-// (display exp, display zeny, display skill delay fail, ...)
-reloadbattleconf: 99,100
-
-// Re-load status database (admin command)
-reloadstatusdb: 99,100
-
-// Re-load player info database (admin command)
-reloadpcdb: 99,100
-
-// Re-load the Message of the Day (admin command)
-reloadmotd: 99,100
-
-// Changes the GM level of another character
-// (lasts until reboot, or gm list reload)
-adjgmlvl: 99,100
-
-// Changes the required GM level of an @ command
-// (effect lasts until restart or command reload)
-adjcmdlvl: 99,100
-
-// [Un]Disguise All Players (admin command)
-disguiseall: 99,100
-undisguiseall: 99,100
-
-// Mutes every player on screen (admin command)
-mutearea: 99,100 [stfu]
-
-// Makes you immune to attacks (monsters/players/skills cannot target/hit you, admin command)
-battleignore: 99,100 [monsterignore]
-
-//---------------------------------------------------------------
-// 99: Weather effects
-snow: 99,100
-clouds: 99,100
-clouds2: 99,100
-fog: 99,100
-fireworks: 99,100
-sakura: 99,100
-leaves: 99,100
-
-// Stop all weather effects
-clearweather: 99,100
-
-//---------------------------------------------------------------
-// 100: Disabled commands
-
-//---------------------
-// OTHER: not a command
-import:conf/import/atcommand_conf.txt
+/* Atcommands and charcommands configuration file */
+
+/* The symbol that will be used to recognize commands.
+You can set any one character except:
+ - control-characters (0x00-0x1f),
+ - '%' (party chat symbol)
+ - '$' (guild chat symbol)
+ - '/' (client commands symbol)
+atcommand_symbol represents @commands used locally.
+charcommand_symbol represents #commands used on other players.
+*/
+
+atcommand_symbol : "@"
+charcommand_symbol: "#"
+
+/* Command aliases
+You can define aliases for any command. Aliases work just like original
+command.
+Format is
+	<commandname>: ["<alias>", ...]
+*/
+
+aliases: {
+	mobinfo: ["monsterinfo", "mi"]
+	iteminfo: ["ii"]
+	time: ["date", "serverdate", "servertime"]
+	autotrade: ["at"]
+	help: ["h"]
+	jumpto: ["goto", "warpto"]
+	mount: ["mountpeco"]
+	who: ["whois"]
+	npctalk: ["npctalkc"]
+	gvgon: ["gpvpon"]
+	gvgoff: ["gpvpoff"]
+	jobchange: ["job"]
+	load: ["return"]
+	warp: ["rura", "mapmove"]
+	dye: ["ccolor"]
+	hairstyle: ["hstyle"]
+	haircolor: ["hcolor"]
+	monster: ["spawn"]
+	blvl: ["lvup", "blevel", "baselvl", "baselvup", "baselevel", "baselvlup"]
+	jlvl: ["jlevel", "joblvl", "joblvup", "joblevel", "joblvlup"]
+	glvl: ["glevel", "guildlvl", "guildlvup", "guildlevel", "guildlvlup"]
+	allskill: ["allskills", "skillall", "skillsall"]
+	allstats: ["allstat", "statall", "statsall"]
+	ban: ["banish"]
+	unban: ["unbanish"]
+	unjail: ["discharge"]
+	homlevel: ["hlvl", "hlevel", "homlvl", "homlvup"]
+	homevolution: ["homevolve"]
+	mutearea: ["stfu"]
+	monsterignore: ["battleignore"]
+	raise: ["revive"]
+}
+
+/* Commands help file */
+help: {
+	@include "conf/help.txt"
+}

+ 0 - 87
conf/battle/gm.conf

@@ -18,97 +18,10 @@ atcommand_slave_clone_limit: 25
 // current map server.
 partial_name_scan: yes
 
-// The level at which a player with access is considered a GM. 
-// An account with an access level lower than this is not effected
-// by gm_can_drop_lv (battle_athena.conf). 
-lowest_gm_level: 1
-
-// [GM] Can use all skills? (No or mimimum GM level)
-gm_all_skill: no
-
-// [GM] Can equip anything? (No or minimum GM level, can cause client errors.)
-gm_all_equipment: no
-
-// [GM] Can use skills without meeting the required conditions (items, etc...)?
-// 'no' or minimum GM level to bypass requirements.
-gm_skill_unconditional: no
-
-// [GM] Can join a password protected chat? (No or mimimum GM level)
-gm_join_chat: no
-
-// [GM] Can't be kicked from a chat? (No or mimimum GM level)
-gm_kick_chat: no
-
-// (@) GM Commands available only to GM's? (Note 1)
-// set to 'No', Normal players (gm level 0) can use GM commands _IF_ you set the command level to 0.
-// set to 'Yes', Normal players (gm level 0) can never use a GM command even if you set the command level to 0.
-atcommand_gm_only: no
-
 // (@) @allstats/@str/@agi/@vit/@int/@dex/@luk
 // allow gms to bypass the maximum stat parameter? ( if yes gm stats can go up to 32k ) default: no
 atcommand_max_stat_bypass: no
 
-// Is the character of a GM account set as the object of a display by @ command etc. or not?
-hide_GM_session: no
-
-// At what GM level can you see GMs and Account/Char IDs in the @who command?
-who_display_aid: 40
-
 // Ban people that try trade dupe.
 // Duration of the ban, in minutes (default: 5). To disable the ban, set 0.
 ban_hack_trade: 5
-
-// Set here minimum level of a (online) GM that can receive all informations about any player that try to hack, spoof a name, etc.
-// Values are from 0 to 100.
-// 100: disable information
-// 0: send to any people, including normal players
-// default: 60, according to GM definition in atcommand_athena.conf
-hack_info_GM_level: 60
-
-// The minimum GM level to bypass nowarp and nowarpto mapflags.
-// This option is mainly used in commands which modify a character's
-// map/coordinates (like @memo, @warp, @charwarp, @go, @jump, etc...).
-// default: 20 (first level after normal player or super'normal' player)
-any_warp_GM_min_level: 20
-
-// The minimum level for a GM to be unable to distribute items.
-// You should set this to the same level @item is set to in the atcommand.conf
-// NEVER SET THIS VALUE TO 0, or you will block drop/trade for normal players
-gm_cant_drop_min_lv: 1
-
-//The trust level for your GMs. Any GMs ABOVE this level will be able to distribute items
-//ie: Use Storage/Guild Storage, Drop Items, Use Vend, Trade items. 
-gm_cant_drop_max_lv: 0
-
-// Minimum GM level to see the hp of every player? (Default: 60)
-// no/0 can be used to disable it.
-disp_hpmeter: 0
-
-// Minimum GM level to view players equip regardless of their setting.
-// (Default: 0 = Disabled).
-gm_viewequip_min_lv: 0
-
-// Can GMs invite non GMs to a party? (Note 1)
-// set to 'No', GMs under the party invite trust level may not invite non GMs to a party.
-// set to 'Yes', All GMs can invite any player to a party.
-// Also, as long as this is off, players cannot invite GMs to a party as well.
-gm_can_party: no
-
-//The trust level for GMs to invite to a party. Any GMs ABOVE OR EQUAL TO this level will be able to invite normal
-//players into their party in addittion to other GMs. (regardless of gm_can_party)
-gm_cant_party_min_lv: 20
-
-// Players Titles (check msg_athena.conf for title strings)
-// You may assign different titles for your Players and GMs
-title_lvl1: 1
-title_lvl2: 10
-title_lvl3: 20
-title_lvl4: 40
-title_lvl5: 50
-title_lvl6: 60
-title_lvl7: 80
-title_lvl8: 99
-
-// Minimum GM level required for client command /check (display character status) to work.
-// Default: 60
-gm_check_minlevel: 60

+ 4 - 2
conf/char_athena.conf

@@ -93,8 +93,10 @@ char_new_display: 0
 // Maximum users able to connect to the server. Set to 0 for unlimited.
 max_connect_user: 0
 
-// Minimum GM level that is allowed to bypass the server limit of users.
-gm_allow_level: 99
+// Group ID that is allowed to bypass the server limit of users.
+// Default: -1 = nobody (there are no groups with ID < 0)
+// See: conf/groups.conf
+gm_allow_group: -1
 
 // How often should the server save all files? (In seconds)
 // Note: Applies to all data files on TXT servers.

+ 274 - 0
conf/groups.conf

@@ -0,0 +1,274 @@
+/*
+
+Player groups configuration file
+---------------------------------
+
+This file defines "player groups" and their privileges.
+
+Each group has its id and name, lists of available commands and other 
+permissions, and a list of other groups it inherits from.
+
+
+Group settings
+--------------
+<id>
+Unique group number. The only required field.
+
+<name>
+Any string. If empty, defaults to "Group <id>". It is used in several @who 
+commands.
+
+<level>
+Equivalent of GM level, which was used in revisions before r xxxxx. You can 
+set it to any number, but usually it's between 0 (default) and 99. Members of 
+groups with lower level can not perform some actions/commands (like @kick) on 
+members of groups with higher level. It is what script command getgmlevel() 
+returns. Group level can also be used to override trade restrictions 
+(db/item_trade.txt).
+
+<commands>
+A group of settings
+	<command name> : <bool>
+or
+	<commandname> : [ <bool>, <bool> ]
+First boolean value is for atcommand, second one for charcommand. If set to 
+true, group can use command. If only atcommand value is provided, false is 
+assumed for charcommand. If a command name is not included, false is assumed for 
+both atcommand and charcommand.
+For a full list of available commands, see: doc/atcommands.txt.
+Command names must not be aliases.
+
+<log_commands>
+Boolean value. If true then all commands used by the group will be logged to 
+atcommandlog. If setting is omitted in a group definition, false is assumed.
+Requires 'log_commands' to be enabled in 'conf/log_athena.conf'.
+
+<permissions>
+A group of settings
+	<permission> : <bool>
+If a permission is not included, false is assumed.
+For a full list of available permissions, see: doc/permissions.txt
+
+<inherit>
+A list of group names that given group will inherit commands and permissions 
+from. Group names are case-sensitive.
+
+Inheritance results
+-------------------
+Both multiple inheritance (Group 2 -> Group 1 and Group 3 -> Group 1) and
+recursive inheritance (Group 3 -> Group 2 -> Group 1) are allowed.
+
+Inheritance rules should not create cycles (eg Group 1 inherits from Group 2, 
+and Group inherits from Group 1 at the same time). Configuration with cycles is 
+considered faulty and can't be processed fully by server.
+
+Command or permission is inherited ONLY if it's not already defined for the 
+group.
+If group inherits from multiple groups, and the same command or permission is 
+defined for more than one of these groups, it's undefined which one will be 
+inherited.
+
+Syntax
+------
+This config file uses libconfig syntax: 
+http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-Files
+
+
+Upgrading from revisions before XXXXX
+-------------------------------------
+<forum link>
+*/
+
+groups: (
+{
+	id: 0 /* group 0 is the default group for every new account */
+	name: "Player"
+	level: 0
+	inherit: ( /*empty list*/ )
+	commands: {
+		/* no commands by default */
+	}
+	permissions: {
+		/* without this basic permissions regular players could not 
+		trade or party */
+		can_trade: true
+		can_party: true
+	}
+},
+{
+	id: 1
+	name: "Super Player"
+	inherit: ( "Player" ) /* can do everything Players can and more */
+	level: 0
+	commands: {
+		/* informational commands */
+		commands: true
+		charcommands: true
+		help: true
+		rates: true
+		uptime: true
+		showdelay: true
+		exp: true
+		mobinfo: true
+		iteminfo: true
+		whodrops: true
+		time: true
+		jailtime: true
+		hominfo: true
+		homstats: true
+		showexp: true
+		showzeny: true
+		whereis: true
+		/* feature commands */
+		refresh: true
+		noask: true
+		noks: true
+		main: true
+		autoloot: true
+		alootid: true
+		autotrade: true
+		request: true
+		go: true
+	}
+	permissions: {
+	}
+},
+{
+	id: 2
+	name: "Support"
+	inherit: ( "Super Player" )
+	level: 1
+	commands: {
+		version: true
+		where: true
+		jumpto: true
+		who: true
+		who2: true
+		who3: true
+		whomap: true
+		whomap2: true
+		whomap3: true
+		users: true
+		broadcast: true
+		localbroadcast: true
+	}
+	log_commands: true
+	permissions: {
+		receive_requests: true
+		view_equipment: true
+	}
+},
+{
+	id: 3
+	name: "Script Manager"
+	inherit: ( "Support" )
+	level: 1
+	commands: {
+		tonpc: true
+		hidenpc: true
+		shownpc: true
+		loadnpc: true
+		unloadnpc: true
+		npcmove: true
+		addwarp: true
+	}
+	log_commands: true
+	permissions: {
+		any_warp: true
+	}
+},
+{
+	id: 4
+	name: "Event Manager"
+	inherit: ( "Support" )
+	level: 1
+	commands: {
+		monster: true
+		monstersmall: true
+		monsterbig: true
+		killmonster2: true
+		cleanmap: true
+		item: [true, true]
+		zeny: [true, true]
+		disguise: [true, true]
+		undisguise: [true, true]
+		size: [true, true]
+		raise: true
+		raisemap: true
+		day: true
+		night: true
+		skillon: true
+		skilloff: true
+		pvpon: true
+		pvpoff: true
+		gvgon: true
+		gvgoff: true
+		allowks: true
+		me: true
+		marry: true
+		divorce: true
+	}
+	log_commands: true
+	permissions: {
+		can_trade: false
+		any_warp: true
+	}
+},
+{
+	id: 10
+	name: "Law Enforcement"
+	inherit: ( "Support" )
+	level: 2
+	commands: {
+		hide: true
+		follow: true
+		kick: true
+		disguise: true
+		fakename: true
+		option: true
+		speed: true
+		warp: true
+		kill: true
+		recall: true
+		ban: true
+		block: true
+		jail: true
+		jailfor: true
+		mute: true
+		storagelist: true
+		cartlist: true
+		itemlist: true
+		stats: true
+	}
+	log_commands: true
+	permissions: {
+		join_chat: true
+		kick_chat: true
+		hide_session: true
+		who_display_aid: true
+		hack_info: true
+		any_warp: true
+		view_hpmeter: true
+	}
+},
+{
+	id: 99
+	name: "Admin"
+	level: 99
+	inherit: ( "Support", "Law Enforcement" )
+	commands: {
+	}
+	log_commands: true
+	permissions: {
+		can_trade: true
+		can_party: true
+		all_skill: true
+		all_equipment: true
+		skill_unconditional: true
+		use_check: true
+		use_changemaptype: true
+		all_commands: true
+	}
+}
+)
+

+ 230 - 172
conf/help.txt

@@ -1,172 +1,230 @@
-// put at first, the minimum level to display the line
-  1:To use one command, type it inside the message window where you usually type to chat.
- 20:@h/@help - display this help guide.
- 20:@h2/@help2 - displays the second help guide.
-  1: 
-  1:--- MESSAGE CMD ---
-  1:@main [on|off|message] - Turns on or off global chat (@main must be on to see global chat messages)
-  1:@noask - Auto rejects Deals/Invites
- 20:@gmotd - Broadcasts the Message of The Day file to all players.
- 20:@me <message> - Displays normal text as a message in this format: *name message* (like /me in mIRC)
- 20:@fakename [Name] - Changes your name to your choice temporarly.
- 20:@npctalk [NPC Name],[Message] - Forces a NPC to display a message in normal chat.
- 40:/b/@broadcast <message> - Broadcasts a GM message with name of the GM (in yellow)
- 40:/nb <message>/@kami <message> - Broadcasts a GM message without name of the GM (in yellow)
- 40:@kamib <message> - Broadcasts a GM message without name of the GM (in blue)
- 40:/lb/@localbroadcast <message> - Broadcasts a GM message with name of the GM (in yellow) ONLY on your map
- 40:/nlb <message> - Broadcasts a GM message without name of the GM (in yellow) ONLY on your map
-  1: 
-  1:--- INFORMATION CMD ---
-  1:@commands - Displays a list of commands that you can use.
-  1:@rates - Displays the server's current rates.
-  1:@uptime - Displays how long the server has been online.
-  1:@showdelay - Shows/Hides the "there is a delay after this skill" message.
-  1:@exp - Displays current levels and % progress
-  1:@mobinfo/@monsterinfo/@mi [Mob ID|Part of monster name] - Shows Monster Info (rates, stats, drops, MVP stuff)
-  1:@iteminfo/@ii [Item ID|Part of item name] - Shows Item info (type, price, etc)
-  1:@whodrops [Item ID|Part of item name] - Shows who drops an item (mobs with highest drop rates)
-  1:@version - Displays SVN version of the server
-  1:@email <actual@email> <new@email> - to change your e-mail (characters protection)
-  1:@where [char name] - Tells you the location of a character
-  1:@time/@date/@server_date/@serverdate/@server_time/@servertime - Display the date/time of the server
- 10:@showexp - Displays/Hides Experience gained.
- 10:@showzeny - Displays/Hides Zeny gained.
- 10:@mobsearch [Mob ID|Monster Name] - Shows the location of a certain mob on the current map.
- 20:@who/@whois/@w [match_text] - Display a listing of who is online and their party/guild.
- 20:@who2 [match_text] - Display a listing of who is online and their job.
- 20:@who3 [match_text] - Display a listing of who is online and where.
- 20:@whomap/@whomap2/@whomap3 [map] - like @who/@who2/@who3 but only for specifical map.
- 20:@whogm [match_text] - Like @who+@who2+who3, but only for GM.
- 40:@charcartlist <char name> - Displays all items of a player's cart.
- 60: 
- 60:@guildspy <guild_name/id> - You will receive all messages of the guild channel (Chat logging must be enabled)
- 60:@partyspy <party_name/id> - You will receive all messages of the party channel (Chat logging must be enabled)
- 99:@mapinfo [<0-3> [map]] - Give information about a map (general info +: 0: no more, 1: players, 2: NPC, 3: shops/chat).
-  1: 
-  1:--- CHANGE GM STATE CMD ---
-  1:@die - Kills yourself
- 10:@go <number/city_name> - Warps you to a city.
- 10:  -3: (Memo point 2)  1: morocc   5: izlude         9: yuno     13: niflheim
- 10:  -2: (Memo point 1)  2: geffen   6: aldebaran     10: amatsu   14: louyang
- 10:  -1: (Memo point 0)  3: payon    7: xmas (lutie)  11: gonryun  15: start point
- 10:   0: prontera        4: alberta  8: comodo        12: umbala   16: prison/jail
- 10: 
- 20:/shift/@jumpto/@warpto/@goto <char name> - Warps you to selected character
- 20:@follow <char_name> - follow a player
- 20:@mountpeco - Give/remove you a peco (Class is required, but not skill)
- 20:@disguise <monster_name_or_monster_ID> - Change your appearence to other players to a mob.
- 20:@undisguise - Restore your normal appearance.
- 20:@model <hair ID: 0-17> <hair color: 0-8> <clothes color: 0-4> - Changes your characters appearence.
- 20:@size <1-3> Changes your size (1-Smallest 2-Biggest 3-Normal)
- 40:/hide/@hide - Makes you character invisible (GM invisibility). Type /hide or@hide again become visible.
- 40:@save - Sets respawn point to current spot
- 40:@load/@return - Warps you to your save point
- 40:/mm//mapmove/@warp/@rura/@mapmove <mapname> <x> <y> - Warps you to the selected position
- 40:@jump [x [y]]- Randomly warps you like a flywing.
- 40:@job/@jobchange <job ID> - Changes your job
- 40:   0: Novice           18: Alchemist      4015: Paladin
- 40:   1: Swordman         19: Bard           4016: Champion
- 40:   2: Mage             20: Dancer         4017: Professor
- 40:   3: Archer           23: Super Novice   4018: Stalker
- 40:   4: Acolyte        4001: High Novice    4019: Creator
- 40:   5: Merchant       4002: High Swordman  4020: Clown
- 40:   6: Thief          4003: High Mage      4021: Gypsy
- 40:   7: Knight         4004: High Archer    4046: Taekwon
- 40:   8: Priest         4005: High Acolyte   4047: Star Gladiator
- 40:   9: Wizard         4006: High Merchant  4049: Soul Linker
- 40:  10: Blacksmith     4007: High Thief     24: Gunslinger
- 40:  11: Hunter         4008: Lord Knight    25: Ninja
- 40:  12: Assassin       4009: High Priest
- 40:  14: Crusader       4010: High Wizard
- 40:  15: Monk           4011: Whitesmith
- 40:  16: Sage           4012: Sniper
- 40:  17: Rogue          4013: Assassin Cross
- 40: ---- Baby Classes ----
- 40: 4023: Baby          4024: Baby Swordman   4025: Baby Mage
- 40: 4026: Baby Archer   4027: Baby Acolyte    4028: Baby Merchant
- 40: 4029: Baby Thief    4030: Baby Knight     4031: Baby Priest
- 40: 4032: Baby Wizard   4033: Baby Blacksmith 4034: Baby Hunter
- 40: 4035: Baby Assassin 4037: Baby Crusader   4038: Baby Monk
- 40: 4039: Baby Sage     4040: Baby Rogue      4041: Baby Alchemist
- 40: 4042: Baby Bard     4043: Baby Dancer     4045: Super Baby
- 40: 
- 40:	<param1>      <param2>      <p3>(stackable)   <param3>               <param3>
- 40:	1 Petrified   (stackable)   01 Sight           32 Peco Peco riding   2048 Orc Head
- 40:	2 Frozen      01 Poison     02 Hide            64 GM Perfect Hide    4096 Wedding Sprites
- 40:	3 Stunned     02 Cursed     04 Cloak          128 Level 2 Cart       8192 Ruwach
- 40:	4 Sleeping    04 Silenced   08 Level 1 Cart   256 Level 3 Cart
- 40:	6 darkness    08 ???        16 Falcon         512 Level 4 Cart
- 40:	              16 darkness                    1024 Level 5 Cart
- 40: 
- 40:@heal [<HP> <SP>] - Heals the desired amount of HP and SP. No value specified will do a full heal.
- 40:@option <param1> <param2> <param3> - Adds different visual effects on or around your character
- 40:@dye/@ccolor <clothes color: 0-4> - Changes your characters appearence (only clothes color).
- 40:@hairstyle/@hstyle <hair ID: 0-17> - Changes your characters appearence (only hair style).
- 40:@haircolor/@hcolor <hair color: 0-8> - Changes your characters appearence (only hair color).
- 40:@speed <1-1000> - Changes you walking speed. 1 being the fastest and 1000 the slowest. Default 150.
- 40:@effect <effect_id> [flag] - Give an efect to your character.
- 40:@dropall - throws all your possession on the ground
- 40:@storeall - puts all your possessions in storage
- 40:@killable - make your character killable
- 40:@memo [memo_position] - set/change a memo location (no position: display memo points).
- 40:@spiritball <number: 1-1000> - Gives you "spirit spheres" like from the skill "Call Spirits"
- 40:	(If the number you use is > 1000, your server may become instable or crash)
- 40:@questskill <#> - Gives you the specified quest skill
- 40:@lostskill <#> - Takes away the specified quest skill from you
- 40:@skillid <name> - look up a skill by name
- 40:@useskill <skillid> <skillv> <target> - use a skill on target
- 40:  Novice                 Swordsman                  Thief                Merchant
- 40:  142 = Emergency Care   144 = Moving HP Recovery   149 = Throw Sand     153 = Cart Revolution
- 40:  143 = Act dead         145 = Attack Weak Point    150 = Back Sliding   154 = Change Cart
- 40:  Archer                 146 = Auto Berserk         151 = Take Stone     155 = Crazy Uproar/Loud Voice
- 40:  147 = Arrow Creation   Acolyte                    152 = Stone Throw    Magician
- 40:  148 = Charge Arrows    156 = Holy Light                                157 = Energy Coat
- 40: @skilltree <
- 40: @marry <player1>,<player2> - marry two players
- 40: @divorce <player>  - divorces the two players (you need just one name of them)
- 60:@alive - Revives yourself from death
- 60:@lvup/@blevel/@baselvlup <number of levels> - Raises your base level the desired number of levels. The max is 255 (User Defined).
- 60:@joblvup/@jlevel/@joblvlup <number of levels> -Raises your job level the desired number of levels. The max is 50 For Basic Classes. For Super Novice and Advanced Classes it is 70.
- 60:@allskill/@allskills/@skillall/@skillsall - Give you all skills.
- 60:@stpoint <number of points> - Gives you the desired number of stat points.
- 60:@skpoint <number of points> - Gives you the desired number of skill points.
- 60:@zeny <amount> - Gives you desired amount of Zeny.
- 60:@cash <amount> - Gives you the specified amount of cash points.
- 60:@points <amount> - Gives you the specified amount of Kafra Points.
- 60:@str,@agi,@vit,@int,@dex,@luk <amount> - Adds desired amount to any stat. For example "@str 10" raises your str by 10
- 60:@statall/@statsall/@allstats/@allstat [value] - Adds value in all stats (maximum if no value).
- 60: @addwarp <map name> <x coord> <y coord>
- 40: 
- 40:--- MONSTERS CMD ---
- 40:@killmonster2 - kill all monsters of your map (without drops)
- 50:/monster <monster_name> - Spawns 1 of the desired monster.
- 50:@spawn/@monster/@summon <monster_name_or_monster_ID> [<number to spawn> [<desired_monster_name> [<x coord> [<y coord>]]]]
- 50:@monster2 <desired_monster_name> <monster_name_or_monster_ID> [<number to spawn> [<x coord> [<y coord>]]]
- 50:@spawn/@monster/@summon/@monster2 "desired monster name" <monster_name_or_monster_ID> [<number to spawn> [<x coord> [<y coord>]]]
- 50:@spawn/@monster/@summon/@monster2 <monster_name_or_monster_ID> "desired monster name" [<number to spawn> [<x coord> [<y coord>]]]
- 50:	Spawns the desired monster with any desired name.
- 50:@monstersmall [Mob ID|Mob Name] - Spawns a smaller version of a monster.
- 50:@monsterbig [Mob ID|Mob Name] - Spawns a larger version of a monster.
- 60:@killmonster [map] - kill all monsters of the map (they drop)
- 40: 
- 10:--- MISC CMD ---
- 10:@autoloot [on|off|#] - Makes items go straight into your inventory.
- 10:@autotrade/@at - Allows you to vend while you are offline.
- 10:@changegm [Player Name] - Changes the leader of your guild (You must be guild leader)
- 10:@changeleader [Player Name] - Changes the leader of your party (You must be party leader)
- 20:@request [Message] - Sends a message to all connected GMs (via the gm whisper system)
- 40:@sound [Path way to file in Data or GRF file] - Plays a sound from the data or grf file located on the client.
- 50:@clone [Player Name] - Spawns a supportive clone of the given player.
- 50:@slaveclone [Player Name] - Spawns a supportive clone of the given player that follows the creator around.
- 50:@evilclone [Player Name] - Spawns an agressive clone of the given player.
- 60:@changesex - Changes your gender.
- 10: 
-  1:--- DUEL CMD ---
-  1:@duel - Starts a duel.
-  1:@invite - Invites a player to a duel.
-  1:@accept - Accepts an invitation to a duel.
-  1:@reject - Rejects an invitation to a duel.
-  1:@leave - Leaves a duel.
-  1: 
-  1:--- MAIL SYSTEM --- (SQL Only)
-  1:@mail - Open mail box.
+// This is help file that contains help messages for atcommands/charcommands.
+
+// Format:
+// <command>: "<help message>"
+
+// This file uses libconfig syntax.
+
+help: "Params: <command>\n" "Shows help for specified command."
+main: "Params: [on|off|<message>]\n" "Turns on or off main (server-wide) chat. Sends message to main chat."
+noask: "Auto rejects deals/invites."
+gmotd: "Broadcasts the Message of The Day to all players."
+me: "Params: <message>\n" "Displays normal text as a message in this format: *name message* (like /me in mIRC)."
+fakename: "Params: <name>\n" "Changes your name to your choice temporarily."
+npctalk: "Params: <NPC name> <message>\n" "Forces a NPC to display a message in normal chat."
+broadcast: "Params: <message>\n" "Broadcasts a message with your name (in yellow)."
+kami: "Params: <message>\n" "Broadcasts a message without your name (in yellow)."
+kamib: "Params: <message>\n" "Broadcasts a message without your name (in blue)."
+localbroadcast: "Params: <message>\n" "Broadcasts a message with your name (in yellow) only on your map."
+commands: "Displays a list of commands that you can use."
+rates: "Displays the server's current rates."
+uptime: "Displays how long the server has been online."
+showdelay: "Shows/hides the \"There is a delay after this skill\" message."
+exp: "Displays current levels and % progress."
+mobinfo: "Params: <monster ID>|<monster name>\n" "Shows monster info (stats, exp, drops etc)."
+iteminfo: "Params: <item ID>|<item name>\n" "Shows item info (type, price etc)."
+whodrops: "Params: <item ID>|<item name>\n" "Shows who drops an item (monster with highest drop rates)."
+version: "Displays SVN version of the server."
+email: "Params: <current email> <new email>\n" "Changes your account e-mail address."
+where: "Params: <char name>\n" "Tells you the location of a character."
+time: "Shows the date and time of the server."
+showexp: "Displays/hides experience gained."
+showzeny: "Displays/hides Zeny gained."
+mobsearch: "Params: <monster ID>|<monster name>\n" "Shows the location of a certain mob on the current map."
+who: "Params: [<name>]\n" "Shows a list of online players and their party and guild."
+who2: "Params: [<name>]\n" "Shows a list of online players and their job."
+who3: "Params: [<name>]\n" "Shows a list of online players and their location."
+whomap: "@whomap/@whomap2/@whomap3 [map] - like @who/@who2/@who3 but only for specifical map."
+whogm: "Params: [match_text] - Like @who+@who2+who3, but only for GM."
+guildspy: "Params: <guild_name/id> - You will receive all messages of the guild channel (Chat logging must be enabled)"
+partyspy: "@partyspy <party_name/id> - You will receive all messages of the party channel (Chat logging must be enabled)"
+mapinfo: "Params: [<0-3> [map]] - Give information about a map (general info +: 0: no more, 1: players, 2: NPC, 3: shops/chat)."
+die: "Kills yourself."
+go: "Params: <number/city_name>\n" "Warps you to a city.\n"
+	"  -3: (Memo point 2)  1: morocc   5: izlude         9: yuno     13: niflheim \n"
+	"  -2: (Memo point 1)  2: geffen   6: aldebaran     10: amatsu   14: louyang\n"
+	"  -1: (Memo point 0)  3: payon    7: xmas (lutie)  11: gonryun  15: start point\n"
+	"   0: prontera        4: alberta  8: comodo        12: umbala   16: prison/jail\n"
+jumpto: "Params: <char name>\n" "Warps you to selected character."
+follow: "Params: <char_name>\n" "Follow a player."
+mount: "Give/remove you a peco (Class is required, but not skill)"
+disguise: "Params: <monster_name_or_monster_ID>\n" "Change your appearence to other players to a mob."
+undisguise: "Restore your normal appearance."
+model: "Params:  <hair ID: 0-17> <hair color: 0-8> <clothes color: 0-4> - Changes your characters appearence."
+size: "Params:  <1-3> Changes your size (1-Smallest 2-Biggest 3-Normal)"
+hide: "Makes you character invisible (GM invisibility). Type again to become visible."
+save: "Sets respawn point to current spot."
+load: "Warps you to your save point."
+warp: "Params: <mapname> [<x> <y>]\n" "Warps you to the selected map and position."
+jump: "Params: [<x> [<y>]]\n" "Randomly warps you like a flywing."
+jobchange: "Params: <job ID>\n" "Changes your job.\n"
+"   0: Novice           18: Alchemist      4015: Paladin\n"
+"   1: Swordman         19: Bard           4016: Champion\n"
+"   2: Mage             20: Dancer         4017: Professor\n"
+"   3: Archer           23: Super Novice   4018: Stalker\n"
+"   4: Acolyte        4001: High Novice    4019: Creator\n"
+"   5: Merchant       4002: High Swordman  4020: Clown\n"
+"   6: Thief          4003: High Mage      4021: Gypsy\n"
+"   7: Knight         4004: High Archer    4046: Taekwon\n"
+"   8: Priest         4005: High Acolyte   4047: Star Gladiator\n"
+"   9: Wizard         4006: High Merchant  4049: Soul Linker\n"
+"  10: Blacksmith     4007: High Thief     24: Gunslinger\n"
+"  11: Hunter         4008: Lord Knight    25: Ninja\n"
+"  12: Assassin       4009: High Priest\n"
+"  14: Crusader       4010: High Wizard\n"
+"  15: Monk           4011: Whitesmith\n"
+"  16: Sage           4012: Sniper\n"
+"  17: Rogue          4013: Assassin Cross\n"
+" ---- Baby Classes ----\n"
+" 4023: Baby          4024: Baby Swordman   4025: Baby Mage\n"
+" 4026: Baby Archer   4027: Baby Acolyte    4028: Baby Merchant\n"
+" 4029: Baby Thief    4030: Baby Knight     4031: Baby Priest\n"
+" 4032: Baby Wizard   4033: Baby Blacksmith 4034: Baby Hunter\n"
+" 4035: Baby Assassin 4037: Baby Crusader   4038: Baby Monk\n"
+" 4039: Baby Sage     4040: Baby Rogue      4041: Baby Alchemist\n"
+" 4042: Baby Bard     4043: Baby Dancer     4045: Super Baby\n"
+option: "Params: <param1> <param2> <param3>\n" "Adds different visual effects on or around your character.\n"
+"<param1>      <param2>      <p3>(stackable)   <param3>               <param3>\n"
+"1 Petrified   (stackable)   01 Sight           32 Peco Peco riding   2048 Orc Head\n"
+"2 Frozen      01 Poison     02 Hide            64 GM Perfect Hide    4096 Wedding Sprites\n"
+"3 Stunned     02 Cursed     04 Cloak          128 Level 2 Cart       8192 Ruwach\n"
+"4 Sleeping    04 Silenced   08 Level 1 Cart   256 Level 3 Cart\n"
+"6 darkness    08 ???        16 Falcon         512 Level 4 Cart\n"
+"              16 darkness                    1024 Level 5 Cart\n"
+heal: "Params: [<HP> <SP>]\n" "Heals the desired amount of HP and SP. No value specified will do a full heal."
+dye: "Params: <clothes palette no.>\n" "Changes your characters clothes color."
+hairstyle: "Params: <hairstyle no.>\n" "Changes your hair style."
+haircolor: "Params <hair palette no.>\n" "Changes your hair color."
+speed: "Params: <1-1000>\n" "Changes you walking speed. 1 being the fastest and 1000 the slowest. Default is 150."
+effect: "Params: <effect id> [<flag>]\n" "Give an effect to your character."
+dropall: "Throws all your possession on the ground."
+storeall: "Puts all your possessions in storage."
+killable: "Make your character killable."
+memo: "Params: [memo position]\n" "Set/change a memo location (no position: display memo points)."
+spiritball: "Params: <1-100>\n" "Gives you \"spirit spheres\" like from the skill \"Call Spirits\".\n"
+questskill: "Params: <#>\n" "Gives you the specified quest skill"
+lostskill: "Params: <#>\n" "Takes away the specified quest skill from you\n"
+"   Novice                 Swordsman                  Thief                Merchant\n"
+"   142 = Emergency Care   144 = Moving HP Recovery   149 = Throw Sand     153 = Cart Revolution\n"
+"   143 = Act dead         145 = Attack Weak Point    150 = Back Sliding   154 = Change Cart\n"
+"   Archer                 146 = Auto Berserk         151 = Take Stone     155 = Crazy Uproar/Loud Voice\n"
+"   147 = Arrow Creation   Acolyte                    152 = Stone Throw    Magician\n"
+"   148 = Charge Arrows    156 = Holy Light                                157 = Energy Coat\n"
+skillid: "Params: <name>\n" "Look up a skill by name"
+useskill: "Params: <skillid> <skillv> <target>\n" "Use a skill on target"
+skilltree: "Params: <"
+marry: "Params: <player1>,<player2>\n" "Marry two players."
+divorce: "Params: <player>\n" "Divorces the two players (you need just one name of them)"
+alive: "Revives yourself from death."
+blvl: "Params: <number of levels>\n" "Raises your base level the desired number of levels."
+jlvl: "Params: <number of levels>\n" "Raises your job level the desired number of levels."
+allskill: "Give you all skills."
+stpoint: "Params: <number of points> - Gives you the desired number of stat points."
+skpoint: "Params: <number of points> - Gives you the desired number of skill points."
+zeny: "Params: <amount> - Gives you desired amount of Zeny."
+cash: "Params: <amount> - Gives you the specified amount of cash points."
+points: "Params: <amount> - Gives you the specified amount of Kafra Points."
+str: "Params: <amount>\n" "Raises STR by given amount."
+agi: "Params: <amount>\n" "Raises AGI by given amount."
+dex: "Params: <amount>\n" "Raises DEX by given amount."
+vit: "Params: <amount>\n" "Raises VIT by given amount."
+int: "Params: <amount>\n" "Raises INT by given amount."
+luk: "Params: <amount>\n" "Raises LUK by given amount."
+allstats: "Params: <value>\n" "Adds value in all stats (maximum if no value)."
+addwarp: "Params: <map name> <x coord> <y coord>\n"
+killmonster2: "Kills all monsters of your map (without drops)."
+monster: "Params: <monster_name_or_monster_ID> [<number to spawn> [<desired_monster_name> [<x coord> [<y coord>]]]]\n"
+ "@monster2 <desired_monster_name> <monster_name_or_monster_ID> [<number to spawn> [<x coord> [<y coord>]]]\n"
+"@spawn/@monster/@summon/@monster2 \"desired monster name\" <monster_name_or_monster_ID> [<number to spawn> [<x coord> [<y coord>]]]\n"
+"@spawn/@monster/@summon/@monster2 <monster_name_or_monster_ID> \"desired monster name\" [<number to spawn> [<x coord> [<y coord>]]]\n"
+"	Spawns the desired monster with any desired name."
+monstersmall: "Params: [Mob ID|Mob Name]\n" "Spawns a smaller version of a monster."
+monsterbig: "Params: [Mob ID|Mob Name]\n" "Spawns a larger version of a monster."
+killmonster: "Params: [map]\n" "Kill all monsters of the map (they drop)"
+autoloot: "Params: [on|off|#]\n" "Makes items go straight into your inventory."
+autotrade: "Allows you to vend while you are offline."
+changegm: "Params: [Player Name]\n" "Changes the leader of your guild (You must be guild leader)"
+changeleader: "Params: [Player Name]\n" "Changes the leader of your party (You must be party leader)"
+request: "Params: [Message]\n" "Sends a message to all connected GMs (via the gm whisper system)"
+sound: "Params: [Path way to file in Data or GRF file]\n" "Plays a sound from the data or grf file located on the client."
+clone: "Params: [Player Name]\n" "Spawns a supportive clone of the given player."
+slaveclone: "Params: [Player Name]\n" "Spawns a supportive clone of the given player that follows the creator around."
+evilclone: "Params: [Player Name]\n" "Spawns an agressive clone of the given player."
+changesex: "Changes your gender."
+duel: "Starts a duel."
+invite: "Invites a player to a duel."
+accept: "Accepts an invitation to a duel."
+reject: "Rejects an invitation to a duel."
+leave: "Leaves a duel."
+mail: "Open mail box."
+storage: "Opens storage."
+itemreset: "Remove all your items."
+guildstorage: "Opens guild storage."
+idsearch: "Params: <part_of_item_name>\n" "Search all items that name have part_of_item_name"
+refine: "Params: <equip position> <+/- amount>"
+produce: "Params: <equip name or equip ID> <element> <# of very's>\n"
+"	Element: 0=None 1=Ice 2=Earth 3=Fire 4=Wind\n"
+"	You can add up to 3 Star Crumbs and 1 element\n"
+repairall: "Repair all items of your inventory"
+item: "Params: <item name or ID> <quantity>\n" "Gives you the desired item."
+item2: "Params: <item name or ID> <quantity> <identified_flag> <refine> <broken_flag> <Card1> <Card2> <Card3> <Card4>\n" "Gives you the desired item."
+pvpon: "Turns pvp on on the current map"
+pvpoff: "Turns pvp off on the current map"
+gvgon: "Turns gvg on on the current map"
+gvgoff: "Turns gvg off on the current map"
+agitstart: "Starts War of Emperium"
+agitend: "End War of Emperium"
+party: "Params: <party_name>\n" "Create a party."
+guild: "Params: <guild_name>\n" "Create a guild."
+glvl: "Params: <# of levels>\n" "Raise Guild by desired number of levels"
+guildrecall: "Params: <guild_name/id>\n" "Warps all online characters of a guild to you."
+partyrecall: "Params: <party_name/id>\n" "Warps all online characters of a party to you."
+petrename: "Re-enable pet rename"
+pettalk: "Params: [Message]\n" "Makes your pet say a message."
+petfriendly: "Params: <#>\n" "Set pet friendly amount (0-1000) 1000 = Max"
+pethungry: "Params: <#>\n" "Set pet hungry amount (0-100) 100 = Max"
+hatch: "Create a pet from your inventory eggs list."
+makeegg: "Params: <pet_id>\n" "Gives pet egg for monster number in pet DB"
+kick: "Params: <char name>\n" "Kicks specified character off the server"
+unjail: "Params: <char name>\n" "Discharges specified character/prisoner"
+kill: "Params: <char name>\n" "Kills specified character."
+recall: "Params: <char name>\n" "Warps target character to you."
+raise: "Params: <char name>\n" "Revives target character."
+block: "Params: <char name>\n" "Blocks definitively a account"
+unblock: "Params: <char name>\n" "Unblocks a account"
+ban: "Params: <time> <name>\n" "Ban temporarily a account\n"
+ "	time usage: adjustment (+/- value) and element (y/a, m, d/j, h, mn, s)\n"
+ "	Example: @ban +1m-2mn1s-6y testplayer\n"
+unban: "Params: <name> - Unban a account"
+jail: "Params: <char name> - Sends specified character in jails"
+trade: "Params: <char name> - Open a trade window with a another player"
+recallall: "Warps every character online to you."
+doom: "Kills all NON GM chars on the server."
+doommap: "Kills all non GM characters on the map."
+raisemap: "Resurrects all characters on the map."
+night: "Uses @option 00 16 00 on all characters. All characters are in darkness."
+day: "Uses @option 00 00 00 on all characters."
+skillon: "turn skills on for a map"
+skilloff: "turn skills on for a map"
+snow: "Makes all maps to have the snow weather effect."
+clouds: "Makes all maps to have the cloudy weather effect."
+clouds2: "Makes all maps to have another cloudy weather effect."
+fog: "Makes all maps to have the fog weather effect."
+fireworks: "Makes all maps to have the fireworks weather effect."
+sakura: "Makes all maps to have the sakura weather effect."
+leaves: "Makes all maps to have the leaves weather effect."
+shownpc: "Params: <NPC name>\n" "Enable a NPC"
+hidenpc: "Params: <NPC name>\n" "Disable a NPC"
+loadnpc: "Params: <path to script>\n" "Load script"
+unloadnpc: "Params: <NPC name>\n" "Unload script"
+adjgroup: "Params: <level> <char name> - Do a temporary adjustment of the GM level of a player"
+kickall: "Kick all characters off the server"
+mapexit: "Kick all players and shut down map-server."
+reloaditemdb: "Reload item database."
+reloadmobdb: "Reload monster database."
+reloadskilldb: "Reload skills definition database."
+reloadscript: "Reload all scripts."
+gat: "For debugging (you inspect around gat)"
+send: "For debugging (packet variety)"
+nuke: "Params: <char name>\n"
+

+ 0 - 94
conf/help2.txt

@@ -1,94 +0,0 @@
-  0:To use one command, type it inside the message window where you usually type to chat.
-  1:--- ITEMS CMD ---
-  1:@storage - Opens storage
- 40:@itemreset - Remove all your items.
- 50:@gstorage - Opens guild storage
- 60:@itemcheck - Check your items with authorised items.
- 60:@idsearch <part_of_item_name> - Search all items that name have part_of_item_name
- 60:@refine <equip position> <+/- amount>
- 60:@produce <equip name or equip ID> <element> <# of very's>
- 60:	Element: 0=None 1=Ice 2=Earth 3=Fire 4=Wind
- 60:	You can add up to 3 Star Crumbs and 1 element
- 60:@repairall - Repair all items of your inventory
- 60:/item <item_name> - Gives you 1 of the desired item.
- 60:@item <item name or ID> <quantity> - Gives you the desired item.
- 60:@item2 <item name or ID> <quantity> <identified_flag> <refine> <broken_flag> <Card1> <Card2> <Card3> <Card4> - Gives you the desired item.
- 40: 
- 40:--- PVP CMD ---
- 40:@pvpon - Turns pvp on on the current map
- 40:@pvpoff - Turns pvp off on the current map
- 40:@gvgon/@gpvpon - Turns gvg on on the current map
- 40:@gvgoff/@gpvpoff - Turns gvg off on the current map
- 60:@agitstart - Starts War of Emperium
- 60:@agitend - End War of Emperium
-  1: 
-  1:--- GROUPS CMD ---
-  1:@party <party_name> - Create a party.
- 50:@guild <guild_name> - Create a guild.
- 60:@guildlvup/@guildlvlup <# of levels> - Raise Guild by desired number of levels
- 60:@guildrecall <guild_name/id> - Warps all online characters of a guild to you.
- 60:@partyrecall <party_name/id> - Warps all online characters of a party to you.
-  1: 
-  1:--- PETS CMD ---
-  1:@petrename - Re-enable pet rename
- 10:@pettalk [Message] - Makes your pet say a message.
- 40:@petfriendly <#> - Set pet friendly amount (0-1000) 1000 = Max
- 40:@pethungry <#> - Set pet hungry amount (0-100) 100 = Max
- 60:@hatch - Create a pet from your inventory eggs list.
- 60:@makeegg <pet_id> - Gives pet egg for monster number in pet DB
- 20: 
- 20:--- REMOTE CHAR CMD ---
- 20:@kick <char name> - Kicks specified character off the server
- 40:@charkillable <char name> - make another character killable
- 60:@unjail/@discharge <char name> - Discharges specified character/prisoner
- 60:@kill <char name> - Kills specified character.
- 60:@chardropall <char name> - throws all a chars possession on the ground
- 60:@charstoreall <char name> - puts all of anothers charactes possessions in storage
- 60:/recall/@recall <char name> - Warps target character to you.
- 60:@revive <char name> - Revives target character.
- 60:@charblock/@block <char name> - Blocks definitively a account
- 60:@charunblock/@unblock <char name> - Unblocks a account
- 60:@charban/@ban/@banish/@charbanish <time> <name> - Ban temporarily a account
- 60:	time usage: adjustment (+/- value) and element (y/a, m, d/j, h, mn, s)
- 60:	Example: @ban +1m-2mn1s-6y testplayer
- 60:@charunban/@unban/@unbanish/@charunbanish <name> - Unban a account
- 60:@jail <char name> - Sends specified character in jails
- 60:@trade <char name> - Open a trade window with a another player
- 80:@recallall - Warps every character online to you.
- 80:@doom - Kills all NON GM chars on the server.
- 80:@doommap - Kills all non GM characters on the map.
- 80:@raise - Resurrects all characters on the server.
- 80:@raisemap - Resurrects all characters on the map.
- 80: 
- 80:--- ENVIRONMENT CMD ---
- 80:@night - Uses @option 00 16 00 on all characters. All characters are in darkness.
- 80:@day - Uses @option 00 00 00 on all characters.
- 80:@skillon - turn skills on for a map
- 80:@skilloff - turn skills on for a map
- 99:@rain - Makes all maps to have the rain weather effect.
- 99:@snow - Makes all maps to have the snow weather effect.
- 99:@clouds - Makes all maps to have the cloudy weather effect.
- 99:@clouds2 - Makes all maps to have another cloudy weather effect.
- 99:@fog - Makes all maps to have the fog weather effect.
- 99:@fireworks - Makes all maps to have the fireworks weather effect.
- 99:@sakura - Makes all maps to have the sakura weather effect.
- 99:@leaves - Makes all maps to have the leaves weather effect.
- 80: 
- 80:--- ADMIN CMD ---
- 80:@shownpc <NPC name> - Enable a NPC
- 80:@hidenpc <NPC name> - Disable a NPC
- 80:@loadnpc <path to script> - Load script
- 80:@unloadnpc <NPC name> - Unload script
- 99:@adjgmlvl <level> <char name> - Do a temporary adjustment of the GM level of a player
- 99:@adjcmdlvl <level> <command> - Do a temporary adjustment of the GM level of a command
- 99:@kickall - Kick all characters off the server
- 99:@mapexit - Kick all players and shut down map-server.
- 99:@reloaditemdb - Reload item database.
- 99:@reloadmobdb - Reload monster database.
- 99:@reloadskilldb - Reload skills definition database.
- 99:@reloadscript - Reload all scripts.
- 99:@reloadgmdb - Reload GM levels.
- 99: 
- 99:@gat - For debugging (you inspect around gat)
- 99:@packet - For debugging (packet variety)
-100:@nuke <char name> -

+ 4 - 2
conf/log_athena.conf

@@ -84,8 +84,10 @@ log_zeny: 0
 // Outdated. Use Pick_Log instead. But this log could be useful to keep track slayed MVPs
 log_mvpdrop: no
 
-// Log GM Commands (set to minimum level of Logged Commands)
-log_gm: 40
+// Log AtCommands & Charcommands (Note 1)
+// Only commands issued by player groups ('conf/groups.conf') with
+// 'log_commands' setting set to 'true' will be logged.
+log_commands: yes
 
 // Log NPC 'logmes' commands (Note 1)
 log_npc: no

+ 4 - 3
conf/login_athena.conf

@@ -62,9 +62,10 @@ log_login: yes
 // Indicate how to display date in logs, to players, etc.
 date_format: %Y-%m-%d %H:%M:%S
 
-// Indicate the minimum GM level of player that the server accepts to connection.
-// 0: all players (normal player are 0. it's default), 1-99: GM level at least with level x
-min_level_to_connect: 0
+// Required account group id to connect to server.
+// -1: disabled
+// 0 or more: group id
+group_id_to_connect: -1
 
 // Starting additional sec from now for the limited time at creation of account
 // -1: new account are created with UNlimited time (default value)

+ 1 - 11
conf/msg_athena.conf

@@ -44,7 +44,7 @@
 24: Job level raised.
 25: Job level lowered.
 26: Help commands:
-27: File help.txt not found.
+27: Commands help is not available.
 28: No player found.
 29: 1 player found.
 30: %d players found.
@@ -348,16 +348,6 @@
 // 334: Thirty-Four Castles
 334: Total Domination
 
-// Players Titles (for @who, etc commands, check battle_athena.conf for titles level setting)
-// Useful note: you may remove ':%d' from the line, then you will see only player title, w/o his level
-335: Super player:%d
-336: Super player+:%d
-337: Mediator:%d
-338: Sub-GM:%d
-339: Sub-GM+:%d
-340: GM:%d
-341: GM Chief:%d
-342: Administrator:%d
 // Templates for @who output
 343: Name: %s 
 344: (%s) 

+ 286 - 2
configure

@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.in Revision: 15238 .
+# From configure.in Revision: 15503 .
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.59.
 #
@@ -1334,7 +1334,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
                     ac_config_files="$ac_config_files Makefile src/common/Makefile"
 
-          ac_config_files="$ac_config_files 3rdparty/mt19937ar/Makefile"
+                    ac_config_files="$ac_config_files 3rdparty/mt19937ar/Makefile 3rdparty/libconfig/Makefile"
 
                     ac_config_files="$ac_config_files src/char/Makefile src/login/Makefile"
 
@@ -3737,6 +3737,289 @@ if test $ac_cv_func_strnlen = yes; then
 fi
 
 
+# libconfig
+echo "$as_me:$LINENO: checking for uselocale" >&5
+echo $ECHO_N "checking for uselocale... $ECHO_C" >&6
+if test "${ac_cv_func_uselocale+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define uselocale to an innocuous variant, in case <limits.h> declares uselocale.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define uselocale innocuous_uselocale
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char uselocale (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef uselocale
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char uselocale ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_uselocale) || defined (__stub___uselocale)
+choke me
+#else
+char (*f) () = uselocale;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != uselocale;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_uselocale=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_uselocale=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_uselocale" >&5
+echo "${ECHO_T}$ac_cv_func_uselocale" >&6
+if test $ac_cv_func_uselocale = yes; then
+  CFLAGS="$CFLAGS -DHAVE_USELOCALE"
+fi
+
+echo "$as_me:$LINENO: checking for newlocale" >&5
+echo $ECHO_N "checking for newlocale... $ECHO_C" >&6
+if test "${ac_cv_func_newlocale+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define newlocale to an innocuous variant, in case <limits.h> declares newlocale.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define newlocale innocuous_newlocale
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char newlocale (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef newlocale
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char newlocale ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_newlocale) || defined (__stub___newlocale)
+choke me
+#else
+char (*f) () = newlocale;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != newlocale;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_newlocale=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_newlocale=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_newlocale" >&5
+echo "${ECHO_T}$ac_cv_func_newlocale" >&6
+if test $ac_cv_func_newlocale = yes; then
+  CFLAGS="$CFLAGS -DHAVE_NEWLOCALE"
+fi
+
+echo "$as_me:$LINENO: checking for freelocale" >&5
+echo $ECHO_N "checking for freelocale... $ECHO_C" >&6
+if test "${ac_cv_func_freelocale+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define freelocale to an innocuous variant, in case <limits.h> declares freelocale.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define freelocale innocuous_freelocale
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char freelocale (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef freelocale
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char freelocale ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_freelocale) || defined (__stub___freelocale)
+choke me
+#else
+char (*f) () = freelocale;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != freelocale;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_freelocale=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_freelocale=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_freelocale" >&5
+echo "${ECHO_T}$ac_cv_func_freelocale" >&6
+if test $ac_cv_func_freelocale = yes; then
+  CFLAGS="$CFLAGS -DHAVE_FREELOCALE"
+fi
+
 
 #
 # Memory manager
@@ -6166,6 +6449,7 @@ do
   "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
   "src/common/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/common/Makefile" ;;
   "3rdparty/mt19937ar/Makefile" ) CONFIG_FILES="$CONFIG_FILES 3rdparty/mt19937ar/Makefile" ;;
+  "3rdparty/libconfig/Makefile" ) CONFIG_FILES="$CONFIG_FILES 3rdparty/libconfig/Makefile" ;;
   "src/char/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/char/Makefile" ;;
   "src/login/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/login/Makefile" ;;
   "src/map/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/map/Makefile" ;;

+ 5 - 1
configure.in

@@ -6,7 +6,7 @@ AC_REVISION($Revision$)
 AC_PREREQ([2.59])
 AC_CONFIG_SRCDIR([src/common/cbasetypes.h])
 AC_CONFIG_FILES([Makefile src/common/Makefile])
-AC_CONFIG_FILES([3rdparty/mt19937ar/Makefile])
+AC_CONFIG_FILES([3rdparty/mt19937ar/Makefile 3rdparty/libconfig/Makefile])
 AC_CONFIG_FILES([src/char/Makefile src/login/Makefile])
 AC_CONFIG_FILES([src/map/Makefile src/plugins/Makefile src/tool/Makefile])
 
@@ -468,6 +468,10 @@ AC_CHECK_FUNC([setrlimit],[CFLAGS="$CFLAGS -DHAVE_SETRLIMIT"])
 #
 AC_CHECK_FUNC([strnlen],[CFLAGS="$CFLAGS -DHAVE_STRNLEN"])
 
+# libconfig
+AC_CHECK_FUNC([uselocale],[CFLAGS="$CFLAGS -DHAVE_USELOCALE"])
+AC_CHECK_FUNC([newlocale],[CFLAGS="$CFLAGS -DHAVE_NEWLOCALE"])
+AC_CHECK_FUNC([freelocale],[CFLAGS="$CFLAGS -DHAVE_FREELOCALE"])
 
 #
 # Memory manager

+ 213 - 0
doc/atcommands.txt

@@ -0,0 +1,213 @@
+TODO: With such short descriptions, it's duplicated 'conf/help.txt' 
+Consider explaining commands in detail, similar to 'doc/script_commands.txt'
+
+commands: Displays a list of @ commands available to the player.
+charcommands: Displays a list of # commands available to the player.
+rates: Displays the server rates.
+uptime: Show server uptime since last map server restart.
+showdelay: Shows/Hides the "there is a delay after a skill" message.
+exp: Displays current levels and % progress.
+email: To change your (own) email. Note: this command doesn't check email itself, but check structure of the email (xxx@xxx).
+monsterinfo: Show Monster info (rates, stats, drops, MVP stuff).
+iteminfo: Show Item info (type, price, etc).
+whodrops: Show who drops an item (mobs with highest drop rate).
+refresh: Syncs the player's position on the client with the one stored on the server.
+time: Give server time.
+version: Displays SVN version of the server.
+die: Suicide your character.
+petrename: Enables you to rename your pet.
+party: Organize a new party, with you as the party leader.
+storage: Opens your Kafra storage wherever you are.
+mail: Opens your mailbox.
+auction: Opens auctions window.
+where: Locate someone on a map, returns your coordinates if the person isn't on.
+duel, invite, accept, reject, leave: Duel organizing commands.
+main: Main chat.
+noask: Autorejecting Deals/Invites.
+jailtime: Displays remaining jail time.
+hominfo, homstats: Homunculus commands for players
+noks: Kill Steal Protection.
+font: Set Font.
+showexp: Displays/Hides Experience gained messages.
+showzeny: Displays/Hides Zeny gained messages.
+go: Warps you to predefined locations in major cities.
+autoloot: Enables/disables autolooting from killed mobs.
+alootid: Enables/disables autolooting an item.
+autotrade: Allows you continue vending offline.
+changegm: Change Guild Master of your Guild.
+changeleader: Change the leader of your party.
+partyoption: Change the party exp- and item share rules.
+pettalk: Command what the player's pet will say.
+homtalk: Command what the player's homunculus will say.
+mobsearch: Locates and displays the position of a certain mob on the current map.
+showmobs: Locates and displays the position of a certain mob on your mini-map.
+whereis: Prints out in which maps a monster normally spawns at (does not count script-invoked mobs).
+feelreset: Resets a Star Gladiator's marked maps
+help: Displays help about commands.
+goto: Warp yourself to a person.
+gmotd: Displays the motd file to all players.
+follow: Follow a player (including warping to them).
+request: Sends a request to all connected GMs (via the gm whisper system).
+kick: Disconnects a user from the server.
+model: Changes your appearance.
+mount: To get a peco to (un)ride.
+who: Returns list of logged in characters with their position.
+who2: Returns list of logged in characters with their job.
+who3: Returns list of logged in characters with their party/guild.
+whomap: Returns list of logged in characters with their position in a specifical map.
+whomap2: Returns list of logged in characters with their job in a specifical map.
+whomap3: Returns list of logged in characters with their party/guild in a specifical map.
+whogm: Displays GMs online. For those who are higher GM level than yourself, only the name is shown, for the rest, it displays the same info of @who+@who2+who3.
+disguise: Change your appearence to other players to a mob.
+undisguise: Restore your normal appearance.
+me: Displays the text as a normal message with the format "*name message*" instead of "name : message" (Like the /me command in IRC).
+fakename: Changes your name to your choice temporarily.
+size: Changes your size.
+npctalk: Can command what other npcs (by name) can say.
+broadcast: Broadcast to the whole server.
+localbroadcast: Broadcast to the map you are on.
+kami: Broadcast (with or without name).
+kamib: Same as kami but with blue color.
+kamic: Same as kami but you can choose the color (uses different packet).
+gvgon: Enables GvG on a map.
+gvgoff: Turns GvG (Guild vs. Guild) off on a map
+allowks: Activate/Deactivate kill steal protection on a map.
+heal: Modifies your HP/SP.
+hide: GM Hide (total invisibility to characters and monsters)
+job: Changes your job to one you specify.
+jump: Enables you to to jump randomly on a map (that you are already on).
+load: Warps you to your last save point
+tonpc: Warps you to a specific npc.
+memo: Saves a warp point.
+option: Set your character display options. (Visual effects of your character)
+petfriendly: Sets the level of intemecy of your pet.
+pethungry: Sets hunger level of your pet.
+pvpoff: Turns PvP (Person vs. Person) off on a map.
+pvpon: Enables PvP on a map.
+questskill: Permanently adds a quest skill.
+lostskill: Permanently removes a quest skill
+speed: Sets the speed you can walk/attack at. Default is 150.
+spiritball: Summons spirit spheres around you.
+warp: Warp yourself to a certain map, at (x,y) coordinates (2 same commands) + also /mm or /mapmove.
+dye: Changes clothes color.
+hairstyle: Changes hair style.
+haircolor: Changes hair color.
+itemreset: Deletes all your items.
+reset: Does a skill/stat reset.
+users: Displays distribution of players on the server per map (% on each map which has players).
+cleanmap: Deletes floor items in sight range.
+killmonster2: Kill all monsters in map (without drops).
+save: Sets spawn point (aka save point).
+effect: Do some visual effect on a character.
+misceffect: Do some visual effect on a character (misceffect)
+identify: Magnifier.
+dropall: Drop all items.
+storeall: Store all items.
+killable: Allow other players to hit you out of PvP.
+skillid: Look up a skill by name.
+useskill: Use a skill by id.
+skilltree: What skills are required to get this skill.
+marry, divorce: Marriage commands.
+adopt: Adopt a novice into a family.
+sound: Play a Sound!
+storagelist: Displays a player's storage.
+cartlist: Displays a player's cart contents.
+itemlist: Displays a player's inventory.
+stats: Displays player's stats.
+guild: Creates a new guild, with you as the guildmaster.
+gstorage: Brings up your guild storage wherever you are.
+monster: Spawns a monster, and a certain amount.
+monstersmall: Spawns a smaller sized version of a monster.
+monsterbig: Spawns a larger sized version of a monster.
+summon: Spawns mobs that treat you as their master (they disappear after some time).
+clone: It will spawn a supportive clone of the given player.
+slaveclone: It will spawn a supportive clone of the given player that follows the creator around.
+evilclone: It will spawn an aggresive clone of the given player.
+cash: Add or Remove Cash Points
+points: Add or Remove Kafra Points
+agitstart: Starts Guild Wars
+agitend: Ends Guild Wars
+alive: Resurects yourself.
+blvl: Raises your base level by specified amount
+jlvl: Raises your job level by specified amount
+changesex: Changes the sex of yourself
+glvl: Raises your guild level by specified amount
+idsearch: Find an itemID based on item name
+item: Creates an item of your choosing, either Item ID or Name
+item2: Creates a complete item (card, etc...) of your choosing, either Item ID or Name.
+delitem: Deletes an item of your choosing, either Item ID or Name.
+kill: Kill another character without hitting them.
+killmonster: Kill all monsters in map (with drops)
+makeegg: Creates yourself a pet egg.
+hatch: Hatches an egg.
+nuke: Instantly kills player whose name is entered and deals insane damage to everything around.
+killer: Enable hitting a player even when not in PvP
+produce: Creates weapon of desired element.
+recall: Warps a character to you.
+refine: Refines all weapons in your items list.
+repairall: Will repair all broken items in inventory.
+str, agi, vit, int, dex, luk: Change Status of your character.
+allskill: Gives all skills
+allstats: Sets stats to maximum
+stpoint: Gives you stat points.
+skpoint: Gives you skill points of desired amount.
+guildrecall: Warps all online character of a guild to you. (at least one member of that guild must be on.)
+partyrecall: Warps all online character of a party to you. (at least one party member must be online.)
+guildspy: Allows you to spy on any Guilds Guild chat. (at least one member of that guild must be on.) NOTE: map server needs to be configured to enable spying to use this command (enable_spy: yes)
+partyspy: Allows you to spy on any party's party chat. (at least one party member must be online.) NOTE: map server needs to be configured to enable spying to use this command (enable_spy: yes)
+zeny: Gives you zeny (or subtracts, if amount is negative).
+block: Block a player indefinitely.
+unblock: Unblock a player.
+ban: Ban a player for a limited time.
+unban: Unban a player.
+jail: To send specified character in jails.
+unjail: To discharge a jailed character.
+jailfor: Timed jailing.
+addwarp: Create a static warp portal that lasts until the next reboot.
+trade: Open a trade window with any player.
+changelook: Changes the player's appearance (headgear).
+hlvl, homevolve, makehomun, homfriendly, homhungry: Homunculus commands for GMs.
+homshuffle: Re-calculates stats, as if the homun was sent back to level 1 and re-leveled.
+agitstart2, agitend2: WoE 2 start/stop commands.
+streset: Resets player stats
+skreset: Resets player skills
+day: Set the server to day.
+night: Set the server to night.
+doom: Kills everyone on the server.
+doommap: Kills everyone on the map you are on.
+recallall: Recalls Everyone To Your Coordinates
+raisemap: Revives all players on the map.
+raise: Revives all players on the server.
+hidenpc: Hides a NPC.
+shownpc: Unhides a NPC.
+loadnpc: Loads an NPC script by path.
+unloadnpc: Unloads a NPC.
+npcmove: Move a NPC.
+skillon: Turn skills on for a map
+skilloff: Turn skills off for a map
+mute: Mute a player (prevents talking, usage of skills and commands)
+unmute: Unmute a player
+kickall: Disconnect all users from the server.
+mapexit: Closes Map-Server.
+send: Used for testing packet sends from the client (debug function).
+gat: Give information about terrain/area (debug function).
+displaystatus: Displays a status change without really applying it (debug function).
+displayskill: Displays the animation of a skill without really using it (debug function).
+mapinfo: Shows information about the map.
+mapflag: Set Map Flags
+reloaditemdb: Re-load item database (admin command)
+reloadmobdb: Re-load monsters database (admin command)
+reloadskilldb: Re-load skills database (admin command)
+reloadscript: Re-load scripts (admin command)
+setbattleflag: Change a battle_config flag without rebooting server
+reloadatcommand: Re-load atcommand config (admin command)
+reloadbattleconf: Re-load battle config (admin command) Note that some player config settings won't take effect until relog (display exp, display zeny, display skill delay fail, ...)
+reloadstatusdb: Re-load status database (admin command)
+reloadpcdb: Re-load player info database (admin command)
+reloadmotd: Re-load the Message of the Day (admin command)
+adjgroup: Changes the group of another character (lasts until relog)
+disguiseall, undisguiseall: [Un]Disguise All Players (admin command)
+mutearea: Mutes every player on screen (admin command)
+battleignore: Makes you immune to attacks (monsters/players/skills cannot target/hit you, admin command)
+snow, clouds, clouds2, fog, fireworks, sakura, leaves: Weather effects
+clearweather: Stop all weather effects

+ 21 - 0
doc/permissions.txt

@@ -0,0 +1,21 @@
+These are possible permissions of player groups, configured in conf/groups.conf.
+
+can_trade : Ability to trade or otherwise distribute items (drop, storage, vending etc)
+can_party : Ability to join parties.
+all_skill : Ability to use all skills.
+all_equipment : Ability to equip anything (can cause client errors).
+skill_unconditional : Ability to use skills without meeting the required conditions (SP, items, etc...).
+join_chat : Ability to join a password protected chatrooms.
+kick_chat : Protection from being kicked from a chat.
+hide_session : Hides player session from being displayed by @commands.
+who_display_aid : Ability to see GMs and Account/Char IDs in the @who command.
+hack_info : Ability to receive all informations about any player that try to hack, spoof a name, etc.
+any_warp : Ability to bypass nowarp, nowarpto, noteleport and nomemo mapflags.
+          This option is mainly used in commands which modify a character's
+          map/coordinates (like @memo, @mapmove, @go, @jump, etc...).
+view_hpmeter : Ability to see HP bar of every player.
+view_equipment : Ability to view players equipment regardless of their setting.
+use_check : Ability to use client command /check (display character status).
+use_changemaptype : Ability to use client command /changemaptype.
+all_commands: Ability to use ALL atcommands/charcommands.
+receive_requests: Ability to receive @requests.

+ 3 - 0
sql-files/upgrade_svn15572.sql

@@ -0,0 +1,3 @@
+-- Rename `level` column to `group_id` in `login` table
+
+ALTER TABLE `login` CHANGE COLUMN `level` `group_id` TINYINT(3) NOT NULL DEFAULT '0';

+ 15 - 5
src/char/Makefile.in

@@ -3,17 +3,24 @@ COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_a
 	../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \
 	../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \
 	../common/obj_all/strlib.o \
-	../common/obj_all/mapindex.o ../common/obj_all/ers.o ../common/obj_all/random.o
+	../common/obj_all/mapindex.o ../common/obj_all/ers.o ../common/obj_all/random.o ../common/obj_all/conf.o
 COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \
 	../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \
 	../common/malloc.h ../common/showmsg.h ../common/utils.h \
 	../common/strlib.h \
-	../common/mapindex.h ../common/ers.h ../common/random.h
+	../common/mapindex.h ../common/ers.h ../common/random.h ../common/obj_all/conf.h
 
 MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o
 MT19937AR_H = ../../3rdparty/mt19937ar/mt19937ar.h
 MT19937AR_INCLUDE = -I../../3rdparty/mt19937ar
 
+LIBCONFIG_OBJ = ../../3rdparty/libconfig/libconfig.o ../../3rdparty/libconfig/grammar.o \
+	../../3rdparty/libconfig/scanctx.o ../../3rdparty/libconfig/scanner.o ../../3rdparty/libconfig/strbuf.o
+LIBCONFIG_H = ../../3rdparty/libconfig/libconfig.h ../../3rdparty/libconfig/grammar.h \
+	../../3rdparty/libconfig/parsectx.h ../../3rdparty/libconfig/scanctx.h ../../3rdparty/libconfig/scanner.h \
+	../../3rdparty/libconfig/strbuf.h ../../3rdparty/libconfig/wincompat.h
+LIBCONFIG_INCLUDE = -I../../3rdparty/libconfig
+
 COMMON_SQL_OBJ = ../common/obj_sql/sql.o
 COMMON_H = ../common/sql.h
 
@@ -36,7 +43,7 @@ endif
 all: char-server_sql
 
 char-server_sql: $(CHAR_SERVER_SQL_DEPENDS)
-	@CC@ @LDFLAGS@ -o ../../char-server_sql@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) @LIBS@ @MYSQL_LIBS@
+	@CC@ @LDFLAGS@ -o ../../char-server_sql@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) @LIBS@ @MYSQL_LIBS@
 
 clean:
 	rm -rf *.o obj_sql ../../char-server_sql@EXEEXT@
@@ -57,8 +64,8 @@ needs_mysql:
 obj_sql:
 	-mkdir obj_sql
 
-obj_sql/%.o: %.c $(CHAR_H) $(COMMON_H) $(COMMON_SQL_H) $(MT19937AR_H)
-	@CC@ @CFLAGS@ $(MT19937AR_INCLUDE) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
+obj_sql/%.o: %.c $(CHAR_H) $(COMMON_H) $(COMMON_SQL_H) $(MT19937AR_H) $(LIBCONFIG_H)
+	@CC@ @CFLAGS@ $(MT19937AR_INCLUDE) $(LIBCONFIG_INCLUDE) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
 
 # missing object files
 ../common/obj_all/%.o:
@@ -69,3 +76,6 @@ obj_sql/%.o: %.c $(CHAR_H) $(COMMON_H) $(COMMON_SQL_H) $(MT19937AR_H)
 
 MT19937AR_OBJ:
 	@$(MAKE) -C ../../3rdparty/mt19937ar
+
+LIBCONFIG_OBJ:
+	@$(MAKE) -C ../../3rdparty/libconfig

+ 10 - 12
src/char/char.c

@@ -126,7 +126,7 @@ struct char_session_data {
 	int found_char[MAX_CHARS]; // ids of chars on this account
 	char email[40]; // e-mail (default: a@a.com) by [Yor]
 	time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
-	int gmlevel;
+	int group_id;
 	uint32 version;
 	uint8 clienttype;
 	char new_name[NAME_LENGTH];
@@ -134,7 +134,7 @@ struct char_session_data {
 };
 
 int max_connect_user = 0;
-int gm_allow_level = 99;
+int gm_allow_group = -1;
 int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
 int start_zeny = 0;
 int start_weapon = 1201;
@@ -174,7 +174,7 @@ struct auth_node {
 	uint32 ip;
 	int sex;
 	time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
-	int gmlevel;
+	int group_id;
 	unsigned changing_mapservers : 1;
 };
 
@@ -1972,12 +1972,12 @@ int parse_fromlogin(int fd)
 				int server_id;
 				memcpy(sd->email, RFIFOP(fd,6), 40);
 				sd->expiration_time = (time_t)RFIFOL(fd,46);
-				sd->gmlevel = RFIFOB(fd,50);
+				sd->group_id = RFIFOB(fd,50);
 				safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,51), sizeof(sd->birthdate));
 				ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] );
 				// continued from char_auth_ok...
 				if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359
-					( max_connect_user && count_users() >= max_connect_user && sd->gmlevel < gm_allow_level ) ) {
+					( max_connect_user && count_users() >= max_connect_user && sd->group_id != gm_allow_group ) ) {
 					// refuse connection (over populated)
 					WFIFOHEAD(i,3);
 					WFIFOW(i,0) = 0x6c;
@@ -2741,7 +2741,7 @@ int parse_frommap(int fd)
 				node->sex = RFIFOB(fd,30);
 				node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing)
 				node->ip = ntohl(RFIFOL(fd,31));
-				node->gmlevel = RFIFOL(fd,35);
+				node->group_id = RFIFOL(fd,35);
 				node->changing_mapservers = 1;
 				idb_put(auth_db, RFIFOL(fd,2), node);
 
@@ -3102,7 +3102,7 @@ int parse_frommap(int fd)
 				WFIFOL(fd,8) = node->login_id1;
 				WFIFOL(fd,12) = node->login_id2;
 				WFIFOL(fd,16) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT"
-				WFIFOL(fd,20) = node->gmlevel;
+				WFIFOL(fd,20) = node->group_id;
 				WFIFOB(fd,24) = node->changing_mapservers;
 				memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus));
 				WFIFOSET(fd, WFIFOW(fd,2));
@@ -3664,7 +3664,7 @@ int parse_char(int fd)
 			node->login_id2 = sd->login_id2;
 			node->sex = sd->sex;
 			node->expiration_time = sd->expiration_time;
-			node->gmlevel = sd->gmlevel;
+			node->group_id = sd->group_id;
 			node->ip = ipl;
 			idb_put(auth_db, sd->account_id, node);
 
@@ -4366,10 +4366,8 @@ int char_config_read(const char* cfgName)
 			max_connect_user = atoi(w2);
 			if (max_connect_user < 0)
 				max_connect_user = 0; // unlimited online players
-		} else if(strcmpi(w1, "gm_allow_level") == 0) {
-			gm_allow_level = atoi(w2);
-			if(gm_allow_level < 0)
-				gm_allow_level = 99;
+		} else if(strcmpi(w1, "gm_allow_group") == 0) {
+			gm_allow_group = atoi(w2);
 		} else if (strcmpi(w1, "autosave_time") == 0) {
 			autosave_interval = atoi(w2)*1000;
 			if (autosave_interval <= 0)

+ 21 - 9
src/common/Makefile.in

@@ -2,11 +2,13 @@
 COMMON_OBJ = obj_all/core.o obj_all/socket.o obj_all/timer.o obj_all/db.o obj_all/plugins.o obj_all/lock.o \
 	obj_all/nullpo.o obj_all/malloc.o obj_all/showmsg.o obj_all/strlib.o obj_all/utils.o \
 	obj_all/grfio.o obj_all/mapindex.o obj_all/ers.o obj_all/md5calc.o \
-	obj_all/minicore.o obj_all/minisocket.o obj_all/minimalloc.o obj_all/random.o obj_all/des.o
+	obj_all/minicore.o obj_all/minisocket.o obj_all/minimalloc.o obj_all/random.o obj_all/des.o \
+	obj_all/conf.o
 COMMON_H = mmo.h plugin.h version.h \
 	core.h socket.h timer.h db.h plugins.h lock.h \
 	nullpo.h malloc.h showmsg.h  strlib.h utils.h \
-	grfio.h mapindex.h ers.h md5calc.h random.h des.h
+	grfio.h mapindex.h ers.h md5calc.h random.h des.h \
+	conf.h
 
 COMMON_SQL_OBJ = obj_sql/sql.o
 COMMON_SQL_H = sql.h
@@ -15,6 +17,13 @@ MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o
 MT19937AR_H = ../../3rdparty/mt19937ar/mt19937ar.h
 MT19937AR_INCLUDE = -I../../3rdparty/mt19937ar
 
+LIBCONFIG_OBJ = ../../3rdparty/libconfig/libconfig.o ../../3rdparty/libconfig/grammar.o \
+	../../3rdparty/libconfig/scanctx.o ../../3rdparty/libconfig/scanner.o ../../3rdparty/libconfig/strbuf.o
+LIBCONFIG_H = ../../3rdparty/libconfig/libconfig.h ../../3rdparty/libconfig/grammar.h \
+	../../3rdparty/libconfig/parsectx.h ../../3rdparty/libconfig/scanctx.h ../../3rdparty/libconfig/scanner.h \
+	../../3rdparty/libconfig/strbuf.h ../../3rdparty/libconfig/wincompat.h
+LIBCONFIG_INCLUDE = -I../../3rdparty/libconfig
+
 HAVE_MYSQL=@HAVE_MYSQL@
 ifeq ($(HAVE_MYSQL),yes)
 	ALL_DEPENDS=txt sql
@@ -59,21 +68,24 @@ obj_all:
 obj_sql:
 	-mkdir obj_sql
 
-common: obj_all $(COMMON_OBJ) $(MT19937AR_OBJ)
+common: obj_all $(COMMON_OBJ) $(MT19937AR_OBJ) $(LIBCONFIG_OBJ)
 
 common_sql: obj_sql $(COMMON_SQL_OBJ)
 
 
-obj_all/%.o: %.c $(COMMON_H) $(MT19937AR_H)
-	@CC@ @CFLAGS@ $(MT19937AR_INCLUDE) @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
+obj_all/%.o: %.c $(COMMON_H) $(MT19937AR_H) $(LIBCONFIG_H)
+	@CC@ @CFLAGS@ $(MT19937AR_INCLUDE) $(LIBCONFIG_INCLUDE) @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
 
-obj_all/mini%.o: %.c $(COMMON_H) $(MT19937AR_H)
-	@CC@ @CFLAGS@ $(MT19937AR_INCLUDE) -DMINICORE @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
+obj_all/mini%.o: %.c $(COMMON_H) $(MT19937AR_H) $(LIBCONFIG_H)
+	@CC@ @CFLAGS@ $(MT19937AR_INCLUDE) $(LIBCONFIG_INCLUDE) -DMINICORE @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
 
-obj_sql/%.o: %.c $(COMMON_H) $(COMMON_SQL_H)
-	@CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
+obj_sql/%.o: %.c $(COMMON_H) $(COMMON_SQL_H) $(LIBCONFIG_H)
+	@CC@ @CFLAGS@ $(LIBCONFIG_INCLUDE) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
 
 
 # missing object files
 MT19937AR_OBJ:
 	@$(MAKE) -C ../../3rdparty/mt19937ar
+
+LIBCONFIG_OBJ:
+	@$(MAKE) -C ../../3rdparty/libconfig

+ 109 - 0
src/common/conf.c

@@ -0,0 +1,109 @@
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#include "conf.h"
+#include <libconfig.h>
+
+#include "../common/showmsg.h" // ShowError
+
+int conf_read_file(config_t *config, const char *config_filename)
+{
+	config_init(config);
+	if (!config_read_file(config, config_filename)) {
+		ShowError("%s:%d - %s\n", config_error_file(config),
+		          config_error_line(config), config_error_text(config));
+		config_destroy(config);
+		return 1;
+	}
+	return 0;
+}
+
+//
+// Functions to copy settings from libconfig/contrib
+//
+static void config_setting_copy_simple(config_setting_t *parent, const config_setting_t *src);
+static void config_setting_copy_elem(config_setting_t *parent, const config_setting_t *src);
+static void config_setting_copy_aggregate(config_setting_t *parent, const config_setting_t *src);
+int config_setting_copy(config_setting_t *parent, const config_setting_t *src);
+
+void config_setting_copy_simple(config_setting_t *parent, const config_setting_t *src)
+{
+	if (config_setting_is_aggregate(src)) {
+		config_setting_copy_aggregate(parent, src);
+	}
+	else {
+		config_setting_t *set = config_setting_add(parent, config_setting_name(src), config_setting_type(src));
+
+		if (set == NULL)
+			return;
+
+		if (CONFIG_TYPE_INT == config_setting_type(src)) {
+			config_setting_set_int(set, config_setting_get_int(src));
+			config_setting_set_format(set, src->format);
+		} else if (CONFIG_TYPE_INT64 == config_setting_type(src)) {
+			config_setting_set_int64(set, config_setting_get_int64(src));
+			config_setting_set_format(set, src->format);
+		} else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) {
+			config_setting_set_float(set, config_setting_get_float(src));
+		} else if (CONFIG_TYPE_STRING == config_setting_type(src)) {
+			config_setting_set_string(set, config_setting_get_string(src));
+		} else if (CONFIG_TYPE_BOOL == config_setting_type(src)) {
+			config_setting_set_bool(set, config_setting_get_bool(src));
+		}
+	}
+}
+
+void config_setting_copy_elem(config_setting_t *parent, const config_setting_t *src)
+{
+	config_setting_t *set = NULL;
+
+	if (config_setting_is_aggregate(src))
+		config_setting_copy_aggregate(parent, src);
+	else if (CONFIG_TYPE_INT == config_setting_type(src)) {
+		set = config_setting_set_int_elem(parent, -1, config_setting_get_int(src));
+		config_setting_set_format(set, src->format);
+	} else if (CONFIG_TYPE_INT64 == config_setting_type(src)) {
+		set = config_setting_set_int64_elem(parent, -1, config_setting_get_int64(src));
+		config_setting_set_format(set, src->format);   
+	} else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) {
+		set = config_setting_set_float_elem(parent, -1, config_setting_get_float(src));
+	} else if (CONFIG_TYPE_STRING == config_setting_type(src)) {
+		set = config_setting_set_string_elem(parent, -1, config_setting_get_string(src));
+	} else if (CONFIG_TYPE_BOOL == config_setting_type(src)) {
+		set = config_setting_set_bool_elem(parent, -1, config_setting_get_bool(src));
+	}
+}
+
+void config_setting_copy_aggregate(config_setting_t *parent, const config_setting_t *src)
+{
+	config_setting_t *newAgg;
+	int i, n;
+
+	newAgg = config_setting_add(parent, config_setting_name(src), config_setting_type(src));
+
+	if (newAgg == NULL)
+		return;
+
+	n = config_setting_length(src);
+	
+	for (i = 0; i < n; i++) {
+		if (config_setting_is_group(src)) {
+			config_setting_copy_simple(newAgg, config_setting_get_elem(src, i));            
+		} else {
+			config_setting_copy_elem(newAgg, config_setting_get_elem(src, i));
+		}
+	}
+}
+
+int config_setting_copy(config_setting_t *parent, const config_setting_t *src)
+{
+	if (!config_setting_is_group(parent) && !config_setting_is_list(parent))
+		return CONFIG_FALSE;
+
+	if (config_setting_is_aggregate(src)) {
+		config_setting_copy_aggregate(parent, src);
+	} else {
+		config_setting_copy_simple(parent, src);
+	}
+	return CONFIG_TRUE;
+}

+ 13 - 0
src/common/conf.h

@@ -0,0 +1,13 @@
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#ifndef _CONF_H_
+#define _CONF_H_
+
+#include "../common/cbasetypes.h"
+#include <libconfig.h>
+
+int conf_read_file(config_t *config, const char *config_filename);
+int config_setting_copy(config_setting_t *parent, const config_setting_t *src);
+
+#endif // _CONF_H_

+ 16 - 0
src/common/showmsg.c

@@ -13,6 +13,8 @@
 #include <time.h>
 #include <stdlib.h> // atexit
 
+#include <libconfig.h>
+
 #ifdef WIN32
 	#define WIN32_LEAN_AND_MEAN
 	#include <windows.h>
@@ -872,6 +874,20 @@ int ShowWarning(const char *string, ...) {
 	va_end(ap);
 	return ret;
 }
+int ShowConfigWarning(config_setting_t *config, const char *string, ...)
+{
+	StringBuf buf;
+	int ret;
+	va_list ap;
+	StringBuf_Init(&buf);
+	StringBuf_AppendStr(&buf, string);
+	StringBuf_Printf(&buf, " (%s:%d)\n", config_setting_source_file(config), config_setting_source_line(config));
+	va_start(ap, string);
+	ret = _vShowMessage(MSG_WARNING, StringBuf_Value(&buf), ap);
+	va_end(ap);
+	StringBuf_Destroy(&buf);
+	return ret;
+}
 int ShowDebug(const char *string, ...) {
 	int ret;
 	va_list ap;

+ 3 - 0
src/common/showmsg.h

@@ -4,6 +4,8 @@
 #ifndef _SHOWMSG_H_
 #define _SHOWMSG_H_
 
+#include <libconfig.h>
+
 // for help with the console colors look here:
 // http://www.edoceo.com/liberum/?doc=printf-with-color
 // some code explanation (used here):
@@ -92,5 +94,6 @@ extern int ShowWarning(const char *, ...);
 extern int ShowDebug(const char *, ...);
 extern int ShowError(const char *, ...);
 extern int ShowFatalError(const char *, ...);
+extern int ShowConfigWarning(config_setting_t *config, const char *string, ...);
 
 #endif /* _SHOWMSG_H_ */

+ 16 - 5
src/login/Makefile.in

@@ -3,12 +3,13 @@ COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_a
 	../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \
 	../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \
 	../common/obj_all/strlib.o ../common/obj_all/mapindex.o \
-	../common/obj_all/ers.o ../common/obj_all/md5calc.o ../common/obj_all/random.o
+	../common/obj_all/ers.o ../common/obj_all/md5calc.o ../common/obj_all/random.o \
+	../common/obj_all/conf.o
 COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \
 	../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \
 	../common/malloc.h ../common/showmsg.h ../common/utils.h ../common/strlib.h \
 	../common/mapindex.h \
-	../common/ers.h ../common/md5calc.h ../common/random.h
+	../common/ers.h ../common/md5calc.h ../common/random.h ../common/conf.h
 
 COMMON_SQL_OBJ = ../common/obj_sql/sql.o
 COMMON_SQL_H = ../common/sql.h
@@ -17,6 +18,13 @@ MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o
 MT19937AR_H = ../../3rdparty/mt19937ar/mt19937ar.h
 MT19937AR_INCLUDE = -I../../3rdparty/mt19937ar
 
+LIBCONFIG_OBJ = ../../3rdparty/libconfig/libconfig.o ../../3rdparty/libconfig/grammar.o \
+	../../3rdparty/libconfig/scanctx.o ../../3rdparty/libconfig/scanner.o ../../3rdparty/libconfig/strbuf.o
+LIBCONFIG_H = ../../3rdparty/libconfig/libconfig.h ../../3rdparty/libconfig/grammar.h \
+	../../3rdparty/libconfig/parsectx.h ../../3rdparty/libconfig/scanctx.h ../../3rdparty/libconfig/scanner.h \
+	../../3rdparty/libconfig/strbuf.h ../../3rdparty/libconfig/wincompat.h
+LIBCONFIG_INCLUDE = -I../../3rdparty/libconfig
+
 LOGIN_OBJ = login.o
 LOGIN_SQL_OBJ = $(LOGIN_OBJ:%=obj_sql/%) \
 	obj_sql/account_sql.o obj_sql/ipban_sql.o obj_sql/loginlog_sql.o
@@ -62,12 +70,12 @@ obj_sql:
 #executables
 
 login-server_sql: $(LOGIN_SERVER_SQL_DEPENDS)
-	@CC@ @LDFLAGS@ -o ../../login-server_sql@EXEEXT@ $(LOGIN_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) @LIBS@ @MYSQL_LIBS@
+	@CC@ @LDFLAGS@ -o ../../login-server_sql@EXEEXT@ $(LOGIN_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) @LIBS@ @MYSQL_LIBS@
 
 # login object files
 
-obj_sql/%.o: %.c $(LOGIN_H) $(COMMON_H) $(MT19937AR_H)
-	@CC@ @CFLAGS@ $(MT19937AR_INCLUDE) -DWITH_SQL @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
+obj_sql/%.o: %.c $(LOGIN_H) $(COMMON_H) $(MT19937AR_H) $(LIBCONFIG_H)
+	@CC@ @CFLAGS@ $(MT19937AR_INCLUDE) $(LIBCONFIG_INCLUDE) -DWITH_SQL @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
 
 # missing object files
 ../common/obj_all/%.o:
@@ -78,3 +86,6 @@ obj_sql/%.o: %.c $(LOGIN_H) $(COMMON_H) $(MT19937AR_H)
 
 MT19937AR_OBJ:
 	@$(MAKE) -C ../../3rdparty/mt19937ar
+
+LIBCONFIG_OBJ:
+	@$(MAKE) -C ../../3rdparty/libconfig

+ 1 - 1
src/login/account.h

@@ -41,7 +41,7 @@ struct mmo_account
 	char pass[32+1];        // 23+1 for plaintext, 32+1 for md5-ed passwords
 	char sex;               // gender (M/F/S)
 	char email[40];         // e-mail (by default: a@a.com)
-	int level;              // GM level
+	int group_id;           // player group id
 	unsigned int state;     // packet 0x006a value + 1 (0: compte OK)
 	time_t unban_time;      // (timestamp): ban time limit of the account (0 = no ban)
 	time_t expiration_time; // (timestamp): validity limit of the account (0 = unlimited)

+ 6 - 6
src/login/account_sql.c

@@ -522,7 +522,7 @@ static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int acc
 
 	// retrieve login entry for the specified account
 	if( SQL_ERROR == Sql_Query(sql_handle,
-	    "SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`level`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate` FROM `%s` WHERE `account_id` = %d",
+	    "SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`group_id`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate` FROM `%s` WHERE `account_id` = %d",
 		db->account_db, account_id )
 	) {
 		Sql_ShowDebug(sql_handle);
@@ -540,7 +540,7 @@ static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int acc
 	Sql_GetData(sql_handle,  2, &data, NULL); safestrncpy(acc->pass, data, sizeof(acc->pass));
 	Sql_GetData(sql_handle,  3, &data, NULL); acc->sex = data[0];
 	Sql_GetData(sql_handle,  4, &data, NULL); safestrncpy(acc->email, data, sizeof(acc->email));
-	Sql_GetData(sql_handle,  5, &data, NULL); acc->level = atoi(data);
+	Sql_GetData(sql_handle,  5, &data, NULL); acc->group_id = atoi(data);
 	Sql_GetData(sql_handle,  6, &data, NULL); acc->state = strtoul(data, NULL, 10);
 	Sql_GetData(sql_handle,  7, &data, NULL); acc->unban_time = atol(data);
 	Sql_GetData(sql_handle,  8, &data, NULL); acc->expiration_time = atol(data);
@@ -596,14 +596,14 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
 	if( is_new )
 	{// insert into account table
 		if( SQL_SUCCESS != SqlStmt_Prepare(stmt,
-			"INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `level`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+			"INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
 			db->account_db)
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  0, SQLDT_INT,    (void*)&acc->account_id,      sizeof(acc->account_id))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  1, SQLDT_STRING, (void*)acc->userid,           strlen(acc->userid))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  2, SQLDT_STRING, (void*)acc->pass,             strlen(acc->pass))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  3, SQLDT_ENUM,   (void*)&acc->sex,             sizeof(acc->sex))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  4, SQLDT_STRING, (void*)&acc->email,           strlen(acc->email))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  5, SQLDT_INT,    (void*)&acc->level,           sizeof(acc->level))
+		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  5, SQLDT_INT,    (void*)&acc->group_id,        sizeof(acc->group_id))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  6, SQLDT_UINT,   (void*)&acc->state,           sizeof(acc->state))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  7, SQLDT_LONG,   (void*)&acc->unban_time,      sizeof(acc->unban_time))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  8, SQLDT_INT,    (void*)&acc->expiration_time, sizeof(acc->expiration_time))
@@ -619,12 +619,12 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
 	}
 	else
 	{// update account table
-		if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`level`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=? WHERE `account_id` = '%d'", db->account_db, acc->account_id)
+		if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=? WHERE `account_id` = '%d'", db->account_db, acc->account_id)
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  0, SQLDT_STRING, (void*)acc->userid,           strlen(acc->userid))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  1, SQLDT_STRING, (void*)acc->pass,             strlen(acc->pass))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  2, SQLDT_ENUM,   (void*)&acc->sex,             sizeof(acc->sex))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  3, SQLDT_STRING, (void*)acc->email,            strlen(acc->email))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  4, SQLDT_INT,    (void*)&acc->level,           sizeof(acc->level))
+		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  4, SQLDT_INT,    (void*)&acc->group_id,        sizeof(acc->group_id))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  5, SQLDT_UINT,   (void*)&acc->state,           sizeof(acc->state))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  6, SQLDT_LONG,   (void*)&acc->unban_time,      sizeof(acc->unban_time))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  7, SQLDT_LONG,   (void*)&acc->expiration_time, sizeof(acc->expiration_time))

+ 10 - 14
src/login/login.c

@@ -548,7 +548,7 @@ int parse_fromchar(int fd)
 			struct mmo_account acc;
 			time_t expiration_time = 0;
 			char email[40] = "";
-			int gmlevel = 0;
+			int group_id = 0;
 			char birthdate[10+1] = "";
 
 			int account_id = RFIFOL(fd,2);
@@ -560,7 +560,7 @@ int parse_fromchar(int fd)
 			{
 				safestrncpy(email, acc.email, sizeof(email));
 				expiration_time = acc.expiration_time;
-				gmlevel = acc.level;
+				group_id = acc.group_id;
 				safestrncpy(birthdate, acc.birthdate, sizeof(birthdate));
 			}
 
@@ -569,7 +569,7 @@ int parse_fromchar(int fd)
 			WFIFOL(fd,2) = account_id;
 			safestrncpy((char*)WFIFOP(fd,6), email, 40);
 			WFIFOL(fd,46) = (uint32)expiration_time;
-			WFIFOB(fd,50) = gmlevel;
+			WFIFOB(fd,50) = group_id;
 			safestrncpy((char*)WFIFOP(fd,51), birthdate, 10+1);
 			WFIFOSET(fd,62);
 		}
@@ -1068,7 +1068,7 @@ int mmo_auth(struct login_session_data* sd)
 	sd->login_id2 = rnd();
 	safestrncpy(sd->lastlogin, acc.lastlogin, sizeof(sd->lastlogin));
 	sd->sex = acc.sex;
-	sd->level = acc.level;
+	sd->group_id = acc.group_id;
 
 	// update account data
 	timestamp2string(acc.lastlogin, sizeof(acc.lastlogin), time(NULL), "%Y-%m-%d %H:%M:%S");
@@ -1104,9 +1104,9 @@ void login_auth_ok(struct login_session_data* sd)
 		return;
 	}
 
-	if( sd->level < login_config.min_level_to_connect )
+	if( login_config.group_id_to_connect >= 0 && sd->group_id != login_config.group_id_to_connect )
 	{
-		ShowStatus("Connection refused: the minimum GM level for connection is %d (account: %s, GM level: %d).\n", login_config.min_level_to_connect, sd->userid, sd->level);
+		ShowStatus("Connection refused: the required group id for connection is %d (account: %s, group: %d).\n", login_config.group_id_to_connect, sd->userid, sd->group_id);
 		WFIFOHEAD(fd,3);
 		WFIFOW(fd,0) = 0x81;
 		WFIFOB(fd,2) = 1; // 01 = Server closed
@@ -1161,11 +1161,7 @@ void login_auth_ok(struct login_session_data* sd)
 	}
 
 	login_log(ip, sd->userid, 100, "login ok");
-
-	if( sd->level > 0 )
-		ShowStatus("Connection of the GM (level:%d) account '%s' accepted.\n", sd->level, sd->userid);
-	else
-		ShowStatus("Connection of the account '%s' accepted.\n", sd->userid);
+	ShowStatus("Connection of the account '%s' accepted.\n", sd->userid);
 
 	WFIFOHEAD(fd,47+32*server_num);
 	WFIFOW(fd,0) = 0x69;
@@ -1508,7 +1504,7 @@ void login_set_defaults()
 	login_config.new_account_flag = true;
 	login_config.new_acc_length_limit = true;
 	login_config.use_md5_passwds = false;
-	login_config.min_level_to_connect = 0;
+	login_config.group_id_to_connect = -1;
 	login_config.check_client_version = false;
 	login_config.client_version_to_connect = 20;
 
@@ -1575,8 +1571,8 @@ int login_config_read(const char* cfgName)
 			login_config.client_version_to_connect = strtoul(w2, NULL, 10);
 		else if(!strcmpi(w1, "use_MD5_passwords"))
 			login_config.use_md5_passwds = (bool)config_switch(w2);
-		else if(!strcmpi(w1, "min_level_to_connect"))
-			login_config.min_level_to_connect = atoi(w2);
+		else if(!strcmpi(w1, "group_id_to_connect"))
+			login_config.group_id_to_connect = atoi(w2);
 		else if(!strcmpi(w1, "date_format"))
 			safestrncpy(login_config.date_format, w2, sizeof(login_config.date_format));
 		else if(!strcmpi(w1, "console"))

+ 2 - 2
src/login/login.h

@@ -34,7 +34,7 @@ struct login_session_data {
 	uint16 md5keylen;
 
 	char lastlogin[24];
-	uint8 level;
+	uint8 group_id;
 	uint8 clienttype;
 	uint32 version;
 
@@ -64,7 +64,7 @@ struct Login_Config {
 	bool new_account_flag,new_acc_length_limit;     // autoregistration via _M/_F ? / if yes minimum length is 4?
 	int start_limited_time;                         // new account expiration time (-1: unlimited)
 	bool use_md5_passwds;                           // work with password hashes instead of plaintext passwords?
-	int min_level_to_connect;                       // minimum level of player/GM (0: player, 1-99: GM) to connect
+	int group_id_to_connect;                        // required group id to connect
 	bool check_client_version;                      // check the clientversion set in the clientinfo ?
 	uint32 client_version_to_connect;               // the client version needed to connect (if checking is enabled)
 

+ 17 - 7
src/map/Makefile.in

@@ -4,13 +4,13 @@ COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_a
 	../common/obj_all/nullpo.o ../common/obj_all/malloc.o ../common/obj_all/showmsg.o \
 	../common/obj_all/utils.o ../common/obj_all/strlib.o ../common/obj_all/grfio.o \
 	../common/obj_all/mapindex.o ../common/obj_all/ers.o ../common/obj_all/md5calc.o \
-	../common/obj_all/random.o ../common/obj_all/des.o
+	../common/obj_all/random.o ../common/obj_all/des.o ../common/obj_all/conf.o
 COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h \
 	../common/db.h ../common/plugins.h ../common/lock.h \
 	../common/nullpo.h ../common/malloc.h ../common/showmsg.h \
 	../common/utils.h ../common/strlib.h ../common/grfio.h \
 	../common/mapindex.h ../common/ers.h ../common/md5calc.h \
-	../common/random.h ../common/des.h
+	../common/random.h ../common/des.h ../common/conf.h
 
 COMMON_SQL_OBJ = ../common/obj_sql/sql.o
 COMMON_SQL_H = ../common/sql.h
@@ -19,12 +19,19 @@ MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o
 MT19937AR_H = ../../3rdparty/mt19937ar/mt19937ar.h
 MT19937AR_INCLUDE = -I../../3rdparty/mt19937ar
 
+LIBCONFIG_OBJ = ../../3rdparty/libconfig/libconfig.o ../../3rdparty/libconfig/grammar.o \
+	../../3rdparty/libconfig/scanctx.o ../../3rdparty/libconfig/scanner.o ../../3rdparty/libconfig/strbuf.o
+LIBCONFIG_H = ../../3rdparty/libconfig/libconfig.h ../../3rdparty/libconfig/grammar.h \
+	../../3rdparty/libconfig/parsectx.h ../../3rdparty/libconfig/scanctx.h ../../3rdparty/libconfig/scanner.h \
+	../../3rdparty/libconfig/strbuf.h ../../3rdparty/libconfig/wincompat.h
+LIBCONFIG_INCLUDE = -I../../3rdparty/libconfig
+
 MAP_OBJ = map.o chrif.o clif.o pc.o status.o npc.o \
 	npc_chat.o chat.o path.o itemdb.o mob.o script.o \
 	storage.o skill.o atcommand.o battle.o battleground.o \
 	intif.o trade.o party.o vending.o guild.o pet.o \
 	log.o mail.o date.o unit.o homunculus.o mercenary.o quest.o instance.o \
-	buyingstore.o searchstore.o duel.o
+	buyingstore.o searchstore.o duel.o pc_groups.o
 MAP_SQL_OBJ = $(MAP_OBJ:%=obj_sql/%) \
 	obj_sql/mapreg_sql.o
 MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \
@@ -32,7 +39,7 @@ MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \
 	storage.h skill.h atcommand.h battle.h battleground.h \
 	intif.h trade.h party.h vending.h guild.h pet.h \
 	log.h mail.h date.h unit.h homunculus.h mercenary.h quest.h instance.h mapreg.h \
-	buyingstore.h searchstore.h duel.h \
+	buyingstore.h searchstore.h duel.h pc_groups.h \
 	config/Core.h config/Renewal.h config/Secure.h config/Data/Const.h \
 	config/Skills/General.h config/Skills/Mage_Classes.h config/Skills/Swordsman_Classes.h
 
@@ -95,12 +102,12 @@ obj_sql:
 # executables
 
 map-server_sql: obj_sql $(MAP_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ)
-	@CC@ @LDFLAGS@ -o ../../map-server_sql@EXEEXT@ $(MAP_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) @LIBS@ @PCRE_LIBS@ @MYSQL_LIBS@
+	@CC@ @LDFLAGS@ -o ../../map-server_sql@EXEEXT@ $(MAP_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) @LIBS@ @PCRE_LIBS@ @MYSQL_LIBS@
 
 # map object files
 
-obj_sql/%.o: %.c $(MAP_H) $(COMMON_H) $(COMMON_SQL_H) $(MT19937AR_H)
-	@CC@ @CFLAGS@ $(MT19937AR_INCLUDE) $(PCRE_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
+obj_sql/%.o: %.c $(MAP_H) $(COMMON_H) $(COMMON_SQL_H) $(MT19937AR_H) $(LIBCONFIG_H)
+	@CC@ @CFLAGS@ $(MT19937AR_INCLUDE) $(LIBCONFIG_INCLUDE) $(PCRE_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
 
 # missing object files
 ../common/obj_all/%.o:
@@ -111,3 +118,6 @@ obj_sql/%.o: %.c $(MAP_H) $(COMMON_H) $(COMMON_SQL_H) $(MT19937AR_H)
 
 MT19937AR_OBJ:
 	@$(MAKE) -C ../../3rdparty/mt19937ar
+
+LIBCONFIG_OBJ:
+	@$(MAKE) -C ../../3rdparty/libconfig

文件差异内容过多而无法显示
+ 174 - 408
src/map/atcommand.c


+ 9 - 21
src/map/atcommand.h

@@ -4,7 +4,6 @@
 #ifndef _ATCOMMAND_H_
 #define _ATCOMMAND_H_
 
-//#include "map.h"
 struct map_session_data;
 
 //This is the distance at which @autoloot works,
@@ -15,32 +14,21 @@ struct map_session_data;
 
 extern char atcommand_symbol;
 extern char charcommand_symbol;
+
+typedef enum {
+	COMMAND_ATCOMMAND = 1,
+	COMMAND_CHARCOMMAND = 2,
+} AtCommandType;
+
 typedef int (*AtCommandFunc)(const int fd, struct map_session_data* sd, const char* command, const char* message);
 
 bool is_atcommand(const int fd, struct map_session_data* sd, const char* message, int type);
-int get_atcommand_level(const char* name);
 
 void do_init_atcommand(void);
 void do_final_atcommand(void);
-int atcommand_config_read(const char *cfgName);
-
-int atcommand_mail(const int fd, struct map_session_data* sd,const char* command, const char* message);
-int atcommand_item(const int fd, struct map_session_data* sd,const char* command, const char* message);
-int atcommand_mapmove(const int fd, struct map_session_data* sd,const char* command, const char* message);
-int atcommand_monster(const int fd, struct map_session_data* sd, const char* command, const char* message);
-int atcommand_jumpto(const int fd, struct map_session_data* sd, const char* command, const char* message);
-int atcommand_recall(const int fd, struct map_session_data* sd, const char* command, const char* message);
-int atcommand_hide(const int fd, struct map_session_data* sd, const char* command, const char* message);
-int atcommand_mute(const int fd, struct map_session_data* sd, const char* command, const char* message);
-int atcommand_kick(const int fd, struct map_session_data* sd, const char* command, const char* message);
-int atcommand_broadcast(const int fd, struct map_session_data* sd,const char* command, const char* message);
-int atcommand_localbroadcast(const int fd, struct map_session_data* sd,const char* command, const char* message);
-int atcommand_reset(const int fd, struct map_session_data* sd,const char* command, const char* message);
-int atcommand_unloadnpc(const int fd, struct map_session_data* sd, const char* command, const char* message);
-int atcommand_killmonster(const int fd, struct map_session_data* sd, const char* command, const char* message);
-
-#define MAX_MSG 1000
-extern char* msg_table[MAX_MSG];
+
+bool atcommand_exists(const char* name);
+
 const char* msg_txt(int msg_number);
 int msg_config_read(const char* cfgName);
 void do_final_msg(void);

+ 0 - 26
src/map/battle.c

@@ -4441,18 +4441,9 @@ static const struct _battle_data {
 	{ "guild_max_castles",                  &battle_config.guild_max_castles,               0,      0,      INT_MAX,        },
 	{ "guild_skill_relog_delay",            &battle_config.guild_skill_relog_delay,         0,      0,      1,              },
 	{ "emergency_call",                     &battle_config.emergency_call,                  11,     0,      31,             },
-	{ "lowest_gm_level",                    &battle_config.lowest_gm_level,                 1,      0,      99,             },
-	{ "atcommand_gm_only",                  &battle_config.atc_gmonly,                      0,      0,      1,              },
 	{ "atcommand_spawn_quantity_limit",     &battle_config.atc_spawn_quantity_limit,        100,    0,      INT_MAX,        },
 	{ "atcommand_slave_clone_limit",        &battle_config.atc_slave_clone_limit,           25,     0,      INT_MAX,        },
 	{ "partial_name_scan",                  &battle_config.partial_name_scan,               0,      0,      1,              },
-	{ "gm_all_skill",                       &battle_config.gm_allskill,                     0,      0,      100,            },
-	{ "gm_all_equipment",                   &battle_config.gm_allequip,                     0,      0,      100,            },
-	{ "gm_skill_unconditional",             &battle_config.gm_skilluncond,                  0,      0,      100,            },
-	{ "gm_join_chat",                       &battle_config.gm_join_chat,                    0,      0,      100,            },
-	{ "gm_kick_chat",                       &battle_config.gm_kick_chat,                    0,      0,      100,            },
-	{ "gm_can_party",                       &battle_config.gm_can_party,                    0,      0,      1,              },
-	{ "gm_cant_party_min_lv",               &battle_config.gm_cant_party_min_lv,            20,     0,      100,            },
 	{ "player_skillfree",                   &battle_config.skillfree,                       0,      0,      1,              },
 	{ "player_skillup_limit",               &battle_config.skillup_limit,                   1,      0,      1,              },
 	{ "weapon_produce_rate",                &battle_config.wp_rate,                         100,    0,      INT_MAX,        },
@@ -4588,15 +4579,11 @@ static const struct _battle_data {
 	{ "gx_disptype",                        &battle_config.gx_disptype,                     1,      0,      1,              },
 	{ "devotion_level_difference",          &battle_config.devotion_level_difference,       10,     0,      INT_MAX,        },
 	{ "player_skill_partner_check",         &battle_config.player_skill_partner_check,      1,      0,      1,              },
-	{ "hide_GM_session",                    &battle_config.hide_GM_session,                 0,      0,      1,              },
 	{ "invite_request_check",               &battle_config.invite_request_check,            1,      0,      1,              },
 	{ "skill_removetrap_type",              &battle_config.skill_removetrap_type,           0,      0,      1,              },
 	{ "disp_experience",                    &battle_config.disp_experience,                 0,      0,      1,              },
 	{ "disp_zeny",                          &battle_config.disp_zeny,                       0,      0,      1,              },
 	{ "castle_defense_rate",                &battle_config.castle_defense_rate,             100,    0,      100,            },
-	{ "gm_cant_drop_min_lv",                &battle_config.gm_cant_drop_min_lv,             1,      0,      100,            },
-	{ "gm_cant_drop_max_lv",                &battle_config.gm_cant_drop_max_lv,             0,      0,      100,            },
-	{ "disp_hpmeter",                       &battle_config.disp_hpmeter,                    0,      0,      100,            },
 	{ "bone_drop",                          &battle_config.bone_drop,                       0,      0,      2,              },
 	{ "buyer_name",                         &battle_config.buyer_name,                      1,      0,      1,              },
 	{ "skill_wall_check",                   &battle_config.skill_wall_check,                1,      0,      1,              },
@@ -4649,9 +4636,6 @@ static const struct _battle_data {
 	{ "night_at_start",                     &battle_config.night_at_start,                  0,      0,      1,              },
 	{ "show_mob_info",                      &battle_config.show_mob_info,                   0,      0,      1|2|4,          },
 	{ "ban_hack_trade",                     &battle_config.ban_hack_trade,                  0,      0,      INT_MAX,        },
-	{ "hack_info_GM_level",                 &battle_config.hack_info_GM_level,              60,     0,      100,            },
-	{ "any_warp_GM_min_level",              &battle_config.any_warp_GM_min_level,           20,     0,      100,            },
-	{ "who_display_aid",                    &battle_config.who_display_aid,                 40,     0,      100,            },
 	{ "packet_ver_flag",                    &battle_config.packet_ver_flag,                 0xFFFFFF,0x0000,INT_MAX,        },
 	{ "min_hair_style",                     &battle_config.min_hair_style,                  0,      0,      INT_MAX,        },
 	{ "max_hair_style",                     &battle_config.max_hair_style,                  23,     0,      INT_MAX,        },
@@ -4699,14 +4683,6 @@ static const struct _battle_data {
 	{ "mob_max_skilllvl",                   &battle_config.mob_max_skilllvl,                MAX_SKILL_LEVEL, 1, MAX_SKILL_LEVEL, },
 	{ "retaliate_to_master",                &battle_config.retaliate_to_master,             1,      0,      1,              },
 	{ "rare_drop_announce",                 &battle_config.rare_drop_announce,              0,      0,      10000,          },
-	{ "title_lvl1",                         &battle_config.title_lvl1,                      1,      0,      100,            },
-	{ "title_lvl2",                         &battle_config.title_lvl2,                      10,     0,      100,            },
-	{ "title_lvl3",                         &battle_config.title_lvl3,                      20,     0,      100,            },
-	{ "title_lvl4",                         &battle_config.title_lvl4,                      40,     0,      100,            },
-	{ "title_lvl5",                         &battle_config.title_lvl5,                      50,     0,      100,            },
-	{ "title_lvl6",                         &battle_config.title_lvl6,                      60,     0,      100,            },
-	{ "title_lvl7",                         &battle_config.title_lvl7,                      80,     0,      100,            },
-	{ "title_lvl8",                         &battle_config.title_lvl8,                      99,     0,      100,            },
 	{ "duel_allow_pvp",                     &battle_config.duel_allow_pvp,                  0,      0,      1,              },
 	{ "duel_allow_gvg",                     &battle_config.duel_allow_gvg,                  0,      0,      1,              },
 	{ "duel_allow_teleport",                &battle_config.duel_allow_teleport,             0,      0,      1,              },
@@ -4750,7 +4726,6 @@ static const struct _battle_data {
 	{ "ksprotection",                       &battle_config.ksprotection,                    5000,   0,      INT_MAX,        },
 	{ "auction_feeperhour",                 &battle_config.auction_feeperhour,              12000,  0,      INT_MAX,        },
 	{ "auction_maximumprice",               &battle_config.auction_maximumprice,            500000000, 0,   MAX_ZENY,       },
-	{ "gm_viewequip_min_lv",                &battle_config.gm_viewequip_min_lv,             0,      0,      99,             },
 	{ "homunculus_auto_vapor",              &battle_config.homunculus_auto_vapor,           1,      0,      1,              },
 	{ "display_status_timers",              &battle_config.display_status_timers,           1,      0,      1,              },
 	{ "skill_add_heal_rate",                &battle_config.skill_add_heal_rate,             7,      0,      INT_MAX,        },
@@ -4760,7 +4735,6 @@ static const struct _battle_data {
 	{ "autospell_check_range",              &battle_config.autospell_check_range,           0,      0,      1,              },
 	{ "client_reshuffle_dice",              &battle_config.client_reshuffle_dice,           0,      0,      1,              },
 	{ "client_sort_storage",                &battle_config.client_sort_storage,             0,      0,      1,              },
-	{ "gm_check_minlevel",                  &battle_config.gm_check_minlevel,               60,     0,      100,            },
 	{ "feature.buying_store",               &battle_config.feature_buying_store,            1,      0,      1,              },
 	{ "feature.search_stores",              &battle_config.feature_search_stores,           1,      0,      1,              },
 	{ "searchstore_querydelay",             &battle_config.searchstore_querydelay,         10,      0,      INT_MAX,        },

+ 0 - 27
src/map/battle.h

@@ -151,16 +151,9 @@ extern struct Battle_Config
 	int monster_max_aspd;
 	int view_range_rate;
 	int chase_range_rate;
-	int lowest_gm_level;
-	int atc_gmonly;
 	int atc_spawn_quantity_limit;
 	int atc_slave_clone_limit;
 	int partial_name_scan;
-	int gm_allskill;
-	int gm_allequip;
-	int gm_skilluncond;
-	int gm_join_chat;
-	int gm_kick_chat;
 	int skillfree;
 	int skillup_limit;
 	int wp_rate;
@@ -327,7 +320,6 @@ extern struct Battle_Config
 	int gx_disptype;
 	int devotion_level_difference;
 	int player_skill_partner_check;
-	int hide_GM_session;
 	int invite_request_check;
 	int skill_removetrap_type;
 	int disp_experience;
@@ -336,21 +328,14 @@ extern struct Battle_Config
 	int backstab_bow_penalty;
 	int hp_rate;
 	int sp_rate;
-	int gm_cant_drop_min_lv;
-	int gm_cant_drop_max_lv;
-	int disp_hpmeter;
 	int bone_drop;
 	int buyer_name;
-	int gm_cant_party_min_lv;
-	int gm_can_party; // [SketchyPhoenix]
 
 // eAthena additions
 	int night_at_start; // added by [Yor]
 	int day_duration; // added by [Yor]
 	int night_duration; // added by [Yor]
 	int ban_hack_trade; // added by [Yor]
-	int hack_info_GM_level; // added by [Yor]
-	int any_warp_GM_min_level; // added by [Yor]
 	int packet_ver_flag; // added by [Yor]
 	
 	int min_hair_style; // added by [MouseJstr]
@@ -387,7 +372,6 @@ extern struct Battle_Config
 	int delay_battle_damage;
 	int hide_woe_damage;
 	int display_version;
-	int who_display_aid;
 
 	int display_hallucination;	// [Skotlex]
 	int use_statpoint_table;	// [Skotlex]
@@ -415,15 +399,6 @@ extern struct Battle_Config
 
 	int retaliate_to_master;	//Whether when a mob is attacked by another mob, it will retaliate versus the mob or the mob's master. [Skotlex]
 
-	int title_lvl1; // Players titles [Lupus]
-	int title_lvl2; // Players titles [Lupus]
-	int title_lvl3; // Players titles [Lupus]
-	int title_lvl4; // Players titles [Lupus]
-	int title_lvl5; // Players titles [Lupus]
-	int title_lvl6; // Players titles [Lupus]
-	int title_lvl7; // Players titles [Lupus]
-	int title_lvl8; // Players titles [Lupus]
-	
 	int duel_allow_pvp; // [LuzZza]
 	int duel_allow_gvg; // [LuzZza]
 	int duel_allow_teleport; // [LuzZza]
@@ -466,7 +441,6 @@ extern struct Battle_Config
 	int ksprotection;
 	int auction_feeperhour;
 	int auction_maximumprice;
-	int gm_viewequip_min_lv;
 	int homunculus_auto_vapor;	//Keep Homunculus from Vaporizing when master dies. [L0ne_W0lf]
 	int display_status_timers;	//Show or hide skill buff/delay timers in recent clients [Sara]
 	int skill_add_heal_rate;	//skills that bHealPower has effect on [Inkfish]
@@ -476,7 +450,6 @@ extern struct Battle_Config
 	int autospell_check_range;	//Enable range check for autospell bonus. [L0ne_W0lf]
 	int client_reshuffle_dice;  // Reshuffle /dice
 	int client_sort_storage;
-	int gm_check_minlevel;  // min GM level for /check
 	int feature_buying_store;
 	int feature_search_stores;
 	int searchstore_querydelay;

+ 5 - 5
src/map/buyingstore.c

@@ -98,7 +98,7 @@ void buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha
 		return;
 	}
 
-	if( !pc_can_give_items(pc_isGM(sd)) )
+	if( !pc_can_give_items(sd) )
 	{// custom: GM is not allowed to buy (give zeny)
 		sd->buyingstore.slots = 0;
 		clif_displaymessage(sd->fd, msg_txt(246));
@@ -145,7 +145,7 @@ void buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha
 			break;
 		}
 
-		if( !id->flag.buyingstore || !itemdb_cantrade_sub(id, pc_isGM(sd), pc_isGM(sd)) || ( idx = pc_search_inventory(sd, nameid) ) == -1 )
+		if( !id->flag.buyingstore || !itemdb_cantrade_sub(id, pc_get_group_level(sd), pc_get_group_level(sd)) || ( idx = pc_search_inventory(sd, nameid) ) == -1 )
 		{// restrictions: allowed, no character-bound items and at least one must be owned
 			break;
 		}
@@ -219,7 +219,7 @@ void buyingstore_open(struct map_session_data* sd, int account_id)
 		return;
 	}
 
-	if( !pc_can_give_items(pc_isGM(sd)) )
+	if( !pc_can_give_items(sd) )
 	{// custom: GM is not allowed to sell
 		clif_displaymessage(sd->fd, msg_txt(246));
 		return;
@@ -257,7 +257,7 @@ void buyingstore_trade(struct map_session_data* sd, int account_id, unsigned int
 		return;
 	}
 
-	if( !pc_can_give_items(pc_isGM(sd)) )
+	if( !pc_can_give_items(sd) )
 	{// custom: GM is not allowed to sell
 		clif_displaymessage(sd->fd, msg_txt(246));
 		clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
@@ -312,7 +312,7 @@ void buyingstore_trade(struct map_session_data* sd, int account_id, unsigned int
 			return;
 		}
 
-		if( sd->status.inventory[index].expire_time || !itemdb_cantrade(&sd->status.inventory[index], pc_isGM(sd), pc_isGM(pl_sd)) || memcmp(sd->status.inventory[index].card, buyingstore_blankslots, sizeof(buyingstore_blankslots)) )
+		if( sd->status.inventory[index].expire_time || !itemdb_cantrade(&sd->status.inventory[index], pc_get_group_level(sd), pc_get_group_level(pl_sd)) || memcmp(sd->status.inventory[index].card, buyingstore_blankslots, sizeof(buyingstore_blankslots)) )
 		{// non-tradable item
 			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
 			return;

+ 2 - 2
src/map/chat.c

@@ -125,7 +125,7 @@ int chat_joinchat(struct map_session_data* sd, int chatid, const char* pass)
 		return 0;
 	}
 
-	if( !cd->pub && strncmp(pass, cd->pass, sizeof(cd->pass)) != 0 && !(battle_config.gm_join_chat && pc_isGM(sd) >= battle_config.gm_join_chat) )
+	if( !cd->pub && strncmp(pass, cd->pass, sizeof(cd->pass)) != 0 && !pc_has_permission(sd, PC_PERM_JOIN_ALL_CHAT) )
 	{
 		clif_joinchatfail(sd,1);
 		return 0;
@@ -316,7 +316,7 @@ int chat_kickchat(struct map_session_data* sd, const char* kickusername)
 	if( i == cd->users )
 		return -1;
 
-	if( battle_config.gm_kick_chat && pc_isGM(cd->usersd[i]) >= battle_config.gm_kick_chat )
+	if (pc_has_permission(cd->usersd[i], PC_PERM_NO_CHAT_KICK))
 		return 0; //gm kick protection [Valaris]
 	
 	idb_put(cd->kick_list,cd->usersd[i]->status.char_id,(void*)1);

+ 4 - 4
src/map/chrif.c

@@ -412,7 +412,7 @@ int chrif_changemapserver(struct map_session_data* sd, uint32 ip, uint16 port)
 	WFIFOW(char_fd,28) = htons(port);
 	WFIFOB(char_fd,30) = sd->status.sex;
 	WFIFOL(char_fd,31) = htonl(session[sd->fd]->client_addr);
-	WFIFOL(char_fd,35) = sd->gmlevel;
+	WFIFOL(char_fd,35) = sd->group_id;
 	WFIFOSET(char_fd,39);
 	return 0;
 }
@@ -578,7 +578,7 @@ void chrif_authok(int fd)
 	uint32 login_id1;
 	uint32 login_id2;
 	time_t expiration_time;
-	int gmlevel;
+	int group_id;
 	struct mmo_charstatus* status;
 	int char_id;
 	struct auth_node *node;
@@ -595,7 +595,7 @@ void chrif_authok(int fd)
 	login_id1 = RFIFOL(fd,8);
 	login_id2 = RFIFOL(fd,12);
 	expiration_time = (time_t)(int32)RFIFOL(fd,16);
-	gmlevel = RFIFOL(fd,20);
+	group_id = RFIFOL(fd,20);
 	changing_mapservers = (RFIFOB(fd,24));
 	status = (struct mmo_charstatus*)RFIFOP(fd,25);
 	char_id = status->char_id;
@@ -628,7 +628,7 @@ void chrif_authok(int fd)
 		node->char_id == char_id &&
 		node->login_id1 == login_id1 )
 	{ //Auth Ok
-		if (pc_authok(sd, login_id2, expiration_time, gmlevel, status, changing_mapservers))
+		if (pc_authok(sd, login_id2, expiration_time, group_id, status, changing_mapservers))
 			return;
 	} else { //Auth Failed
 		pc_authfail(sd);

+ 152 - 347
src/map/clif.c

@@ -1779,7 +1779,7 @@ void clif_selllist(struct map_session_data *sd)
 	{
 		if( sd->status.inventory[i].nameid > 0 && sd->inventory_data[i] )
 		{
-			if( !itemdb_cansell(&sd->status.inventory[i], pc_isGM(sd)) )
+			if( !itemdb_cansell(&sd->status.inventory[i], pc_get_group_level(sd)) )
 				continue;
 
 			if( sd->status.inventory[i].expire_time )
@@ -2625,6 +2625,59 @@ void clif_guild_xy_remove(struct map_session_data *sd)
 	clif_send(buf,packet_len(0x1eb),&sd->bl,GUILD_SAMEMAP_WOS);
 }
 
+/*==========================================
+ *
+ *------------------------------------------*/
+static int clif_hpmeter_sub(struct block_list *bl, va_list ap)
+{
+	struct map_session_data *sd, *tsd;
+#if PACKETVER < 20100126
+	const int cmd = 0x106;
+#else
+	const int cmd = 0x80e;
+#endif
+
+	sd = va_arg(ap, struct map_session_data *);
+	tsd = (TBL_PC *)bl;
+
+	nullpo_ret(sd);
+	nullpo_ret(tsd);
+
+	if( !tsd->fd || tsd == sd )
+		return 0;
+
+	if( !pc_has_permission(tsd, PC_PERM_VIEW_HPMETER) )
+		return 0;
+	WFIFOHEAD(tsd->fd,packet_len(cmd));
+	WFIFOW(tsd->fd,0) = cmd;
+	WFIFOL(tsd->fd,2) = sd->status.account_id;
+#if PACKETVER < 20100126
+	if( sd->battle_status.max_hp > INT16_MAX )
+	{ //To correctly display the %hp bar. [Skotlex]
+		WFIFOW(tsd->fd,6) = sd->battle_status.hp/(sd->battle_status.max_hp/100);
+		WFIFOW(tsd->fd,8) = 100;
+	} else {
+		WFIFOW(tsd->fd,6) = sd->battle_status.hp;
+		WFIFOW(tsd->fd,8) = sd->battle_status.max_hp;
+	}
+#else
+	WFIFOL(tsd->fd,6) = sd->battle_status.hp;
+	WFIFOL(tsd->fd,10) = sd->battle_status.max_hp;
+#endif
+	WFIFOSET(tsd->fd,packet_len(cmd));
+	return 0;
+}
+
+/*==========================================
+ * Server tells all players that are allowed to view HP bars
+ * and are nearby 'sd' that 'sd' hp bar was updated.
+ *------------------------------------------*/
+static int clif_hpmeter(struct map_session_data *sd)
+{
+	nullpo_ret(sd);
+	map_foreachinarea(clif_hpmeter_sub, sd->bl.m, sd->bl.x-AREA_SIZE, sd->bl.y-AREA_SIZE, sd->bl.x+AREA_SIZE, sd->bl.y+AREA_SIZE, BL_PC, sd);
+	return 0;
+}
 
 /// Notifies client of a character parameter change.
 /// 00b0 <var id>.W <value>.L (ZC_PAR_CHANGE)
@@ -2700,8 +2753,7 @@ void clif_updatestatus(struct map_session_data *sd,int type)
 	case SP_HP:
 		WFIFOL(fd,4)=sd->battle_status.hp;
 		// TODO: Won't these overwrite the current packet?
-		if( battle_config.disp_hpmeter )
-			clif_hpmeter(sd);
+		clif_hpmeter(sd);
 		if( !battle_config.party_hp_mode && sd->status.party_id )
 			clif_party_hp(sd);
 		if( sd->bg_id )
@@ -3922,7 +3974,6 @@ int clif_status_load_single(int fd, int id,int type,int flag,int val1, int val2,
  *------------------------------------------*/
 static void clif_getareachar_pc(struct map_session_data* sd,struct map_session_data* dstsd)
 {
-	int gmlvl;
 	struct block_list *d_bl;
 	int i;
 
@@ -3943,7 +3994,8 @@ static void clif_getareachar_pc(struct map_session_data* sd,struct map_session_d
 	}
 	if( (sd->status.party_id && dstsd->status.party_id == sd->status.party_id) || //Party-mate, or hpdisp setting.
 		(sd->bg_id && sd->bg_id == dstsd->bg_id) || //BattleGround
-		(battle_config.disp_hpmeter && (gmlvl = pc_isGM(sd)) >= battle_config.disp_hpmeter && gmlvl >= pc_isGM(dstsd)) )
+		pc_has_permission(sd, PC_PERM_VIEW_HPMETER)
+	)
 		clif_hpmeter_single(sd->fd, dstsd->bl.id, dstsd->battle_status.hp, dstsd->battle_status.max_hp);
 
 	// display link (sd - dstsd) to sd
@@ -5235,26 +5287,31 @@ void clif_status_change(struct block_list *bl,int type,int flag,unsigned int tic
 /// 008e <packet len>.W <message>.?B
 void clif_displaymessage(const int fd, const char* mes)
 {
-	// invalid pointer?
 	nullpo_retv(mes);
 	
 	//Scrapped, as these are shared by disconnected players =X [Skotlex]
 	if (fd == 0)
 		;
 	else {
-		int len_mes = strlen(mes);
-
-		if (len_mes > 0) { // don't send a void message (it's not displaying on the client chat). @help can send void line.
-			WFIFOHEAD(fd, 5 + len_mes);
-			WFIFOW(fd,0) = 0x8e;
-			WFIFOW(fd,2) = 5 + len_mes; // 4 + len + NULL teminate
-			memcpy(WFIFOP(fd,4), mes, len_mes + 1);
-			WFIFOSET(fd, 5 + len_mes);
+		char *message, *line;
+
+		message = aStrdup(mes);
+		line = strtok(message, "\n");
+		while(line != NULL) {
+			int len = strlen(line);
+			if (len > 0) { // don't send a void message (it's not displaying on the client chat). @help can send void line.
+				WFIFOHEAD(fd, 5 + len);
+				WFIFOW(fd,0) = 0x8e;
+				WFIFOW(fd,2) = 5 + len; // 4 + len + NULL teminate
+				memcpy(WFIFOP(fd,4), line, len + 1);
+				WFIFOSET(fd, 5 + len);
+			}
+			line = strtok(NULL, "\n");
 		}
+		aFree(message);
 	}
 }
 
-
 /// Send broadcast message in yellow or blue without font formatting (ZC_BROADCAST).
 /// 009a <packet len>.W <message>.?B
 void clif_broadcast(struct block_list* bl, const char* mes, int len, int type, enum send_target target)
@@ -5518,7 +5575,7 @@ void clif_wis_message(int fd, const char* nick, const char* mes, int mes_len)
 	WFIFOW(fd,2) = mes_len + NAME_LENGTH + 8;
 	safestrncpy((char*)WFIFOP(fd,4), nick, NAME_LENGTH);
 	WFIFOL(fd,28) = 0; // isAdmin; if nonzero, also displays text above char
-	// TODO: WFIFOL(fd,28) = ( pc_isGM(ssd) >= battle_config.lowest_gm_level );
+	// TODO: WFIFOL(fd,28) = pc_get_group_level(ssd);
 	safestrncpy((char*)WFIFOP(fd,32), mes, mes_len);
 	WFIFOSET(fd,WFIFOW(fd,2));
 #endif
@@ -6419,64 +6476,6 @@ void clif_hpmeter_single(int fd, int id, unsigned int hp, unsigned int maxhp)
 	WFIFOSET(fd, packet_len(cmd));
 }
 
-/*==========================================
- *
- *------------------------------------------*/
-int clif_hpmeter_sub(struct block_list *bl, va_list ap)
-{
-	struct map_session_data *sd, *tsd;
-	int level;
-#if PACKETVER < 20100126
-	const int cmd = 0x106;
-#else
-	const int cmd = 0x80e;
-#endif
-
-	sd = va_arg(ap, struct map_session_data *);
-	tsd = (TBL_PC *)bl;
-
-	nullpo_ret(sd);
-	nullpo_ret(tsd);
-
-	if( !tsd->fd || tsd == sd )
-		return 0;
-
-	if( (level = pc_isGM(tsd)) < battle_config.disp_hpmeter || level < pc_isGM(sd) )
-		return 0;
-	WFIFOHEAD(tsd->fd,packet_len(cmd));
-	WFIFOW(tsd->fd,0) = cmd;
-	WFIFOL(tsd->fd,2) = sd->status.account_id;
-#if PACKETVER < 20100126
-	if( sd->battle_status.max_hp > INT16_MAX )
-	{ //To correctly display the %hp bar. [Skotlex]
-		WFIFOW(tsd->fd,6) = sd->battle_status.hp/(sd->battle_status.max_hp/100);
-		WFIFOW(tsd->fd,8) = 100;
-	} else {
-		WFIFOW(tsd->fd,6) = sd->battle_status.hp;
-		WFIFOW(tsd->fd,8) = sd->battle_status.max_hp;
-	}
-#else
-	WFIFOL(tsd->fd,6) = sd->battle_status.hp;
-	WFIFOL(tsd->fd,10) = sd->battle_status.max_hp;
-#endif
-	WFIFOSET(tsd->fd,packet_len(cmd));
-	return 0;
-}
-
-/*==========================================
- * Server tells all nearby gms to 'sd' that 'sd' hp bar was updated
- *------------------------------------------*/
-int clif_hpmeter(struct map_session_data *sd)
-{
-	nullpo_ret(sd);
-
-	if( battle_config.disp_hpmeter )
-		map_foreachinarea(clif_hpmeter_sub, sd->bl.m, sd->bl.x-AREA_SIZE, sd->bl.y-AREA_SIZE, sd->bl.x+AREA_SIZE, sd->bl.y+AREA_SIZE, BL_PC, sd);
-
-	return 0;
-}
-
-
 /// Notifies the client, that it's attack target is too far (ZC_ATTACK_FAILURE_FOR_DISTANCE).
 /// 0139 <target id>.L <target x>.W <target y>.W <x>.W <y>.W <atk range>.W
 void clif_movetoattack(struct map_session_data *sd,struct block_list *bl)
@@ -9417,7 +9416,7 @@ void clif_parse_GetCharNameRequest(int fd, struct map_session_data *sd)
 	sc = status_get_sc(bl);
 	if (sc && sc->option&OPTION_INVISIBLE && !disguised(bl) &&
 		bl->type != BL_NPC && //Skip hidden NPCs which can be seen using Maya Purple
-		pc_isGM(sd) < battle_config.hack_info_GM_level
+		pc_get_group_level(sd) < battle_config.hack_info_GM_level
 	) {
 		char gm_msg[256];
 		sprintf(gm_msg, "Hack on NameRequest: character '%s' (account: %d) requested the name of an invisible target (id: %d).\n", sd->status.name, sd->status.account_id, id);
@@ -9506,21 +9505,13 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd)
 /// 0140 <map name>.16B <x>.W <y>.W
 void clif_parse_MapMove(int fd, struct map_session_data *sd)
 {
-	char output[MAP_NAME_LENGTH_EXT+15]; // Max length of a short: ' -6XXXX' -> 7 digits
-	char message[MAP_NAME_LENGTH_EXT+15+5]; // "/mm "+output
+	char command[MAP_NAME_LENGTH_EXT+25];
 	char* map_name;
 
-	if (battle_config.atc_gmonly && !pc_isGM(sd))
-		return;
-	if(pc_isGM(sd) < get_atcommand_level("warp"))
-		return;
-
 	map_name = (char*)RFIFOP(fd,2);
 	map_name[MAP_NAME_LENGTH_EXT-1]='\0';
-	sprintf(output, "%s %d %d", map_name, RFIFOW(fd,18), RFIFOW(fd,20));
-	atcommand_mapmove(fd, sd, "@mapmove", output);
-	sprintf(message, "/mm %s", output);
-	log_atcommand(sd, get_atcommand_level("warp"), message);
+	sprintf(command, "@mapmove %s %d %d", map_name, RFIFOW(fd,18), RFIFOW(fd,20));
+	is_atcommand(fd, sd, command, 1);
 }
 
 
@@ -9861,7 +9852,7 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd)
 	// if player ignores everyone
 	if (dstsd->state.ignoreAll)
 	{
-		if (dstsd->sc.option & OPTION_INVISIBLE && pc_isGM(sd) < pc_isGM(dstsd))
+		if (dstsd->sc.option & OPTION_INVISIBLE && pc_get_group_level(sd) < pc_get_group_level(dstsd))
 			clif_wis_end(fd, 1); // 1: target character is not loged in
 		else
 			clif_wis_end(fd, 3); // 3: everyone ignored by target
@@ -9897,25 +9888,14 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd)
 /// 0099 <packet len>.W <text>.?B 00
 void clif_parse_Broadcast(int fd, struct map_session_data* sd)
 {
+	char command[CHAT_SIZE_MAX+11];
 	char* msg = (char*)RFIFOP(fd,4);
 	unsigned int len = RFIFOW(fd,2)-4;
-	int lv;
-
-	if( battle_config.atc_gmonly && !pc_isGM(sd) )
-		return;
-	if( pc_isGM(sd) < (lv=get_atcommand_level("broadcast")) )
-		return;
 
 	// as the length varies depending on the command used, just block unreasonably long strings
 	len = mes_len_check(msg, len, CHAT_SIZE_MAX);
-
-	intif_broadcast(msg, len, 0);
-
-	{
-		char logmsg[CHAT_SIZE_MAX+4];
-		sprintf(logmsg, "/b %s", msg);
-		log_atcommand(sd, lv, logmsg);
-	}
+	sprintf(command, "@broadcast %s", msg);
+	is_atcommand(fd, sd, command, 1);
 }
 
 
@@ -11066,23 +11046,10 @@ void clif_parse_SolveCharName(int fd, struct map_session_data *sd)
 ///     1 = skill
 void clif_parse_ResetChar(int fd, struct map_session_data *sd)
 {
-	if( battle_config.atc_gmonly && !pc_isGM(sd) )
-		return;
-
-	if( pc_isGM(sd) < get_atcommand_level("reset") )
-		return;
-
 	if( RFIFOW(fd,2) )
-		pc_resetskill(sd,1);
-	else {
-		pc_resetstate(sd);
-		if( sd->mission_mobid ) { //bugreport:2200
-			sd->mission_mobid = 0;
-			sd->mission_count = 0;
-			pc_setglobalreg(sd,"TK_MISSION_ID", 0);
-		}
-	}
-	log_atcommand(sd, get_atcommand_level("reset"), RFIFOW(fd,2) ? "/resetskill" : "/resetstate");
+		is_atcommand(fd, sd, "@resetskill", 1);
+	else
+		is_atcommand(fd, sd, "@resetstat", 1);
 }
 
 
@@ -11091,26 +11058,15 @@ void clif_parse_ResetChar(int fd, struct map_session_data *sd)
 /// 019c <packet len>.W <text>.?B
 void clif_parse_LocalBroadcast(int fd, struct map_session_data* sd)
 {
+	char command[CHAT_SIZE_MAX+16];
 	char* msg = (char*)RFIFOP(fd,4);
 	unsigned int len = RFIFOW(fd,2)-4;
-	int lv;
-
-	if( battle_config.atc_gmonly && !pc_isGM(sd) )
-		return;
-
-	if( pc_isGM(sd) < (lv=get_atcommand_level("localbroadcast")) )
-		return;
-
+	
 	// as the length varies depending on the command used, just block unreasonably long strings
 	len = mes_len_check(msg, len, CHAT_SIZE_MAX);
 
-	clif_broadcast(&sd->bl, msg, len, 0, ALL_SAMEMAP);
-
-	{
-		char logmsg[CHAT_SIZE_MAX+5];
-		sprintf(logmsg, "/lb %s", msg);
-		log_atcommand(sd, lv, logmsg);
-	}
+	sprintf(command, "@localbroadcast %s", msg);
+	is_atcommand(fd, sd, command, 1);
 }
 
 
@@ -12168,10 +12124,7 @@ void clif_parse_ChangePetName(int fd, struct map_session_data *sd)
 void clif_parse_GMKick(int fd, struct map_session_data *sd)
 {
 	struct block_list *target;
-	int tid,lv;
-
-	if( battle_config.atc_gmonly && !pc_isGM(sd) )
-		return;
+	int tid;
 
 	tid = RFIFOL(fd,2);
 	target = map_id2bl(tid);
@@ -12183,69 +12136,36 @@ void clif_parse_GMKick(int fd, struct map_session_data *sd)
 	switch (target->type) {
 	case BL_PC:
 	{
-		struct map_session_data *tsd = (struct map_session_data *)target;
-		if (pc_isGM(sd) <= pc_isGM(tsd))
-		{
-			clif_GM_kickack(sd, 0);
-			return;
-		}
-
-		lv = get_atcommand_level("kick");
-		if( pc_isGM(sd) < lv )
-		{
-			clif_GM_kickack(sd, 0);
-			return;
-		}
-
-		{
-			char message[256];
-			sprintf(message, "/kick %s (%d)", tsd->status.name, tsd->status.char_id);
-			log_atcommand(sd, lv, message);
-		}
-
-		clif_GM_kick(sd, tsd);
+		char command[NAME_LENGTH+6];
+		sprintf(command, "@kick %s", status_get_name(target));
+		is_atcommand(fd, sd, command, 1);
 	}
 	break;
+
+	/**
+	 * This one does not invoke any atcommand, so we need to check for permissions.
+	 */
 	case BL_MOB:
 	{
-		lv = get_atcommand_level("killmonster");
-		if( pc_isGM(sd) < lv )
-		{
+		char command[100];
+		if( !pc_can_use_command(sd, "killmonster", COMMAND_ATCOMMAND)) {
 			clif_GM_kickack(sd, 0);
 			return;
 		}
-
-		{
-			char message[256];
-			sprintf(message, "/kick %s (%d)", status_get_name(target), status_get_class(target));
-			log_atcommand(sd, lv, message);
-		}
-
+		sprintf(command, "/kick %s (%d)", status_get_name(target), status_get_class(target));
+		log_atcommand(sd, command);
 		status_percent_damage(&sd->bl, target, 100, 0, true); // can invalidate 'target'
 	}
 	break;
+
 	case BL_NPC:
 	{
-		struct npc_data* nd = (struct npc_data *)target;
-		lv = get_atcommand_level("unloadnpc");
-		if( pc_isGM(sd) < lv )
-		{
-			clif_GM_kickack(sd, 0);
-			return;
-		}
-
-		{
-			char message[256];
-			sprintf(message, "/kick %s (%d)", status_get_name(target), status_get_class(target));
-			log_atcommand(sd, lv, message);
-		}
-
-		// copy-pasted from atcommand_unloadnpc
-		npc_unload_duplicates(nd);
-		npc_unload(nd); // invalidates 'target'
-		npc_read_event_script();
+		char command[NAME_LENGTH+11];
+		sprintf(command, "@unloadnpc %s", status_get_name(target));
+		is_atcommand(fd, sd, command, 1);
 	}
 	break;
+
 	default:
 		clif_GM_kickack(sd, 0);
 	}
@@ -12271,21 +12191,13 @@ void clif_parse_GMKickAll(int fd, struct map_session_data* sd)
 void clif_parse_GMShift(int fd, struct map_session_data *sd)
 {// FIXME: remove is supposed to receive account name for clients prior 20100803RE
 	char *player_name;
-	int lv;
-
-	if( battle_config.atc_gmonly && !pc_isGM(sd) )
-		return;
-	if( pc_isGM(sd) < (lv=get_atcommand_level("goto")) )
-		return;
+	char command[NAME_LENGTH+8];
 
 	player_name = (char*)RFIFOP(fd,2);
 	player_name[NAME_LENGTH-1] = '\0';
-	atcommand_jumpto(fd, sd, "@jumpto", player_name); // as @jumpto
-	{
-		char message[NAME_LENGTH+7];
-		sprintf(message, "/shift %s", player_name);
-		log_atcommand(sd, lv, message);
-	}
+	
+	sprintf(command, "@jumpto %s", player_name);
+	is_atcommand(fd, sd, command, 1);
 }
 
 
@@ -12294,31 +12206,15 @@ void clif_parse_GMShift(int fd, struct map_session_data *sd)
 /// 0843 <account id>.L
 void clif_parse_GMRemove2(int fd, struct map_session_data* sd)
 {
-	int account_id, lv;
+	int account_id;
 	struct map_session_data* pl_sd;
 
-	if( battle_config.atc_gmonly && !pc_isGM(sd) )
-	{
-		return;
-	}
-
-	if( pc_isGM(sd) < ( lv = get_atcommand_level("goto") ) )
-	{
-		return;
-	}
-
 	account_id = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
-
-	if( ( pl_sd = map_id2sd(account_id) ) != NULL && pc_isGM(sd) >= pc_isGM(pl_sd) )
+	if( (pl_sd = map_id2sd(account_id)) != NULL )
 	{
-		pc_warpto(sd, pl_sd);
-	}
-
-	{
-		char message[32];
-
-		sprintf(message, "/remove %d", account_id);
-		log_atcommand(sd, lv, message);
+		char command[NAME_LENGTH+8];
+		sprintf(command, "@jumpto %s", pl_sd->status.name);
+		is_atcommand(fd, sd, command, 1);
 	}
 }
 
@@ -12333,22 +12229,13 @@ void clif_parse_GMRemove2(int fd, struct map_session_data* sd)
 void clif_parse_GMRecall(int fd, struct map_session_data *sd)
 {// FIXME: recall is supposed to receive account name for clients prior 20100803RE
 	char *player_name;
-	int lv;
-
-	if( battle_config.atc_gmonly && !pc_isGM(sd) )
-		return;
-
-	if( pc_isGM(sd) < (lv=get_atcommand_level("recall")) )
-		return;
+	char command [NAME_LENGTH+8];
 
 	player_name = (char*)RFIFOP(fd,2);
 	player_name[NAME_LENGTH-1] = '\0';
-	atcommand_recall(fd, sd, "@recall", player_name); // as @recall
-	{
-		char message[NAME_LENGTH+8];
-		sprintf(message, "/recall %s", player_name);
-		log_atcommand(sd, lv, message);
-	}
+	
+	sprintf(command, "@recall %s", player_name);
+	is_atcommand(fd, sd, command, 1);
 }
 
 
@@ -12357,31 +12244,15 @@ void clif_parse_GMRecall(int fd, struct map_session_data *sd)
 /// 0842 <account id>.L
 void clif_parse_GMRecall2(int fd, struct map_session_data* sd)
 {
-	int account_id, lv;
+	int account_id;
 	struct map_session_data* pl_sd;
 
-	if( battle_config.atc_gmonly && !pc_isGM(sd) )
-	{
-		return;
-	}
-
-	if( pc_isGM(sd) < ( lv = get_atcommand_level("recall") ) )
-	{
-		return;
-	}
-
 	account_id = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
-
-	if( ( pl_sd = map_id2sd(account_id) ) != NULL && pc_isGM(sd) >= pc_isGM(pl_sd) )
+	if( (pl_sd = map_id2sd(account_id)) != NULL )
 	{
-		pc_recall(sd, pl_sd);
-	}
-
-	{
-		char message[32];
-
-		sprintf(message, "/recall %d", account_id);
-		log_atcommand(sd, lv, message);
+		char command[NAME_LENGTH+8];
+		sprintf(command, "@recall %s", pl_sd->status.name);
+		is_atcommand(fd, sd, command, 1);
 	}
 }
 
@@ -12392,33 +12263,21 @@ void clif_parse_GMRecall2(int fd, struct map_session_data* sd)
 void clif_parse_GM_Monster_Item(int fd, struct map_session_data *sd)
 {
 	char *monster_item_name;
-	char message[NAME_LENGTH+10]; //For logging.
-	int level;
-
-	if( battle_config.atc_gmonly && !pc_isGM(sd) )
-		return;
+	char command[NAME_LENGTH+10];
 
 	monster_item_name = (char*)RFIFOP(fd,2);
 	monster_item_name[NAME_LENGTH-1] = '\0';
 
 	if( mobdb_searchname(monster_item_name) ) {
-		if( pc_isGM(sd) < (level=get_atcommand_level("monster")) )
-			return;
-		atcommand_monster(fd, sd, "@monster", monster_item_name); // as @monster
-		{	//Log action. [Skotlex]
-			snprintf(message, sizeof(message)-1, "@monster %s", monster_item_name);
-			log_atcommand(sd, level, message);
-		}
+		snprintf(command, sizeof(command)-1, "@monster %s", monster_item_name);
+		is_atcommand(fd, sd, command, 1);
 		return;
 	}
-	if( itemdb_searchname(monster_item_name) == NULL )
-		return;
-	if( pc_isGM(sd) < (level = get_atcommand_level("item")) )
+
+	if( itemdb_searchname(monster_item_name) ) {
+		snprintf(command, sizeof(command)-1, "@item %s", monster_item_name);
+		is_atcommand(fd, sd, command, 1);
 		return;
-	atcommand_item(fd, sd, "@item", monster_item_name); // as @item
-	{	//Log action. [Skotlex]
-		sprintf(message, "@item %s", monster_item_name);
-		log_atcommand(sd, level, message);
 	}
 }
 
@@ -12429,26 +12288,7 @@ void clif_parse_GM_Monster_Item(int fd, struct map_session_data *sd)
 ///     TODO: Any OPTION_* ?
 void clif_parse_GMHide(int fd, struct map_session_data *sd)
 {
-	if( battle_config.atc_gmonly && !pc_isGM(sd) )
-		return;
-
-	if( pc_isGM(sd) < get_atcommand_level("hide") )
-		return;
-
-	if( sd->sc.option & OPTION_INVISIBLE ) {
-		sd->sc.option &= ~OPTION_INVISIBLE;
-		if (sd->disguise)
-			status_set_viewdata(&sd->bl, sd->disguise);
-		else
-			status_set_viewdata(&sd->bl, sd->status.class_);
-		clif_displaymessage(fd, "Invisible: Off.");
-	} else {
-		sd->sc.option |= OPTION_INVISIBLE;
-		sd->vd.class_ = INVISIBLE_CLASS;
-		clif_displaymessage(fd, "Invisible: On.");
-		log_atcommand(sd, get_atcommand_level("hide"), "/hide");
-	}
-	clif_changeoption(&sd->bl);
+	is_atcommand(fd, sd, "@hide", 1);
 }
 
 
@@ -12460,41 +12300,28 @@ void clif_parse_GMHide(int fd, struct map_session_data *sd)
 ///     2 = self mute (+10 minutes)
 void clif_parse_GMReqNoChat(int fd,struct map_session_data *sd)
 {
-	int id, type, value, level;
+	int id, type, value;
 	struct map_session_data *dstsd;
+	char command[NAME_LENGTH+15];
 
 	id = RFIFOL(fd,2);
 	type = RFIFOB(fd,6);
 	value = RFIFOW(fd,7);
 
 	if( type == 0 )
-		value = 0 - value;
+		value = -value;
 
 	//If type is 2 and the ids don't match, this is a crafted hacked packet!
 	//Disabled because clients keep self-muting when you give players public @ commands... [Skotlex]
-	if (type == 2 /* && (pc_isGM(sd) > 0 || sd->bl.id != id)*/)
+	if (type == 2 /* && (pc_get_group_level(sd) > 0 || sd->bl.id != id)*/)
 		return;
 
 	dstsd = map_id2sd(id);
 	if( dstsd == NULL )
 		return;
 
-	if( (level = pc_isGM(sd)) > pc_isGM(dstsd) && level >= get_atcommand_level("mute") )
-	{
-		clif_manner_message(sd, 0);
-		clif_manner_message(dstsd, 5);
-
-		if( dstsd->status.manner < value ) {
-			dstsd->status.manner -= value;
-			sc_start(&dstsd->bl,SC_NOCHAT,100,0,0);
-		} else {
-			dstsd->status.manner = 0;
-			status_change_end(&dstsd->bl, SC_NOCHAT, INVALID_TIMER);
-		}
-
-		if( type != 2 )
-			clif_GM_silence(sd, dstsd, type);
-	}
+	sprintf(command, "@mute %d %s", value, dstsd->status.name);
+	is_atcommand(fd, sd, command, 1);
 }
 
 
@@ -12503,23 +12330,12 @@ void clif_parse_GMReqNoChat(int fd,struct map_session_data *sd)
 /// 0212 <char name>.24B
 void clif_parse_GMRc(int fd, struct map_session_data* sd)
 {
-	char* name = (char*)RFIFOP(fd,2);
-	struct map_session_data* dstsd;
-	name[23] = '\0';
-	dstsd = map_nick2sd(name);
-	if( dstsd == NULL )
-		return;
-
-	if( pc_isGM(sd) > pc_isGM(dstsd) && pc_isGM(sd) >= get_atcommand_level("mute") )
-	{
-		clif_manner_message(sd, 0);
-		clif_manner_message(dstsd, 3);
-
-		dstsd->status.manner -= 60;
-		sc_start(&dstsd->bl,SC_NOCHAT,100,0,0);
+	char command[NAME_LENGTH+15];
+	char *name = (char*)RFIFOP(fd,2);
 
-		clif_GM_silence(sd, dstsd, 1);
-	}
+	name[NAME_LENGTH-1] = '\0';
+	sprintf(command, "@mute %d %s", 60, name);
+	is_atcommand(fd, sd, command, 1);
 }
 
 
@@ -12552,10 +12368,7 @@ void clif_parse_GMChangeMapType(int fd, struct map_session_data *sd)
 {
 	int x,y,type;
 
-	if( battle_config.atc_gmonly && !pc_isGM(sd) )
-		return;
-
-	if( pc_isGM(sd) < 99 ) //TODO: add proper check
+	if( pc_has_permission(sd, PC_PERM_USE_CHANGEMAPTYPE) )
 		return;
 
 	x = RFIFOW(fd,2);
@@ -12576,7 +12389,6 @@ void clif_parse_GMChangeMapType(int fd, struct map_session_data *sd)
 ///     1 = (/in nick) allow speech from nick
 void clif_parse_PMIgnore(int fd, struct map_session_data* sd)
 {
-	char output[512];
 	char* nick;
 	uint8 type;
 	int i;
@@ -12592,12 +12404,7 @@ void clif_parse_PMIgnore(int fd, struct map_session_data* sd)
 	
 	if( type == 0 )
 	{	// Add name to ignore list (block)
-
-		// Bot-check...
-		if (strcmp(wisp_server_name, nick) == 0)
-		{	// to find possible bot users who automaticaly ignore people
-			sprintf(output, "Character '%s' (account: %d) has tried to block wisps from '%s' (wisp name of the server). Bot user?", sd->status.name, sd->status.account_id, wisp_server_name);
-			intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, output);
+		if (strcmp(wisp_server_name, nick) == 0) {
 			WFIFOB(fd,3) = 1; // fail
 			WFIFOSET(fd, packet_len(0x0d1));
 			return;
@@ -13412,14 +13219,12 @@ void clif_parse_Check(int fd, struct map_session_data *sd)
 	char charname[NAME_LENGTH];
 	struct map_session_data* pl_sd;
 
-	if( pc_isGM(sd) < battle_config.gm_check_minlevel )
-	{
+	if(!pc_has_permission(sd, PC_PERM_USE_CHECK))
 		return;
-	}
 
 	safestrncpy(charname, (const char*)RFIFOP(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]), sizeof(charname));
 
-	if( ( pl_sd = map_nick2sd(charname) ) == NULL || pc_isGM(sd) < pc_isGM(pl_sd) )
+	if( ( pl_sd = map_nick2sd(charname) ) == NULL || pc_get_group_level(sd) < pc_get_group_level(pl_sd) )
 	{
 		return;
 	}
@@ -14003,9 +13808,9 @@ void clif_parse_Auction_setitem(int fd, struct map_session_data *sd)
 		return;
 	}
 	
-	if( !pc_can_give_items(pc_isGM(sd)) || sd->status.inventory[idx].expire_time ||
+	if( !pc_can_give_items(sd) || sd->status.inventory[idx].expire_time ||
 			!sd->status.inventory[idx].identify ||
-				!itemdb_canauction(&sd->status.inventory[idx],pc_isGM(sd)) ) { // Quest Item or something else
+				!itemdb_canauction(&sd->status.inventory[idx],pc_get_group_level(sd)) ) { // Quest Item or something else
 		clif_Auction_setitem(sd->fd, idx, true);
 		return;
 	}
@@ -14158,7 +13963,7 @@ void clif_parse_Auction_bid(int fd, struct map_session_data *sd)
 	unsigned int auction_id = RFIFOL(fd,2);
 	int bid = RFIFOL(fd,6);
 
-	if( !pc_can_give_items(pc_isGM(sd)) ) { //They aren't supposed to give zeny [Inkfish]
+	if( !pc_can_give_items(sd) ) { //They aren't supposed to give zeny [Inkfish]
 		clif_displaymessage(sd->fd, msg_txt(246));
 		return;
 	}
@@ -14456,7 +14261,7 @@ void clif_parse_ViewPlayerEquip(int fd, struct map_session_data* sd)
 	if (!tsd)
 		return;
 
-	if( tsd->status.show_equip || (battle_config.gm_viewequip_min_lv && pc_isGM(sd) >= battle_config.gm_viewequip_min_lv) )
+	if( tsd->status.show_equip || pc_has_permission(sd, PC_PERM_VIEW_EQUIPMENT) )
 		clif_viewequip_ack(sd, tsd);
 	else
 		clif_viewequip_fail(sd);
@@ -15995,11 +15800,11 @@ static int clif_parse(int fd)
 				//Disassociate character from the socket connection.
 				session[fd]->session_data = NULL;
 				sd->fd = 0;
-				ShowInfo("%sCharacter '"CL_WHITE"%s"CL_RESET"' logged off (using @autotrade).\n", (pc_isGM(sd))?"GM ":"", sd->status.name);
+				ShowInfo("Character '"CL_WHITE"%s"CL_RESET"' logged off (using @autotrade).\n", sd->status.name);
 			} else
 			if (sd->state.active) {
 				// Player logout display [Valaris]
-				ShowInfo("%sCharacter '"CL_WHITE"%s"CL_RESET"' logged off.\n", (pc_isGM(sd))?"GM ":"", sd->status.name);
+				ShowInfo("Character '"CL_WHITE"%s"CL_RESET"' logged off.\n", sd->status.name);
 				clif_quitsave(fd, sd);
 			} else {
 				//Unusual logout (during log on/off/map-changer procedure)

+ 0 - 2
src/map/clif.h

@@ -504,8 +504,6 @@ void clif_party_xy(struct map_session_data *sd);
 void clif_party_xy_single(int fd, struct map_session_data *sd);
 void clif_party_hp(struct map_session_data *sd);
 void clif_hpmeter_single(int fd, int id, unsigned int hp, unsigned int maxhp);
-int clif_hpmeter(struct map_session_data *sd);
-int clif_hpmeter_sub(struct block_list *bl, va_list ap);
 
 // guild
 void clif_guild_created(struct map_session_data *sd,int flag);

+ 18 - 16
src/map/intif.c

@@ -237,22 +237,22 @@ int intif_wis_replay(int id, int flag)
 }
 
 // The transmission of GM only Wisp/Page from server to inter-server
-int intif_wis_message_to_gm(char *Wisp_name, int min_gm_level, char *mes)
+int intif_wis_message_to_gm(char *wisp_name, int permission, char *mes)
 {
 	int mes_len;
 	if (CheckForCharServer())
 		return 0;
 	mes_len = strlen(mes) + 1; // + null
-	WFIFOHEAD(inter_fd, mes_len + 30);
+	WFIFOHEAD(inter_fd, mes_len + 32);
 	WFIFOW(inter_fd,0) = 0x3003;
-	WFIFOW(inter_fd,2) = mes_len + 30;
-	memcpy(WFIFOP(inter_fd,4), Wisp_name, NAME_LENGTH);
-	WFIFOW(inter_fd,4+NAME_LENGTH) = (short)min_gm_level;
-	memcpy(WFIFOP(inter_fd,6+NAME_LENGTH), mes, mes_len);
+	WFIFOW(inter_fd,2) = mes_len + 32;
+	memcpy(WFIFOP(inter_fd,4), wisp_name, NAME_LENGTH);
+	WFIFOL(inter_fd,4+NAME_LENGTH) = permission;
+	memcpy(WFIFOP(inter_fd,8+NAME_LENGTH), mes, mes_len);
 	WFIFOSET(inter_fd, WFIFOW(inter_fd,2));
 
 	if (battle_config.etc_log)
-		ShowNotice("intif_wis_message_to_gm: from: '%s', min level: %d, message: '%s'.\n", Wisp_name, min_gm_level, mes);
+		ShowNotice("intif_wis_message_to_gm: from: '%s', required permission: %d, message: '%s'.\n", wisp_name, permission, mes);
 
 	return 0;
 }
@@ -860,11 +860,13 @@ int intif_parse_WisEnd(int fd)
 
 static int mapif_parse_WisToGM_sub(struct map_session_data* sd,va_list va)
 {
-	int min_gm_level = va_arg(va, int);
+	int permission = va_arg(va, int);
 	char *wisp_name;
 	char *message;
 	int len;
-	if (pc_isGM(sd) < min_gm_level) return 0;
+	
+	if (!pc_has_permission(sd, permission))
+		return 0;
 	wisp_name = va_arg(va, char*);
 	message = va_arg(va, char*);
 	len = va_arg(va, int);
@@ -873,22 +875,22 @@ static int mapif_parse_WisToGM_sub(struct map_session_data* sd,va_list va)
 }
 
 // Received wisp message from map-server via char-server for ALL gm
-// 0x3003/0x3803 <packet_len>.w <wispname>.24B <min_gm_level>.w <message>.?B
+// 0x3003/0x3803 <packet_len>.w <wispname>.24B <permission>.l <message>.?B
 int mapif_parse_WisToGM(int fd)
 {
-	int min_gm_level, mes_len;
+	int permission, mes_len;
 	char Wisp_name[NAME_LENGTH];
 	char mbuf[255];
 	char *message;
 
-	mes_len =  RFIFOW(fd,2) - 30;
+	mes_len =  RFIFOW(fd,2) - 32;
 	message = (char *) (mes_len >= 255 ? (char *) aMallocA(mes_len) : mbuf);
 
-	min_gm_level = (int)RFIFOW(fd,28);
+	permission = RFIFOL(fd,28);
 	safestrncpy(Wisp_name, (char*)RFIFOP(fd,4), NAME_LENGTH);
-	safestrncpy(message, (char*)RFIFOP(fd,30), mes_len);
-	// information is sended to all online GM
-	map_foreachpc(mapif_parse_WisToGM_sub, min_gm_level, Wisp_name, message, mes_len);
+	safestrncpy(message, (char*)RFIFOP(fd,32), mes_len);
+	// information is sent to all online GM
+	map_foreachpc(mapif_parse_WisToGM_sub, permission, Wisp_name, message, mes_len);
 
 	if (message != mbuf)
 		aFree(message);

+ 1 - 1
src/map/intif.h

@@ -20,7 +20,7 @@ int intif_broadcast(const char* mes, int len, int type);
 int intif_broadcast2(const char* mes, int len, unsigned long fontColor, short fontType, short fontSize, short fontAlign, short fontY);
 
 int intif_wis_message(struct map_session_data *sd,char *nick,char *mes,int mes_len);
-int intif_wis_message_to_gm(char *Wisp_name, int min_gm_level, char *mes);
+int intif_wis_message_to_gm(char *Wisp_name, int permission, char *mes);
 
 int intif_saveregistry(struct map_session_data *sd, int type);
 int intif_request_registry(struct map_session_data *sd, int flag);

+ 8 - 7
src/map/log.c

@@ -282,12 +282,13 @@ void log_mvpdrop(struct map_session_data* sd, int monster_id, int* log_mvp)
 }
 
 
-/// logs used GM commands
-void log_atcommand(struct map_session_data* sd, int cmdlvl, const char* message)
+/// logs used atcommands
+void log_atcommand(struct map_session_data* sd, const char* message)
 {
 	nullpo_retv(sd);
 
-	if( cmdlvl < log_config.gm )
+	if( !log_config.commands ||
+	    !pc_should_log_commands(sd) )
 		return;
 
 	if( log_config.sql_logs )
@@ -460,8 +461,8 @@ int log_config_read(const char* cfgName)
 				log_config.filter = config_switch(w2);
 			else if( strcmpi(w1, "log_zeny") == 0 )
 				log_config.zeny = config_switch(w2);
-			else if( strcmpi(w1, "log_gm") == 0 )
-				log_config.gm = config_switch(w2);
+			else if( strcmpi(w1, "log_commands") == 0 )
+				log_config.commands = config_switch(w2);
 			else if( strcmpi(w1, "log_npc") == 0 )
 				log_config.npc = config_switch(w2);
 			else if( strcmpi(w1, "log_chat") == 0 )
@@ -508,9 +509,9 @@ int log_config_read(const char* cfgName)
 		{
 			ShowInfo("Logging chat to %s '%s'.\n", target, log_config.log_chat);
 		}
-		if( log_config.gm )
+		if( log_config.commands )
 		{
-			ShowInfo("Logging gm commands to %s '%s'.\n", target, log_config.log_gm);
+			ShowInfo("Logging commands to %s '%s'.\n", target, log_config.log_gm);
 		}
 		if( log_config.mvpdrop )
 		{

+ 2 - 2
src/map/log.h

@@ -59,7 +59,7 @@ void log_zeny(struct map_session_data* sd, e_log_pick_type type, struct map_sess
 
 void log_npc(struct map_session_data* sd, const char *message);
 void log_chat(e_log_chat_type type, int type_id, int src_charid, int src_accid, const char* map, int x, int y, const char* dst_charname, const char* message);
-void log_atcommand(struct map_session_data* sd, int cmdlvl, const char* message);
+void log_atcommand(struct map_session_data* sd, const char* message);
 
 /// old, but useful logs
 void log_branch(struct map_session_data* sd);
@@ -74,7 +74,7 @@ extern struct Log_Config
 	bool sql_logs;
 	bool log_chat_woe_disable;
 	int rare_items_log,refine_items_log,price_items_log,amount_items_log; //for filter
-	int branch, mvpdrop, zeny, gm, npc, chat;
+	int branch, mvpdrop, zeny, commands, npc, chat;
 	char log_branch[64], log_pick[64], log_zeny[64], log_mvpdrop[64], log_gm[64], log_npc[64], log_chat[64];
 }
 log_config;

+ 4 - 4
src/map/mail.c

@@ -63,7 +63,7 @@ unsigned char mail_setitem(struct map_session_data *sd, int idx, int amount)
 {
 	if( idx == 0 )
 	{ // Zeny Transfer
-		if( amount < 0 || !pc_can_give_items(pc_isGM(sd)) )
+		if( amount < 0 || !pc_can_give_items(sd) )
 			return 1;
 
 		if( amount > sd->status.zeny )
@@ -82,8 +82,8 @@ unsigned char mail_setitem(struct map_session_data *sd, int idx, int amount)
 			return 1;
 		if( amount < 0 || amount > sd->status.inventory[idx].amount )
 			return 1;
-		if( !pc_can_give_items(pc_isGM(sd)) || sd->status.inventory[idx].expire_time ||
-				!itemdb_canmail(&sd->status.inventory[idx],pc_isGM(sd)) )
+		if( !pc_can_give_items(sd) || sd->status.inventory[idx].expire_time ||
+				!itemdb_canmail(&sd->status.inventory[idx],pc_get_group_level(sd)) )
 			return 1;
 
 		sd->mail.index = idx;
@@ -184,7 +184,7 @@ void mail_deliveryfail(struct map_session_data *sd, struct mail_message *msg)
 // This function only check if the mail operations are valid
 bool mail_invalid_operation(struct map_session_data *sd)
 {
-	if( !map[sd->bl.m].flag.town && pc_isGM(sd) < get_atcommand_level("mail") )
+	if( !map[sd->bl.m].flag.town && !pc_can_use_command(sd, "mail", COMMAND_ATCOMMAND) )
 	{
 		ShowWarning("clif_parse_Mail: char '%s' trying to do invalid mail operations.\n", sd->status.name);
 		return true;

+ 2 - 6
src/map/party.c

@@ -344,12 +344,8 @@ int party_invite(struct map_session_data *sd,struct map_session_data *tsd)
 		return 0;
 	}
 	
-	if ( (pc_isGM(sd) >= battle_config.lowest_gm_level && pc_isGM(tsd) < battle_config.lowest_gm_level && !battle_config.gm_can_party && pc_isGM(sd) < battle_config.gm_cant_party_min_lv)
-		|| ( pc_isGM(sd) < battle_config.lowest_gm_level && pc_isGM(tsd) >= battle_config.lowest_gm_level && !battle_config.gm_can_party && pc_isGM(tsd) < battle_config.gm_cant_party_min_lv) )
-	{
-		//GMs can't invite non GMs to the party if not above the invite trust level
-		//Likewise, as long as gm_can_party is off, players can't invite GMs.
-		clif_displaymessage(sd->fd, msg_txt(81));
+	if (!pc_has_permission(sd, PC_PERM_PARTY) || !pc_has_permission(tsd, PC_PERM_PARTY)) {
+		clif_displaymessage(sd->fd, msg_txt(81)); // "Your GM level doesn't authorize you to preform this action on the specified player."
 		return 0;
 	}
 	

+ 71 - 73
src/map/pc.c

@@ -37,6 +37,7 @@
 #include "skill.h"
 #include "status.h" // struct status_data
 #include "pc.h"
+#include "pc_groups.h"
 #include "quest.h"
 
 #include <stdio.h>
@@ -81,9 +82,14 @@ int pc_class2idx(int class_) {
 	return class_;
 }
 
-int pc_isGM(struct map_session_data* sd)
+int inline pc_get_group_id(struct map_session_data *sd)
 {
-	return sd->gmlevel;
+	return sd->group_id;
+}
+
+int inline pc_get_group_level(struct map_session_data *sd)
+{
+	return pc_group_id2level(pc_get_group_id(sd));
 }
 
 static int pc_invincible_timer(int tid, unsigned int tick, int id, intptr_t data)
@@ -478,13 +484,12 @@ void pc_inventory_rental_add(struct map_session_data *sd, int seconds)
 		sd->rental_timer = add_timer(gettick() + min(tick,3600000), pc_inventory_rental_end, sd->bl.id, 0);
 }
 
-/*==========================================
-	Determines if the GM can give / drop / trade / vend items
-    Args: GM Level (current player GM level)
- *------------------------------------------*/
-bool pc_can_give_items(int level)
+/**
+ * Determines if player can give / drop / trade / vend items
+ */
+bool pc_can_give_items(struct map_session_data *sd)
 {
-	return( level < battle_config.gm_cant_drop_min_lv || level > battle_config.gm_cant_drop_max_lv );
+	return pc_has_permission(sd, PC_PERM_TRADE);
 }
 
 /*==========================================
@@ -815,7 +820,7 @@ int pc_isequip(struct map_session_data *sd,int n)
 
 	item = sd->inventory_data[n];
 
-	if( battle_config.gm_allequip>0 && pc_isGM(sd)>=battle_config.gm_allequip )
+	if(pc_has_permission(sd, PC_PERM_USE_ALL_EQUIPMENT))
 		return 1;
 
 	if(item == NULL)
@@ -885,14 +890,14 @@ int pc_isequip(struct map_session_data *sd,int n)
  * session idに問題無し
  * char鯖から送られてきたステ?タスを設定
  *------------------------------------------*/
-bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_time, int gmlevel, struct mmo_charstatus *st, bool changing_mapservers)
+bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_time, int group_id, struct mmo_charstatus *st, bool changing_mapservers)
 {
 	int i;
 	unsigned long tick = gettick();
 	uint32 ip = session[sd->fd]->client_addr;
 
 	sd->login_id2 = login_id2;
-	sd->gmlevel = gmlevel;
+	sd->group_id = group_id;
 	memcpy(&sd->status, st, sizeof(*st));
 
 	if (st->sex != sd->status.sex) {
@@ -975,7 +980,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
 	pc_setequipindex(sd);
 
 	status_change_init(&sd->bl);
-	if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) && (pc_isGM(sd) >= get_atcommand_level("hide")))
+	if (pc_can_use_command(sd, "hide", COMMAND_ATCOMMAND))
 		sd->status.option &= (OPTION_MASK | OPTION_INVISIBLE);
 	else
 		sd->status.option &= OPTION_MASK;
@@ -1015,20 +1020,12 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
 	sd->die_counter=-1;
 
 	//display login notice
-	if( sd->gmlevel >= battle_config.lowest_gm_level )
-		ShowInfo("GM '"CL_WHITE"%s"CL_RESET"' logged in."
-			" (AID/CID: '"CL_WHITE"%d/%d"CL_RESET"',"
-			" Packet Ver: '"CL_WHITE"%d"CL_RESET"', IP: '"CL_WHITE"%d.%d.%d.%d"CL_RESET"',"
-			" GM Level '"CL_WHITE"%d"CL_RESET"').\n",
-			sd->status.name, sd->status.account_id, sd->status.char_id,
-			sd->packet_ver, CONVIP(ip), sd->gmlevel);
-	else
-		ShowInfo("'"CL_WHITE"%s"CL_RESET"' logged in."
-			" (AID/CID: '"CL_WHITE"%d/%d"CL_RESET"',"
-			" Packet Ver: '"CL_WHITE"%d"CL_RESET"', IP: '"CL_WHITE"%d.%d.%d.%d"CL_RESET"').\n",
-			sd->status.name, sd->status.account_id, sd->status.char_id,
-			sd->packet_ver, CONVIP(ip));
-	
+	ShowInfo("'"CL_WHITE"%s"CL_RESET"' logged in."
+	         " (AID/CID: '"CL_WHITE"%d/%d"CL_RESET"',"
+	         " Packet Ver: '"CL_WHITE"%d"CL_RESET"', IP: '"CL_WHITE"%d.%d.%d.%d"CL_RESET"',"
+	         " Group '"CL_WHITE"%d"CL_RESET"').\n",
+	         sd->status.name, sd->status.account_id, sd->status.char_id,
+	         sd->packet_ver, CONVIP(ip), sd->group_id);	
 	// Send friends list
 	clif_friendslist_send(sd);
 
@@ -1280,7 +1277,7 @@ int pc_calc_skilltree(struct map_session_data *sd)
 		}
 	}
 
-	if( battle_config.gm_allskill > 0 && pc_isGM(sd) >= battle_config.gm_allskill ) {
+	if( pc_has_permission(sd, PC_PERM_ALL_SKILL) ) {
 		for( i = 0; i < MAX_SKILL; i++ ) {
 			switch(i) {
 				/**
@@ -4004,7 +4001,7 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun
 		return 1;
 	data = itemdb_search(item_data->nameid);
 
-	if( !itemdb_cancartstore(item_data, pc_isGM(sd)) )
+	if( !itemdb_cancartstore(item_data, pc_get_group_level(sd)) )
 	{ // Check item trade restrictions	[Skotlex]
 		clif_displaymessage (sd->fd, msg_txt(264));
 		return 1;
@@ -4451,45 +4448,6 @@ int pc_randomwarp(struct map_session_data *sd, clr_type type)
 	return 0;
 }
 
-
-/// Warps one player to another.
-/// @param sd player to warp.
-/// @param pl_sd player to warp to.
-int pc_warpto(struct map_session_data* sd, struct map_session_data* pl_sd)
-{
-	if( map[sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd) )
-	{
-		return -2;
-	}
-
-	if( map[pl_sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd) )
-	{
-		return -3;
-	}
-
-	return pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT);
-}
-
-
-/// Recalls one player to another.
-/// @param sd player to warp to.
-/// @param pl_sd player to warp.
-int pc_recall(struct map_session_data* sd, struct map_session_data* pl_sd)
-{
-	if( map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd) )
-	{
-		return -2;
-	}
-
-	if( map[sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd) )
-	{
-		return -3;
-	}
-
-	return pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
-}
-
-
 /*==========================================
  * Records a memo point at sd's current position
  * pos - entry to replace, (-1: shift oldest entry out)
@@ -4501,7 +4459,7 @@ int pc_memo(struct map_session_data* sd, int pos)
 	nullpo_ret(sd);
 
 	// check mapflags
-	if( sd->bl.m >= 0 && (map[sd->bl.m].flag.nomemo || map[sd->bl.m].flag.nowarpto) && battle_config.any_warp_GM_min_level > pc_isGM(sd) ) {
+	if( sd->bl.m >= 0 && (map[sd->bl.m].flag.nomemo || map[sd->bl.m].flag.nowarpto) && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE) ) {
 		clif_skill_teleportmessage(sd, 1); // "Saved point cannot be memorized."
 		return 0;
 	}
@@ -5586,7 +5544,7 @@ int pc_allskillup(struct map_session_data *sd)
 	}
 
 	//pc_calc_skilltree takes care of setting the ID to valid skills. [Skotlex]
-	if (battle_config.gm_allskill > 0 && pc_isGM(sd) >= battle_config.gm_allskill)
+	if (pc_has_permission(sd, PC_PERM_ALL_SKILL))
 	{	//Get ALL skills except npc/guild ones. [Skotlex]
 		//and except SG_DEVIL [Komurka] and MO_TRIPLEATTACK and RG_SNATCHER [ultramage]
 		for(i=0;i<MAX_SKILL;i++){
@@ -5761,6 +5719,13 @@ int pc_resetstate(struct map_session_data* sd)
 	clif_updatestatus(sd,SP_ULUK);	// End Addition
 	
 	clif_updatestatus(sd,SP_STATUSPOINT);
+
+	if( sd->mission_mobid ) { //bugreport:2200
+		sd->mission_mobid = 0;
+		sd->mission_count = 0;
+		pc_setglobalreg(sd,"TK_MISSION_ID", 0);
+	}
+
 	status_calc_pc(sd,0);
 
 	return 1;
@@ -7026,14 +6991,13 @@ int pc_setriding(TBL_PC* sd, int flag)
 /*==========================================
  * アイテムドロップ可不可判定
  *------------------------------------------*/
-int pc_candrop(struct map_session_data *sd,struct item *item)
+int pc_candrop(struct map_session_data *sd, struct item *item)
 {
-	int level = pc_isGM(sd);
 	if( item && item->expire_time )
 		return 0;
-	if( !pc_can_give_items(level) ) //check if this GM level can drop items
+	if( !pc_can_give_items(sd) ) //check if this GM level can drop items
 		return 0;
-	return (itemdb_isdropable(item, level));
+	return (itemdb_isdropable(item, pc_get_group_level(sd)));
 }
 
 /*==========================================
@@ -8255,6 +8219,37 @@ bool pc_isautolooting(struct map_session_data *sd, int nameid)
 	return (i != AUTOLOOTITEM_SIZE);
 }
 
+/**
+ * Checks if player can use @/#command
+ * @param sd Player map session data
+ * @param command Command name without @/# and params
+ * @param type is it atcommand or charcommand
+ */
+bool pc_can_use_command(struct map_session_data *sd, const char *command, AtCommandType type)
+{
+	return pc_group_can_use_command(pc_get_group_id(sd), command, type);
+}
+
+/**
+ * Checks if player has a permission
+ * @param sd Player map session data
+ * @param permission permission to check
+ */
+bool pc_has_permission(struct map_session_data *sd, int permission)
+{
+	return pc_group_has_permission(pc_get_group_id(sd), permission);
+}
+
+/**
+ * Checks if commands used by a player should be logged
+ * according to their group setting.
+ * @param sd Player map session data
+ */
+bool pc_should_log_commands(struct map_session_data *sd)
+{
+	return pc_group_should_log_commands(pc_get_group_id(sd));
+}
+
 int pc_split_str(char *str,char **val,int num)
 {
 	int i;
@@ -8628,6 +8623,7 @@ int pc_read_motd(void)
  *------------------------------------------*/
 void do_final_pc(void)
 {
+	do_final_pc_groups();
 	return;
 }
 
@@ -8665,5 +8661,7 @@ int do_init_pc(void)
 		}
 	}
 
+	do_init_pc_groups();
+
 	return 0;
 }

+ 31 - 6
src/map/pc.h

@@ -6,6 +6,7 @@
 
 #include "../common/mmo.h" // JOB_*, MAX_FAME_LIST, struct fame_list, struct mmo_charstatus
 #include "../common/timer.h" // INVALID_TIMER
+#include "atcommand.h" // AtCommandType
 #include "battle.h" // battle_config
 #include "buyingstore.h"  // struct s_buyingstore
 #include "itemdb.h" // MAX_ITEMGROUP
@@ -159,7 +160,7 @@ struct map_session_data {
 	} special_state;
 	int login_id1, login_id2;
 	unsigned short class_;	//This is the internal job ID used by the map server to simplify comparisons/queries/etc. [Skotlex]
-	int gmlevel;
+	int group_id;
 
 	int packet_ver;  // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 ... 18
 	struct mmo_charstatus status;
@@ -568,6 +569,27 @@ enum equip_index {
 	EQI_MAX
 };
 
+enum e_pc_permission {
+	PC_PERM_NONE                = 0,
+	PC_PERM_TRADE               = 0x00001,
+	PC_PERM_PARTY               = 0x00002,
+	PC_PERM_ALL_SKILL           = 0x00004,
+	PC_PERM_USE_ALL_EQUIPMENT   = 0x00008,
+	PC_PERM_SKILL_UNCONDITIONAL = 0x00010,
+	PC_PERM_JOIN_ALL_CHAT       = 0x00020,
+	PC_PERM_NO_CHAT_KICK        = 0x00040,
+	PC_PERM_HIDE_SESSION        = 0x00080,
+	PC_PERM_WHO_DISPLAY_AID     = 0x00100,
+	PC_PERM_RECEIVE_HACK_INFO   = 0x00200,
+	PC_PERM_WARP_ANYWHERE       = 0x00400,
+	PC_PERM_VIEW_HPMETER        = 0x00800,
+	PC_PERM_VIEW_EQUIPMENT      = 0x01000,
+	PC_PERM_USE_CHECK           = 0x02000,
+	PC_PERM_USE_CHANGEMAPTYPE   = 0x04000,
+	PC_PERM_USE_ALL_COMMANDS    = 0x08000,
+	PC_PERM_RECEIVE_REQUESTS    = 0x10000,
+};
+
 #define pc_setdead(sd)        ( (sd)->state.dead_sit = (sd)->vd.dead_sit = 1 )
 #define pc_setsit(sd)         ( (sd)->state.dead_sit = (sd)->vd.dead_sit = 2 )
 #define pc_isdead(sd)         ( (sd)->state.dead_sit == 1 )
@@ -608,15 +630,20 @@ enum equip_index {
 )
 
 int pc_class2idx(int class_);
-int pc_isGM(struct map_session_data *sd);
+int pc_get_group_level(struct map_session_data *sd);
+int pc_get_group_id(struct map_session_data *sd);
 int pc_getrefinebonus(int lv,int type);
-bool pc_can_give_items(int level);
+bool pc_can_give_items(struct map_session_data *sd);
+
+bool pc_can_use_command(struct map_session_data *sd, const char *command, AtCommandType type);
+bool pc_has_permission(struct map_session_data *sd, int permission);
+bool pc_should_log_commands(struct map_session_data *sd);
 
 int pc_setrestartvalue(struct map_session_data *sd,int type);
 int pc_makesavestatus(struct map_session_data *);
 void pc_respawn(struct map_session_data* sd, clr_type clrtype);
 int pc_setnewpc(struct map_session_data*,int,int,int,unsigned int,int,int);
-bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_time, int gmlevel, struct mmo_charstatus *st, bool changing_mapservers);
+bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_time, int group_id, struct mmo_charstatus *st, bool changing_mapservers);
 void pc_authfail(struct map_session_data *);
 int pc_reg_received(struct map_session_data *sd);
 
@@ -638,8 +665,6 @@ int pc_clean_skilltree(struct map_session_data *sd);
 int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, clr_type clrtype);
 int pc_setsavepoint(struct map_session_data*,short,int,int);
 int pc_randomwarp(struct map_session_data *sd,clr_type type);
-int pc_warpto(struct map_session_data* sd, struct map_session_data* pl_sd);
-int pc_recall(struct map_session_data* sd, struct map_session_data* pl_sd);
 int pc_memo(struct map_session_data* sd, int pos);
 
 int pc_checkadditem(struct map_session_data*,int,int);

+ 459 - 0
src/map/pc_groups.c

@@ -0,0 +1,459 @@
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#include "../common/conf.h"
+#include "../common/db.h"
+#include "../common/malloc.h"
+#include "../common/nullpo.h"
+#include "../common/showmsg.h"
+#include "../common/strlib.h" // strcmp
+
+#include "atcommand.h" // AtCommandType
+#include "pc_groups.h"
+#include "pc.h" // e_pc_permission
+
+
+typedef struct GroupSettings GroupSettings;
+
+// Cached config settings/pointers for quick lookup
+struct GroupSettings {
+	unsigned int id; // groups.[].id
+	int level; // groups.[].level
+	const char *name; // groups.[].name
+	config_setting_t *commands; // groups.[].commands
+	unsigned int e_permissions; // packed groups.[].permissions
+	bool log_commands; // groups.[].log_commands
+	/// Following are used only during config reading
+	config_setting_t *permissions; // groups.[].permissions
+	config_setting_t *inherit; // groups.[].inherit
+	bool inheritance_done; // have all inheritance rules been evaluated?
+	config_setting_t *root; // groups.[]
+};
+
+
+static config_t pc_group_config;
+static DBMap* pc_group_db; // id -> GroupSettings
+static DBMap* pc_groupname_db; // name -> GroupSettings
+
+static const struct {
+	const char *name;
+	int permission;
+} permission_name[] = {
+	{ "can_trade", PC_PERM_TRADE },
+	{ "can_party", PC_PERM_PARTY },
+	{ "all_skill", PC_PERM_ALL_SKILL },
+	{ "all_equipment", PC_PERM_USE_ALL_EQUIPMENT },
+	{ "skill_unconditional", PC_PERM_SKILL_UNCONDITIONAL },
+	{ "join_chat", PC_PERM_JOIN_ALL_CHAT },
+	{ "kick_chat", PC_PERM_NO_CHAT_KICK },
+	{ "hide_session", PC_PERM_HIDE_SESSION },
+	{ "who_display_aid", PC_PERM_WHO_DISPLAY_AID },
+	{ "hack_info", PC_PERM_RECEIVE_HACK_INFO },
+	{ "any_warp", PC_PERM_WARP_ANYWHERE },
+	{ "view_hpmeter", PC_PERM_VIEW_HPMETER },
+	{ "view_equipment", PC_PERM_VIEW_EQUIPMENT },
+	{ "use_check", PC_PERM_USE_CHECK },
+	{ "use_changemaptype", PC_PERM_USE_CHANGEMAPTYPE },
+	{ "all_commands", PC_PERM_USE_ALL_COMMANDS },
+	{ "receive_requests", PC_PERM_RECEIVE_REQUESTS },
+};
+
+/**
+ * @retval NULL if not found
+ * @private
+ */
+static inline GroupSettings* id2group(int group_id)
+{
+	return (GroupSettings*)idb_get(pc_group_db, group_id);
+}
+
+/**
+ * @retval NULL if not found
+ * @private
+ */
+static inline GroupSettings* name2group(const char* group_name)
+{
+	return (GroupSettings*)strdb_get(pc_groupname_db, group_name);
+}
+
+/**
+ * Loads group configuration from config file into memory.
+ * @private
+ */
+static void read_config(void)
+{
+	config_setting_t *groups = NULL;
+	const char *config_filename = "conf/groups.conf"; // FIXME hardcoded name
+	int group_count = 0;
+
+	if (conf_read_file(&pc_group_config, config_filename))
+		return;
+
+	groups = config_lookup(&pc_group_config, "groups");
+	
+	if (groups != NULL) {
+		GroupSettings *group_settings = NULL;
+		DBIterator *iter = NULL;
+		int i, loop = 0;
+
+		group_count = config_setting_length(groups);
+		for (i = 0; i < group_count; ++i) {
+			int id = 0, level = 0;
+			const char *groupname = NULL;
+			int log_commands = 0;
+			config_setting_t *group = config_setting_get_elem(groups, i);
+
+			if (!config_setting_lookup_int(group, "id", &id)) {
+				ShowConfigWarning(group, "pc_groups:read_config: \"groups\" list member #%d has undefined id, removing...", i);
+				config_setting_remove_elem(groups, i);
+				--i;
+				--group_count;
+				continue;
+			}
+
+			if (id2group(id) != NULL) {
+				ShowConfigWarning(group, "pc_groups:read_config: duplicate group id %d, removing...", i);
+				config_setting_remove_elem(groups, i);
+				--i;
+				--group_count;
+				continue;
+			}
+
+			config_setting_lookup_int(group, "level", &level);
+			config_setting_lookup_int(group, "log_commands", &log_commands);
+
+			if (!config_setting_lookup_string(group, "name", &groupname)) {
+				char temp[20];
+				config_setting_t *name = NULL;
+				snprintf(temp, sizeof(temp), "Group %d", id);
+				if ((name = config_setting_add(group, "name", CONFIG_TYPE_STRING)) == NULL ||
+				    !config_setting_set_string(name, temp)) {
+					ShowError("pc_groups:read_config: failed to set missing group name, id=%d, skipping... (%s:%d)\n",
+					          id, config_setting_source_file(group), config_setting_source_line(group));
+					continue;
+				}
+				config_setting_lookup_string(group, "name", &groupname); // Retrieve the pointer
+			}
+
+			if (name2group(groupname) != NULL) {
+				ShowConfigWarning(group, "pc_groups:read_config: duplicate group name %s, removing...", groupname);
+				config_setting_remove_elem(groups, i);
+				--i;
+				--group_count;
+				continue;
+			}
+
+			CREATE(group_settings, GroupSettings, 1);
+			group_settings->id = id;
+			group_settings->level = level;
+			group_settings->name = groupname;
+			group_settings->log_commands = (bool)log_commands;
+			group_settings->inherit = config_setting_get_member(group, "inherit");
+			group_settings->commands = config_setting_get_member(group, "commands");
+			group_settings->permissions = config_setting_get_member(group, "permissions");
+			group_settings->inheritance_done = false;
+			group_settings->root = group;
+
+			strdb_put(pc_groupname_db, groupname, group_settings);
+			idb_put(pc_group_db, id, group_settings);
+			
+		}
+		group_count = config_setting_length(groups); // Save number of groups
+		
+		// Check if all commands and permissions exist
+		iter = pc_group_db->iterator(pc_group_db);
+		for (group_settings = (GroupSettings*)iter->first(iter, NULL);
+			 iter->exists(iter);
+			 group_settings = (GroupSettings*)iter->next(iter, NULL)) {
+			config_setting_t *commands = group_settings->commands, *permissions = group_settings->permissions;
+			int count = 0, i;
+
+			// Make sure there is "commands" group
+			if (commands == NULL)
+				commands = group_settings->commands = config_setting_add(group_settings->root, "commands", CONFIG_TYPE_GROUP);
+			count = config_setting_length(commands);
+
+			for (i = 0; i < count; ++i) {
+				config_setting_t *command = config_setting_get_elem(commands, i);
+				const char *name = config_setting_name(command);
+				if (!atcommand_exists(name)) {
+					ShowConfigWarning(command, "pc_groups:read_config: non-existent command name '%s', removing...", name);
+					config_setting_remove(commands, name);
+					--i;
+					--count;
+				}
+			}
+
+			// Make sure there is "permissions" group
+			if (permissions == NULL)
+				permissions = group_settings->permissions = config_setting_add(group_settings->root, "permissions", CONFIG_TYPE_GROUP);
+			count = config_setting_length(permissions);
+
+			for(i = 0; i < count; ++i) {
+				config_setting_t *permission = config_setting_get_elem(permissions, i);
+				const char *name = config_setting_name(permission);
+				int j;
+
+				ARR_FIND(0, ARRAYLENGTH(permission_name), j, strcmp(permission_name[j].name, name) == 0);
+				if (j == ARRAYLENGTH(permission_name)) {
+					ShowConfigWarning(permission, "pc_groups:read_config: non-existent permission name '%s', removing...", name);
+					config_setting_remove(permissions, name);
+					--i;
+					--count;
+				}
+			}
+		}
+		iter->destroy(iter);
+
+		// Apply inheritance
+		i = 0; // counter for processed groups
+		while (i < group_count) {
+			iter = pc_group_db->iterator(pc_group_db);
+			for (group_settings = (GroupSettings*)iter->first(iter, NULL);
+			     iter->exists(iter);
+			     group_settings = (GroupSettings*)iter->next(iter, NULL)) {
+				config_setting_t *inherit = NULL,
+				                 *commands = group_settings->commands,
+					             *permissions = group_settings->permissions;
+				int j, inherit_count = 0, done = 0;
+				
+				if (group_settings->inheritance_done) // group already processed
+					continue; 
+
+				if ((inherit = group_settings->inherit) == NULL ||
+				    (inherit_count = config_setting_length(inherit)) <= 0) { // this group does not inherit from others
+					++i;
+					group_settings->inheritance_done = true;
+					continue;
+				}
+				
+				for (j = 0; j < inherit_count; ++j) {
+					GroupSettings *inherited_group = NULL;
+					const char *groupname = config_setting_get_string_elem(inherit, j);
+
+					if (groupname == NULL) {
+						ShowConfigWarning(inherit, "pc_groups:read_config: \"inherit\" array member #%d is not a name, removing...", j);
+						config_setting_remove_elem(inherit,j);
+						continue;
+					}
+					if ((inherited_group = name2group(groupname)) == NULL) {
+						ShowConfigWarning(inherit, "pc_groups:read_config: non-existent group name \"%s\", removing...", groupname);
+						config_setting_remove_elem(inherit,j);
+						continue;
+					}
+					if (!inherited_group->inheritance_done)
+						continue; // we need to do that group first
+
+					// Copy settings (commands/permissions) that are not defined yet
+					if (inherited_group->commands != NULL) {
+						int i = 0, commands_count = config_setting_length(inherited_group->commands);
+						for (i = 0; i < commands_count; ++i)
+							config_setting_copy(commands, config_setting_get_elem(inherited_group->commands, i));
+					}
+
+					if (inherited_group->permissions != NULL) {
+						int i = 0, permissions_count = config_setting_length(inherited_group->permissions);
+						for (i = 0; i < permissions_count; ++i)
+							config_setting_copy(permissions, config_setting_get_elem(inherited_group->permissions, i));
+					}
+
+					++done; // copied commands and permissions from one of inherited groups
+				}
+				
+				if (done == inherit_count) { // copied commands from all of inherited groups
+					++i;
+					group_settings->inheritance_done = true; // we're done with this group
+				}
+			}
+			iter->destroy(iter);
+
+			if (++loop > group_count) {
+				ShowWarning("pc_groups:read_config: Could not process inheritance rules, check your config '%s' for cycles...\n",
+				            config_filename);
+				break;
+			}
+		} // while(i < group_count)
+
+		// Pack permissions into GroupSettings.e_permissions for faster checking
+		iter = db_iterator(pc_group_db);
+		for (group_settings = (GroupSettings*)dbi_first(iter);
+		     dbi_exists(iter);
+		     group_settings = (GroupSettings*)dbi_next(iter)) {
+			config_setting_t *permissions = group_settings->permissions;
+			int i, count = config_setting_length(permissions);
+
+			for (i = 0; i < count; ++i) {
+				config_setting_t *perm = config_setting_get_elem(permissions, i);
+				const char *name = config_setting_name(perm);
+				int j;
+
+				ARR_FIND(0, ARRAYLENGTH(permission_name), j, strcmp(permission_name[j].name, name) == 0);
+				group_settings->e_permissions |= permission_name[j].permission;
+			}
+		}
+		iter->destroy(iter);
+	}
+
+	ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' groups in '"CL_WHITE"%s"CL_RESET"'.\n", group_count, config_filename);
+}
+
+/**
+ * Removes group configuration from memory.
+ * @private
+ */
+static void destroy_config(void)
+{
+	config_destroy(&pc_group_config);
+}
+
+/**
+ * In group configuration file, setting for each command is either
+ * <commandname> : <bool> (only atcommand), or
+ * <commandname> : [ <bool>, <bool> ] ([ atcommand, charcommand ])
+ * Maps AtCommandType enums to indexes of <commandname> value array,
+ * COMMAND_ATCOMMAND (1) being index 0, COMMAND_CHARCOMMAND (2) being index 1.
+ * @private
+ */
+static inline int AtCommandType2idx(AtCommandType type) { return (type-1); }
+
+/**
+ * Checks if player group can use @/#command
+ * @param group_id ID of the group
+ * @param command Command name without @/# and params
+ * @param type enum AtCommanndType { COMMAND_ATCOMMAND = 1, COMMAND_CHARCOMMAND = 2 }
+ */
+bool pc_group_can_use_command(int group_id, const char *command, AtCommandType type)
+{
+	int result = 0;
+	config_setting_t *commands = NULL;
+	GroupSettings *group = NULL;
+
+	if (pc_group_has_permission(group_id, PC_PERM_USE_ALL_COMMANDS))
+		return true;
+
+	if ((group = id2group(group_id)) == NULL)
+		return false;
+
+	commands = group->commands;
+	if (commands != NULL) {
+		config_setting_t *cmd = NULL;
+		
+		// <commandname> : <bool> (only atcommand)
+		if (type == COMMAND_ATCOMMAND && config_setting_lookup_bool(commands, command, &result))
+			return (bool)result;
+
+		// <commandname> : [ <bool>, <bool> ] ([ atcommand, charcommand ])
+		if ((cmd = config_setting_get_member(commands, command)) != NULL &&
+		    config_setting_is_aggregate(cmd) && config_setting_length(cmd) == 2)
+			return (bool)config_setting_get_bool_elem(cmd, AtCommandType2idx(type));
+	}
+	return false;
+}
+
+/**
+ * Checks if player group has a permission
+ * @param group_id ID of the group
+ * @param permission permission to check
+ */
+bool pc_group_has_permission(int group_id, int permission)
+{
+	GroupSettings *group = NULL;
+	if ((group = id2group(group_id)) == NULL) 
+		return false;
+	return ((group->e_permissions&permission) != 0);
+}
+
+/**
+ * Checks commands used by player group should be logged
+ * @param group_id ID of the group
+ */
+bool pc_group_should_log_commands(int group_id)
+{
+	GroupSettings *group = NULL;
+	if ((group = id2group(group_id)) == NULL) 
+		return false;
+	return group->log_commands;
+}
+
+/**
+ * Checks if player group with given ID exists.
+ * @param group_id group id
+ * @returns true if group exists, false otherwise
+ */
+bool pc_group_exists(int group_id)
+{
+	return idb_exists(pc_group_db, group_id);
+}
+
+/**
+ * Group ID -> group name lookup. Used only in @who atcommands.
+ * @param group_id group id
+ * @return group name
+ * @public
+ */
+const char* pc_group_id2name(int group_id)
+{
+	GroupSettings *group = id2group(group_id);
+	if (group == NULL)
+		return "Non-existent group!";
+	return group->name;
+}
+
+/**
+ * Group ID -> group level lookup. A way to provide backward compatibility with GM level system.
+ * @param group id
+ * @return group level
+ * @public
+ */
+int pc_group_id2level(int group_id)
+{
+	GroupSettings *group = id2group(group_id);
+	if (group == NULL)
+		return 0;
+	return group->level;
+}
+
+/**
+ * Initialize PC Groups: allocate DBMaps and read config.
+ * @public
+ */
+void do_init_pc_groups(void)
+{
+	pc_group_db = idb_alloc(DB_OPT_BASE);
+	pc_groupname_db = stridb_alloc(DB_OPT_DUP_KEY, 0);
+	read_config();
+}
+
+/**
+ * DBApply helper function for do_final_pc_groups
+ * @private
+ */
+static int group_db_free(DBKey key, void *data, va_list args)
+{
+	aFree((GroupSettings*)data);
+	return 1;
+}
+
+/**
+ * Finalize PC Groups: free DBMaps and config.
+ * @public
+ */
+void do_final_pc_groups(void)
+{
+	if (pc_group_db != NULL)
+		pc_group_db->destroy(pc_group_db, group_db_free);
+	if (pc_groupname_db != NULL )
+		db_destroy(pc_groupname_db);
+	destroy_config();
+}
+
+/**
+ * Reload PC Groups
+ * Used in @reloadatcommand
+ * @public
+ */
+void pc_groups_reload(void)
+{
+	do_final_pc_groups();
+	do_init_pc_groups();
+}

+ 20 - 0
src/map/pc_groups.h

@@ -0,0 +1,20 @@
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#ifndef _PC_GROUPS_H_
+#define _PC_GROUPS_H_
+
+#include "atcommand.h" // AtCommandType
+
+bool pc_group_exists(int group_id);
+bool pc_group_can_use_command(int group_id, const char *command, AtCommandType type);
+bool pc_group_has_permission(int group_id, int permission);
+bool pc_group_should_log_commands(int group_id);
+const char* pc_group_id2name(int group_id);
+int pc_group_id2level(int group_id);
+
+void do_init_pc_groups(void);
+void do_final_pc_groups(void);
+void pc_groups_reload(void);
+
+#endif // _PC_GROUPS_H_

+ 9 - 50
src/map/script.c

@@ -7345,7 +7345,7 @@ BUILDIN_FUNC(getgmlevel)
 	if( sd == NULL )
 		return 0;// no player attached, report source
 
-	script_pushint(st, pc_isGM(sd));
+	script_pushint(st, pc_get_group_level(sd));
 
 	return 0;
 }
@@ -8704,17 +8704,18 @@ BUILDIN_FUNC(getusers)
 BUILDIN_FUNC(getusersname)
 {
 	TBL_PC *sd, *pl_sd;
-	int disp_num=1;
+	int disp_num=1, group_level = 0;
 	struct s_mapiterator* iter;
 
 	sd = script_rid2sd(st);
 	if (!sd) return 0;
 
+	group_level = pc_get_group_level(sd);
 	iter = mapit_getallusers();
 	for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
 	{
-		if( battle_config.hide_GM_session && pc_isGM(pl_sd) )
-			continue; // skip hidden GMs
+		if (pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc_get_group_level(pl_sd) > group_level)
+			continue; // skip hidden sessions
 
 		if((disp_num++)%10==0)
 			clif_scriptnext(sd,st->oid);
@@ -11586,9 +11587,6 @@ BUILDIN_FUNC(nude)
 
 /*==========================================
  * gmcommand [MouseJstr]
- *
- * suggested on the forums...
- * splitted into atcommand & charcommand by [Skotlex]
  *------------------------------------------*/
 BUILDIN_FUNC(atcommand)
 {
@@ -11616,51 +11614,12 @@ BUILDIN_FUNC(atcommand)
 		}
 	}
 
-	// compatibility with previous implementation (deprecated!)
-	if(cmd[0] != atcommand_symbol)
-	{
-		cmd += strlen(sd->status.name);
-		while(*cmd != atcommand_symbol && *cmd != 0)
-			cmd++;
-	}
-
-	is_atcommand(fd, sd, cmd, 0);
-	return 0;
-}
-
-BUILDIN_FUNC(charcommand)
-{
-	TBL_PC dummy_sd;
-	TBL_PC* sd;
-	int fd;
-	const char* cmd;
-
-	cmd = script_getstr(st,2);
-
-	if (st->rid) {
-		sd = script_rid2sd(st);
-		fd = sd->fd;
-	} else { //Use a dummy character.
-		sd = &dummy_sd;
-		fd = 0;
-
-		memset(&dummy_sd, 0, sizeof(TBL_PC));
-		if (st->oid)
-		{
-			struct block_list* bl = map_id2bl(st->oid);
-			memcpy(&dummy_sd.bl, bl, sizeof(struct block_list));
-			if (bl->type == BL_NPC)
-				safestrncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH);
-		}
-	}
-
-	if (*cmd != charcommand_symbol) {
-		ShowWarning("script: buildin_charcommand: No '#' symbol!\n");
+	if (!is_atcommand(fd, sd, cmd, 0)) {
+		ShowWarning("script: buildin_atcommand: failed to execute command '%s'\n", cmd);
 		script_reportsrc(st);
 		return 1;
 	}
-	
-	is_atcommand(fd, sd, cmd, 0);
+
 	return 0;
 }
 
@@ -16170,7 +16129,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(nude,""), // nude command [Valaris]
 	BUILDIN_DEF(mapwarp,"ssii??"),		// Added by RoVeRT
 	BUILDIN_DEF(atcommand,"s"), // [MouseJstr]
-	BUILDIN_DEF(charcommand,"s"), // [MouseJstr]
+	BUILDIN_DEF2(atcommand,"charcommand","s"), // [MouseJstr]
 	BUILDIN_DEF(movenpc,"sii?"), // [MouseJstr]
 	BUILDIN_DEF(message,"ss"), // [MouseJstr]
 	BUILDIN_DEF(npctalk,"s"), // [Valaris]

+ 6 - 7
src/map/skill.c

@@ -436,8 +436,8 @@ int skillnotok (int skillid, struct map_session_data *sd)
 	if (i == 0)
 		return 1; // invalid skill id
 
-	if (battle_config.gm_skilluncond && pc_isGM(sd) >= battle_config.gm_skilluncond)
-		return 0; // GMs can do any damn thing they want
+	if (pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL))
+		return 0; // can do any damn thing they want
 
 	if( skillid == AL_TELEPORT && sd->skillitem == skillid && sd->skillitemlv > 2 )
 		return 0; // Teleport lv 3 bypasses this check.[Inkfish]
@@ -5412,7 +5412,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 	case MC_VENDING:
 		if(sd)
 		{	//Prevent vending of GMs with unnecessary Level to trade/drop. [Skotlex]
-			if ( !pc_can_give_items(pc_isGM(sd)) )
+			if ( !pc_can_give_items(sd) )
 				clif_skill_fail(sd,skillid,USESKILL_FAIL_LEVEL,0);
 			else {
 				sd->state.prevend = 1;
@@ -10256,8 +10256,7 @@ int skill_check_pc_partner (struct map_session_data *sd, short skill_id, short*
 	static int p_sd[2] = { 0, 0 };
 	int i;
 
-	if (!battle_config.player_skill_partner_check ||
-		(battle_config.gm_skilluncond && pc_isGM(sd) >= battle_config.gm_skilluncond))
+	if (!battle_config.player_skill_partner_check || pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL))
 		return 99; //As if there were infinite partners.
 
 	if (cast_flag)
@@ -10352,7 +10351,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh
 
 	if (lv <= 0 || sd->chatID) return 0;
 
-	if( battle_config.gm_skilluncond && pc_isGM(sd)>= battle_config.gm_skilluncond && sd->skillitem != skill )
+	if( pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->skillitem != skill )
 	{	//GMs don't override the skillItem check, otherwise they can use items without them being consumed! [Skotlex]
 		sd->state.arrow_atk = skill_get_ammotype(skill)?1:0; //Need to do arrow state check.
 		sd->spiritball_old = sd->spiritball; //Need to do Spiritball check.
@@ -11028,7 +11027,7 @@ int skill_check_condition_castend(struct map_session_data* sd, short skill, shor
 	if( lv <= 0 || sd->chatID )
 		return 0;
 
-	if( battle_config.gm_skilluncond && pc_isGM(sd) >= battle_config.gm_skilluncond && sd->skillitem != skill )
+	if( pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->skillitem != skill )
 	{	//GMs don't override the skillItem check, otherwise they can use items without them being consumed! [Skotlex]
 		sd->state.arrow_atk = skill_get_ammotype(skill)?1:0; //Need to do arrow state check.
 		sd->spiritball_old = sd->spiritball; //Need to do Spiritball check.

+ 4 - 4
src/map/storage.c

@@ -95,7 +95,7 @@ int storage_storageopen(struct map_session_data *sd)
 	if(sd->state.storage_flag)
 		return 1; //Already open?
 	
-	if( !pc_can_give_items(pc_isGM(sd)) )
+	if( !pc_can_give_items(sd) )
   	{ //check is this GM level is allowed to put items to storage
 		clif_displaymessage(sd->fd, msg_txt(246));
 		return 1;
@@ -138,7 +138,7 @@ static int storage_additem(struct map_session_data* sd, struct item* item_data,
 	
 	data = itemdb_search(item_data->nameid);
 
-	if( !itemdb_canstore(item_data, pc_isGM(sd)) )
+	if( !itemdb_canstore(item_data, pc_get_group_level(sd)) )
 	{	//Check if item is storable. [Skotlex]
 		clif_displaymessage (sd->fd, msg_txt(264));
 		return 1;
@@ -357,7 +357,7 @@ int storage_guild_storageopen(struct map_session_data* sd)
 	if(sd->state.storage_flag)
 		return 1; //Can't open both storages at a time.
 	
-	if( !pc_can_give_items(pc_isGM(sd)) ) { //check is this GM level can open guild storage and store items [Lupus]
+	if( !pc_can_give_items(sd) ) { //check is this GM level can open guild storage and store items [Lupus]
 		clif_displaymessage(sd->fd, msg_txt(246));
 		return 1;
 	}
@@ -391,7 +391,7 @@ int guild_storage_additem(struct map_session_data* sd, struct guild_storage* sto
 
 	data = itemdb_search(item_data->nameid);
 
-	if( !itemdb_canguildstore(item_data, pc_isGM(sd)) || item_data->expire_time )
+	if( !itemdb_canguildstore(item_data, pc_get_group_level(sd)) || item_data->expire_time )
 	{	//Check if item is storable. [Skotlex]
 		clif_displaymessage (sd->fd, msg_txt(264));
 		return 1;

+ 13 - 17
src/map/trade.c

@@ -29,8 +29,6 @@
  *------------------------------------------*/
 void trade_traderequest(struct map_session_data *sd, struct map_session_data *target_sd)
 {
-	int level;
-
 	nullpo_retv(sd);
 
 	if (map[sd->bl.m].flag.notrade) {
@@ -61,18 +59,16 @@ void trade_traderequest(struct map_session_data *sd, struct map_session_data *ta
 		return;
 	}
 
-	level = pc_isGM(sd);
-	if ( !pc_can_give_items(level) || !pc_can_give_items(pc_isGM(target_sd)) ) //check if both GMs are allowed to trade
+	if (!pc_can_give_items(sd) || !pc_can_give_items(target_sd)) //check if both GMs are allowed to trade
 	{
 		clif_displaymessage(sd->fd, msg_txt(246));
 		clif_tradestart(sd, 2); // GM is not allowed to trade
 		return;
 	} 
 	
-	//Fixed. Only real GMs can request trade from far away! [Lupus] 
-	if (level < battle_config.lowest_gm_level && (sd->bl.m != target_sd->bl.m ||
-		!check_distance_bl(&sd->bl, &target_sd->bl, TRADE_DISTANCE)
-	)) {
+	// Players can not request trade from far away, unless they are allowed to use @trade.
+	if (!pc_can_use_command(sd, "trade", COMMAND_ATCOMMAND) &&
+	    (sd->bl.m != target_sd->bl.m || !check_distance_bl(&sd->bl, &target_sd->bl, TRADE_DISTANCE))) {
 		clif_tradestart(sd, 0); // too far
 		return ;
 	}
@@ -127,10 +123,10 @@ void trade_tradeack(struct map_session_data *sd, int type)
 	if (type != 3)
 		return; //If client didn't send accept, it's a broken packet?
 
-	//Copied here as well since the original character could had warped.
-	if (pc_isGM(tsd) < battle_config.lowest_gm_level && (sd->bl.m != tsd->bl.m ||
-		!check_distance_bl(&sd->bl, &tsd->bl, TRADE_DISTANCE)
-	)) {
+	// Players can not request trade from far away, unless they are allowed to use @trade.
+	// Check here as well since the original character could had warped.
+	if (!pc_can_use_command(sd, "trade", COMMAND_ATCOMMAND) &&
+	    (sd->bl.m != tsd->bl.m || !check_distance_bl(&sd->bl, &tsd->bl, TRADE_DISTANCE))) {
 		clif_tradestart(sd, 0); // too far
 		sd->trade_partner=0;
 		tsd->trade_partner = 0;
@@ -196,9 +192,9 @@ int impossible_trade_check(struct map_session_data *sd)
 		if (inventory[index].amount < sd->deal.item[i].amount)
 		{ // if more than the player have -> hack
 			sprintf(message_to_gm, msg_txt(538), sd->status.name, sd->status.account_id); // Hack on trade: character '%s' (account: %d) try to trade more items that he has.
-			intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm);
+			intif_wis_message_to_gm(wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm);
 			sprintf(message_to_gm, msg_txt(539), inventory[index].amount, inventory[index].nameid, sd->deal.item[i].amount); // This player has %d of a kind of item (id: %d), and try to trade %d of them.
-			intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm);
+			intif_wis_message_to_gm(wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm);
 			// if we block people
 			if (battle_config.ban_hack_trade < 0) {
 				chrif_char_ask_name(-1, sd->status.name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block
@@ -215,7 +211,7 @@ int impossible_trade_check(struct map_session_data *sd)
 				// message about the ban
 				strcpy(message_to_gm, msg_txt(508)); //  This player hasn't been banned (Ban option is disabled).
 			
-			intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm);
+			intif_wis_message_to_gm(wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm);
 			return 1;
 		}
 		inventory[index].amount -= sd->deal.item[i].amount; // remove item from inventory
@@ -345,8 +341,8 @@ void trade_tradeadditem(struct map_session_data *sd, short index, short amount)
 		return;
 
 	item = &sd->status.inventory[index];
-	src_lv = pc_isGM(sd);
-	dst_lv = pc_isGM(target_sd);
+	src_lv = pc_get_group_level(sd);
+	dst_lv = pc_get_group_level(target_sd);
 	if( !itemdb_cantrade(item, src_lv, dst_lv) && //Can't trade
 		(pc_get_partner(sd) != target_sd || !itemdb_canpartnertrade(item, src_lv, dst_lv)) ) //Can't partner-trade
 	{

+ 2 - 2
src/map/vending.c

@@ -54,7 +54,7 @@ void vending_vendinglistreq(struct map_session_data* sd, int id)
 	if( !vsd->state.vending )
 		return; // not vending
 
-	if ( !pc_can_give_items(pc_isGM(sd)) || !pc_can_give_items(pc_isGM(vsd)) ) //check if both GMs are allowed to trade
+	if (!pc_can_give_items(sd) || !pc_can_give_items(vsd)) //check if both GMs are allowed to trade
 	{	// GM is not allowed to trade
 		clif_displaymessage(sd->fd, msg_txt(246));
 		return;
@@ -281,7 +281,7 @@ void vending_openvending(struct map_session_data* sd, const char* message, bool
 		||  !sd->status.cart[index].identify // unidentified item
 		||  sd->status.cart[index].attribute == 1 // broken item
 		||  sd->status.cart[index].expire_time // It should not be in the cart but just in case
-		||  !itemdb_cantrade(&sd->status.cart[index], pc_isGM(sd), pc_isGM(sd)) ) // untradeable item
+		||  !itemdb_cantrade(&sd->status.cart[index], pc_get_group_level(sd), pc_get_group_level(sd)) ) // untradeable item
 			continue;
 
 		sd->vending[i].index = index;

+ 12 - 2
src/tool/Makefile.in

@@ -6,6 +6,13 @@ COMMON_H = ../common/core.h ../common/mmo.h ../common/version.h \
 	../common/malloc.h ../common/showmsg.h ../common/strlib.h \
 	../common/utils.h ../common/cbasetypes.h ../common/des.h ../common/grfio.h
 
+LIBCONFIG_OBJ = ../../3rdparty/libconfig/libconfig.o ../../3rdparty/libconfig/grammar.o \
+	../../3rdparty/libconfig/scanctx.o ../../3rdparty/libconfig/scanner.o ../../3rdparty/libconfig/strbuf.o
+LIBCONFIG_H = ../../3rdparty/libconfig/libconfig.h ../../3rdparty/libconfig/grammar.h \
+	../../3rdparty/libconfig/parsectx.h ../../3rdparty/libconfig/scanctx.h ../../3rdparty/libconfig/scanner.h \
+	../../3rdparty/libconfig/strbuf.h ../../3rdparty/libconfig/wincompat.h
+LIBCONFIG_INCLUDE = -I../../3rdparty/libconfig
+
 MAPCACHE_OBJ = obj_all/mapcache.o
 
 @SET_MAKE@
@@ -15,8 +22,8 @@ MAPCACHE_OBJ = obj_all/mapcache.o
 
 all: mapcache
 
-mapcache: obj_all $(MAPCACHE_OBJ) $(COMMON_OBJ)
-	@CC@ @LDFLAGS@ -o ../../mapcache@EXEEXT@ $(MAPCACHE_OBJ) $(COMMON_OBJ) @LIBS@
+mapcache: obj_all $(MAPCACHE_OBJ) $(COMMON_OBJ) $(LIBCONFIG_OBJ)
+	@CC@ @LDFLAGS@ $(LIBCONFIG_INCLUDE) -o ../../mapcache@EXEEXT@ $(MAPCACHE_OBJ) $(COMMON_OBJ) $(LIBCONFIG_OBJ) @LIBS@
 
 clean:
 	rm -rf obj_all/*.o ../../mapcache@EXEEXT@
@@ -42,3 +49,6 @@ obj_all/%.o: %.c $(COMMON_H)
 
 ../common/obj_all/mini%.o:
 	@$(MAKE) -C ../common txt
+
+LIBCONFIG_OBJ:
+	@$(MAKE) -C ../../3rdparty/libconfig

+ 16 - 4
vcproj-10/char-server_sql.vcxproj

@@ -51,8 +51,8 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
       <Optimization>Disabled</Optimization>
-      <AdditionalIncludeDirectories>..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;LIBCONFIG_STATIC;YY_USE_CONST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PreprocessToFile>false</PreprocessToFile>
       <PreprocessSuppressLineNumbers>false</PreprocessSuppressLineNumbers>
       <ExceptionHandling>
@@ -94,8 +94,8 @@
       <OmitFramePointers>true</OmitFramePointers>
       <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
       <WholeProgramOptimization>true</WholeProgramOptimization>
-      <AdditionalIncludeDirectories>..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;LIBCONFIG_STATIC;YY_USE_CONST;FD_SETSIZE=4096;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <StringPooling>true</StringPooling>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <AdditionalOptions>
@@ -127,6 +127,13 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClInclude Include="..\3rdparty\libconfig\grammar.h" />
+    <ClInclude Include="..\3rdparty\libconfig\libconfig.h" />
+    <ClInclude Include="..\3rdparty\libconfig\parsectx.h" />
+    <ClInclude Include="..\3rdparty\libconfig\scanctx.h" />
+    <ClInclude Include="..\3rdparty\libconfig\scanner.h" />
+    <ClInclude Include="..\3rdparty\libconfig\strbuf.h" />
+    <ClInclude Include="..\3rdparty\libconfig\wincompat.h" />
     <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h" />
     <ClInclude Include="..\src\common\cbasetypes.h" />
     <ClInclude Include="..\src\common\core.h" />
@@ -159,6 +166,11 @@
     <ClInclude Include="..\src\char\inter.h" />
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="..\3rdparty\libconfig\grammar.c" />
+    <ClCompile Include="..\3rdparty\libconfig\libconfig.c" />
+    <ClCompile Include="..\3rdparty\libconfig\scanctx.c" />
+    <ClCompile Include="..\3rdparty\libconfig\scanner.c" />
+    <ClCompile Include="..\3rdparty\libconfig\strbuf.c" />
     <ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c" />
     <ClCompile Include="..\src\common\core.c" />
     <ClCompile Include="..\src\common\db.c" />

+ 48 - 6
vcproj-10/char-server_sql.vcxproj.filters

@@ -1,9 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c">
-      <Filter>3rdparty</Filter>
-    </ClCompile>
     <ClCompile Include="..\src\common\core.c">
       <Filter>common</Filter>
     </ClCompile>
@@ -79,11 +76,26 @@
     <ClCompile Include="..\src\char\inter.c">
       <Filter>char_sql</Filter>
     </ClCompile>
+    <ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c">
+      <Filter>3rdparty\mt19937ar</Filter>
+    </ClCompile>
+    <ClCompile Include="..\3rdparty\libconfig\grammar.c">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClCompile>
+    <ClCompile Include="..\3rdparty\libconfig\libconfig.c">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClCompile>
+    <ClCompile Include="..\3rdparty\libconfig\scanctx.c">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClCompile>
+    <ClCompile Include="..\3rdparty\libconfig\scanner.c">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClCompile>
+    <ClCompile Include="..\3rdparty\libconfig\strbuf.c">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h">
-      <Filter>3rdparty</Filter>
-    </ClInclude>
     <ClInclude Include="..\src\common\cbasetypes.h">
       <Filter>common</Filter>
     </ClInclude>
@@ -171,6 +183,30 @@
     <ClInclude Include="..\src\char\int_storage.h">
       <Filter>char_sql</Filter>
     </ClInclude>
+    <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h">
+      <Filter>3rdparty\mt19937ar</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\grammar.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\libconfig.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\parsectx.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\scanctx.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\scanner.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\strbuf.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\wincompat.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <Filter Include="common">
@@ -182,5 +218,11 @@
     <Filter Include="3rdparty">
       <UniqueIdentifier>{b3f5c857-79c0-4a55-b8c5-7e7f56a8f948}</UniqueIdentifier>
     </Filter>
+    <Filter Include="3rdparty\mt19937ar">
+      <UniqueIdentifier>{847768ab-8c4b-431b-8667-00f8ae3b915c}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="3rdparty\libconfig">
+      <UniqueIdentifier>{9e8badd7-548f-4eb4-9e87-613e87e772ff}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
 </Project>

+ 16 - 4
vcproj-10/login-server_sql.vcxproj

@@ -51,8 +51,8 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
       <Optimization>Disabled</Optimization>
-      <AdditionalIncludeDirectories>..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;WITH_SQL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;WITH_SQL;LIBCONFIG_STATIC;YY_USE_CONST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PreprocessToFile>false</PreprocessToFile>
       <PreprocessSuppressLineNumbers>false</PreprocessSuppressLineNumbers>
       <ExceptionHandling>
@@ -94,8 +94,8 @@
       <OmitFramePointers>true</OmitFramePointers>
       <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
       <WholeProgramOptimization>true</WholeProgramOptimization>
-      <AdditionalIncludeDirectories>..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;WITH_SQL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;WITH_SQL;LIBCONFIG_STATIC;YY_USE_CONST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <StringPooling>true</StringPooling>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <AdditionalOptions>
@@ -131,6 +131,13 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClInclude Include="..\3rdparty\libconfig\grammar.h" />
+    <ClInclude Include="..\3rdparty\libconfig\libconfig.h" />
+    <ClInclude Include="..\3rdparty\libconfig\parsectx.h" />
+    <ClInclude Include="..\3rdparty\libconfig\scanctx.h" />
+    <ClInclude Include="..\3rdparty\libconfig\scanner.h" />
+    <ClInclude Include="..\3rdparty\libconfig\strbuf.h" />
+    <ClInclude Include="..\3rdparty\libconfig\wincompat.h" />
     <ClInclude Include="..\src\login\account.h" />
     <ClInclude Include="..\src\login\ipban.h" />
     <ClInclude Include="..\src\login\login.h" />
@@ -156,6 +163,11 @@
     <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h" />
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="..\3rdparty\libconfig\grammar.c" />
+    <ClCompile Include="..\3rdparty\libconfig\libconfig.c" />
+    <ClCompile Include="..\3rdparty\libconfig\scanctx.c" />
+    <ClCompile Include="..\3rdparty\libconfig\scanner.c" />
+    <ClCompile Include="..\3rdparty\libconfig\strbuf.c" />
     <ClCompile Include="..\src\login\account_sql.c" />
     <ClCompile Include="..\src\login\ipban_sql.c" />
     <ClCompile Include="..\src\login\login.c" />

+ 48 - 6
vcproj-10/login-server_sql.vcxproj.filters

@@ -13,9 +13,6 @@
     <ClCompile Include="..\src\login\loginlog_sql.c">
       <Filter>login_sql</Filter>
     </ClCompile>
-    <ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c">
-      <Filter>3rdparty</Filter>
-    </ClCompile>
     <ClCompile Include="..\src\common\core.c">
       <Filter>common</Filter>
     </ClCompile>
@@ -58,6 +55,24 @@
     <ClCompile Include="..\src\common\utils.c">
       <Filter>common</Filter>
     </ClCompile>
+    <ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c">
+      <Filter>3rdparty\mt19937ar</Filter>
+    </ClCompile>
+    <ClCompile Include="..\3rdparty\libconfig\grammar.c">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClCompile>
+    <ClCompile Include="..\3rdparty\libconfig\libconfig.c">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClCompile>
+    <ClCompile Include="..\3rdparty\libconfig\scanctx.c">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClCompile>
+    <ClCompile Include="..\3rdparty\libconfig\scanner.c">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClCompile>
+    <ClCompile Include="..\3rdparty\libconfig\strbuf.c">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\src\login\account.h">
@@ -72,9 +87,6 @@
     <ClInclude Include="..\src\login\login.h">
       <Filter>login_sql</Filter>
     </ClInclude>
-    <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h">
-      <Filter>3rdparty</Filter>
-    </ClInclude>
     <ClInclude Include="..\src\common\cbasetypes.h">
       <Filter>common</Filter>
     </ClInclude>
@@ -129,6 +141,30 @@
     <ClInclude Include="..\src\common\utils.h">
       <Filter>common</Filter>
     </ClInclude>
+    <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h">
+      <Filter>3rdparty\mt19937ar</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\grammar.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\libconfig.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\parsectx.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\scanctx.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\scanner.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\strbuf.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\wincompat.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <Filter Include="common">
@@ -140,5 +176,11 @@
     <Filter Include="3rdparty">
       <UniqueIdentifier>{ab5c90ec-923d-4847-a214-45b40818211e}</UniqueIdentifier>
     </Filter>
+    <Filter Include="3rdparty\mt19937ar">
+      <UniqueIdentifier>{68e3bcee-28d9-4b2d-8701-614d50f32999}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="3rdparty\libconfig">
+      <UniqueIdentifier>{779e8145-9bb2-4a88-9149-60586ab0bdd4}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
 </Project>

+ 20 - 4
vcproj-10/map-server_sql.vcxproj

@@ -50,8 +50,8 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
       <Optimization>Disabled</Optimization>
-      <AdditionalIncludeDirectories>..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;_DEBUG;PCRE_SUPPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;..\3rdparty\libconfig;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;_DEBUG;PCRE_SUPPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;LIBCONFIG_STATIC;YY_USE_CONST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PreprocessToFile>false</PreprocessToFile>
       <PreprocessSuppressLineNumbers>false</PreprocessSuppressLineNumbers>
       <ExceptionHandling>
@@ -93,8 +93,8 @@
       <OmitFramePointers>true</OmitFramePointers>
       <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
       <WholeProgramOptimization>true</WholeProgramOptimization>
-      <AdditionalIncludeDirectories>..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;NDEBUG;PCRE_SUPPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;..\3rdparty\libconfig;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;NDEBUG;PCRE_SUPPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;LIBCONFIG_STATIC;YY_USE_CONST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <StringPooling>true</StringPooling>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <AdditionalOptions>
@@ -126,8 +126,16 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClInclude Include="..\3rdparty\libconfig\grammar.h" />
+    <ClInclude Include="..\3rdparty\libconfig\libconfig.h" />
+    <ClInclude Include="..\3rdparty\libconfig\parsectx.h" />
+    <ClInclude Include="..\3rdparty\libconfig\scanctx.h" />
+    <ClInclude Include="..\3rdparty\libconfig\scanner.h" />
+    <ClInclude Include="..\3rdparty\libconfig\strbuf.h" />
+    <ClInclude Include="..\3rdparty\libconfig\wincompat.h" />
     <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h" />
     <ClInclude Include="..\src\common\cbasetypes.h" />
+    <ClInclude Include="..\src\common\conf.h" />
     <ClInclude Include="..\src\common\core.h" />
     <ClInclude Include="..\src\common\db.h" />
     <ClInclude Include="..\src\common\des.h" />
@@ -172,6 +180,7 @@
     <ClInclude Include="..\src\map\party.h" />
     <ClInclude Include="..\src\map\path.h" />
     <ClInclude Include="..\src\map\pc.h" />
+    <ClInclude Include="..\src\map\pc_groups.h" />
     <ClInclude Include="..\src\map\pet.h" />
     <ClInclude Include="..\src\map\quest.h" />
     <ClInclude Include="..\src\map\config\Core.h" />
@@ -191,7 +200,13 @@
     <ClInclude Include="..\src\map\vending.h" />
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="..\3rdparty\libconfig\grammar.c" />
+    <ClCompile Include="..\3rdparty\libconfig\libconfig.c" />
+    <ClCompile Include="..\3rdparty\libconfig\scanctx.c" />
+    <ClCompile Include="..\3rdparty\libconfig\scanner.c" />
+    <ClCompile Include="..\3rdparty\libconfig\strbuf.c" />
     <ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c" />
+    <ClCompile Include="..\src\common\conf.c" />
     <ClCompile Include="..\src\common\core.c" />
     <ClCompile Include="..\src\common\db.c" />
     <ClCompile Include="..\src\common\des.c" />
@@ -234,6 +249,7 @@
     <ClCompile Include="..\src\map\party.c" />
     <ClCompile Include="..\src\map\path.c" />
     <ClCompile Include="..\src\map\pc.c" />
+    <ClCompile Include="..\src\map\pc_groups.c" />
     <ClCompile Include="..\src\map\pet.c" />
     <ClCompile Include="..\src\map\quest.c" />
     <ClCompile Include="..\src\map\script.c" />

+ 73 - 12
vcproj-10/map-server_sql.vcxproj.filters

@@ -88,9 +88,6 @@
     <ClCompile Include="..\src\map\searchstore.c">
       <Filter>map_sql</Filter>
     </ClCompile>
-    <ClCompile Include="..\src\common\showmsg.c">
-      <Filter>map_sql</Filter>
-    </ClCompile>
     <ClCompile Include="..\src\map\skill.c">
       <Filter>map_sql</Filter>
     </ClCompile>
@@ -109,9 +106,6 @@
     <ClCompile Include="..\src\map\vending.c">
       <Filter>map_sql</Filter>
     </ClCompile>
-    <ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c">
-      <Filter>3rdparty</Filter>
-    </ClCompile>
     <ClCompile Include="..\src\common\core.c">
       <Filter>common</Filter>
     </ClCompile>
@@ -160,6 +154,33 @@
     <ClCompile Include="..\src\common\utils.c">
       <Filter>common</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\common\conf.c">
+      <Filter>common</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\map\pc_groups.c">
+      <Filter>map_sql</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\common\showmsg.c">
+      <Filter>common</Filter>
+    </ClCompile>
+    <ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c">
+      <Filter>3rdparty\mt19937ar</Filter>
+    </ClCompile>
+    <ClCompile Include="..\3rdparty\libconfig\grammar.c">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClCompile>
+    <ClCompile Include="..\3rdparty\libconfig\libconfig.c">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClCompile>
+    <ClCompile Include="..\3rdparty\libconfig\scanctx.c">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClCompile>
+    <ClCompile Include="..\3rdparty\libconfig\scanner.c">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClCompile>
+    <ClCompile Include="..\3rdparty\libconfig\strbuf.c">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\src\map\atcommand.h">
@@ -246,9 +267,6 @@
     <ClInclude Include="..\src\map\searchstore.h">
       <Filter>map_sql</Filter>
     </ClInclude>
-    <ClInclude Include="..\src\common\showmsg.h">
-      <Filter>map_sql</Filter>
-    </ClInclude>
     <ClInclude Include="..\src\map\skill.h">
       <Filter>map_sql</Filter>
     </ClInclude>
@@ -267,9 +285,6 @@
     <ClInclude Include="..\src\map\vending.h">
       <Filter>map_sql</Filter>
     </ClInclude>
-    <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h">
-      <Filter>3rdparty</Filter>
-    </ClInclude>
     <ClInclude Include="..\src\common\version.h">
       <Filter>common</Filter>
     </ClInclude>
@@ -330,6 +345,46 @@
     <ClInclude Include="..\src\common\utils.h">
       <Filter>common</Filter>
     </ClInclude>
+    <ClInclude Include="..\src\map\config\Core.h" />
+    <ClInclude Include="..\src\map\config\Renewal.h" />
+    <ClInclude Include="..\src\map\config\Secure.h" />
+    <ClInclude Include="..\src\map\config\Data\Const.h" />
+    <ClInclude Include="..\src\map\config\Skills\General.h" />
+    <ClInclude Include="..\src\map\config\Skills\Mage_Classes.h" />
+    <ClInclude Include="..\src\map\config\Skills\Swordsman_Classes.h" />
+    <ClInclude Include="..\src\common\conf.h">
+      <Filter>common</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\map\pc_groups.h">
+      <Filter>map_sql</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\common\showmsg.h">
+      <Filter>common</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h">
+      <Filter>3rdparty\mt19937ar</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\grammar.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\libconfig.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\parsectx.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\scanctx.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\scanner.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\strbuf.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
+    <ClInclude Include="..\3rdparty\libconfig\wincompat.h">
+      <Filter>3rdparty\libconfig</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <Filter Include="common">
@@ -341,5 +396,11 @@
     <Filter Include="3rdparty">
       <UniqueIdentifier>{c4845ea8-bcc7-411b-af29-e3842adb6714}</UniqueIdentifier>
     </Filter>
+    <Filter Include="3rdparty\mt19937ar">
+      <UniqueIdentifier>{fcf23386-ddba-4a72-9b41-62f8e2d0e6c0}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="3rdparty\libconfig">
+      <UniqueIdentifier>{9caf40b7-c4d1-43b4-bd1f-0376b4f920e7}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
 </Project>

+ 4 - 4
vcproj-10/mapcache.vcxproj

@@ -49,8 +49,8 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
       <Optimization>Disabled</Optimization>
-      <AdditionalIncludeDirectories>..\3rdparty\zlib\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;MINICORE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>..\3rdparty\libconfig;..\3rdparty\zlib\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;MINICORE;LIBCONFIG_STATIC;YY_USE_CONST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PreprocessToFile>false</PreprocessToFile>
       <PreprocessSuppressLineNumbers>false</PreprocessSuppressLineNumbers>
       <ExceptionHandling>
@@ -91,8 +91,8 @@
       <OmitFramePointers>true</OmitFramePointers>
       <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
       <WholeProgramOptimization>true</WholeProgramOptimization>
-      <AdditionalIncludeDirectories>..\3rdparty\zlib\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;MINICORE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>..\3rdparty\libconfig;..\3rdparty\zlib\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;MINICORE;LIBCONFIG_STATIC;YY_USE_CONST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <StringPooling>true</StringPooling>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <FunctionLevelLinking>false</FunctionLevelLinking>

+ 75 - 11
vcproj-9/char-server_sql.vcproj

@@ -43,8 +43,8 @@
 				Name="VCCLCompilerTool"
 				AdditionalOptions="/MP"
 				Optimization="0"
-				AdditionalIncludeDirectories="..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
-				PreprocessorDefinitions="WIN32;_WIN32;__WIN32;_DEBUG;FD_SETSIZE=4096"
+				AdditionalIncludeDirectories="..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
+				PreprocessorDefinitions="WIN32;_WIN32;__WIN32;_DEBUG;FD_SETSIZE=4096;LIBCONFIG_STATIC;YY_USE_CONST"
 				GeneratePreprocessedFile="0"
 				ExceptionHandling="0"
 				BasicRuntimeChecks="3"
@@ -137,8 +137,8 @@
 				OmitFramePointers="true"
 				EnableFiberSafeOptimizations="true"
 				WholeProgramOptimization="true"
-				AdditionalIncludeDirectories="..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
-				PreprocessorDefinitions="WIN32;_WIN32;__WIN32;NDEBUG;FD_SETSIZE=4096"
+				AdditionalIncludeDirectories="..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
+				PreprocessorDefinitions="WIN32;_WIN32;__WIN32;NDEBUG;FD_SETSIZE=4096;LIBCONFIG_STATIC;YY_USE_CONST"
 				StringPooling="true"
 				RuntimeLibrary="0"
 				DefaultCharIsUnsigned="false"
@@ -204,20 +204,84 @@
 		<Filter
 			Name="3rdparty"
 			>
+			<Filter
+				Name="mt19937ar"
+				>
+				<File
+					RelativePath="..\3rdparty\mt19937ar\mt19937ar.c"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\mt19937ar\mt19937ar.h"
+					>
+				</File>
+			</Filter>
+			<Filter
+				Name="libconfig"
+				>
+				<File
+					RelativePath="..\3rdparty\libconfig\grammar.c"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\grammar.h"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\libconfig.c"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\libconfig.h"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\parsectx.h"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\scanctx.c"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\scanctx.h"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\scanner.c"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\scanner.h"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\strbuf.c"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\strbuf.h"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\wincompat.h"
+					>
+				</File>
+			</Filter>
+		</Filter>
+		<Filter
+			Name="common"
+			>
 			<File
-				RelativePath="..\3rdparty\mt19937ar\mt19937ar.c"
+				RelativePath="..\src\common\cbasetypes.h"
 				>
 			</File>
 			<File
-				RelativePath="..\3rdparty\mt19937ar\mt19937ar.h"
+				RelativePath="..\src\common\conf.c"
 				>
 			</File>
-		</Filter>
-		<Filter
-			Name="common"
-			>
 			<File
-				RelativePath="..\src\common\cbasetypes.h"
+				RelativePath="..\src\common\conf.h"
 				>
 			</File>
 			<File

+ 76 - 12
vcproj-9/login-server_sql.vcproj

@@ -43,8 +43,8 @@
 				Name="VCCLCompilerTool"
 				AdditionalOptions="/MP"
 				Optimization="0"
-				AdditionalIncludeDirectories="..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
-				PreprocessorDefinitions="WIN32;_WIN32;__WIN32;_DEBUG;FD_SETSIZE=4096;WITH_SQL"
+				AdditionalIncludeDirectories="..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
+				PreprocessorDefinitions="WIN32;_WIN32;__WIN32;_DEBUG;FD_SETSIZE=4096;LIBCONFIG_STATIC;YY_USE_CONST;WITH_SQL"
 				GeneratePreprocessedFile="0"
 				ExceptionHandling="0"
 				BasicRuntimeChecks="3"
@@ -137,8 +137,8 @@
 				OmitFramePointers="true"
 				EnableFiberSafeOptimizations="true"
 				WholeProgramOptimization="true"
-				AdditionalIncludeDirectories="..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
-				PreprocessorDefinitions="WIN32;_WIN32;__WIN32;NDEBUG;FD_SETSIZE=4096;WITH_SQL"
+				AdditionalIncludeDirectories="..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
+				PreprocessorDefinitions="WIN32;_WIN32;__WIN32;NDEBUG;FD_SETSIZE=4096;LIBCONFIG_STATIC;YY_USE_CONST;WITH_SQL"
 				StringPooling="true"
 				RuntimeLibrary="0"
 				DefaultCharIsUnsigned="false"
@@ -246,6 +246,14 @@
 				RelativePath="..\src\common\cbasetypes.h"
 				>
 			</File>
+			<File
+				RelativePath="..\src\common\conf.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\common\conf.h"
+				>
+			</File>
 			<File
 				RelativePath="..\src\common\core.c"
 				>
@@ -382,14 +390,70 @@
 		<Filter
 			Name="3rdparty"
 			>
-			<File
-				RelativePath="..\3rdparty\mt19937ar\mt19937ar.c"
-				>
-			</File>
-			<File
-				RelativePath="..\3rdparty\mt19937ar\mt19937ar.h"
-				>
-			</File>
+			<Filter
+				Name="mt19937ar"
+				>
+				<File
+					RelativePath="..\3rdparty\mt19937ar\mt19937ar.c"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\mt19937ar\mt19937ar.h"
+					>
+				</File>
+			</Filter>
+			<Filter
+				Name="libconfig"
+				>
+				<File
+					RelativePath="..\3rdparty\libconfig\grammar.c"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\grammar.h"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\libconfig.c"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\libconfig.h"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\parsectx.h"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\scanctx.c"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\scanctx.h"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\scanner.c"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\scanner.h"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\strbuf.c"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\strbuf.h"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\wincompat.h"
+					>
+				</File>
+			</Filter>
 		</Filter>
 	</Files>
 	<Globals>

+ 106 - 34
vcproj-9/map-server_sql.vcproj

@@ -42,8 +42,8 @@
 				Name="VCCLCompilerTool"
 				AdditionalOptions="/MP"
 				Optimization="0"
-				AdditionalIncludeDirectories="..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
-				PreprocessorDefinitions="WIN32;_WIN32;__WIN32;_DEBUG;PCRE_SUPPORT;FD_SETSIZE=4096"
+				AdditionalIncludeDirectories="..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
+				PreprocessorDefinitions="WIN32;_WIN32;__WIN32;_DEBUG;PCRE_SUPPORT;FD_SETSIZE=4096;LIBCONFIG_STATIC;YY_USE_CONST"
 				GeneratePreprocessedFile="0"
 				ExceptionHandling="0"
 				BasicRuntimeChecks="3"
@@ -136,8 +136,8 @@
 				OmitFramePointers="true"
 				EnableFiberSafeOptimizations="true"
 				WholeProgramOptimization="true"
-				AdditionalIncludeDirectories="..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
-				PreprocessorDefinitions="WIN32;_WIN32;__WIN32;NDEBUG;PCRE_SUPPORT;FD_SETSIZE=4096"
+				AdditionalIncludeDirectories="..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
+				PreprocessorDefinitions="WIN32;_WIN32;__WIN32;NDEBUG;PCRE_SUPPORT;FD_SETSIZE=4096;LIBCONFIG_STATIC;YY_USE_CONST"
 				StringPooling="true"
 				RuntimeLibrary="0"
 				DefaultCharIsUnsigned="false"
@@ -203,20 +203,84 @@
 		<Filter
 			Name="3rdparty"
 			>
+			<Filter
+				Name="mt19937ar"
+				>
+				<File
+					RelativePath="..\3rdparty\mt19937ar\mt19937ar.c"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\mt19937ar\mt19937ar.h"
+					>
+				</File>
+			</Filter>
+			<Filter
+				Name="libconfig"
+				>
+				<File
+					RelativePath="..\3rdparty\libconfig\grammar.c"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\grammar.h"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\libconfig.c"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\libconfig.h"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\parsectx.h"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\scanctx.c"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\scanctx.h"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\scanner.c"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\scanner.h"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\strbuf.c"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\strbuf.h"
+					>
+				</File>
+				<File
+					RelativePath="..\3rdparty\libconfig\wincompat.h"
+					>
+				</File>
+			</Filter>
+		</Filter>
+		<Filter
+			Name="common"
+			>
 			<File
-				RelativePath="..\3rdparty\mt19937ar\mt19937ar.c"
+				RelativePath="..\src\common\cbasetypes.h"
 				>
 			</File>
 			<File
-				RelativePath="..\3rdparty\mt19937ar\mt19937ar.h"
+				RelativePath="..\src\common\conf.c"
 				>
 			</File>
-		</Filter>
-		<Filter
-			Name="common"
-			>
 			<File
-				RelativePath="..\src\common\cbasetypes.h"
+				RelativePath="..\src\common\conf.h"
 				>
 			</File>
 			<File
@@ -435,6 +499,14 @@
 				RelativePath="..\src\map\clif.h"
 				>
 			</File>
+			<File
+				RelativePath="..\src\map\config\Data\Const.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\map\config\Core.h"
+				>
+			</File>
 			<File
 				RelativePath="..\src\map\date.c"
 				>
@@ -451,6 +523,10 @@
 				RelativePath="..\src\map\duel.h"
 				>
 			</File>
+			<File
+				RelativePath="..\src\map\config\Skills\General.h"
+				>
+			</File>
 			<File
 				RelativePath="..\src\map\guild.c"
 				>
@@ -499,6 +575,10 @@
 				RelativePath="..\src\map\log.h"
 				>
 			</File>
+			<File
+				RelativePath="..\src\map\config\Skills\Mage_Classes.h"
+				>
+			</File>
 			<File
 				RelativePath="..\src\map\mail.c"
 				>
@@ -576,47 +656,31 @@
 				>
 			</File>
 			<File
-				RelativePath="..\src\map\pet.c"
+				RelativePath="..\src\map\pc_groups.c"
 				>
 			</File>
 			<File
-				RelativePath="..\src\map\pet.h"
+				RelativePath="..\src\map\pc_groups.h"
 				>
 			</File>
 			<File
-				RelativePath="..\src\map\quest.c"
-				>
-			</File>
-			<File
-				RelativePath="..\src\map\quest.h"
+				RelativePath="..\src\map\pet.c"
 				>
 			</File>
 			<File
-				RelativePath="..\src\map\config\Core.h"
+				RelativePath="..\src\map\pet.h"
 				>
 			</File>
 			<File
-				RelativePath="..\src\map\config\Renewal.h"
+				RelativePath="..\src\map\quest.c"
 				>
 			</File>
 			<File
-				RelativePath="..\src\map\config\Secure.h"
+				RelativePath="..\src\map\quest.h"
 				>
 			</File>
 			<File
-				RelativePath="..\src\map\config\Data\Const.h"
-				>
-			</File>
-    			<File
-				RelativePath="..\src\map\config\Skills\General.h"
-				>
-			</File>
-    			<File
-				RelativePath="..\src\map\config\Skills\Mage_Classes.h"
-				>
-			</File>
-    			<File
-				RelativePath="..\src\map\config\Skills\Swordsman_Classes.h"
+				RelativePath="..\src\map\config\Renewal.h"
 				>
 			</File>
 			<File
@@ -635,6 +699,10 @@
 				RelativePath="..\src\map\searchstore.h"
 				>
 			</File>
+			<File
+				RelativePath="..\src\map\config\Secure.h"
+				>
+			</File>
 			<File
 				RelativePath="..\src\map\skill.c"
 				>
@@ -659,6 +727,10 @@
 				RelativePath="..\src\map\storage.h"
 				>
 			</File>
+			<File
+				RelativePath="..\src\map\config\Skills\Swordsman_Classes.h"
+				>
+			</File>
 			<File
 				RelativePath="..\src\map\trade.c"
 				>

+ 6 - 6
vcproj-9/mapcache.vcproj

@@ -42,8 +42,8 @@
 				Name="VCCLCompilerTool"
 				AdditionalOptions="/MP"
 				Optimization="0"
-				AdditionalIncludeDirectories="..\3rdparty\zlib\include;..\3rdparty\msinttypes\include"
-				PreprocessorDefinitions="WIN32;_WIN32;__WIN32;_DEBUG;MINICORE"
+				AdditionalIncludeDirectories="..\3rdparty\libconfig;..\3rdparty\zlib\include;..\3rdparty\msinttypes\include"
+				PreprocessorDefinitions="WIN32;_WIN32;__WIN32;_DEBUG;MINICORE;LIBCONFIG_STATIC;YY_USE_CONST"
 				GeneratePreprocessedFile="0"
 				ExceptionHandling="0"
 				BasicRuntimeChecks="3"
@@ -135,8 +135,8 @@
 				OmitFramePointers="true"
 				EnableFiberSafeOptimizations="true"
 				WholeProgramOptimization="true"
-				AdditionalIncludeDirectories="..\3rdparty\zlib\include;..\3rdparty\msinttypes\include"
-				PreprocessorDefinitions="WIN32;_WIN32;__WIN32;NDEBUG;MINICORE"
+				AdditionalIncludeDirectories="..\3rdparty\libconfig;..\3rdparty\zlib\include;..\3rdparty\msinttypes\include"
+				PreprocessorDefinitions="WIN32;_WIN32;__WIN32;NDEBUG;MINICORE;LIBCONFIG_STATIC;YY_USE_CONST"
 				StringPooling="true"
 				RuntimeLibrary="0"
 				EnableFunctionLevelLinking="false"
@@ -211,11 +211,11 @@
 				>
 			</File>
 			<File
-				RelativePath="..\src\common\des.h"
+				RelativePath="..\src\common\des.c"
 				>
 			</File>
 			<File
-				RelativePath="..\src\common\des.c"
+				RelativePath="..\src\common\des.h"
 				>
 			</File>
 			<File

部分文件因为文件数量过多而无法显示