Initial release:
authorroot <root@hwdev.(none)>
Thu, 3 Mar 2011 15:44:26 +0000 (15:44 +0000)
committerroot <root@hwdev.(none)>
Thu, 3 Mar 2011 15:44:26 +0000 (15:44 +0000)
* very alpha, but on 32-bit archs it runs
* network stack only, grabs an IPv6 on any network
* netdb not implemented, netinput should be improved

63 files changed:
INSTALL [new file with mode: 0644]
LICENSE [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
bin/kconfig/.gitignore [new file with mode: 0644]
bin/kconfig/.kxgettext.o.d [new file with mode: 0644]
bin/kconfig/Makefile [new file with mode: 0644]
bin/kconfig/Makefile.linux [new file with mode: 0644]
bin/kconfig/POTFILES.in [new file with mode: 0644]
bin/kconfig/check.sh [new file with mode: 0755]
bin/kconfig/conf.c [new file with mode: 0644]
bin/kconfig/confdata.c [new file with mode: 0644]
bin/kconfig/expr.c [new file with mode: 0644]
bin/kconfig/expr.h [new file with mode: 0644]
bin/kconfig/gconf.c [new file with mode: 0644]
bin/kconfig/gconf.glade [new file with mode: 0644]
bin/kconfig/images.c [new file with mode: 0644]
bin/kconfig/kconfig_load.c [new file with mode: 0644]
bin/kconfig/kxgettext.c [new file with mode: 0644]
bin/kconfig/lex.zconf.c_shipped [new file with mode: 0644]
bin/kconfig/lkc.h [new file with mode: 0644]
bin/kconfig/lkc_proto.h [new file with mode: 0644]
bin/kconfig/lxdialog/.gitignore [new file with mode: 0644]
bin/kconfig/lxdialog/BIG.FAT.WARNING [new file with mode: 0644]
bin/kconfig/lxdialog/check-lxdialog.sh [new file with mode: 0644]
bin/kconfig/lxdialog/checklist.c [new file with mode: 0644]
bin/kconfig/lxdialog/dialog.h [new file with mode: 0644]
bin/kconfig/lxdialog/inputbox.c [new file with mode: 0644]
bin/kconfig/lxdialog/menubox.c [new file with mode: 0644]
bin/kconfig/lxdialog/textbox.c [new file with mode: 0644]
bin/kconfig/lxdialog/util.c [new file with mode: 0644]
bin/kconfig/lxdialog/yesno.c [new file with mode: 0644]
bin/kconfig/mconf.c [new file with mode: 0644]
bin/kconfig/menu.c [new file with mode: 0644]
bin/kconfig/qconf.cc [new file with mode: 0644]
bin/kconfig/qconf.h [new file with mode: 0644]
bin/kconfig/symbol.c [new file with mode: 0644]
bin/kconfig/util.c [new file with mode: 0644]
bin/kconfig/zconf.gperf [new file with mode: 0644]
bin/kconfig/zconf.hash.c_shipped [new file with mode: 0644]
bin/kconfig/zconf.l [new file with mode: 0644]
bin/kconfig/zconf.tab.c_shipped [new file with mode: 0644]
bin/kconfig/zconf.y [new file with mode: 0644]
bin/lex.zconf.c [new file with mode: 0644]
bin/mconf [new file with mode: 0755]
bin/zconf.hash.c [new file with mode: 0644]
bin/zconf.tab.c [new file with mode: 0644]
doc/top2bottom.rst [new file with mode: 0644]
doc/usrman.rst [new file with mode: 0644]
include/0cpm/netcmd.h [new file with mode: 0644]
include/0cpm/netdb.h [new file with mode: 0644]
include/0cpm/netfun.h [new file with mode: 0644]
src/driver/tunnel/tuntest.c [new file with mode: 0644]
src/net/Kconfig [new file with mode: 0644]
src/net/Makefile [new file with mode: 0644]
src/net/core.c [new file with mode: 0644]
src/net/db.c [new file with mode: 0644]
src/net/input.c [new file with mode: 0644]
src/net/reply.c [new file with mode: 0644]
src/net/send.c [new file with mode: 0644]
src/target/Kconfig [new file with mode: 0644]
src/target/tuntest/Makefile [new file with mode: 0644]

diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..6953a63
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,39 @@
+Building and Installing firmly.0cpm
+===================================
+
+You can build firmly.0cpm for any of the target
+architectures included.  If you intend to port
+to another target, please fork off your own git
+repository, work on it until stable, and then
+inform us.  We will be happy to re-integrate
+your work.
+
+If you intend to build a predefined target, please
+read the helping instructions for that target to
+learn how to upload the firmware to your phone.
+It may not always be a matter of toggling a few
+switches; serious hardware tinkering is involved
+on some platforms.  On 0cpm.org you can find a
+list of people inclined to help you with this work
+on your phones.
+
+
+To build the firmware, please run from the main
+directory of the software
+
+       make menuconfig
+
+The first thing you should select is the target
+which is basically make and model of your phone.
+After that, you may have to choose a driver for
+devices like network device chips, if you are
+working on a device that changes its hardware
+without changing its serial numbers.  This may
+imply opening the case and looking at the numbers
+on the chips (best done in broad daylight).
+
+
+Good luck,
+
+Rick van Rein
+OpenFortress / 0cpm
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..94a9ed0
--- /dev/null
+++ b/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>.
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..d74bcec
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,19 @@
+
+# TODO: this should be src/Kconfig
+Kconfig := src/target/Kconfig
+
+.PHONY += all
+all: src/target/tuntest/firmly0cpm.bin
+
+%.o: %.c
+       gcc -c -Iinclude -ggdb3 -o $@ $^
+
+include bin/kconfig/Makefile
+
+include src/target/tuntest/Makefile
+include src/net/Makefile
+
+.PHONY += clean
+clean:
+       find . -name \*\.o -exec rm {} \;
+       rm -f src/target/tuntest/firmly0cpm.bin
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..f263ab9
--- /dev/null
+++ b/README
@@ -0,0 +1,99 @@
+firmly.0cpm
+===========
+
+Digital phones are small computers and are thus equipped
+with built-in software.  This is usually called firmware
+to reflect the fact that this software isn't really very
+soft, as it is difficult to create or replace.
+
+This project is alternate firmware for digital phones,
+named "firmly.0cpm" and hosted on http://firmly.0cpm.org/
+
+This alternate firmware is special in various ways.  The
+idea of being able to innovate telephony is the major
+driving force behind them.
+
+This work is Copyright (c) 2011 OpenFortress, Rick van Rein
+but it may be used freely; read the LICENCSE for details.
+
+
+Open source
+-----------
+
+The problem with many current phones is that each
+manufacturer wants to invent their own firmware.  This lack
+of sharing makes the market situation one hampered by
+just-functioning phones.  The result is a lock-in of
+phone manufacturers and telecom operators, who have come
+to a standstill with a service that does little more than
+simulate old-fashioned analog telephony.
+
+Digital telephony means that you are using a communications
+device with generic computing abilities.  You can do a
+lot more if you control the firmware in a software fashion.
+
+This firmware was created to give control back to the
+users of such phones.  And to break through the mutual
+impairment between telecom operators and phone manufacturers.
+
+Manufacturers of phones would be wise to adopt this openly
+shared firmware, but they should also realise that they
+will be obliged to share any improvements that they make,
+including porting to their platform, and that they are
+formally obliged to permit end users to replace the firmware
+with their own.  This is a legal obligation, as a direct
+result of the open source licensing.  There is of course
+no obligation for a manufacturer to support such different
+versions of firmware, as long as they don't try to block
+it from being used.
+
+If you own a phone that is not currently able to run a port
+of this firmware, you may want to contact a hacker who will
+usually enjoy the challenge of replacing the firmware for
+you.  Unlike what a cracker does, this is usually legal as
+it is just reverse engineering, rather than abusive access
+to someone else's device.  Depending on the make and model
+of your phone the hacker may fail or succeed; depending on
+those same factors and the level of determination/payment
+of your hacker, it may end up in a software-based install
+or it may require per-device hardware tinkering.  Please
+realise that your hacker too will want to, and usually
+be obliged by our license, to share the results of his
+work publicly.  You may want to look for others who can
+contribute in the work so you benefit from sharing too.
+
+
+The 0cpm network
+----------------
+
+We provide a calling network that you may use with this phone,
+although you are not in any way obliged to do so.  Please do
+keep in mind that the firmware was created in support of the
+0cpm calling network, which in itself aims at innovating the
+area of digital telephony, and that it aims to profitably
+integrate open source solutions and external service
+providers as part of a "calling service community".
+
+We have created other tools as well, to help this network
+to flourish.  These are a few pointers of interest:
+
+http://0cpm.com/  --  Phone service, free or commercial.
+http://0cpm.org/  --  Software development.
+http://0cpm.net/  --  Calling service community.
+
+
+Direct connections
+------------------
+
+Privacy
+-------
+
+Zero configuration
+------------------
+
+POTS integration
+----------------
+
+LAN integration
+---------------
+
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..55bc665
--- /dev/null
+++ b/TODO
@@ -0,0 +1,49 @@
+TODO for firmly.0cpm
+====================
+
+The current code is a demonstration of a core principle, an alpha
+level implementation that does work.  It demonstrates a way of getting
+an IPv6 address anywhere, so as to enable embedded firmware to be
+written as IPv6-only software.  The framework presented requires no
+network stack from the supporting OS, and indeed it can be built
+directly on hardware after adding drivers for specific chips.
+
+The current code contains a few things that may or may not be so good
+in the end.  After gaining some experience, it is good to have a good
+look at:
+
+* Pointers are cast back and forth to uint32_t values.  This makes the
+  code unsuitable for 64-bit architectures and, much more of a problem,
+  for 16-bit architectures such as 16-bit digital signal processors.
+
+* Parsing and checksumming is not sufficiently paranoid.  The current
+  netinput code assumes proper behaviour from its networking partners.
+  That is not a proper assumption for an internetworking device :-)
+  Specifically, no effort has been done to check the packet size where
+  indices and offsets are applied.  Before this is handled, the code
+  MUST NOT be released as anything but alpha.
+
+* The use of BPF-style commands in netinput.c -- it can be made fairly
+  compact if matched up with machine commands, but is it really more
+  efficient than an optimising C compiler?  If the difference is
+  negligable, then this code should go, even if it brings advantages
+  on some platforms.  The style is then simply "too inventive".
+
+* The mem[] array is untyped, calling for lots of cast commands.  This
+  is not handy, and a result of the BPF-style architecture for netinput.
+  (The original idea was to do the entire processing in that style, but
+  it turned out not to be sufficiently flexible for that.)
+
+* The replies from netinput.c are functions to be called.  Decide if
+  this is enough, and if it can cover netreply_* as well as netdb_*
+  with the same setup.  Is this all typesafe?
+
+* Must join multicast addresses for local addresses, as described in
+  http://tools.ietf.org/html/rfc4291 section 2.7.1, ff02::1:ff00:0/102
+  for solicited-node address.  WIDE DHCPv6 server actually needs this.
+  Also join ff02::1 as the all-nodes address.
+
+* The netdb module is underdeveloped.  The bindings are not used as
+  they could be, there is no neighbour or ARP cache, there is no
+  storage for servers for dns, ntp, sip-proxy.
+
diff --git a/bin/kconfig/.gitignore b/bin/kconfig/.gitignore
new file mode 100644 (file)
index 0000000..b49584c
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# Generated files
+#
+config*
+lex.*.c
+*.tab.c
+*.tab.h
+zconf.hash.c
+*.moc
+lkc_defs.h
+
+#
+# configuration programs
+#
+conf
+mconf
+qconf
+gconf
+kxgettext
diff --git a/bin/kconfig/.kxgettext.o.d b/bin/kconfig/.kxgettext.o.d
new file mode 100644 (file)
index 0000000..14865f4
--- /dev/null
@@ -0,0 +1,21 @@
+kxgettext.o: bin/kconfig/kxgettext.c /usr/include/stdlib.h \
+  /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
+  /usr/include/gnu/stubs-64.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.3.2/include/stddef.h \
+  /usr/include/sys/types.h /usr/include/bits/types.h \
+  /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \
+  /usr/include/bits/endian.h /usr/include/sys/select.h \
+  /usr/include/bits/select.h /usr/include/bits/sigset.h \
+  /usr/include/bits/time.h /usr/include/sys/sysmacros.h \
+  /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \
+  /usr/include/string.h /usr/include/bits/string.h \
+  /usr/include/bits/string2.h bin/kconfig/lkc.h bin/kconfig/expr.h \
+  /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \
+  /usr/include/wchar.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.3.2/include/stdarg.h \
+  /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+  /usr/include/bits/stdio.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.3.2/include/stdbool.h \
+  /usr/include/libintl.h /usr/include/locale.h /usr/include/bits/locale.h \
+  bin/kconfig/lkc_proto.h
diff --git a/bin/kconfig/Makefile b/bin/kconfig/Makefile
new file mode 100644 (file)
index 0000000..89f2452
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# menconfig/xconfig/... targets for configuring firmly.0cpm
+#
+# This works just like it does for the Linux kernel, from which this
+# code has been shared in.
+#
+
+
+xconfig: bin/qconf
+       $< $(Kconfig)
+
+gconfig: bin/gconf
+       $< $(Kconfig)
+
+menuconfig: bin/mconf
+       $< $(Kconfig)
+
+bin/mconf: bin/kconfig/mconf.c
+       flex -o bin/lex.zconf.c bin/kconfig/zconf.l
+       cp bin/kconfig/zconf.tab.c_shipped bin/zconf.tab.c
+       cp bin/kconfig/zconf.hash.c_shipped bin/zconf.hash.c
+       # bison -o bin/zconf.tab.c bin/kconfig/zconf.y
+       gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer   -DCURSES_LOC="<ncurses.h>" -DLOCALE   -c -o bin/kconfig/kxgettext.o bin/kconfig/kxgettext.c
+       gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer   -DCURSES_LOC="<ncurses.h>" -DLOCALE  -Ibin/kconfig -c -o bin/zconf.tab.o bin/zconf.tab.c
+       gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer   -DCURSES_LOC="<ncurses.h>" -DLOCALE   -c -o bin/mconf.o bin/kconfig/mconf.c
+       gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer   -DCURSES_LOC="<ncurses.h>" -DLOCALE   -c -o bin/checklist.o bin/kconfig/lxdialog/checklist.c
+       gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer   -DCURSES_LOC="<ncurses.h>" -DLOCALE   -c -o bin/inputbox.o bin/kconfig/lxdialog/inputbox.c
+       gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer   -DCURSES_LOC="<ncurses.h>" -DLOCALE   -c -o bin/menubox.o bin/kconfig/lxdialog/menubox.c
+       gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer   -DCURSES_LOC="<ncurses.h>" -DLOCALE   -c -o bin/textbox.o bin/kconfig/lxdialog/textbox.c
+       gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer   -DCURSES_LOC="<ncurses.h>" -DLOCALE   -c -o bin/yesno.o bin/kconfig/lxdialog/yesno.c
+       gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer   -DCURSES_LOC="<ncurses.h>" -DLOCALE   -c -o bin/util.o bin/kconfig/lxdialog/util.c
+       gcc  -o bin/mconf bin/mconf.o bin/zconf.tab.o bin/checklist.o bin/util.o bin/inputbox.o bin/textbox.o bin/yesno.o bin/menubox.o -lncurses
+
+bin/qconf: bin/kconfiq/qconf.cc
+       @echo TODO: Copy from Linux kernel cmd_scripts
+       @exit 1
+
+bin/gconf.o: bin/gconf.c
+       @echo TODO: Copy from Linux kernel cmd_scripts
+       @exit 1
+
diff --git a/bin/kconfig/Makefile.linux b/bin/kconfig/Makefile.linux
new file mode 100644 (file)
index 0000000..fa1a7d5
--- /dev/null
@@ -0,0 +1,285 @@
+# ===========================================================================
+# Kernel configuration targets
+# These targets are used from top-level makefile
+
+PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config
+
+Kconfig := arch/$(SRCARCH)/Kconfig
+
+xconfig: $(obj)/qconf
+       $< $(Kconfig)
+
+gconfig: $(obj)/gconf
+       $< $(Kconfig)
+
+menuconfig: $(obj)/mconf
+       $< $(Kconfig)
+
+config: $(obj)/conf
+       $< $(Kconfig)
+
+oldconfig: $(obj)/conf
+       $< -o $(Kconfig)
+
+silentoldconfig: $(obj)/conf
+       $< -s $(Kconfig)
+
+# Create new linux.pot file
+# Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files
+# The symlink is used to repair a deficiency in arch/um
+update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
+       $(Q)echo "  GEN config"
+       $(Q)xgettext --default-domain=linux              \
+           --add-comments --keyword=_ --keyword=N_      \
+           --from-code=UTF-8                            \
+           --files-from=scripts/kconfig/POTFILES.in     \
+           --output $(obj)/config.pot
+       $(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot
+       $(Q)ln -fs Kconfig.i386 arch/um/Kconfig.arch
+       $(Q)(for i in `ls arch/*/Kconfig`;               \
+           do                                           \
+               echo "  GEN $$i";                        \
+               $(obj)/kxgettext $$i                     \
+                    >> $(obj)/config.pot;               \
+           done )
+       $(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \
+           --output $(obj)/linux.pot
+       $(Q)rm -f arch/um/Kconfig.arch
+       $(Q)rm -f $(obj)/config.pot
+
+PHONY += randconfig allyesconfig allnoconfig allmodconfig defconfig
+
+randconfig: $(obj)/conf
+       $< -r $(Kconfig)
+
+allyesconfig: $(obj)/conf
+       $< -y $(Kconfig)
+
+allnoconfig: $(obj)/conf
+       $< -n $(Kconfig)
+
+allmodconfig: $(obj)/conf
+       $< -m $(Kconfig)
+
+defconfig: $(obj)/conf
+ifeq ($(KBUILD_DEFCONFIG),)
+       $< -d $(Kconfig)
+else
+       @echo "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'"
+       $(Q)$< -D arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig)
+endif
+
+%_defconfig: $(obj)/conf
+       $(Q)$< -D arch/$(SRCARCH)/configs/$@ $(Kconfig)
+
+# Help text used by make help
+help:
+       @echo  '  config          - Update current config utilising a line-oriented program'
+       @echo  '  menuconfig      - Update current config utilising a menu based program'
+       @echo  '  xconfig         - Update current config utilising a QT based front-end'
+       @echo  '  gconfig         - Update current config utilising a GTK based front-end'
+       @echo  '  oldconfig       - Update current config utilising a provided .config as base'
+       @echo  '  silentoldconfig - Same as oldconfig, but quietly'
+       @echo  '  randconfig      - New config with random answer to all options'
+       @echo  '  defconfig       - New config with default answer to all options'
+       @echo  '  allmodconfig    - New config selecting modules when possible'
+       @echo  '  allyesconfig    - New config where all options are accepted with yes'
+       @echo  '  allnoconfig     - New config where all options are answered with no'
+
+# lxdialog stuff
+check-lxdialog  := $(srctree)/$(src)/lxdialog/check-lxdialog.sh
+
+# Use recursively expanded variables so we do not call gcc unless
+# we really need to do so. (Do not call gcc as part of make mrproper)
+HOST_EXTRACFLAGS = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags)
+HOST_LOADLIBES   = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
+
+HOST_EXTRACFLAGS += -DLOCALE
+
+
+# ===========================================================================
+# Shared Makefile for the various kconfig executables:
+# conf:          Used for defconfig, oldconfig and related targets
+# mconf:  Used for the mconfig target.
+#         Utilizes the lxdialog package
+# qconf:  Used for the xconfig target
+#         Based on QT which needs to be installed to compile it
+# gconf:  Used for the gconfig target
+#         Based on GTK which needs to be installed to compile it
+# object files used by all kconfig flavours
+
+lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o
+lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
+
+conf-objs      := conf.o  zconf.tab.o
+mconf-objs     := mconf.o zconf.tab.o $(lxdialog)
+kxgettext-objs := kxgettext.o zconf.tab.o
+
+hostprogs-y := conf qconf gconf kxgettext
+
+ifeq ($(MAKECMDGOALS),menuconfig)
+       hostprogs-y += mconf
+endif
+
+ifeq ($(MAKECMDGOALS),xconfig)
+       qconf-target := 1
+endif
+ifeq ($(MAKECMDGOALS),gconfig)
+       gconf-target := 1
+endif
+
+
+ifeq ($(qconf-target),1)
+qconf-cxxobjs  := qconf.o
+qconf-objs     := kconfig_load.o zconf.tab.o
+endif
+
+ifeq ($(gconf-target),1)
+gconf-objs     := gconf.o kconfig_load.o zconf.tab.o
+endif
+
+clean-files    := lkc_defs.h qconf.moc .tmp_qtcheck \
+                  .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c gconf.glade.h
+clean-files     += mconf qconf gconf
+clean-files     += config.pot linux.pot
+
+# Check that we have the required ncurses stuff installed for lxdialog (menuconfig)
+PHONY += $(obj)/dochecklxdialog
+$(addprefix $(obj)/,$(lxdialog)): $(obj)/dochecklxdialog
+$(obj)/dochecklxdialog:
+       $(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOST_LOADLIBES)
+
+always := dochecklxdialog
+
+# Add environment specific flags
+HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(srctree)/$(src)/check.sh $(HOSTCC) $(HOSTCFLAGS))
+
+# generated files seem to need this to find local include files
+HOSTCFLAGS_lex.zconf.o := -I$(src)
+HOSTCFLAGS_zconf.tab.o := -I$(src)
+
+HOSTLOADLIBES_qconf    = $(KC_QT_LIBS) -ldl
+HOSTCXXFLAGS_qconf.o   = $(KC_QT_CFLAGS) -D LKC_DIRECT_LINK
+
+HOSTLOADLIBES_gconf    = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0`
+HOSTCFLAGS_gconf.o     = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
+                          -D LKC_DIRECT_LINK
+
+$(obj)/qconf.o: $(obj)/.tmp_qtcheck
+
+ifeq ($(qconf-target),1)
+$(obj)/.tmp_qtcheck: $(src)/Makefile
+-include $(obj)/.tmp_qtcheck
+
+# QT needs some extra effort...
+$(obj)/.tmp_qtcheck:
+       @set -e; echo "  CHECK   qt"; dir=""; pkg=""; \
+       pkg-config --exists qt 2> /dev/null && pkg=qt; \
+       pkg-config --exists qt-mt 2> /dev/null && pkg=qt-mt; \
+       if [ -n "$$pkg" ]; then \
+         cflags="\$$(shell pkg-config $$pkg --cflags)"; \
+         libs="\$$(shell pkg-config $$pkg --libs)"; \
+         moc="\$$(shell pkg-config $$pkg --variable=prefix)/bin/moc"; \
+         dir="$$(pkg-config $$pkg --variable=prefix)"; \
+       else \
+         for d in $$QTDIR /usr/share/qt* /usr/lib/qt*; do \
+           if [ -f $$d/include/qconfig.h ]; then dir=$$d; break; fi; \
+         done; \
+         if [ -z "$$dir" ]; then \
+           echo "*"; \
+           echo "* Unable to find the QT3 installation. Please make sure that"; \
+           echo "* the QT3 development package is correctly installed and"; \
+           echo "* either install pkg-config or set the QTDIR environment"; \
+           echo "* variable to the correct location."; \
+           echo "*"; \
+           false; \
+         fi; \
+         libpath=$$dir/lib; lib=qt; osdir=""; \
+         $(HOSTCXX) -print-multi-os-directory > /dev/null 2>&1 && \
+           osdir=x$$($(HOSTCXX) -print-multi-os-directory); \
+         test -d $$libpath/$$osdir && libpath=$$libpath/$$osdir; \
+         test -f $$libpath/libqt-mt.so && lib=qt-mt; \
+         cflags="-I$$dir/include"; \
+         libs="-L$$libpath -Wl,-rpath,$$libpath -l$$lib"; \
+         moc="$$dir/bin/moc"; \
+       fi; \
+       if [ ! -x $$dir/bin/moc -a -x /usr/bin/moc ]; then \
+         echo "*"; \
+         echo "* Unable to find $$dir/bin/moc, using /usr/bin/moc instead."; \
+         echo "*"; \
+         moc="/usr/bin/moc"; \
+       fi; \
+       echo "KC_QT_CFLAGS=$$cflags" > $@; \
+       echo "KC_QT_LIBS=$$libs" >> $@; \
+       echo "KC_QT_MOC=$$moc" >> $@
+endif
+
+$(obj)/gconf.o: $(obj)/.tmp_gtkcheck
+
+ifeq ($(gconf-target),1)
+-include $(obj)/.tmp_gtkcheck
+
+# GTK needs some extra effort, too...
+$(obj)/.tmp_gtkcheck:
+       @if `pkg-config --exists gtk+-2.0 gmodule-2.0 libglade-2.0`; then               \
+               if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then                  \
+                       touch $@;                                                               \
+               else                                                                    \
+                       echo "*";                                                       \
+                       echo "* GTK+ is present but version >= 2.0.0 is required.";     \
+                       echo "*";                                                       \
+                       false;                                                          \
+               fi                                                                      \
+       else                                                                            \
+               echo "*";                                                               \
+               echo "* Unable to find the GTK+ installation. Please make sure that";   \
+               echo "* the GTK+ 2.0 development package is correctly installed...";    \
+               echo "* You need gtk+-2.0, glib-2.0 and libglade-2.0.";                 \
+               echo "*";                                                               \
+               false;                                                                  \
+       fi
+endif
+
+$(obj)/zconf.tab.o: $(obj)/lex.zconf.c $(obj)/zconf.hash.c
+
+$(obj)/kconfig_load.o: $(obj)/lkc_defs.h
+
+$(obj)/qconf.o: $(obj)/qconf.moc $(obj)/lkc_defs.h
+
+$(obj)/gconf.o: $(obj)/lkc_defs.h
+
+$(obj)/%.moc: $(src)/%.h
+       $(KC_QT_MOC) -i $< -o $@
+
+$(obj)/lkc_defs.h: $(src)/lkc_proto.h
+       sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
+
+# Extract gconf menu items for I18N support
+$(obj)/gconf.glade.h: $(obj)/gconf.glade
+       intltool-extract --type=gettext/glade $(obj)/gconf.glade
+
+###
+# The following requires flex/bison/gperf
+# By default we use the _shipped versions, uncomment the following line if
+# you are modifying the flex/bison src.
+# LKC_GENPARSER := 1
+
+ifdef LKC_GENPARSER
+
+$(obj)/zconf.tab.c: $(src)/zconf.y
+$(obj)/lex.zconf.c: $(src)/zconf.l
+$(obj)/zconf.hash.c: $(src)/zconf.gperf
+
+%.tab.c: %.y
+       bison -l -b $* -p $(notdir $*) $<
+       cp $@ $@_shipped
+
+lex.%.c: %.l
+       flex -L -P$(notdir $*) -o$@ $<
+       cp $@ $@_shipped
+
+%.hash.c: %.gperf
+       gperf < $< > $@
+       cp $@ $@_shipped
+
+endif
diff --git a/bin/kconfig/POTFILES.in b/bin/kconfig/POTFILES.in
new file mode 100644 (file)
index 0000000..9674573
--- /dev/null
@@ -0,0 +1,12 @@
+scripts/kconfig/lxdialog/checklist.c
+scripts/kconfig/lxdialog/inputbox.c
+scripts/kconfig/lxdialog/menubox.c
+scripts/kconfig/lxdialog/textbox.c
+scripts/kconfig/lxdialog/util.c
+scripts/kconfig/lxdialog/yesno.c
+scripts/kconfig/mconf.c
+scripts/kconfig/conf.c
+scripts/kconfig/confdata.c
+scripts/kconfig/gconf.c
+scripts/kconfig/gconf.glade.h
+scripts/kconfig/qconf.cc
diff --git a/bin/kconfig/check.sh b/bin/kconfig/check.sh
new file mode 100755 (executable)
index 0000000..fa59cbf
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Needed for systems without gettext
+$* -xc -o /dev/null - > /dev/null 2>&1 << EOF
+#include <libintl.h>
+int main()
+{
+       gettext("");
+       return 0;
+}
+EOF
+if [ ! "$?" -eq "0"  ]; then
+       echo -DKBUILD_NO_NLS;
+fi
+
diff --git a/bin/kconfig/conf.c b/bin/kconfig/conf.c
new file mode 100644 (file)
index 0000000..fda6313
--- /dev/null
@@ -0,0 +1,634 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <locale.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static void conf(struct menu *menu);
+static void check_conf(struct menu *menu);
+
+enum {
+       ask_all,
+       ask_new,
+       ask_silent,
+       set_default,
+       set_yes,
+       set_mod,
+       set_no,
+       set_random
+} input_mode = ask_all;
+char *defconfig_file;
+
+static int indent = 1;
+static int valid_stdin = 1;
+static int conf_cnt;
+static char line[128];
+static struct menu *rootEntry;
+
+static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
+
+static const char *get_help(struct menu *menu)
+{
+       if (menu_has_help(menu))
+               return _(menu_get_help(menu));
+       else
+               return nohelp_text;
+}
+
+static void strip(char *str)
+{
+       char *p = str;
+       int l;
+
+       while ((isspace(*p)))
+               p++;
+       l = strlen(p);
+       if (p != str)
+               memmove(str, p, l + 1);
+       if (!l)
+               return;
+       p = str + l - 1;
+       while ((isspace(*p)))
+               *p-- = 0;
+}
+
+static void check_stdin(void)
+{
+       if (!valid_stdin && input_mode == ask_silent) {
+               printf(_("aborted!\n\n"));
+               printf(_("Console input/output is redirected. "));
+               printf(_("Run 'make oldconfig' to update configuration.\n\n"));
+               exit(1);
+       }
+}
+
+static int conf_askvalue(struct symbol *sym, const char *def)
+{
+       enum symbol_type type = sym_get_type(sym);
+       tristate val;
+
+       if (!sym_has_value(sym))
+               printf(_("(NEW) "));
+
+       line[0] = '\n';
+       line[1] = 0;
+
+       if (!sym_is_changable(sym)) {
+               printf("%s\n", def);
+               line[0] = '\n';
+               line[1] = 0;
+               return 0;
+       }
+
+       switch (input_mode) {
+       case set_no:
+       case set_mod:
+       case set_yes:
+       case set_random:
+               if (sym_has_value(sym)) {
+                       printf("%s\n", def);
+                       return 0;
+               }
+               break;
+       case ask_new:
+       case ask_silent:
+               if (sym_has_value(sym)) {
+                       printf("%s\n", def);
+                       return 0;
+               }
+               check_stdin();
+       case ask_all:
+               fflush(stdout);
+               fgets(line, 128, stdin);
+               return 1;
+       case set_default:
+               printf("%s\n", def);
+               return 1;
+       default:
+               break;
+       }
+
+       switch (type) {
+       case S_INT:
+       case S_HEX:
+       case S_STRING:
+               printf("%s\n", def);
+               return 1;
+       default:
+               ;
+       }
+       switch (input_mode) {
+       case set_yes:
+               if (sym_tristate_within_range(sym, yes)) {
+                       line[0] = 'y';
+                       line[1] = '\n';
+                       line[2] = 0;
+                       break;
+               }
+       case set_mod:
+               if (type == S_TRISTATE) {
+                       if (sym_tristate_within_range(sym, mod)) {
+                               line[0] = 'm';
+                               line[1] = '\n';
+                               line[2] = 0;
+                               break;
+                       }
+               } else {
+                       if (sym_tristate_within_range(sym, yes)) {
+                               line[0] = 'y';
+                               line[1] = '\n';
+                               line[2] = 0;
+                               break;
+                       }
+               }
+       case set_no:
+               if (sym_tristate_within_range(sym, no)) {
+                       line[0] = 'n';
+                       line[1] = '\n';
+                       line[2] = 0;
+                       break;
+               }
+       case set_random:
+               do {
+                       val = (tristate)(rand() % 3);
+               } while (!sym_tristate_within_range(sym, val));
+               switch (val) {
+               case no: line[0] = 'n'; break;
+               case mod: line[0] = 'm'; break;
+               case yes: line[0] = 'y'; break;
+               }
+               line[1] = '\n';
+               line[2] = 0;
+               break;
+       default:
+               break;
+       }
+       printf("%s", line);
+       return 1;
+}
+
+int conf_string(struct menu *menu)
+{
+       struct symbol *sym = menu->sym;
+       const char *def;
+
+       while (1) {
+               printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
+               printf("(%s) ", sym->name);
+               def = sym_get_string_value(sym);
+               if (sym_get_string_value(sym))
+                       printf("[%s] ", def);
+               if (!conf_askvalue(sym, def))
+                       return 0;
+               switch (line[0]) {
+               case '\n':
+                       break;
+               case '?':
+                       /* print help */
+                       if (line[1] == '\n') {
+                               printf("\n%s\n", get_help(menu));
+                               def = NULL;
+                               break;
+                       }
+               default:
+                       line[strlen(line)-1] = 0;
+                       def = line;
+               }
+               if (def && sym_set_string_value(sym, def))
+                       return 0;
+       }
+}
+
+static int conf_sym(struct menu *menu)
+{
+       struct symbol *sym = menu->sym;
+       int type;
+       tristate oldval, newval;
+
+       while (1) {
+               printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
+               if (sym->name)
+                       printf("(%s) ", sym->name);
+               type = sym_get_type(sym);
+               putchar('[');
+               oldval = sym_get_tristate_value(sym);
+               switch (oldval) {
+               case no:
+                       putchar('N');
+                       break;
+               case mod:
+                       putchar('M');
+                       break;
+               case yes:
+                       putchar('Y');
+                       break;
+               }
+               if (oldval != no && sym_tristate_within_range(sym, no))
+                       printf("/n");
+               if (oldval != mod && sym_tristate_within_range(sym, mod))
+                       printf("/m");
+               if (oldval != yes && sym_tristate_within_range(sym, yes))
+                       printf("/y");
+               if (menu_has_help(menu))
+                       printf("/?");
+               printf("] ");
+               if (!conf_askvalue(sym, sym_get_string_value(sym)))
+                       return 0;
+               strip(line);
+
+               switch (line[0]) {
+               case 'n':
+               case 'N':
+                       newval = no;
+                       if (!line[1] || !strcmp(&line[1], "o"))
+                               break;
+                       continue;
+               case 'm':
+               case 'M':
+                       newval = mod;
+                       if (!line[1])
+                               break;
+                       continue;
+               case 'y':
+               case 'Y':
+                       newval = yes;
+                       if (!line[1] || !strcmp(&line[1], "es"))
+                               break;
+                       continue;
+               case 0:
+                       newval = oldval;
+                       break;
+               case '?':
+                       goto help;
+               default:
+                       continue;
+               }
+               if (sym_set_tristate_value(sym, newval))
+                       return 0;
+help:
+               printf("\n%s\n", get_help(menu));
+       }
+}
+
+static int conf_choice(struct menu *menu)
+{
+       struct symbol *sym, *def_sym;
+       struct menu *child;
+       int type;
+       bool is_new;
+
+       sym = menu->sym;
+       type = sym_get_type(sym);
+       is_new = !sym_has_value(sym);
+       if (sym_is_changable(sym)) {
+               conf_sym(menu);
+               sym_calc_value(sym);
+               switch (sym_get_tristate_value(sym)) {
+               case no:
+                       return 1;
+               case mod:
+                       return 0;
+               case yes:
+                       break;
+               }
+       } else {
+               switch (sym_get_tristate_value(sym)) {
+               case no:
+                       return 1;
+               case mod:
+                       printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
+                       return 0;
+               case yes:
+                       break;
+               }
+       }
+
+       while (1) {
+               int cnt, def;
+
+               printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
+               def_sym = sym_get_choice_value(sym);
+               cnt = def = 0;
+               line[0] = 0;
+               for (child = menu->list; child; child = child->next) {
+                       if (!menu_is_visible(child))
+                               continue;
+                       if (!child->sym) {
+                               printf("%*c %s\n", indent, '*', _(menu_get_prompt(child)));
+                               continue;
+                       }
+                       cnt++;
+                       if (child->sym == def_sym) {
+                               def = cnt;
+                               printf("%*c", indent, '>');
+                       } else
+                               printf("%*c", indent, ' ');
+                       printf(" %d. %s", cnt, _(menu_get_prompt(child)));
+                       if (child->sym->name)
+                               printf(" (%s)", child->sym->name);
+                       if (!sym_has_value(child->sym))
+                               printf(_(" (NEW)"));
+                       printf("\n");
+               }
+               printf(_("%*schoice"), indent - 1, "");
+               if (cnt == 1) {
+                       printf("[1]: 1\n");
+                       goto conf_childs;
+               }
+               printf("[1-%d", cnt);
+               if (menu_has_help(menu))
+                       printf("?");
+               printf("]: ");
+               switch (input_mode) {
+               case ask_new:
+               case ask_silent:
+                       if (!is_new) {
+                               cnt = def;
+                               printf("%d\n", cnt);
+                               break;
+                       }
+                       check_stdin();
+               case ask_all:
+                       fflush(stdout);
+                       fgets(line, 128, stdin);
+                       strip(line);
+                       if (line[0] == '?') {
+                               printf("\n%s\n", get_help(menu));
+                               continue;
+                       }
+                       if (!line[0])
+                               cnt = def;
+                       else if (isdigit(line[0]))
+                               cnt = atoi(line);
+                       else
+                               continue;
+                       break;
+               case set_random:
+                       if (is_new)
+                               def = (rand() % cnt) + 1;
+               case set_default:
+               case set_yes:
+               case set_mod:
+               case set_no:
+                       cnt = def;
+                       printf("%d\n", cnt);
+                       break;
+               }
+
+       conf_childs:
+               for (child = menu->list; child; child = child->next) {
+                       if (!child->sym || !menu_is_visible(child))
+                               continue;
+                       if (!--cnt)
+                               break;
+               }
+               if (!child)
+                       continue;
+               if (line[strlen(line) - 1] == '?') {
+                       printf("\n%s\n", get_help(child));
+                       continue;
+               }
+               sym_set_choice_value(sym, child->sym);
+               for (child = child->list; child; child = child->next) {
+                       indent += 2;
+                       conf(child);
+                       indent -= 2;
+               }
+               return 1;
+       }
+}
+
+static void conf(struct menu *menu)
+{
+       struct symbol *sym;
+       struct property *prop;
+       struct menu *child;
+
+       if (!menu_is_visible(menu))
+               return;
+
+       sym = menu->sym;
+       prop = menu->prompt;
+       if (prop) {
+               const char *prompt;
+
+               switch (prop->type) {
+               case P_MENU:
+                       if (input_mode == ask_silent && rootEntry != menu) {
+                               check_conf(menu);
+                               return;
+                       }
+               case P_COMMENT:
+                       prompt = menu_get_prompt(menu);
+                       if (prompt)
+                               printf("%*c\n%*c %s\n%*c\n",
+                                       indent, '*',
+                                       indent, '*', _(prompt),
+                                       indent, '*');
+               default:
+                       ;
+               }
+       }
+
+       if (!sym)
+               goto conf_childs;
+
+       if (sym_is_choice(sym)) {
+               conf_choice(menu);
+               if (sym->curr.tri != mod)
+                       return;
+               goto conf_childs;
+       }
+
+       switch (sym->type) {
+       case S_INT:
+       case S_HEX:
+       case S_STRING:
+               conf_string(menu);
+               break;
+       default:
+               conf_sym(menu);
+               break;
+       }
+
+conf_childs:
+       if (sym)
+               indent += 2;
+       for (child = menu->list; child; child = child->next)
+               conf(child);
+       if (sym)
+               indent -= 2;
+}
+
+static void check_conf(struct menu *menu)
+{
+       struct symbol *sym;
+       struct menu *child;
+
+       if (!menu_is_visible(menu))
+               return;
+
+       sym = menu->sym;
+       if (sym && !sym_has_value(sym)) {
+               if (sym_is_changable(sym) ||
+                   (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
+                       if (!conf_cnt++)
+                               printf(_("*\n* Restart config...\n*\n"));
+                       rootEntry = menu_get_parent_menu(menu);
+                       conf(rootEntry);
+               }
+       }
+
+       for (child = menu->list; child; child = child->next)
+               check_conf(child);
+}
+
+int main(int ac, char **av)
+{
+       int opt;
+       const char *name;
+       struct stat tmpstat;
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       while ((opt = getopt(ac, av, "osdD:nmyrh")) != -1) {
+               switch (opt) {
+               case 'o':
+                       input_mode = ask_new;
+                       break;
+               case 's':
+                       input_mode = ask_silent;
+                       valid_stdin = isatty(0) && isatty(1) && isatty(2);
+                       break;
+               case 'd':
+                       input_mode = set_default;
+                       break;
+               case 'D':
+                       input_mode = set_default;
+                       defconfig_file = optarg;
+                       break;
+               case 'n':
+                       input_mode = set_no;
+                       break;
+               case 'm':
+                       input_mode = set_mod;
+                       break;
+               case 'y':
+                       input_mode = set_yes;
+                       break;
+               case 'r':
+                       input_mode = set_random;
+                       srand(time(NULL));
+                       break;
+               case 'h':
+                       printf(_("See README for usage info\n"));
+                       exit(0);
+                       break;
+               default:
+                       fprintf(stderr, _("See README for usage info\n"));
+                       exit(1);
+               }
+       }
+       if (ac == optind) {
+               printf(_("%s: Kconfig file missing\n"), av[0]);
+               exit(1);
+       }
+       name = av[optind];
+       conf_parse(name);
+       //zconfdump(stdout);
+       switch (input_mode) {
+       case set_default:
+               if (!defconfig_file)
+                       defconfig_file = conf_get_default_confname();
+               if (conf_read(defconfig_file)) {
+                       printf(_("***\n"
+                               "*** Can't find default configuration \"%s\"!\n"
+                               "***\n"), defconfig_file);
+                       exit(1);
+               }
+               break;
+       case ask_silent:
+               if (stat(".config", &tmpstat)) {
+                       printf(_("***\n"
+                               "*** You have not yet configured your kernel!\n"
+                               "*** (missing kernel .config file)\n"
+                               "***\n"
+                               "*** Please run some configurator (e.g. \"make oldconfig\" or\n"
+                               "*** \"make menuconfig\" or \"make xconfig\").\n"
+                               "***\n"));
+                       exit(1);
+               }
+       case ask_all:
+       case ask_new:
+               conf_read(NULL);
+               break;
+       case set_no:
+       case set_mod:
+       case set_yes:
+       case set_random:
+               name = getenv("KCONFIG_ALLCONFIG");
+               if (name && !stat(name, &tmpstat)) {
+                       conf_read_simple(name, S_DEF_USER);
+                       break;
+               }
+               switch (input_mode) {
+               case set_no:     name = "allno.config"; break;
+               case set_mod:    name = "allmod.config"; break;
+               case set_yes:    name = "allyes.config"; break;
+               case set_random: name = "allrandom.config"; break;
+               default: break;
+               }
+               if (!stat(name, &tmpstat))
+                       conf_read_simple(name, S_DEF_USER);
+               else if (!stat("all.config", &tmpstat))
+                       conf_read_simple("all.config", S_DEF_USER);
+               break;
+       default:
+               break;
+       }
+
+       if (input_mode != ask_silent) {
+               rootEntry = &rootmenu;
+               conf(&rootmenu);
+               if (input_mode == ask_all) {
+                       input_mode = ask_silent;
+                       valid_stdin = 1;
+               }
+       } else if (conf_get_changed()) {
+               name = getenv("KCONFIG_NOSILENTUPDATE");
+               if (name && *name) {
+                       fprintf(stderr, _("\n*** Kernel configuration requires explicit update.\n\n"));
+                       return 1;
+               }
+       } else
+               goto skip_check;
+
+       do {
+               conf_cnt = 0;
+               check_conf(&rootmenu);
+       } while (conf_cnt);
+       if (conf_write(NULL)) {
+               fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
+               return 1;
+       }
+skip_check:
+       if (input_mode == ask_silent && conf_write_autoconf()) {
+               fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
+               return 1;
+       }
+
+       return 0;
+}
diff --git a/bin/kconfig/confdata.c b/bin/kconfig/confdata.c
new file mode 100644 (file)
index 0000000..1ab48f0
--- /dev/null
@@ -0,0 +1,814 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <sys/stat.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static void conf_warning(const char *fmt, ...)
+       __attribute__ ((format (printf, 1, 2)));
+
+static const char *conf_filename;
+static int conf_lineno, conf_warnings, conf_unsaved;
+
+const char conf_defname[] = "arch/$ARCH/defconfig";
+
+static void conf_warning(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
+       vfprintf(stderr, fmt, ap);
+       fprintf(stderr, "\n");
+       va_end(ap);
+       conf_warnings++;
+}
+
+const char *conf_get_configname(void)
+{
+       char *name = getenv("KCONFIG_CONFIG");
+
+       return name ? name : ".config";
+}
+
+static char *conf_expand_value(const char *in)
+{
+       struct symbol *sym;
+       const char *src;
+       static char res_value[SYMBOL_MAXLENGTH];
+       char *dst, name[SYMBOL_MAXLENGTH];
+
+       res_value[0] = 0;
+       dst = name;
+       while ((src = strchr(in, '$'))) {
+               strncat(res_value, in, src - in);
+               src++;
+               dst = name;
+               while (isalnum(*src) || *src == '_')
+                       *dst++ = *src++;
+               *dst = 0;
+               sym = sym_lookup(name, 0);
+               sym_calc_value(sym);
+               strcat(res_value, sym_get_string_value(sym));
+               in = src;
+       }
+       strcat(res_value, in);
+
+       return res_value;
+}
+
+char *conf_get_default_confname(void)
+{
+       struct stat buf;
+       static char fullname[PATH_MAX+1];
+       char *env, *name;
+
+       name = conf_expand_value(conf_defname);
+       env = getenv(SRCTREE);
+       if (env) {
+               sprintf(fullname, "%s/%s", env, name);
+               if (!stat(fullname, &buf))
+                       return fullname;
+       }
+       return name;
+}
+
+static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
+{
+       char *p2;
+
+       switch (sym->type) {
+       case S_TRISTATE:
+               if (p[0] == 'm') {
+                       sym->def[def].tri = mod;
+                       sym->flags |= def_flags;
+                       break;
+               }
+       case S_BOOLEAN:
+               if (p[0] == 'y') {
+                       sym->def[def].tri = yes;
+                       sym->flags |= def_flags;
+                       break;
+               }
+               if (p[0] == 'n') {
+                       sym->def[def].tri = no;
+                       sym->flags |= def_flags;
+                       break;
+               }
+               conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+               break;
+       case S_OTHER:
+               if (*p != '"') {
+                       for (p2 = p; *p2 && !isspace(*p2); p2++)
+                               ;
+                       sym->type = S_STRING;
+                       goto done;
+               }
+       case S_STRING:
+               if (*p++ != '"')
+                       break;
+               for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
+                       if (*p2 == '"') {
+                               *p2 = 0;
+                               break;
+                       }
+                       memmove(p2, p2 + 1, strlen(p2));
+               }
+               if (!p2) {
+                       conf_warning("invalid string found");
+                       return 1;
+               }
+       case S_INT:
+       case S_HEX:
+       done:
+               if (sym_string_valid(sym, p)) {
+                       sym->def[def].val = strdup(p);
+                       sym->flags |= def_flags;
+               } else {
+                       conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+                       return 1;
+               }
+               break;
+       default:
+               ;
+       }
+       return 0;
+}
+
+int conf_read_simple(const char *name, int def)
+{
+       FILE *in = NULL;
+       char line[1024];
+       char *p, *p2;
+       struct symbol *sym;
+       int i, def_flags;
+
+       if (name) {
+               in = zconf_fopen(name);
+       } else {
+               struct property *prop;
+
+               name = conf_get_configname();
+               in = zconf_fopen(name);
+               if (in)
+                       goto load;
+               sym_add_change_count(1);
+               if (!sym_defconfig_list)
+                       return 1;
+
+               for_all_defaults(sym_defconfig_list, prop) {
+                       if (expr_calc_value(prop->visible.expr) == no ||
+                           prop->expr->type != E_SYMBOL)
+                               continue;
+                       name = conf_expand_value(prop->expr->left.sym->name);
+                       in = zconf_fopen(name);
+                       if (in) {
+                               printf(_("#\n"
+                                        "# using defaults found in %s\n"
+                                        "#\n"), name);
+                               goto load;
+                       }
+               }
+       }
+       if (!in)
+               return 1;
+
+load:
+       conf_filename = name;
+       conf_lineno = 0;
+       conf_warnings = 0;
+       conf_unsaved = 0;
+
+       def_flags = SYMBOL_DEF << def;
+       for_all_symbols(i, sym) {
+               sym->flags |= SYMBOL_CHANGED;
+               sym->flags &= ~(def_flags|SYMBOL_VALID);
+               if (sym_is_choice(sym))
+                       sym->flags |= def_flags;
+               switch (sym->type) {
+               case S_INT:
+               case S_HEX:
+               case S_STRING:
+                       if (sym->def[def].val)
+                               free(sym->def[def].val);
+               default:
+                       sym->def[def].val = NULL;
+                       sym->def[def].tri = no;
+               }
+       }
+
+       while (fgets(line, sizeof(line), in)) {
+               conf_lineno++;
+               sym = NULL;
+               switch (line[0]) {
+               case '#':
+                       if (memcmp(line + 2, "CONFIG_", 7))
+                               continue;
+                       p = strchr(line + 9, ' ');
+                       if (!p)
+                               continue;
+                       *p++ = 0;
+                       if (strncmp(p, "is not set", 10))
+                               continue;
+                       if (def == S_DEF_USER) {
+                               sym = sym_find(line + 9);
+                               if (!sym) {
+                                       conf_warning("trying to assign nonexistent symbol %s", line + 9);
+                                       break;
+                               }
+                       } else {
+                               sym = sym_lookup(line + 9, 0);
+                               if (sym->type == S_UNKNOWN)
+                                       sym->type = S_BOOLEAN;
+                       }
+                       if (sym->flags & def_flags) {
+                               conf_warning("override: reassigning to symbol %s", sym->name);
+                       }
+                       switch (sym->type) {
+                       case S_BOOLEAN:
+                       case S_TRISTATE:
+                               sym->def[def].tri = no;
+                               sym->flags |= def_flags;
+                               break;
+                       default:
+                               ;
+                       }
+                       break;
+               case 'C':
+                       if (memcmp(line, "CONFIG_", 7)) {
+                               conf_warning("unexpected data");
+                               continue;
+                       }
+                       p = strchr(line + 7, '=');
+                       if (!p)
+                               continue;
+                       *p++ = 0;
+                       p2 = strchr(p, '\n');
+                       if (p2) {
+                               *p2-- = 0;
+                               if (*p2 == '\r')
+                                       *p2 = 0;
+                       }
+                       if (def == S_DEF_USER) {
+                               sym = sym_find(line + 7);
+                               if (!sym) {
+                                       conf_warning("trying to assign nonexistent symbol %s", line + 7);
+                                       break;
+                               }
+                       } else {
+                               sym = sym_lookup(line + 7, 0);
+                               if (sym->type == S_UNKNOWN)
+                                       sym->type = S_OTHER;
+                       }
+                       if (sym->flags & def_flags) {
+                               conf_warning("override: reassigning to symbol %s", sym->name);
+                       }
+                       if (conf_set_sym_val(sym, def, def_flags, p))
+                               continue;
+                       break;
+               case '\r':
+               case '\n':
+                       break;
+               default:
+                       conf_warning("unexpected data");
+                       continue;
+               }
+               if (sym && sym_is_choice_value(sym)) {
+                       struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+                       switch (sym->def[def].tri) {
+                       case no:
+                               break;
+                       case mod:
+                               if (cs->def[def].tri == yes) {
+                                       conf_warning("%s creates inconsistent choice state", sym->name);
+                                       cs->flags &= ~def_flags;
+                               }
+                               break;
+                       case yes:
+                               if (cs->def[def].tri != no)
+                                       conf_warning("override: %s changes choice state", sym->name);
+                               cs->def[def].val = sym;
+                               break;
+                       }
+                       cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
+               }
+       }
+       fclose(in);
+
+       if (modules_sym)
+               sym_calc_value(modules_sym);
+       return 0;
+}
+
+int conf_read(const char *name)
+{
+       struct symbol *sym, *choice_sym;
+       struct property *prop;
+       struct expr *e;
+       int i, flags;
+
+       sym_set_change_count(0);
+
+       if (conf_read_simple(name, S_DEF_USER))
+               return 1;
+
+       for_all_symbols(i, sym) {
+               sym_calc_value(sym);
+               if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
+                       goto sym_ok;
+               if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
+                       /* check that calculated value agrees with saved value */
+                       switch (sym->type) {
+                       case S_BOOLEAN:
+                       case S_TRISTATE:
+                               if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
+                                       break;
+                               if (!sym_is_choice(sym))
+                                       goto sym_ok;
+                       default:
+                               if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
+                                       goto sym_ok;
+                               break;
+                       }
+               } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
+                       /* no previous value and not saved */
+                       goto sym_ok;
+               conf_unsaved++;
+               /* maybe print value in verbose mode... */
+       sym_ok:
+               if (!sym_is_choice(sym))
+                       continue;
+               /* The choice symbol only has a set value (and thus is not new)
+                * if all its visible childs have values.
+                */
+               prop = sym_get_choice_prop(sym);
+               flags = sym->flags;
+               expr_list_for_each_sym(prop->expr, e, choice_sym)
+                       if (choice_sym->visible != no)
+                               flags &= choice_sym->flags;
+               sym->flags &= flags | ~SYMBOL_DEF_USER;
+       }
+
+       for_all_symbols(i, sym) {
+               if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
+                       /* Reset values of generates values, so they'll appear
+                        * as new, if they should become visible, but that
+                        * doesn't quite work if the Kconfig and the saved
+                        * configuration disagree.
+                        */
+                       if (sym->visible == no && !conf_unsaved)
+                               sym->flags &= ~SYMBOL_DEF_USER;
+                       switch (sym->type) {
+                       case S_STRING:
+                       case S_INT:
+                       case S_HEX:
+                               /* Reset a string value if it's out of range */
+                               if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
+                                       break;
+                               sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
+                               conf_unsaved++;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       sym_add_change_count(conf_warnings || conf_unsaved);
+
+       return 0;
+}
+
+int conf_write(const char *name)
+{
+       FILE *out;
+       struct symbol *sym;
+       struct menu *menu;
+       const char *basename;
+       char dirname[128], tmpname[128], newname[128];
+       int type, l;
+       const char *str;
+       time_t now;
+       int use_timestamp = 1;
+       char *env;
+
+       dirname[0] = 0;
+       if (name && name[0]) {
+               struct stat st;
+               char *slash;
+
+               if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
+                       strcpy(dirname, name);
+                       strcat(dirname, "/");
+                       basename = conf_get_configname();
+               } else if ((slash = strrchr(name, '/'))) {
+                       int size = slash - name + 1;
+                       memcpy(dirname, name, size);
+                       dirname[size] = 0;
+                       if (slash[1])
+                               basename = slash + 1;
+                       else
+                               basename = conf_get_configname();
+               } else
+                       basename = name;
+       } else
+               basename = conf_get_configname();
+
+       sprintf(newname, "%s%s", dirname, basename);
+       env = getenv("KCONFIG_OVERWRITECONFIG");
+       if (!env || !*env) {
+               sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid());
+               out = fopen(tmpname, "w");
+       } else {
+               *tmpname = 0;
+               out = fopen(newname, "w");
+       }
+       if (!out)
+               return 1;
+
+       sym = sym_lookup("KERNELVERSION", 0);
+       sym_calc_value(sym);
+       time(&now);
+       env = getenv("KCONFIG_NOTIMESTAMP");
+       if (env && *env)
+               use_timestamp = 0;
+
+       fprintf(out, _("#\n"
+                      "# Automatically generated make config: don't edit\n"
+                      "# firmly.0cpm version: %s\n"
+                      "%s%s"
+                      "#\n"),
+                    sym_get_string_value(sym),
+                    use_timestamp ? "# " : "",
+                    use_timestamp ? ctime(&now) : "");
+
+       if (!conf_get_changed())
+               sym_clear_all_valid();
+
+       menu = rootmenu.list;
+       while (menu) {
+               sym = menu->sym;
+               if (!sym) {
+                       if (!menu_is_visible(menu))
+                               goto next;
+                       str = menu_get_prompt(menu);
+                       fprintf(out, "\n"
+                                    "#\n"
+                                    "# %s\n"
+                                    "#\n", str);
+               } else if (!(sym->flags & SYMBOL_CHOICE)) {
+                       sym_calc_value(sym);
+                       if (!(sym->flags & SYMBOL_WRITE))
+                               goto next;
+                       sym->flags &= ~SYMBOL_WRITE;
+                       type = sym->type;
+                       if (type == S_TRISTATE) {
+                               sym_calc_value(modules_sym);
+                               if (modules_sym->curr.tri == no)
+                                       type = S_BOOLEAN;
+                       }
+                       switch (type) {
+                       case S_BOOLEAN:
+                       case S_TRISTATE:
+                               switch (sym_get_tristate_value(sym)) {
+                               case no:
+                                       fprintf(out, "# CONFIG_%s is not set\n", sym->name);
+                                       break;
+                               case mod:
+                                       fprintf(out, "CONFIG_%s=m\n", sym->name);
+                                       break;
+                               case yes:
+                                       fprintf(out, "CONFIG_%s=y\n", sym->name);
+                                       break;
+                               }
+                               break;
+                       case S_STRING:
+                               str = sym_get_string_value(sym);
+                               fprintf(out, "CONFIG_%s=\"", sym->name);
+                               while (1) {
+                                       l = strcspn(str, "\"\\");
+                                       if (l) {
+                                               fwrite(str, l, 1, out);
+                                               str += l;
+                                       }
+                                       if (!*str)
+                                               break;
+                                       fprintf(out, "\\%c", *str++);
+                               }
+                               fputs("\"\n", out);
+                               break;
+                       case S_HEX:
+                               str = sym_get_string_value(sym);
+                               if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
+                                       fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
+                                       break;
+                               }
+                       case S_INT:
+                               str = sym_get_string_value(sym);
+                               fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
+                               break;
+                       }
+               }
+
+       next:
+               if (menu->list) {
+                       menu = menu->list;
+                       continue;
+               }
+               if (menu->next)
+                       menu = menu->next;
+               else while ((menu = menu->parent)) {
+                       if (menu->next) {
+                               menu = menu->next;
+                               break;
+                       }
+               }
+       }
+       fclose(out);
+
+       if (*tmpname) {
+               strcat(dirname, basename);
+               strcat(dirname, ".old");
+               rename(newname, dirname);
+               if (rename(tmpname, newname))
+                       return 1;
+       }
+
+       printf(_("#\n"
+                "# configuration written to %s\n"
+                "#\n"), newname);
+
+       sym_set_change_count(0);
+
+       return 0;
+}
+
+int conf_split_config(void)
+{
+       char *name, path[128];
+       char *s, *d, c;
+       struct symbol *sym;
+       struct stat sb;
+       int res, i, fd;
+
+       name = getenv("KCONFIG_AUTOCONFIG");
+       if (!name)
+               name = "include/config/auto.conf";
+       conf_read_simple(name, S_DEF_AUTO);
+
+       if (chdir("include/config"))
+               return 1;
+
+       res = 0;
+       for_all_symbols(i, sym) {
+               sym_calc_value(sym);
+               if ((sym->flags & SYMBOL_AUTO) || !sym->name)
+                       continue;
+               if (sym->flags & SYMBOL_WRITE) {
+                       if (sym->flags & SYMBOL_DEF_AUTO) {
+                               /*
+                                * symbol has old and new value,
+                                * so compare them...
+                                */
+                               switch (sym->type) {
+                               case S_BOOLEAN:
+                               case S_TRISTATE:
+                                       if (sym_get_tristate_value(sym) ==
+                                           sym->def[S_DEF_AUTO].tri)
+                                               continue;
+                                       break;
+                               case S_STRING:
+                               case S_HEX:
+                               case S_INT:
+                                       if (!strcmp(sym_get_string_value(sym),
+                                                   sym->def[S_DEF_AUTO].val))
+                                               continue;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       } else {
+                               /*
+                                * If there is no old value, only 'no' (unset)
+                                * is allowed as new value.
+                                */
+                               switch (sym->type) {
+                               case S_BOOLEAN:
+                               case S_TRISTATE:
+                                       if (sym_get_tristate_value(sym) == no)
+                                               continue;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+               } else if (!(sym->flags & SYMBOL_DEF_AUTO))
+                       /* There is neither an old nor a new value. */
+                       continue;
+               /* else
+                *      There is an old value, but no new value ('no' (unset)
+                *      isn't saved in auto.conf, so the old value is always
+                *      different from 'no').
+                */
+
+               /* Replace all '_' and append ".h" */
+               s = sym->name;
+               d = path;
+               while ((c = *s++)) {
+                       c = tolower(c);
+                       *d++ = (c == '_') ? '/' : c;
+               }
+               strcpy(d, ".h");
+
+               /* Assume directory path already exists. */
+               fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+               if (fd == -1) {
+                       if (errno != ENOENT) {
+                               res = 1;
+                               break;
+                       }
+                       /*
+                        * Create directory components,
+                        * unless they exist already.
+                        */
+                       d = path;
+                       while ((d = strchr(d, '/'))) {
+                               *d = 0;
+                               if (stat(path, &sb) && mkdir(path, 0755)) {
+                                       res = 1;
+                                       goto out;
+                               }
+                               *d++ = '/';
+                       }
+                       /* Try it again. */
+                       fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+                       if (fd == -1) {
+                               res = 1;
+                               break;
+                       }
+               }
+               close(fd);
+       }
+out:
+       if (chdir("../.."))
+               return 1;
+
+       return res;
+}
+
+int conf_write_autoconf(void)
+{
+       struct symbol *sym;
+       const char *str;
+       char *name;
+       FILE *out, *out_h;
+       time_t now;
+       int i, l;
+
+       sym_clear_all_valid();
+
+       file_write_dep("include/config/auto.conf.cmd");
+
+       if (conf_split_config())
+               return 1;
+
+       out = fopen(".tmpconfig", "w");
+       if (!out)
+               return 1;
+
+       out_h = fopen(".tmpconfig.h", "w");
+       if (!out_h) {
+               fclose(out);
+               return 1;
+       }
+
+       sym = sym_lookup("KERNELVERSION", 0);
+       sym_calc_value(sym);
+       time(&now);
+       fprintf(out, "#\n"
+                    "# Automatically generated make config: don't edit\n"
+                    "# firmly.0cpm version: %s\n"
+                    "# %s"
+                    "#\n",
+                    sym_get_string_value(sym), ctime(&now));
+       fprintf(out_h, "/*\n"
+                      " * Automatically generated C config: don't edit\n"
+                      " * firmly.0cpm version: %s\n"
+                      " * %s"
+                      " */\n"
+                      "#define AUTOCONF_INCLUDED\n",
+                      sym_get_string_value(sym), ctime(&now));
+
+       for_all_symbols(i, sym) {
+               sym_calc_value(sym);
+               if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
+                       continue;
+               switch (sym->type) {
+               case S_BOOLEAN:
+               case S_TRISTATE:
+                       switch (sym_get_tristate_value(sym)) {
+                       case no:
+                               break;
+                       case mod:
+                               fprintf(out, "CONFIG_%s=m\n", sym->name);
+                               fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
+                               break;
+                       case yes:
+                               fprintf(out, "CONFIG_%s=y\n", sym->name);
+                               fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
+                               break;
+                       }
+                       break;
+               case S_STRING:
+                       str = sym_get_string_value(sym);
+                       fprintf(out, "CONFIG_%s=\"", sym->name);
+                       fprintf(out_h, "#define CONFIG_%s \"", sym->name);
+                       while (1) {
+                               l = strcspn(str, "\"\\");
+                               if (l) {
+                                       fwrite(str, l, 1, out);
+                                       fwrite(str, l, 1, out_h);
+                                       str += l;
+                               }
+                               if (!*str)
+                                       break;
+                               fprintf(out, "\\%c", *str);
+                               fprintf(out_h, "\\%c", *str);
+                               str++;
+                       }
+                       fputs("\"\n", out);
+                       fputs("\"\n", out_h);
+                       break;
+               case S_HEX:
+                       str = sym_get_string_value(sym);
+                       if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
+                               fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
+                               fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
+                               break;
+                       }
+               case S_INT:
+                       str = sym_get_string_value(sym);
+                       fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
+                       fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
+                       break;
+               default:
+                       break;
+               }
+       }
+       fclose(out);
+       fclose(out_h);
+
+       name = getenv("KCONFIG_AUTOHEADER");
+       if (!name)
+               name = "include/linux/autoconf.h";
+       if (rename(".tmpconfig.h", name))
+               return 1;
+       name = getenv("KCONFIG_AUTOCONFIG");
+       if (!name)
+               name = "include/config/auto.conf";
+       /*
+        * This must be the last step, kbuild has a dependency on auto.conf
+        * and this marks the successful completion of the previous steps.
+        */
+       if (rename(".tmpconfig", name))
+               return 1;
+
+       return 0;
+}
+
+static int sym_change_count;
+static void (*conf_changed_callback)(void);
+
+void sym_set_change_count(int count)
+{
+       int _sym_change_count = sym_change_count;
+       sym_change_count = count;
+       if (conf_changed_callback &&
+           (bool)_sym_change_count != (bool)count)
+               conf_changed_callback();
+}
+
+void sym_add_change_count(int count)
+{
+       sym_set_change_count(count + sym_change_count);
+}
+
+bool conf_get_changed(void)
+{
+       return sym_change_count;
+}
+
+void conf_set_changed_callback(void (*fn)(void))
+{
+       conf_changed_callback = fn;
+}
diff --git a/bin/kconfig/expr.c b/bin/kconfig/expr.c
new file mode 100644 (file)
index 0000000..579ece4
--- /dev/null
@@ -0,0 +1,1106 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define DEBUG_EXPR     0
+
+struct expr *expr_alloc_symbol(struct symbol *sym)
+{
+       struct expr *e = malloc(sizeof(*e));
+       memset(e, 0, sizeof(*e));
+       e->type = E_SYMBOL;
+       e->left.sym = sym;
+       return e;
+}
+
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
+{
+       struct expr *e = malloc(sizeof(*e));
+       memset(e, 0, sizeof(*e));
+       e->type = type;
+       e->left.expr = ce;
+       return e;
+}
+
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
+{
+       struct expr *e = malloc(sizeof(*e));
+       memset(e, 0, sizeof(*e));
+       e->type = type;
+       e->left.expr = e1;
+       e->right.expr = e2;
+       return e;
+}
+
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
+{
+       struct expr *e = malloc(sizeof(*e));
+       memset(e, 0, sizeof(*e));
+       e->type = type;
+       e->left.sym = s1;
+       e->right.sym = s2;
+       return e;
+}
+
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2)
+{
+       if (!e1)
+               return e2;
+       return e2 ? expr_alloc_two(E_AND, e1, e2) : e1;
+}
+
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
+{
+       if (!e1)
+               return e2;
+       return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
+}
+
+struct expr *expr_copy(struct expr *org)
+{
+       struct expr *e;
+
+       if (!org)
+               return NULL;
+
+       e = malloc(sizeof(*org));
+       memcpy(e, org, sizeof(*org));
+       switch (org->type) {
+       case E_SYMBOL:
+               e->left = org->left;
+               break;
+       case E_NOT:
+               e->left.expr = expr_copy(org->left.expr);
+               break;
+       case E_EQUAL:
+       case E_UNEQUAL:
+               e->left.sym = org->left.sym;
+               e->right.sym = org->right.sym;
+               break;
+       case E_AND:
+       case E_OR:
+       case E_LIST:
+               e->left.expr = expr_copy(org->left.expr);
+               e->right.expr = expr_copy(org->right.expr);
+               break;
+       default:
+               printf("can't copy type %d\n", e->type);
+               free(e);
+               e = NULL;
+               break;
+       }
+
+       return e;
+}
+
+void expr_free(struct expr *e)
+{
+       if (!e)
+               return;
+
+       switch (e->type) {
+       case E_SYMBOL:
+               break;
+       case E_NOT:
+               expr_free(e->left.expr);
+               return;
+       case E_EQUAL:
+       case E_UNEQUAL:
+               break;
+       case E_OR:
+       case E_AND:
+               expr_free(e->left.expr);
+               expr_free(e->right.expr);
+               break;
+       default:
+               printf("how to free type %d?\n", e->type);
+               break;
+       }
+       free(e);
+}
+
+static int trans_count;
+
+#define e1 (*ep1)
+#define e2 (*ep2)
+
+static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+       if (e1->type == type) {
+               __expr_eliminate_eq(type, &e1->left.expr, &e2);
+               __expr_eliminate_eq(type, &e1->right.expr, &e2);
+               return;
+       }
+       if (e2->type == type) {
+               __expr_eliminate_eq(type, &e1, &e2->left.expr);
+               __expr_eliminate_eq(type, &e1, &e2->right.expr);
+               return;
+       }
+       if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+           e1->left.sym == e2->left.sym &&
+           (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no))
+               return;
+       if (!expr_eq(e1, e2))
+               return;
+       trans_count++;
+       expr_free(e1); expr_free(e2);
+       switch (type) {
+       case E_OR:
+               e1 = expr_alloc_symbol(&symbol_no);
+               e2 = expr_alloc_symbol(&symbol_no);
+               break;
+       case E_AND:
+               e1 = expr_alloc_symbol(&symbol_yes);
+               e2 = expr_alloc_symbol(&symbol_yes);
+               break;
+       default:
+               ;
+       }
+}
+
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
+{
+       if (!e1 || !e2)
+               return;
+       switch (e1->type) {
+       case E_OR:
+       case E_AND:
+               __expr_eliminate_eq(e1->type, ep1, ep2);
+       default:
+               ;
+       }
+       if (e1->type != e2->type) switch (e2->type) {
+       case E_OR:
+       case E_AND:
+               __expr_eliminate_eq(e2->type, ep1, ep2);
+       default:
+               ;
+       }
+       e1 = expr_eliminate_yn(e1);
+       e2 = expr_eliminate_yn(e2);
+}
+
+#undef e1
+#undef e2
+
+int expr_eq(struct expr *e1, struct expr *e2)
+{
+       int res, old_count;
+
+       if (e1->type != e2->type)
+               return 0;
+       switch (e1->type) {
+       case E_EQUAL:
+       case E_UNEQUAL:
+               return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym;
+       case E_SYMBOL:
+               return e1->left.sym == e2->left.sym;
+       case E_NOT:
+               return expr_eq(e1->left.expr, e2->left.expr);
+       case E_AND:
+       case E_OR:
+               e1 = expr_copy(e1);
+               e2 = expr_copy(e2);
+               old_count = trans_count;
+               expr_eliminate_eq(&e1, &e2);
+               res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+                      e1->left.sym == e2->left.sym);
+               expr_free(e1);
+               expr_free(e2);
+               trans_count = old_count;
+               return res;
+       case E_LIST:
+       case E_RANGE:
+       case E_NONE:
+               /* panic */;
+       }
+
+       if (DEBUG_EXPR) {
+               expr_fprint(e1, stdout);
+               printf(" = ");
+               expr_fprint(e2, stdout);
+               printf(" ?\n");
+       }
+
+       return 0;
+}
+
+struct expr *expr_eliminate_yn(struct expr *e)
+{
+       struct expr *tmp;
+
+       if (e) switch (e->type) {
+       case E_AND:
+               e->left.expr = expr_eliminate_yn(e->left.expr);
+               e->right.expr = expr_eliminate_yn(e->right.expr);
+               if (e->left.expr->type == E_SYMBOL) {
+                       if (e->left.expr->left.sym == &symbol_no) {
+                               expr_free(e->left.expr);
+                               expr_free(e->right.expr);
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_no;
+                               e->right.expr = NULL;
+                               return e;
+                       } else if (e->left.expr->left.sym == &symbol_yes) {
+                               free(e->left.expr);
+                               tmp = e->right.expr;
+                               *e = *(e->right.expr);
+                               free(tmp);
+                               return e;
+                       }
+               }
+               if (e->right.expr->type == E_SYMBOL) {
+                       if (e->right.expr->left.sym == &symbol_no) {
+                               expr_free(e->left.expr);
+                               expr_free(e->right.expr);
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_no;
+                               e->right.expr = NULL;
+                               return e;
+                       } else if (e->right.expr->left.sym == &symbol_yes) {
+                               free(e->right.expr);
+                               tmp = e->left.expr;
+                               *e = *(e->left.expr);
+                               free(tmp);
+                               return e;
+                       }
+               }
+               break;
+       case E_OR:
+               e->left.expr = expr_eliminate_yn(e->left.expr);
+               e->right.expr = expr_eliminate_yn(e->right.expr);
+               if (e->left.expr->type == E_SYMBOL) {
+                       if (e->left.expr->left.sym == &symbol_no) {
+                               free(e->left.expr);
+                               tmp = e->right.expr;
+                               *e = *(e->right.expr);
+                               free(tmp);
+                               return e;
+                       } else if (e->left.expr->left.sym == &symbol_yes) {
+                               expr_free(e->left.expr);
+                               expr_free(e->right.expr);
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_yes;
+                               e->right.expr = NULL;
+                               return e;
+                       }
+               }
+               if (e->right.expr->type == E_SYMBOL) {
+                       if (e->right.expr->left.sym == &symbol_no) {
+                               free(e->right.expr);
+                               tmp = e->left.expr;
+                               *e = *(e->left.expr);
+                               free(tmp);
+                               return e;
+                       } else if (e->right.expr->left.sym == &symbol_yes) {
+                               expr_free(e->left.expr);
+                               expr_free(e->right.expr);
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_yes;
+                               e->right.expr = NULL;
+                               return e;
+                       }
+               }
+               break;
+       default:
+               ;
+       }
+       return e;
+}
+
+/*
+ * bool FOO!=n => FOO
+ */
+struct expr *expr_trans_bool(struct expr *e)
+{
+       if (!e)
+               return NULL;
+       switch (e->type) {
+       case E_AND:
+       case E_OR:
+       case E_NOT:
+               e->left.expr = expr_trans_bool(e->left.expr);
+               e->right.expr = expr_trans_bool(e->right.expr);
+               break;
+       case E_UNEQUAL:
+               // FOO!=n -> FOO
+               if (e->left.sym->type == S_TRISTATE) {
+                       if (e->right.sym == &symbol_no) {
+                               e->type = E_SYMBOL;
+                               e->right.sym = NULL;
+                       }
+               }
+               break;
+       default:
+               ;
+       }
+       return e;
+}
+
+/*
+ * e1 || e2 -> ?
+ */
+struct expr *expr_join_or(struct expr *e1, struct expr *e2)
+{
+       struct expr *tmp;
+       struct symbol *sym1, *sym2;
+
+       if (expr_eq(e1, e2))
+               return expr_copy(e1);
+       if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+               return NULL;
+       if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+               return NULL;
+       if (e1->type == E_NOT) {
+               tmp = e1->left.expr;
+               if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+                       return NULL;
+               sym1 = tmp->left.sym;
+       } else
+               sym1 = e1->left.sym;
+       if (e2->type == E_NOT) {
+               if (e2->left.expr->type != E_SYMBOL)
+                       return NULL;
+               sym2 = e2->left.expr->left.sym;
+       } else
+               sym2 = e2->left.sym;
+       if (sym1 != sym2)
+               return NULL;
+       if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+               return NULL;
+       if (sym1->type == S_TRISTATE) {
+               if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+                   ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+                    (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) {
+                       // (a='y') || (a='m') -> (a!='n')
+                       return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no);
+               }
+               if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+                   ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+                    (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) {
+                       // (a='y') || (a='n') -> (a!='m')
+                       return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod);
+               }
+               if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+                   ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+                    (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) {
+                       // (a='m') || (a='n') -> (a!='y')
+                       return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes);
+               }
+       }
+       if (sym1->type == S_BOOLEAN && sym1 == sym2) {
+               if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) ||
+                   (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL))
+                       return expr_alloc_symbol(&symbol_yes);
+       }
+
+       if (DEBUG_EXPR) {
+               printf("optimize (");
+               expr_fprint(e1, stdout);
+               printf(") || (");
+               expr_fprint(e2, stdout);
+               printf(")?\n");
+       }
+       return NULL;
+}
+
+struct expr *expr_join_and(struct expr *e1, struct expr *e2)
+{
+       struct expr *tmp;
+       struct symbol *sym1, *sym2;
+
+       if (expr_eq(e1, e2))
+               return expr_copy(e1);
+       if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+               return NULL;
+       if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+               return NULL;
+       if (e1->type == E_NOT) {
+               tmp = e1->left.expr;
+               if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+                       return NULL;
+               sym1 = tmp->left.sym;
+       } else
+               sym1 = e1->left.sym;
+       if (e2->type == E_NOT) {
+               if (e2->left.expr->type != E_SYMBOL)
+                       return NULL;
+               sym2 = e2->left.expr->left.sym;
+       } else
+               sym2 = e2->left.sym;
+       if (sym1 != sym2)
+               return NULL;
+       if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+               return NULL;
+
+       if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) ||
+           (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes))
+               // (a) && (a='y') -> (a='y')
+               return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+       if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) ||
+           (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no))
+               // (a) && (a!='n') -> (a)
+               return expr_alloc_symbol(sym1);
+
+       if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) ||
+           (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod))
+               // (a) && (a!='m') -> (a='y')
+               return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+       if (sym1->type == S_TRISTATE) {
+               if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) {
+                       // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+                       sym2 = e1->right.sym;
+                       if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+                               return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+                                                            : expr_alloc_symbol(&symbol_no);
+               }
+               if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) {
+                       // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+                       sym2 = e2->right.sym;
+                       if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+                               return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+                                                            : expr_alloc_symbol(&symbol_no);
+               }
+               if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+                          ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+                           (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes)))
+                       // (a!='y') && (a!='n') -> (a='m')
+                       return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod);
+
+               if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+                          ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+                           (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes)))
+                       // (a!='y') && (a!='m') -> (a='n')
+                       return expr_alloc_comp(E_EQUAL, sym1, &symbol_no);
+
+               if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+                          ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+                           (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod)))
+                       // (a!='m') && (a!='n') -> (a='m')
+                       return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+               if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) ||
+                   (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) ||
+                   (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) ||
+                   (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes))
+                       return NULL;
+       }
+
+       if (DEBUG_EXPR) {
+               printf("optimize (");
+               expr_fprint(e1, stdout);
+               printf(") && (");
+               expr_fprint(e2, stdout);
+               printf(")?\n");
+       }
+       return NULL;
+}
+
+static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+       struct expr *tmp;
+
+       if (e1->type == type) {
+               expr_eliminate_dups1(type, &e1->left.expr, &e2);
+               expr_eliminate_dups1(type, &e1->right.expr, &e2);
+               return;
+       }
+       if (e2->type == type) {
+               expr_eliminate_dups1(type, &e1, &e2->left.expr);
+               expr_eliminate_dups1(type, &e1, &e2->right.expr);
+               return;
+       }
+       if (e1 == e2)
+               return;
+
+       switch (e1->type) {
+       case E_OR: case E_AND:
+               expr_eliminate_dups1(e1->type, &e1, &e1);
+       default:
+               ;
+       }
+
+       switch (type) {
+       case E_OR:
+               tmp = expr_join_or(e1, e2);
+               if (tmp) {
+                       expr_free(e1); expr_free(e2);
+                       e1 = expr_alloc_symbol(&symbol_no);
+                       e2 = tmp;
+                       trans_count++;
+               }
+               break;
+       case E_AND:
+               tmp = expr_join_and(e1, e2);
+               if (tmp) {
+                       expr_free(e1); expr_free(e2);
+                       e1 = expr_alloc_symbol(&symbol_yes);
+                       e2 = tmp;
+                       trans_count++;
+               }
+               break;
+       default:
+               ;
+       }
+#undef e1
+#undef e2
+}
+
+static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+       struct expr *tmp, *tmp1, *tmp2;
+
+       if (e1->type == type) {
+               expr_eliminate_dups2(type, &e1->left.expr, &e2);
+               expr_eliminate_dups2(type, &e1->right.expr, &e2);
+               return;
+       }
+       if (e2->type == type) {
+               expr_eliminate_dups2(type, &e1, &e2->left.expr);
+               expr_eliminate_dups2(type, &e1, &e2->right.expr);
+       }
+       if (e1 == e2)
+               return;
+
+       switch (e1->type) {
+       case E_OR:
+               expr_eliminate_dups2(e1->type, &e1, &e1);
+               // (FOO || BAR) && (!FOO && !BAR) -> n
+               tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+               tmp2 = expr_copy(e2);
+               tmp = expr_extract_eq_and(&tmp1, &tmp2);
+               if (expr_is_yes(tmp1)) {
+                       expr_free(e1);
+                       e1 = expr_alloc_symbol(&symbol_no);
+                       trans_count++;
+               }
+               expr_free(tmp2);
+               expr_free(tmp1);
+               expr_free(tmp);
+               break;
+       case E_AND:
+               expr_eliminate_dups2(e1->type, &e1, &e1);
+               // (FOO && BAR) || (!FOO || !BAR) -> y
+               tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+               tmp2 = expr_copy(e2);
+               tmp = expr_extract_eq_or(&tmp1, &tmp2);
+               if (expr_is_no(tmp1)) {
+                       expr_free(e1);
+                       e1 = expr_alloc_symbol(&symbol_yes);
+                       trans_count++;
+               }
+               expr_free(tmp2);
+               expr_free(tmp1);
+               expr_free(tmp);
+               break;
+       default:
+               ;
+       }
+#undef e1
+#undef e2
+}
+
+struct expr *expr_eliminate_dups(struct expr *e)
+{
+       int oldcount;
+       if (!e)
+               return e;
+
+       oldcount = trans_count;
+       while (1) {
+               trans_count = 0;
+               switch (e->type) {
+               case E_OR: case E_AND:
+                       expr_eliminate_dups1(e->type, &e, &e);
+                       expr_eliminate_dups2(e->type, &e, &e);
+               default:
+                       ;
+               }
+               if (!trans_count)
+                       break;
+               e = expr_eliminate_yn(e);
+       }
+       trans_count = oldcount;
+       return e;
+}
+
+struct expr *expr_transform(struct expr *e)
+{
+       struct expr *tmp;
+
+       if (!e)
+               return NULL;
+       switch (e->type) {
+       case E_EQUAL:
+       case E_UNEQUAL:
+       case E_SYMBOL:
+       case E_LIST:
+               break;
+       default:
+               e->left.expr = expr_transform(e->left.expr);
+               e->right.expr = expr_transform(e->right.expr);
+       }
+
+       switch (e->type) {
+       case E_EQUAL:
+               if (e->left.sym->type != S_BOOLEAN)
+                       break;
+               if (e->right.sym == &symbol_no) {
+                       e->type = E_NOT;
+                       e->left.expr = expr_alloc_symbol(e->left.sym);
+                       e->right.sym = NULL;
+                       break;
+               }
+               if (e->right.sym == &symbol_mod) {
+                       printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name);
+                       e->type = E_SYMBOL;
+                       e->left.sym = &symbol_no;
+                       e->right.sym = NULL;
+                       break;
+               }
+               if (e->right.sym == &symbol_yes) {
+                       e->type = E_SYMBOL;
+                       e->right.sym = NULL;
+                       break;
+               }
+               break;
+       case E_UNEQUAL:
+               if (e->left.sym->type != S_BOOLEAN)
+                       break;
+               if (e->right.sym == &symbol_no) {
+                       e->type = E_SYMBOL;
+                       e->right.sym = NULL;
+                       break;
+               }
+               if (e->right.sym == &symbol_mod) {
+                       printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name);
+                       e->type = E_SYMBOL;
+                       e->left.sym = &symbol_yes;
+                       e->right.sym = NULL;
+                       break;
+               }
+               if (e->right.sym == &symbol_yes) {
+                       e->type = E_NOT;
+                       e->left.expr = expr_alloc_symbol(e->left.sym);
+                       e->right.sym = NULL;
+                       break;
+               }
+               break;
+       case E_NOT:
+               switch (e->left.expr->type) {
+               case E_NOT:
+                       // !!a -> a
+                       tmp = e->left.expr->left.expr;
+                       free(e->left.expr);
+                       free(e);
+                       e = tmp;
+                       e = expr_transform(e);
+                       break;
+               case E_EQUAL:
+               case E_UNEQUAL:
+                       // !a='x' -> a!='x'
+                       tmp = e->left.expr;
+                       free(e);
+                       e = tmp;
+                       e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL;
+                       break;
+               case E_OR:
+                       // !(a || b) -> !a && !b
+                       tmp = e->left.expr;
+                       e->type = E_AND;
+                       e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+                       tmp->type = E_NOT;
+                       tmp->right.expr = NULL;
+                       e = expr_transform(e);
+                       break;
+               case E_AND:
+                       // !(a && b) -> !a || !b
+                       tmp = e->left.expr;
+                       e->type = E_OR;
+                       e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+                       tmp->type = E_NOT;
+                       tmp->right.expr = NULL;
+                       e = expr_transform(e);
+                       break;
+               case E_SYMBOL:
+                       if (e->left.expr->left.sym == &symbol_yes) {
+                               // !'y' -> 'n'
+                               tmp = e->left.expr;
+                               free(e);
+                               e = tmp;
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_no;
+                               break;
+                       }
+                       if (e->left.expr->left.sym == &symbol_mod) {
+                               // !'m' -> 'm'
+                               tmp = e->left.expr;
+                               free(e);
+                               e = tmp;
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_mod;
+                               break;
+                       }
+                       if (e->left.expr->left.sym == &symbol_no) {
+                               // !'n' -> 'y'
+                               tmp = e->left.expr;
+                               free(e);
+                               e = tmp;
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_yes;
+                               break;
+                       }
+                       break;
+               default:
+                       ;
+               }
+               break;
+       default:
+               ;
+       }
+       return e;
+}
+
+int expr_contains_symbol(struct expr *dep, struct symbol *sym)
+{
+       if (!dep)
+               return 0;
+
+       switch (dep->type) {
+       case E_AND:
+       case E_OR:
+               return expr_contains_symbol(dep->left.expr, sym) ||
+                      expr_contains_symbol(dep->right.expr, sym);
+       case E_SYMBOL:
+               return dep->left.sym == sym;
+       case E_EQUAL:
+       case E_UNEQUAL:
+               return dep->left.sym == sym ||
+                      dep->right.sym == sym;
+       case E_NOT:
+               return expr_contains_symbol(dep->left.expr, sym);
+       default:
+               ;
+       }
+       return 0;
+}
+
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
+{
+       if (!dep)
+               return false;
+
+       switch (dep->type) {
+       case E_AND:
+               return expr_depends_symbol(dep->left.expr, sym) ||
+                      expr_depends_symbol(dep->right.expr, sym);
+       case E_SYMBOL:
+               return dep->left.sym == sym;
+       case E_EQUAL:
+               if (dep->left.sym == sym) {
+                       if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod)
+                               return true;
+               }
+               break;
+       case E_UNEQUAL:
+               if (dep->left.sym == sym) {
+                       if (dep->right.sym == &symbol_no)
+                               return true;
+               }
+               break;
+       default:
+               ;
+       }
+       return false;
+}
+
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2)
+{
+       struct expr *tmp = NULL;
+       expr_extract_eq(E_AND, &tmp, ep1, ep2);
+       if (tmp) {
+               *ep1 = expr_eliminate_yn(*ep1);
+               *ep2 = expr_eliminate_yn(*ep2);
+       }
+       return tmp;
+}
+
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2)
+{
+       struct expr *tmp = NULL;
+       expr_extract_eq(E_OR, &tmp, ep1, ep2);
+       if (tmp) {
+               *ep1 = expr_eliminate_yn(*ep1);
+               *ep2 = expr_eliminate_yn(*ep2);
+       }
+       return tmp;
+}
+
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+       if (e1->type == type) {
+               expr_extract_eq(type, ep, &e1->left.expr, &e2);
+               expr_extract_eq(type, ep, &e1->right.expr, &e2);
+               return;
+       }
+       if (e2->type == type) {
+               expr_extract_eq(type, ep, ep1, &e2->left.expr);
+               expr_extract_eq(type, ep, ep1, &e2->right.expr);
+               return;
+       }
+       if (expr_eq(e1, e2)) {
+               *ep = *ep ? expr_alloc_two(type, *ep, e1) : e1;
+               expr_free(e2);
+               if (type == E_AND) {
+                       e1 = expr_alloc_symbol(&symbol_yes);
+                       e2 = expr_alloc_symbol(&symbol_yes);
+               } else if (type == E_OR) {
+                       e1 = expr_alloc_symbol(&symbol_no);
+                       e2 = expr_alloc_symbol(&symbol_no);
+               }
+       }
+#undef e1
+#undef e2
+}
+
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym)
+{
+       struct expr *e1, *e2;
+
+       if (!e) {
+               e = expr_alloc_symbol(sym);
+               if (type == E_UNEQUAL)
+                       e = expr_alloc_one(E_NOT, e);
+               return e;
+       }
+       switch (e->type) {
+       case E_AND:
+               e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+               e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+               if (sym == &symbol_yes)
+                       e = expr_alloc_two(E_AND, e1, e2);
+               if (sym == &symbol_no)
+                       e = expr_alloc_two(E_OR, e1, e2);
+               if (type == E_UNEQUAL)
+                       e = expr_alloc_one(E_NOT, e);
+               return e;
+       case E_OR:
+               e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+               e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+               if (sym == &symbol_yes)
+                       e = expr_alloc_two(E_OR, e1, e2);
+               if (sym == &symbol_no)
+                       e = expr_alloc_two(E_AND, e1, e2);
+               if (type == E_UNEQUAL)
+                       e = expr_alloc_one(E_NOT, e);
+               return e;
+       case E_NOT:
+               return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym);
+       case E_UNEQUAL:
+       case E_EQUAL:
+               if (type == E_EQUAL) {
+                       if (sym == &symbol_yes)
+                               return expr_copy(e);
+                       if (sym == &symbol_mod)
+                               return expr_alloc_symbol(&symbol_no);
+                       if (sym == &symbol_no)
+                               return expr_alloc_one(E_NOT, expr_copy(e));
+               } else {
+                       if (sym == &symbol_yes)
+                               return expr_alloc_one(E_NOT, expr_copy(e));
+                       if (sym == &symbol_mod)
+                               return expr_alloc_symbol(&symbol_yes);
+                       if (sym == &symbol_no)
+                               return expr_copy(e);
+               }
+               break;
+       case E_SYMBOL:
+               return expr_alloc_comp(type, e->left.sym, sym);
+       case E_LIST:
+       case E_RANGE:
+       case E_NONE:
+               /* panic */;
+       }
+       return NULL;
+}
+
+tristate expr_calc_value(struct expr *e)
+{
+       tristate val1, val2;
+       const char *str1, *str2;
+
+       if (!e)
+               return yes;
+
+       switch (e->type) {
+       case E_SYMBOL:
+               sym_calc_value(e->left.sym);
+               return e->left.sym->curr.tri;
+       case E_AND:
+               val1 = expr_calc_value(e->left.expr);
+               val2 = expr_calc_value(e->right.expr);
+               return EXPR_AND(val1, val2);
+       case E_OR:
+               val1 = expr_calc_value(e->left.expr);
+               val2 = expr_calc_value(e->right.expr);
+               return EXPR_OR(val1, val2);
+       case E_NOT:
+               val1 = expr_calc_value(e->left.expr);
+               return EXPR_NOT(val1);
+       case E_EQUAL:
+               sym_calc_value(e->left.sym);
+               sym_calc_value(e->right.sym);
+               str1 = sym_get_string_value(e->left.sym);
+               str2 = sym_get_string_value(e->right.sym);
+               return !strcmp(str1, str2) ? yes : no;
+       case E_UNEQUAL:
+               sym_calc_value(e->left.sym);
+               sym_calc_value(e->right.sym);
+               str1 = sym_get_string_value(e->left.sym);
+               str2 = sym_get_string_value(e->right.sym);
+               return !strcmp(str1, str2) ? no : yes;
+       default:
+               printf("expr_calc_value: %d?\n", e->type);
+               return no;
+       }
+}
+
+int expr_compare_type(enum expr_type t1, enum expr_type t2)
+{
+#if 0
+       return 1;
+#else
+       if (t1 == t2)
+               return 0;
+       switch (t1) {
+       case E_EQUAL:
+       case E_UNEQUAL:
+               if (t2 == E_NOT)
+                       return 1;
+       case E_NOT:
+               if (t2 == E_AND)
+                       return 1;
+       case E_AND:
+               if (t2 == E_OR)
+                       return 1;
+       case E_OR:
+               if (t2 == E_LIST)
+                       return 1;
+       case E_LIST:
+               if (t2 == 0)
+                       return 1;
+       default:
+               return -1;
+       }
+       printf("[%dgt%d?]", t1, t2);
+       return 0;
+#endif
+}
+
+void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
+{
+       if (!e) {
+               fn(data, NULL, "y");
+               return;
+       }
+
+       if (expr_compare_type(prevtoken, e->type) > 0)
+               fn(data, NULL, "(");
+       switch (e->type) {
+       case E_SYMBOL:
+               if (e->left.sym->name)
+                       fn(data, e->left.sym, e->left.sym->name);
+               else
+                       fn(data, NULL, "<choice>");
+               break;
+       case E_NOT:
+               fn(data, NULL, "!");
+               expr_print(e->left.expr, fn, data, E_NOT);
+               break;
+       case E_EQUAL:
+               if (e->left.sym->name)
+                       fn(data, e->left.sym, e->left.sym->name);
+               else
+                       fn(data, NULL, "<choice>");
+               fn(data, NULL, "=");
+               fn(data, e->right.sym, e->right.sym->name);
+               break;
+       case E_UNEQUAL:
+               if (e->left.sym->name)
+                       fn(data, e->left.sym, e->left.sym->name);
+               else
+                       fn(data, NULL, "<choice>");
+               fn(data, NULL, "!=");
+               fn(data, e->right.sym, e->right.sym->name);
+               break;
+       case E_OR:
+               expr_print(e->left.expr, fn, data, E_OR);
+               fn(data, NULL, " || ");
+               expr_print(e->right.expr, fn, data, E_OR);
+               break;
+       case E_AND:
+               expr_print(e->left.expr, fn, data, E_AND);
+               fn(data, NULL, " && ");
+               expr_print(e->right.expr, fn, data, E_AND);
+               break;
+       case E_LIST:
+               fn(data, e->right.sym, e->right.sym->name);
+               if (e->left.expr) {
+                       fn(data, NULL, " ^ ");
+                       expr_print(e->left.expr, fn, data, E_LIST);
+               }
+               break;
+       case E_RANGE:
+               fn(data, NULL, "[");
+               fn(data, e->left.sym, e->left.sym->name);
+               fn(data, NULL, " ");
+               fn(data, e->right.sym, e->right.sym->name);
+               fn(data, NULL, "]");
+               break;
+       default:
+         {
+               char buf[32];
+               sprintf(buf, "<unknown type %d>", e->type);
+               fn(data, NULL, buf);
+               break;
+         }
+       }
+       if (expr_compare_type(prevtoken, e->type) > 0)
+               fn(data, NULL, ")");
+}
+
+static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
+{
+       fwrite(str, strlen(str), 1, data);
+}
+
+void expr_fprint(struct expr *e, FILE *out)
+{
+       expr_print(e, expr_print_file_helper, out, E_NONE);
+}
+
+static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str)
+{
+       str_append((struct gstr*)data, str);
+}
+
+void expr_gstr_print(struct expr *e, struct gstr *gs)
+{
+       expr_print(e, expr_print_gstr_helper, gs, E_NONE);
+}
diff --git a/bin/kconfig/expr.h b/bin/kconfig/expr.h
new file mode 100644 (file)
index 0000000..9d4cba1
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef EXPR_H
+#define EXPR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+struct file {
+       struct file *next;
+       struct file *parent;
+       char *name;
+       int lineno;
+       int flags;
+};
+
+#define FILE_BUSY              0x0001
+#define FILE_SCANNED           0x0002
+
+typedef enum tristate {
+       no, mod, yes
+} tristate;
+
+enum expr_type {
+       E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_LIST, E_SYMBOL, E_RANGE
+};
+
+union expr_data {
+       struct expr *expr;
+       struct symbol *sym;
+};
+
+struct expr {
+       enum expr_type type;
+       union expr_data left, right;
+};
+
+#define EXPR_OR(dep1, dep2)    (((dep1)>(dep2))?(dep1):(dep2))
+#define EXPR_AND(dep1, dep2)   (((dep1)<(dep2))?(dep1):(dep2))
+#define EXPR_NOT(dep)          (2-(dep))
+
+#define expr_list_for_each_sym(l, e, s) \
+       for (e = (l); e && (s = e->right.sym); e = e->left.expr)
+
+struct expr_value {
+       struct expr *expr;
+       tristate tri;
+};
+
+struct symbol_value {
+       void *val;
+       tristate tri;
+};
+
+enum symbol_type {
+       S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER
+};
+
+enum {
+       S_DEF_USER,             /* main user value */
+       S_DEF_AUTO,
+};
+
+struct symbol {
+       struct symbol *next;
+       char *name;
+       enum symbol_type type;
+       struct symbol_value curr;
+       struct symbol_value def[4];
+       tristate visible;
+       int flags;
+       struct property *prop;
+       struct expr_value rev_dep;
+};
+
+#define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
+
+#define SYMBOL_CONST           0x0001
+#define SYMBOL_CHECK           0x0008
+#define SYMBOL_CHOICE          0x0010
+#define SYMBOL_CHOICEVAL       0x0020
+#define SYMBOL_VALID           0x0080
+#define SYMBOL_OPTIONAL                0x0100
+#define SYMBOL_WRITE           0x0200
+#define SYMBOL_CHANGED         0x0400
+#define SYMBOL_AUTO            0x1000
+#define SYMBOL_CHECKED         0x2000
+#define SYMBOL_WARNED          0x8000
+#define SYMBOL_DEF             0x10000
+#define SYMBOL_DEF_USER                0x10000
+#define SYMBOL_DEF_AUTO                0x20000
+#define SYMBOL_DEF3            0x40000
+#define SYMBOL_DEF4            0x80000
+
+#define SYMBOL_MAXLENGTH       256
+#define SYMBOL_HASHSIZE                257
+#define SYMBOL_HASHMASK                0xff
+
+enum prop_type {
+       P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_DEFAULT, P_CHOICE,
+       P_SELECT, P_RANGE, P_ENV
+};
+
+struct property {
+       struct property *next;
+       struct symbol *sym;
+       enum prop_type type;
+       const char *text;
+       struct expr_value visible;
+       struct expr *expr;
+       struct menu *menu;
+       struct file *file;
+       int lineno;
+};
+
+#define for_all_properties(sym, st, tok) \
+       for (st = sym->prop; st; st = st->next) \
+               if (st->type == (tok))
+#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT)
+#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE)
+#define for_all_prompts(sym, st) \
+       for (st = sym->prop; st; st = st->next) \
+               if (st->text)
+
+struct menu {
+       struct menu *next;
+       struct menu *parent;
+       struct menu *list;
+       struct symbol *sym;
+       struct property *prompt;
+       struct expr *dep;
+       unsigned int flags;
+       char *help;
+       struct file *file;
+       int lineno;
+       void *data;
+};
+
+#define MENU_CHANGED           0x0001
+#define MENU_ROOT              0x0002
+
+#ifndef SWIG
+
+extern struct file *file_list;
+extern struct file *current_file;
+struct file *lookup_file(const char *name);
+
+extern struct symbol symbol_yes, symbol_no, symbol_mod;
+extern struct symbol *modules_sym;
+extern struct symbol *sym_defconfig_list;
+extern int cdebug;
+struct expr *expr_alloc_symbol(struct symbol *sym);
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
+struct expr *expr_copy(struct expr *org);
+void expr_free(struct expr *e);
+int expr_eq(struct expr *e1, struct expr *e2);
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
+tristate expr_calc_value(struct expr *e);
+struct expr *expr_eliminate_yn(struct expr *e);
+struct expr *expr_trans_bool(struct expr *e);
+struct expr *expr_eliminate_dups(struct expr *e);
+struct expr *expr_transform(struct expr *e);
+int expr_contains_symbol(struct expr *dep, struct symbol *sym);
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2);
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
+
+void expr_fprint(struct expr *e, FILE *out);
+struct gstr; /* forward */
+void expr_gstr_print(struct expr *e, struct gstr *gs);
+
+static inline int expr_is_yes(struct expr *e)
+{
+       return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
+}
+
+static inline int expr_is_no(struct expr *e)
+{
+       return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EXPR_H */
diff --git a/bin/kconfig/gconf.c b/bin/kconfig/gconf.c
new file mode 100644 (file)
index 0000000..f00ef41
--- /dev/null
@@ -0,0 +1,1632 @@
+/* Hey EMACS -*- linux-c -*- */
+/*
+ *
+ * Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info>
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "lkc.h"
+#include "images.c"
+
+#include <glade/glade.h>
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdlib.h>
+
+//#define DEBUG
+
+enum {
+       SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
+};
+
+static gint view_mode = FULL_VIEW;
+static gboolean show_name = TRUE;
+static gboolean show_range = TRUE;
+static gboolean show_value = TRUE;
+static gboolean show_all = FALSE;
+static gboolean show_debug = FALSE;
+static gboolean resizeable = FALSE;
+
+GtkWidget *main_wnd = NULL;
+GtkWidget *tree1_w = NULL;     // left  frame
+GtkWidget *tree2_w = NULL;     // right frame
+GtkWidget *text_w = NULL;
+GtkWidget *hpaned = NULL;
+GtkWidget *vpaned = NULL;
+GtkWidget *back_btn = NULL;
+GtkWidget *save_btn = NULL;
+GtkWidget *save_menu_item = NULL;
+
+GtkTextTag *tag1, *tag2;
+GdkColor color;
+
+GtkTreeStore *tree1, *tree2, *tree;
+GtkTreeModel *model1, *model2;
+static GtkTreeIter *parents[256];
+static gint indent;
+
+static struct menu *current; // current node for SINGLE view
+static struct menu *browsed; // browsed node for SPLIT view
+
+enum {
+       COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE,
+       COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF,
+       COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD,
+       COL_NUMBER
+};
+
+static void display_list(void);
+static void display_tree(struct menu *menu);
+static void display_tree_part(void);
+static void update_tree(struct menu *src, GtkTreeIter * dst);
+static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
+static gchar **fill_row(struct menu *menu);
+static void conf_changed(void);
+
+/* Helping/Debugging Functions */
+
+
+const char *dbg_print_stype(int val)
+{
+       static char buf[256];
+
+       bzero(buf, 256);
+
+       if (val == S_UNKNOWN)
+               strcpy(buf, "unknown");
+       if (val == S_BOOLEAN)
+               strcpy(buf, "boolean");
+       if (val == S_TRISTATE)
+               strcpy(buf, "tristate");
+       if (val == S_INT)
+               strcpy(buf, "int");
+       if (val == S_HEX)
+               strcpy(buf, "hex");
+       if (val == S_STRING)
+               strcpy(buf, "string");
+       if (val == S_OTHER)
+               strcpy(buf, "other");
+
+#ifdef DEBUG
+       printf("%s", buf);
+#endif
+
+       return buf;
+}
+
+const char *dbg_print_flags(int val)
+{
+       static char buf[256];
+
+       bzero(buf, 256);
+
+       if (val & SYMBOL_CONST)
+               strcat(buf, "const/");
+       if (val & SYMBOL_CHECK)
+               strcat(buf, "check/");
+       if (val & SYMBOL_CHOICE)
+               strcat(buf, "choice/");
+       if (val & SYMBOL_CHOICEVAL)
+               strcat(buf, "choiceval/");
+       if (val & SYMBOL_VALID)
+               strcat(buf, "valid/");
+       if (val & SYMBOL_OPTIONAL)
+               strcat(buf, "optional/");
+       if (val & SYMBOL_WRITE)
+               strcat(buf, "write/");
+       if (val & SYMBOL_CHANGED)
+               strcat(buf, "changed/");
+       if (val & SYMBOL_AUTO)
+               strcat(buf, "auto/");
+
+       buf[strlen(buf) - 1] = '\0';
+#ifdef DEBUG
+       printf("%s", buf);
+#endif
+
+       return buf;
+}
+
+const char *dbg_print_ptype(int val)
+{
+       static char buf[256];
+
+       bzero(buf, 256);
+
+       if (val == P_UNKNOWN)
+               strcpy(buf, "unknown");
+       if (val == P_PROMPT)
+               strcpy(buf, "prompt");
+       if (val == P_COMMENT)
+               strcpy(buf, "comment");
+       if (val == P_MENU)
+               strcpy(buf, "menu");
+       if (val == P_DEFAULT)
+               strcpy(buf, "default");
+       if (val == P_CHOICE)
+               strcpy(buf, "choice");
+
+#ifdef DEBUG
+       printf("%s", buf);
+#endif
+
+       return buf;
+}
+
+
+void replace_button_icon(GladeXML * xml, GdkDrawable * window,
+                        GtkStyle * style, gchar * btn_name, gchar ** xpm)
+{
+       GdkPixmap *pixmap;
+       GdkBitmap *mask;
+       GtkToolButton *button;
+       GtkWidget *image;
+
+       pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
+                                             &style->bg[GTK_STATE_NORMAL],
+                                             xpm);
+
+       button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
+       image = gtk_image_new_from_pixmap(pixmap, mask);
+       gtk_widget_show(image);
+       gtk_tool_button_set_icon_widget(button, image);
+}
+
+/* Main Window Initialization */
+void init_main_window(const gchar * glade_file)
+{
+       GladeXML *xml;
+       GtkWidget *widget;
+       GtkTextBuffer *txtbuf;
+       char title[256];
+       GtkStyle *style;
+
+       xml = glade_xml_new(glade_file, "window1", NULL);
+       if (!xml)
+               g_error(_("GUI loading failed !\n"));
+       glade_xml_signal_autoconnect(xml);
+
+       main_wnd = glade_xml_get_widget(xml, "window1");
+       hpaned = glade_xml_get_widget(xml, "hpaned1");
+       vpaned = glade_xml_get_widget(xml, "vpaned1");
+       tree1_w = glade_xml_get_widget(xml, "treeview1");
+       tree2_w = glade_xml_get_widget(xml, "treeview2");
+       text_w = glade_xml_get_widget(xml, "textview3");
+
+       back_btn = glade_xml_get_widget(xml, "button1");
+       gtk_widget_set_sensitive(back_btn, FALSE);
+
+       widget = glade_xml_get_widget(xml, "show_name1");
+       gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+                                      show_name);
+
+       widget = glade_xml_get_widget(xml, "show_range1");
+       gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+                                      show_range);
+
+       widget = glade_xml_get_widget(xml, "show_data1");
+       gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+                                      show_value);
+
+       save_btn = glade_xml_get_widget(xml, "button3");
+       save_menu_item = glade_xml_get_widget(xml, "save1");
+       conf_set_changed_callback(conf_changed);
+
+       style = gtk_widget_get_style(main_wnd);
+       widget = glade_xml_get_widget(xml, "toolbar1");
+
+#if 0  /* Use stock Gtk icons instead */
+       replace_button_icon(xml, main_wnd->window, style,
+                           "button1", (gchar **) xpm_back);
+       replace_button_icon(xml, main_wnd->window, style,
+                           "button2", (gchar **) xpm_load);
+       replace_button_icon(xml, main_wnd->window, style,
+                           "button3", (gchar **) xpm_save);
+#endif
+       replace_button_icon(xml, main_wnd->window, style,
+                           "button4", (gchar **) xpm_single_view);
+       replace_button_icon(xml, main_wnd->window, style,
+                           "button5", (gchar **) xpm_split_view);
+       replace_button_icon(xml, main_wnd->window, style,
+                           "button6", (gchar **) xpm_tree_view);
+
+#if 0
+       switch (view_mode) {
+       case SINGLE_VIEW:
+               widget = glade_xml_get_widget(xml, "button4");
+               g_signal_emit_by_name(widget, "clicked");
+               break;
+       case SPLIT_VIEW:
+               widget = glade_xml_get_widget(xml, "button5");
+               g_signal_emit_by_name(widget, "clicked");
+               break;
+       case FULL_VIEW:
+               widget = glade_xml_get_widget(xml, "button6");
+               g_signal_emit_by_name(widget, "clicked");
+               break;
+       }
+#endif
+       txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+       tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
+                                         "foreground", "red",
+                                         "weight", PANGO_WEIGHT_BOLD,
+                                         NULL);
+       tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
+                                         /*"style", PANGO_STYLE_OBLIQUE, */
+                                         NULL);
+
+       sprintf(title, _("firmly.0cpm v%s Configuration"),
+               getenv("KERNELVERSION"));
+       gtk_window_set_title(GTK_WINDOW(main_wnd), title);
+
+       gtk_widget_show(main_wnd);
+}
+
+void init_tree_model(void)
+{
+       gint i;
+
+       tree = tree2 = gtk_tree_store_new(COL_NUMBER,
+                                         G_TYPE_STRING, G_TYPE_STRING,
+                                         G_TYPE_STRING, G_TYPE_STRING,
+                                         G_TYPE_STRING, G_TYPE_STRING,
+                                         G_TYPE_POINTER, GDK_TYPE_COLOR,
+                                         G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
+                                         G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+                                         G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+                                         G_TYPE_BOOLEAN);
+       model2 = GTK_TREE_MODEL(tree2);
+
+       for (parents[0] = NULL, i = 1; i < 256; i++)
+               parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
+
+       tree1 = gtk_tree_store_new(COL_NUMBER,
+                                  G_TYPE_STRING, G_TYPE_STRING,
+                                  G_TYPE_STRING, G_TYPE_STRING,
+                                  G_TYPE_STRING, G_TYPE_STRING,
+                                  G_TYPE_POINTER, GDK_TYPE_COLOR,
+                                  G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
+                                  G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+                                  G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+                                  G_TYPE_BOOLEAN);
+       model1 = GTK_TREE_MODEL(tree1);
+}
+
+void init_left_tree(void)
+{
+       GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
+       GtkCellRenderer *renderer;
+       GtkTreeSelection *sel;
+       GtkTreeViewColumn *column;
+
+       gtk_tree_view_set_model(view, model1);
+       gtk_tree_view_set_headers_visible(view, TRUE);
+       gtk_tree_view_set_rules_hint(view, FALSE);
+
+       column = gtk_tree_view_column_new();
+       gtk_tree_view_append_column(view, column);
+       gtk_tree_view_column_set_title(column, _("Options"));
+
+       renderer = gtk_cell_renderer_toggle_new();
+       gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+                                       renderer, FALSE);
+       gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+                                           renderer,
+                                           "active", COL_BTNACT,
+                                           "inconsistent", COL_BTNINC,
+                                           "visible", COL_BTNVIS,
+                                           "radio", COL_BTNRAD, NULL);
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+                                       renderer, FALSE);
+       gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+                                           renderer,
+                                           "text", COL_OPTION,
+                                           "foreground-gdk",
+                                           COL_COLOR, NULL);
+
+       sel = gtk_tree_view_get_selection(view);
+       gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
+       gtk_widget_realize(tree1_w);
+}
+
+static void renderer_edited(GtkCellRendererText * cell,
+                           const gchar * path_string,
+                           const gchar * new_text, gpointer user_data);
+static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
+                            gchar * arg1, gpointer user_data);
+
+void init_right_tree(void)
+{
+       GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
+       GtkCellRenderer *renderer;
+       GtkTreeSelection *sel;
+       GtkTreeViewColumn *column;
+       gint i;
+
+       gtk_tree_view_set_model(view, model2);
+       gtk_tree_view_set_headers_visible(view, TRUE);
+       gtk_tree_view_set_rules_hint(view, FALSE);
+
+       column = gtk_tree_view_column_new();
+       gtk_tree_view_append_column(view, column);
+       gtk_tree_view_column_set_title(column, _("Options"));
+
+       renderer = gtk_cell_renderer_pixbuf_new();
+       gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+                                       renderer, FALSE);
+       gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+                                           renderer,
+                                           "pixbuf", COL_PIXBUF,
+                                           "visible", COL_PIXVIS, NULL);
+       renderer = gtk_cell_renderer_toggle_new();
+       gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+                                       renderer, FALSE);
+       gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+                                           renderer,
+                                           "active", COL_BTNACT,
+                                           "inconsistent", COL_BTNINC,
+                                           "visible", COL_BTNVIS,
+                                           "radio", COL_BTNRAD, NULL);
+       /*g_signal_connect(G_OBJECT(renderer), "toggled",
+          G_CALLBACK(renderer_toggled), NULL); */
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+                                       renderer, FALSE);
+       gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+                                           renderer,
+                                           "text", COL_OPTION,
+                                           "foreground-gdk",
+                                           COL_COLOR, NULL);
+
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_insert_column_with_attributes(view, -1,
+                                                   _("Name"), renderer,
+                                                   "text", COL_NAME,
+                                                   "foreground-gdk",
+                                                   COL_COLOR, NULL);
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_insert_column_with_attributes(view, -1,
+                                                   "N", renderer,
+                                                   "text", COL_NO,
+                                                   "foreground-gdk",
+                                                   COL_COLOR, NULL);
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_insert_column_with_attributes(view, -1,
+                                                   "M", renderer,
+                                                   "text", COL_MOD,
+                                                   "foreground-gdk",
+                                                   COL_COLOR, NULL);
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_insert_column_with_attributes(view, -1,
+                                                   "Y", renderer,
+                                                   "text", COL_YES,
+                                                   "foreground-gdk",
+                                                   COL_COLOR, NULL);
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_insert_column_with_attributes(view, -1,
+                                                   _("Value"), renderer,
+                                                   "text", COL_VALUE,
+                                                   "editable",
+                                                   COL_EDIT,
+                                                   "foreground-gdk",
+                                                   COL_COLOR, NULL);
+       g_signal_connect(G_OBJECT(renderer), "edited",
+                        G_CALLBACK(renderer_edited), NULL);
+
+       column = gtk_tree_view_get_column(view, COL_NAME);
+       gtk_tree_view_column_set_visible(column, show_name);
+       column = gtk_tree_view_get_column(view, COL_NO);
+       gtk_tree_view_column_set_visible(column, show_range);
+       column = gtk_tree_view_get_column(view, COL_MOD);
+       gtk_tree_view_column_set_visible(column, show_range);
+       column = gtk_tree_view_get_column(view, COL_YES);
+       gtk_tree_view_column_set_visible(column, show_range);
+       column = gtk_tree_view_get_column(view, COL_VALUE);
+       gtk_tree_view_column_set_visible(column, show_value);
+
+       if (resizeable) {
+               for (i = 0; i < COL_VALUE; i++) {
+                       column = gtk_tree_view_get_column(view, i);
+                       gtk_tree_view_column_set_resizable(column, TRUE);
+               }
+       }
+
+       sel = gtk_tree_view_get_selection(view);
+       gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
+}
+
+
+/* Utility Functions */
+
+
+static void text_insert_help(struct menu *menu)
+{
+       GtkTextBuffer *buffer;
+       GtkTextIter start, end;
+       const char *prompt = _(menu_get_prompt(menu));
+       gchar *name;
+       const char *help;
+
+       help = menu_get_help(menu);
+
+       /* Gettextize if the help text not empty */
+       if ((help != 0) && (help[0] != 0))
+               help = _(help);
+
+       if (menu->sym && menu->sym->name)
+               name = g_strdup_printf(menu->sym->name);
+       else
+               name = g_strdup("");
+
+       buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+       gtk_text_buffer_get_bounds(buffer, &start, &end);
+       gtk_text_buffer_delete(buffer, &start, &end);
+       gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
+
+       gtk_text_buffer_get_end_iter(buffer, &end);
+       gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
+                                        NULL);
+       gtk_text_buffer_insert_at_cursor(buffer, " ", 1);
+       gtk_text_buffer_get_end_iter(buffer, &end);
+       gtk_text_buffer_insert_with_tags(buffer, &end, name, -1, tag1,
+                                        NULL);
+       gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
+       gtk_text_buffer_get_end_iter(buffer, &end);
+       gtk_text_buffer_insert_with_tags(buffer, &end, help, -1, tag2,
+                                        NULL);
+}
+
+
+static void text_insert_msg(const char *title, const char *message)
+{
+       GtkTextBuffer *buffer;
+       GtkTextIter start, end;
+       const char *msg = message;
+
+       buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+       gtk_text_buffer_get_bounds(buffer, &start, &end);
+       gtk_text_buffer_delete(buffer, &start, &end);
+       gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
+
+       gtk_text_buffer_get_end_iter(buffer, &end);
+       gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
+                                        NULL);
+       gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
+       gtk_text_buffer_get_end_iter(buffer, &end);
+       gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
+                                        NULL);
+}
+
+
+/* Main Windows Callbacks */
+
+void on_save_activate(GtkMenuItem * menuitem, gpointer user_data);
+gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
+                                gpointer user_data)
+{
+       GtkWidget *dialog, *label;
+       gint result;
+
+       if (!conf_get_changed())
+               return FALSE;
+
+       dialog = gtk_dialog_new_with_buttons(_("Warning !"),
+                                            GTK_WINDOW(main_wnd),
+                                            (GtkDialogFlags)
+                                            (GTK_DIALOG_MODAL |
+                                             GTK_DIALOG_DESTROY_WITH_PARENT),
+                                            GTK_STOCK_OK,
+                                            GTK_RESPONSE_YES,
+                                            GTK_STOCK_NO,
+                                            GTK_RESPONSE_NO,
+                                            GTK_STOCK_CANCEL,
+                                            GTK_RESPONSE_CANCEL, NULL);
+       gtk_dialog_set_default_response(GTK_DIALOG(dialog),
+                                       GTK_RESPONSE_CANCEL);
+
+       label = gtk_label_new(_("\nSave configuration ?\n"));
+       gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
+       gtk_widget_show(label);
+
+       result = gtk_dialog_run(GTK_DIALOG(dialog));
+       switch (result) {
+       case GTK_RESPONSE_YES:
+               on_save_activate(NULL, NULL);
+               return FALSE;
+       case GTK_RESPONSE_NO:
+               return FALSE;
+       case GTK_RESPONSE_CANCEL:
+       case GTK_RESPONSE_DELETE_EVENT:
+       default:
+               gtk_widget_destroy(dialog);
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+
+void on_window1_destroy(GtkObject * object, gpointer user_data)
+{
+       gtk_main_quit();
+}
+
+
+void
+on_window1_size_request(GtkWidget * widget,
+                       GtkRequisition * requisition, gpointer user_data)
+{
+       static gint old_h;
+       gint w, h;
+
+       if (widget->window == NULL)
+               gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
+       else
+               gdk_window_get_size(widget->window, &w, &h);
+
+       if (h == old_h)
+               return;
+       old_h = h;
+
+       gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
+}
+
+
+/* Menu & Toolbar Callbacks */
+
+
+static void
+load_filename(GtkFileSelection * file_selector, gpointer user_data)
+{
+       const gchar *fn;
+
+       fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
+                                            (user_data));
+
+       if (conf_read(fn))
+               text_insert_msg(_("Error"), _("Unable to load configuration !"));
+       else
+               display_tree(&rootmenu);
+}
+
+void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkWidget *fs;
+
+       fs = gtk_file_selection_new(_("Load file..."));
+       g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
+                        "clicked",
+                        G_CALLBACK(load_filename), (gpointer) fs);
+       g_signal_connect_swapped(GTK_OBJECT
+                                (GTK_FILE_SELECTION(fs)->ok_button),
+                                "clicked", G_CALLBACK(gtk_widget_destroy),
+                                (gpointer) fs);
+       g_signal_connect_swapped(GTK_OBJECT
+                                (GTK_FILE_SELECTION(fs)->cancel_button),
+                                "clicked", G_CALLBACK(gtk_widget_destroy),
+                                (gpointer) fs);
+       gtk_widget_show(fs);
+}
+
+
+void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       if (conf_write(NULL))
+               text_insert_msg(_("Error"), _("Unable to save configuration !"));
+}
+
+
+static void
+store_filename(GtkFileSelection * file_selector, gpointer user_data)
+{
+       const gchar *fn;
+
+       fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
+                                            (user_data));
+
+       if (conf_write(fn))
+               text_insert_msg(_("Error"), _("Unable to save configuration !"));
+
+       gtk_widget_destroy(GTK_WIDGET(user_data));
+}
+
+void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkWidget *fs;
+
+       fs = gtk_file_selection_new(_("Save file as..."));
+       g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
+                        "clicked",
+                        G_CALLBACK(store_filename), (gpointer) fs);
+       g_signal_connect_swapped(GTK_OBJECT
+                                (GTK_FILE_SELECTION(fs)->ok_button),
+                                "clicked", G_CALLBACK(gtk_widget_destroy),
+                                (gpointer) fs);
+       g_signal_connect_swapped(GTK_OBJECT
+                                (GTK_FILE_SELECTION(fs)->cancel_button),
+                                "clicked", G_CALLBACK(gtk_widget_destroy),
+                                (gpointer) fs);
+       gtk_widget_show(fs);
+}
+
+
+void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       if (!on_window1_delete_event(NULL, NULL, NULL))
+               gtk_widget_destroy(GTK_WIDGET(main_wnd));
+}
+
+
+void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkTreeViewColumn *col;
+
+       show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
+       col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
+       if (col)
+               gtk_tree_view_column_set_visible(col, show_name);
+}
+
+
+void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkTreeViewColumn *col;
+
+       show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
+       col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
+       if (col)
+               gtk_tree_view_column_set_visible(col, show_range);
+       col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
+       if (col)
+               gtk_tree_view_column_set_visible(col, show_range);
+       col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
+       if (col)
+               gtk_tree_view_column_set_visible(col, show_range);
+
+}
+
+
+void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkTreeViewColumn *col;
+
+       show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
+       col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
+       if (col)
+               gtk_tree_view_column_set_visible(col, show_value);
+}
+
+
+void
+on_show_all_options1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       show_all = GTK_CHECK_MENU_ITEM(menuitem)->active;
+
+       gtk_tree_store_clear(tree2);
+       display_tree(&rootmenu);        // instead of update_tree to speed-up
+}
+
+
+void
+on_show_debug_info1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       show_debug = GTK_CHECK_MENU_ITEM(menuitem)->active;
+       update_tree(&rootmenu, NULL);
+}
+
+
+void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkWidget *dialog;
+       const gchar *intro_text = _(
+           "Welcome to gkc, the GTK+ graphical kernel configuration tool\n"
+           "for firmly.0cpm.\n"
+           "For each option, a blank box indicates the feature is disabled, a\n"
+           "check indicates it is enabled, and a dot indicates that it is to\n"
+           "be compiled as a module.  Clicking on the box will cycle through the three states.\n"
+           "\n"
+           "If you do not see an option (e.g., a device driver) that you\n"
+           "believe should be present, try turning on Show All Options\n"
+           "under the Options menu.\n"
+           "Although there is no cross reference yet to help you figure out\n"
+           "what other options must be enabled to support the option you\n"
+           "are interested in, you can still view the help of a grayed-out\n"
+           "option.\n"
+           "\n"
+           "Toggling Show Debug Info under the Options menu will show \n"
+           "the dependencies, which you can then match by examining other options.");
+
+       dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+                                       GTK_DIALOG_DESTROY_WITH_PARENT,
+                                       GTK_MESSAGE_INFO,
+                                       GTK_BUTTONS_CLOSE, intro_text);
+       g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+                                G_CALLBACK(gtk_widget_destroy),
+                                GTK_OBJECT(dialog));
+       gtk_widget_show_all(dialog);
+}
+
+
+void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkWidget *dialog;
+       const gchar *about_text =
+           _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
+             "Based on the source code from Roman Zippel.\n");
+
+       dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+                                       GTK_DIALOG_DESTROY_WITH_PARENT,
+                                       GTK_MESSAGE_INFO,
+                                       GTK_BUTTONS_CLOSE, about_text);
+       g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+                                G_CALLBACK(gtk_widget_destroy),
+                                GTK_OBJECT(dialog));
+       gtk_widget_show_all(dialog);
+}
+
+
+void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkWidget *dialog;
+       const gchar *license_text =
+           _("gkc is released under the terms of the GNU GPL v2.\n"
+             "For more information, please see the source code or\n"
+             "visit http://www.fsf.org/licenses/licenses.html\n");
+
+       dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+                                       GTK_DIALOG_DESTROY_WITH_PARENT,
+                                       GTK_MESSAGE_INFO,
+                                       GTK_BUTTONS_CLOSE, license_text);
+       g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+                                G_CALLBACK(gtk_widget_destroy),
+                                GTK_OBJECT(dialog));
+       gtk_widget_show_all(dialog);
+}
+
+
+void on_back_clicked(GtkButton * button, gpointer user_data)
+{
+       enum prop_type ptype;
+
+       current = current->parent;
+       ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
+       if (ptype != P_MENU)
+               current = current->parent;
+       display_tree_part();
+
+       if (current == &rootmenu)
+               gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_load_clicked(GtkButton * button, gpointer user_data)
+{
+       on_load1_activate(NULL, user_data);
+}
+
+
+void on_single_clicked(GtkButton * button, gpointer user_data)
+{
+       view_mode = SINGLE_VIEW;
+       gtk_paned_set_position(GTK_PANED(hpaned), 0);
+       gtk_widget_hide(tree1_w);
+       current = &rootmenu;
+       display_tree_part();
+}
+
+
+void on_split_clicked(GtkButton * button, gpointer user_data)
+{
+       gint w, h;
+       view_mode = SPLIT_VIEW;
+       gtk_widget_show(tree1_w);
+       gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
+       gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
+       if (tree2)
+               gtk_tree_store_clear(tree2);
+       display_list();
+
+       /* Disable back btn, like in full mode. */
+       gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_full_clicked(GtkButton * button, gpointer user_data)
+{
+       view_mode = FULL_VIEW;
+       gtk_paned_set_position(GTK_PANED(hpaned), 0);
+       gtk_widget_hide(tree1_w);
+       if (tree2)
+               gtk_tree_store_clear(tree2);
+       display_tree(&rootmenu);
+       gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_collapse_clicked(GtkButton * button, gpointer user_data)
+{
+       gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
+}
+
+
+void on_expand_clicked(GtkButton * button, gpointer user_data)
+{
+       gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
+}
+
+
+/* CTree Callbacks */
+
+/* Change hex/int/string value in the cell */
+static void renderer_edited(GtkCellRendererText * cell,
+                           const gchar * path_string,
+                           const gchar * new_text, gpointer user_data)
+{
+       GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
+       GtkTreeIter iter;
+       const char *old_def, *new_def;
+       struct menu *menu;
+       struct symbol *sym;
+
+       if (!gtk_tree_model_get_iter(model2, &iter, path))
+               return;
+
+       gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+       sym = menu->sym;
+
+       gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
+       new_def = new_text;
+
+       sym_set_string_value(sym, new_def);
+
+       update_tree(&rootmenu, NULL);
+
+       gtk_tree_path_free(path);
+}
+
+/* Change the value of a symbol and update the tree */
+static void change_sym_value(struct menu *menu, gint col)
+{
+       struct symbol *sym = menu->sym;
+       tristate oldval, newval;
+
+       if (!sym)
+               return;
+
+       if (col == COL_NO)
+               newval = no;
+       else if (col == COL_MOD)
+               newval = mod;
+       else if (col == COL_YES)
+               newval = yes;
+       else
+               return;
+
+       switch (sym_get_type(sym)) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               oldval = sym_get_tristate_value(sym);
+               if (!sym_tristate_within_range(sym, newval))
+                       newval = yes;
+               sym_set_tristate_value(sym, newval);
+               if (view_mode == FULL_VIEW)
+                       update_tree(&rootmenu, NULL);
+               else if (view_mode == SPLIT_VIEW) {
+                       update_tree(browsed, NULL);
+                       display_list();
+               }
+               else if (view_mode == SINGLE_VIEW)
+                       display_tree_part();    //fixme: keep exp/coll
+               break;
+       case S_INT:
+       case S_HEX:
+       case S_STRING:
+       default:
+               break;
+       }
+}
+
+static void toggle_sym_value(struct menu *menu)
+{
+       if (!menu->sym)
+               return;
+
+       sym_toggle_tristate_value(menu->sym);
+       if (view_mode == FULL_VIEW)
+               update_tree(&rootmenu, NULL);
+       else if (view_mode == SPLIT_VIEW) {
+               update_tree(browsed, NULL);
+               display_list();
+       }
+       else if (view_mode == SINGLE_VIEW)
+               display_tree_part();    //fixme: keep exp/coll
+}
+
+static void renderer_toggled(GtkCellRendererToggle * cell,
+                            gchar * path_string, gpointer user_data)
+{
+       GtkTreePath *path, *sel_path = NULL;
+       GtkTreeIter iter, sel_iter;
+       GtkTreeSelection *sel;
+       struct menu *menu;
+
+       path = gtk_tree_path_new_from_string(path_string);
+       if (!gtk_tree_model_get_iter(model2, &iter, path))
+               return;
+
+       sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
+       if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
+               sel_path = gtk_tree_model_get_path(model2, &sel_iter);
+       if (!sel_path)
+               goto out1;
+       if (gtk_tree_path_compare(path, sel_path))
+               goto out2;
+
+       gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+       toggle_sym_value(menu);
+
+      out2:
+       gtk_tree_path_free(sel_path);
+      out1:
+       gtk_tree_path_free(path);
+}
+
+static gint column2index(GtkTreeViewColumn * column)
+{
+       gint i;
+
+       for (i = 0; i < COL_NUMBER; i++) {
+               GtkTreeViewColumn *col;
+
+               col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
+               if (col == column)
+                       return i;
+       }
+
+       return -1;
+}
+
+
+/* User click: update choice (full) or goes down (single) */
+gboolean
+on_treeview2_button_press_event(GtkWidget * widget,
+                               GdkEventButton * event, gpointer user_data)
+{
+       GtkTreeView *view = GTK_TREE_VIEW(widget);
+       GtkTreePath *path;
+       GtkTreeViewColumn *column;
+       GtkTreeIter iter;
+       struct menu *menu;
+       gint col;
+
+#if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
+       gint tx = (gint) event->x;
+       gint ty = (gint) event->y;
+       gint cx, cy;
+
+       gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
+                                     &cy);
+#else
+       gtk_tree_view_get_cursor(view, &path, &column);
+#endif
+       if (path == NULL)
+               return FALSE;
+
+       if (!gtk_tree_model_get_iter(model2, &iter, path))
+               return FALSE;
+       gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+
+       col = column2index(column);
+       if (event->type == GDK_2BUTTON_PRESS) {
+               enum prop_type ptype;
+               ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+
+               if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
+                       // goes down into menu
+                       current = menu;
+                       display_tree_part();
+                       gtk_widget_set_sensitive(back_btn, TRUE);
+               } else if ((col == COL_OPTION)) {
+                       toggle_sym_value(menu);
+                       gtk_tree_view_expand_row(view, path, TRUE);
+               }
+       } else {
+               if (col == COL_VALUE) {
+                       toggle_sym_value(menu);
+                       gtk_tree_view_expand_row(view, path, TRUE);
+               } else if (col == COL_NO || col == COL_MOD
+                          || col == COL_YES) {
+                       change_sym_value(menu, col);
+                       gtk_tree_view_expand_row(view, path, TRUE);
+               }
+       }
+
+       return FALSE;
+}
+
+/* Key pressed: update choice */
+gboolean
+on_treeview2_key_press_event(GtkWidget * widget,
+                            GdkEventKey * event, gpointer user_data)
+{
+       GtkTreeView *view = GTK_TREE_VIEW(widget);
+       GtkTreePath *path;
+       GtkTreeViewColumn *column;
+       GtkTreeIter iter;
+       struct menu *menu;
+       gint col;
+
+       gtk_tree_view_get_cursor(view, &path, &column);
+       if (path == NULL)
+               return FALSE;
+
+       if (event->keyval == GDK_space) {
+               if (gtk_tree_view_row_expanded(view, path))
+                       gtk_tree_view_collapse_row(view, path);
+               else
+                       gtk_tree_view_expand_row(view, path, FALSE);
+               return TRUE;
+       }
+       if (event->keyval == GDK_KP_Enter) {
+       }
+       if (widget == tree1_w)
+               return FALSE;
+
+       gtk_tree_model_get_iter(model2, &iter, path);
+       gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+
+       if (!strcasecmp(event->string, "n"))
+               col = COL_NO;
+       else if (!strcasecmp(event->string, "m"))
+               col = COL_MOD;
+       else if (!strcasecmp(event->string, "y"))
+               col = COL_YES;
+       else
+               col = -1;
+       change_sym_value(menu, col);
+
+       return FALSE;
+}
+
+
+/* Row selection changed: update help */
+void
+on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
+{
+       GtkTreeSelection *selection;
+       GtkTreeIter iter;
+       struct menu *menu;
+
+       selection = gtk_tree_view_get_selection(treeview);
+       if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
+               gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+               text_insert_help(menu);
+       }
+}
+
+
+/* User click: display sub-tree in the right frame. */
+gboolean
+on_treeview1_button_press_event(GtkWidget * widget,
+                               GdkEventButton * event, gpointer user_data)
+{
+       GtkTreeView *view = GTK_TREE_VIEW(widget);
+       GtkTreePath *path;
+       GtkTreeViewColumn *column;
+       GtkTreeIter iter;
+       struct menu *menu;
+
+       gint tx = (gint) event->x;
+       gint ty = (gint) event->y;
+       gint cx, cy;
+
+       gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
+                                     &cy);
+       if (path == NULL)
+               return FALSE;
+
+       gtk_tree_model_get_iter(model1, &iter, path);
+       gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
+
+       if (event->type == GDK_2BUTTON_PRESS) {
+               toggle_sym_value(menu);
+               current = menu;
+               display_tree_part();
+       } else {
+               browsed = menu;
+               display_tree_part();
+       }
+
+       gtk_widget_realize(tree2_w);
+       gtk_tree_view_set_cursor(view, path, NULL, FALSE);
+       gtk_widget_grab_focus(tree2_w);
+
+       return FALSE;
+}
+
+
+/* Fill a row of strings */
+static gchar **fill_row(struct menu *menu)
+{
+       static gchar *row[COL_NUMBER];
+       struct symbol *sym = menu->sym;
+       const char *def;
+       int stype;
+       tristate val;
+       enum prop_type ptype;
+       int i;
+
+       for (i = COL_OPTION; i <= COL_COLOR; i++)
+               g_free(row[i]);
+       bzero(row, sizeof(row));
+
+       row[COL_OPTION] =
+           g_strdup_printf("%s %s", _(menu_get_prompt(menu)),
+                           sym && sym_has_value(sym) ? "(NEW)" : "");
+
+       if (show_all && !menu_is_visible(menu))
+               row[COL_COLOR] = g_strdup("DarkGray");
+       else
+               row[COL_COLOR] = g_strdup("Black");
+
+       ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+       switch (ptype) {
+       case P_MENU:
+               row[COL_PIXBUF] = (gchar *) xpm_menu;
+               if (view_mode == SINGLE_VIEW)
+                       row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
+               row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+               break;
+       case P_COMMENT:
+               row[COL_PIXBUF] = (gchar *) xpm_void;
+               row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
+               row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+               break;
+       default:
+               row[COL_PIXBUF] = (gchar *) xpm_void;
+               row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
+               row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
+               break;
+       }
+
+       if (!sym)
+               return row;
+       row[COL_NAME] = g_strdup(sym->name);
+
+       sym_calc_value(sym);
+       sym->flags &= ~SYMBOL_CHANGED;
+
+       if (sym_is_choice(sym)) {       // parse childs for getting final value
+               struct menu *child;
+               struct symbol *def_sym = sym_get_choice_value(sym);
+               struct menu *def_menu = NULL;
+
+               row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+
+               for (child = menu->list; child; child = child->next) {
+                       if (menu_is_visible(child)
+                           && child->sym == def_sym)
+                               def_menu = child;
+               }
+
+               if (def_menu)
+                       row[COL_VALUE] =
+                           g_strdup(_(menu_get_prompt(def_menu)));
+       }
+       if (sym->flags & SYMBOL_CHOICEVAL)
+               row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
+
+       stype = sym_get_type(sym);
+       switch (stype) {
+       case S_BOOLEAN:
+               if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
+                       row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
+               if (sym_is_choice(sym))
+                       break;
+       case S_TRISTATE:
+               val = sym_get_tristate_value(sym);
+               switch (val) {
+               case no:
+                       row[COL_NO] = g_strdup("N");
+                       row[COL_VALUE] = g_strdup("N");
+                       row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
+                       row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
+                       break;
+               case mod:
+                       row[COL_MOD] = g_strdup("M");
+                       row[COL_VALUE] = g_strdup("M");
+                       row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
+                       break;
+               case yes:
+                       row[COL_YES] = g_strdup("Y");
+                       row[COL_VALUE] = g_strdup("Y");
+                       row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
+                       row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
+                       break;
+               }
+
+               if (val != no && sym_tristate_within_range(sym, no))
+                       row[COL_NO] = g_strdup("_");
+               if (val != mod && sym_tristate_within_range(sym, mod))
+                       row[COL_MOD] = g_strdup("_");
+               if (val != yes && sym_tristate_within_range(sym, yes))
+                       row[COL_YES] = g_strdup("_");
+               break;
+       case S_INT:
+       case S_HEX:
+       case S_STRING:
+               def = sym_get_string_value(sym);
+               row[COL_VALUE] = g_strdup(def);
+               row[COL_EDIT] = GINT_TO_POINTER(TRUE);
+               row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+               break;
+       }
+
+       return row;
+}
+
+
+/* Set the node content with a row of strings */
+static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
+{
+       GdkColor color;
+       gboolean success;
+       GdkPixbuf *pix;
+
+       pix = gdk_pixbuf_new_from_xpm_data((const char **)
+                                          row[COL_PIXBUF]);
+
+       gdk_color_parse(row[COL_COLOR], &color);
+       gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
+                                 FALSE, FALSE, &success);
+
+       gtk_tree_store_set(tree, node,
+                          COL_OPTION, row[COL_OPTION],
+                          COL_NAME, row[COL_NAME],
+                          COL_NO, row[COL_NO],
+                          COL_MOD, row[COL_MOD],
+                          COL_YES, row[COL_YES],
+                          COL_VALUE, row[COL_VALUE],
+                          COL_MENU, (gpointer) menu,
+                          COL_COLOR, &color,
+                          COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
+                          COL_PIXBUF, pix,
+                          COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
+                          COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
+                          COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
+                          COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
+                          COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
+                          -1);
+
+       g_object_unref(pix);
+}
+
+
+/* Add a node to the tree */
+static void place_node(struct menu *menu, char **row)
+{
+       GtkTreeIter *parent = parents[indent - 1];
+       GtkTreeIter *node = parents[indent];
+
+       gtk_tree_store_append(tree, node, parent);
+       set_node(node, menu, row);
+}
+
+
+/* Find a node in the GTK+ tree */
+static GtkTreeIter found;
+
+/*
+ * Find a menu in the GtkTree starting at parent.
+ */
+GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
+                                   struct menu *tofind)
+{
+       GtkTreeIter iter;
+       GtkTreeIter *child = &iter;
+       gboolean valid;
+       GtkTreeIter *ret;
+
+       valid = gtk_tree_model_iter_children(model2, child, parent);
+       while (valid) {
+               struct menu *menu;
+
+               gtk_tree_model_get(model2, child, 6, &menu, -1);
+
+               if (menu == tofind) {
+                       memcpy(&found, child, sizeof(GtkTreeIter));
+                       return &found;
+               }
+
+               ret = gtktree_iter_find_node(child, tofind);
+               if (ret)
+                       return ret;
+
+               valid = gtk_tree_model_iter_next(model2, child);
+       }
+
+       return NULL;
+}
+
+
+/*
+ * Update the tree by adding/removing entries
+ * Does not change other nodes
+ */
+static void update_tree(struct menu *src, GtkTreeIter * dst)
+{
+       struct menu *child1;
+       GtkTreeIter iter, tmp;
+       GtkTreeIter *child2 = &iter;
+       gboolean valid;
+       GtkTreeIter *sibling;
+       struct symbol *sym;
+       struct property *prop;
+       struct menu *menu1, *menu2;
+
+       if (src == &rootmenu)
+               indent = 1;
+
+       valid = gtk_tree_model_iter_children(model2, child2, dst);
+       for (child1 = src->list; child1; child1 = child1->next) {
+
+               prop = child1->prompt;
+               sym = child1->sym;
+
+             reparse:
+               menu1 = child1;
+               if (valid)
+                       gtk_tree_model_get(model2, child2, COL_MENU,
+                                          &menu2, -1);
+               else
+                       menu2 = NULL;   // force adding of a first child
+
+#ifdef DEBUG
+               printf("%*c%s | %s\n", indent, ' ',
+                      menu1 ? menu_get_prompt(menu1) : "nil",
+                      menu2 ? menu_get_prompt(menu2) : "nil");
+#endif
+
+               if (!menu_is_visible(child1) && !show_all) {    // remove node
+                       if (gtktree_iter_find_node(dst, menu1) != NULL) {
+                               memcpy(&tmp, child2, sizeof(GtkTreeIter));
+                               valid = gtk_tree_model_iter_next(model2,
+                                                                child2);
+                               gtk_tree_store_remove(tree2, &tmp);
+                               if (!valid)
+                                       return; // next parent
+                               else
+                                       goto reparse;   // next child
+                       } else
+                               continue;
+               }
+
+               if (menu1 != menu2) {
+                       if (gtktree_iter_find_node(dst, menu1) == NULL) {       // add node
+                               if (!valid && !menu2)
+                                       sibling = NULL;
+                               else
+                                       sibling = child2;
+                               gtk_tree_store_insert_before(tree2,
+                                                            child2,
+                                                            dst, sibling);
+                               set_node(child2, menu1, fill_row(menu1));
+                               if (menu2 == NULL)
+                                       valid = TRUE;
+                       } else {        // remove node
+                               memcpy(&tmp, child2, sizeof(GtkTreeIter));
+                               valid = gtk_tree_model_iter_next(model2,
+                                                                child2);
+                               gtk_tree_store_remove(tree2, &tmp);
+                               if (!valid)
+                                       return; // next parent
+                               else
+                                       goto reparse;   // next child
+                       }
+               } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
+                       set_node(child2, menu1, fill_row(menu1));
+               }
+
+               indent++;
+               update_tree(child1, child2);
+               indent--;
+
+               valid = gtk_tree_model_iter_next(model2, child2);
+       }
+}
+
+
+/* Display the whole tree (single/split/full view) */
+static void display_tree(struct menu *menu)
+{
+       struct symbol *sym;
+       struct property *prop;
+       struct menu *child;
+       enum prop_type ptype;
+
+       if (menu == &rootmenu) {
+               indent = 1;
+               current = &rootmenu;
+       }
+
+       for (child = menu->list; child; child = child->next) {
+               prop = child->prompt;
+               sym = child->sym;
+               ptype = prop ? prop->type : P_UNKNOWN;
+
+               if (sym)
+                       sym->flags &= ~SYMBOL_CHANGED;
+
+               if ((view_mode == SPLIT_VIEW)
+                   && !(child->flags & MENU_ROOT) && (tree == tree1))
+                       continue;
+
+               if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
+                   && (tree == tree2))
+                       continue;
+
+               if (menu_is_visible(child) || show_all)
+                       place_node(child, fill_row(child));
+#ifdef DEBUG
+               printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
+               printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
+               dbg_print_ptype(ptype);
+               printf(" | ");
+               if (sym) {
+                       dbg_print_stype(sym->type);
+                       printf(" | ");
+                       dbg_print_flags(sym->flags);
+                       printf("\n");
+               } else
+                       printf("\n");
+#endif
+               if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
+                   && (tree == tree2))
+                       continue;
+/*
+                if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
+                   || (view_mode == FULL_VIEW)
+                   || (view_mode == SPLIT_VIEW))*/
+               if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
+                   || (view_mode == FULL_VIEW)
+                   || (view_mode == SPLIT_VIEW)) {
+                       indent++;
+                       display_tree(child);
+                       indent--;
+               }
+       }
+}
+
+/* Display a part of the tree starting at current node (single/split view) */
+static void display_tree_part(void)
+{
+       if (tree2)
+               gtk_tree_store_clear(tree2);
+       if (view_mode == SINGLE_VIEW)
+               display_tree(current);
+       else if (view_mode == SPLIT_VIEW)
+               display_tree(browsed);
+       gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
+}
+
+/* Display the list in the left frame (split view) */
+static void display_list(void)
+{
+       if (tree1)
+               gtk_tree_store_clear(tree1);
+
+       tree = tree1;
+       display_tree(&rootmenu);
+       gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
+       tree = tree2;
+}
+
+void fixup_rootmenu(struct menu *menu)
+{
+       struct menu *child;
+       static int menu_cnt = 0;
+
+       menu->flags |= MENU_ROOT;
+       for (child = menu->list; child; child = child->next) {
+               if (child->prompt && child->prompt->type == P_MENU) {
+                       menu_cnt++;
+                       fixup_rootmenu(child);
+                       menu_cnt--;
+               } else if (!menu_cnt)
+                       fixup_rootmenu(child);
+       }
+}
+
+
+/* Main */
+int main(int ac, char *av[])
+{
+       const char *name;
+       char *env;
+       gchar *glade_file;
+
+#ifndef LKC_DIRECT_LINK
+       kconfig_load();
+#endif
+
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       bind_textdomain_codeset(PACKAGE, "UTF-8");
+       textdomain(PACKAGE);
+
+       /* GTK stuffs */
+       gtk_set_locale();
+       gtk_init(&ac, &av);
+       glade_init();
+
+       //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
+       //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
+
+       /* Determine GUI path */
+       env = getenv(SRCTREE);
+       if (env)
+               glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
+       else if (av[0][0] == '/')
+               glade_file = g_strconcat(av[0], ".glade", NULL);
+       else
+               glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
+
+       /* Load the interface and connect signals */
+       init_main_window(glade_file);
+       init_tree_model();
+       init_left_tree();
+       init_right_tree();
+
+       /* Conf stuffs */
+       if (ac > 1 && av[1][0] == '-') {
+               switch (av[1][1]) {
+               case 'a':
+                       //showAll = 1;
+                       break;
+               case 'h':
+               case '?':
+                       printf("%s <config>\n", av[0]);
+                       exit(0);
+               }
+               name = av[2];
+       } else
+               name = av[1];
+
+       conf_parse(name);
+       fixup_rootmenu(&rootmenu);
+       conf_read(NULL);
+
+       switch (view_mode) {
+       case SINGLE_VIEW:
+               display_tree_part();
+               break;
+       case SPLIT_VIEW:
+               display_list();
+               break;
+       case FULL_VIEW:
+               display_tree(&rootmenu);
+               break;
+       }
+
+       gtk_main();
+
+       return 0;
+}
+
+static void conf_changed(void)
+{
+       bool changed = conf_get_changed();
+       gtk_widget_set_sensitive(save_btn, changed);
+       gtk_widget_set_sensitive(save_menu_item, changed);
+}
diff --git a/bin/kconfig/gconf.glade b/bin/kconfig/gconf.glade
new file mode 100644 (file)
index 0000000..803233f
--- /dev/null
@@ -0,0 +1,648 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="window1">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">Gtk Kernel Configurator</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="default_width">640</property>
+  <property name="default_height">480</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <signal name="destroy" handler="on_window1_destroy" object="window1"/>
+  <signal name="size_request" handler="on_window1_size_request" object="vpaned1" last_modification_time="Fri, 11 Jan 2002 16:17:11 GMT"/>
+  <signal name="delete_event" handler="on_window1_delete_event" object="window1" last_modification_time="Sun, 09 Mar 2003 19:42:46 GMT"/>
+
+  <child>
+    <widget class="GtkVBox" id="vbox1">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child>
+       <widget class="GtkMenuBar" id="menubar1">
+         <property name="visible">True</property>
+
+         <child>
+           <widget class="GtkMenuItem" id="file1">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">_File</property>
+             <property name="use_underline">True</property>
+
+             <child>
+               <widget class="GtkMenu" id="file1_menu">
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="load1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Load a config file</property>
+                     <property name="label" translatable="yes">_Load</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_load1_activate"/>
+                     <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image39">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-open</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="save1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Save the config in .config</property>
+                     <property name="label" translatable="yes">_Save</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_save_activate"/>
+                     <accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image40">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-save</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="save_as1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Save the config in a file</property>
+                     <property name="label" translatable="yes">Save _as</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_save_as1_activate"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image41">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-save-as</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkSeparatorMenuItem" id="separator1">
+                     <property name="visible">True</property>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="quit1">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">_Quit</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_quit1_activate"/>
+                     <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image42">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-quit</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+           </widget>
+         </child>
+
+         <child>
+           <widget class="GtkMenuItem" id="options1">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">_Options</property>
+             <property name="use_underline">True</property>
+
+             <child>
+               <widget class="GtkMenu" id="options1_menu">
+
+                 <child>
+                   <widget class="GtkCheckMenuItem" id="show_name1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Show name</property>
+                     <property name="label" translatable="yes">Show _name</property>
+                     <property name="use_underline">True</property>
+                     <property name="active">False</property>
+                     <signal name="activate" handler="on_show_name1_activate"/>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCheckMenuItem" id="show_range1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Show range (Y/M/N)</property>
+                     <property name="label" translatable="yes">Show _range</property>
+                     <property name="use_underline">True</property>
+                     <property name="active">False</property>
+                     <signal name="activate" handler="on_show_range1_activate"/>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCheckMenuItem" id="show_data1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Show value of the option</property>
+                     <property name="label" translatable="yes">Show _data</property>
+                     <property name="use_underline">True</property>
+                     <property name="active">False</property>
+                     <signal name="activate" handler="on_show_data1_activate"/>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkSeparatorMenuItem" id="separator2">
+                     <property name="visible">True</property>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCheckMenuItem" id="show_all_options1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Show all options</property>
+                     <property name="label" translatable="yes">Show all _options</property>
+                     <property name="use_underline">True</property>
+                     <property name="active">False</property>
+                     <signal name="activate" handler="on_show_all_options1_activate"/>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCheckMenuItem" id="show_debug_info1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Show masked options</property>
+                     <property name="label" translatable="yes">Show _debug info</property>
+                     <property name="use_underline">True</property>
+                     <property name="active">False</property>
+                     <signal name="activate" handler="on_show_debug_info1_activate"/>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+           </widget>
+         </child>
+
+         <child>
+           <widget class="GtkMenuItem" id="help1">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">_Help</property>
+             <property name="use_underline">True</property>
+
+             <child>
+               <widget class="GtkMenu" id="help1_menu">
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="introduction1">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">_Introduction</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_introduction1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+                     <accelerator key="I" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image43">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-dialog-question</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="about1">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">_About</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_about1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+                     <accelerator key="A" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image44">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-properties</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="license1">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">_License</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_license1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image45">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-justify-fill</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">False</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkHandleBox" id="handlebox1">
+         <property name="visible">True</property>
+         <property name="shadow_type">GTK_SHADOW_OUT</property>
+         <property name="handle_position">GTK_POS_LEFT</property>
+         <property name="snap_edge">GTK_POS_TOP</property>
+
+         <child>
+           <widget class="GtkToolbar" id="toolbar1">
+             <property name="visible">True</property>
+             <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
+             <property name="toolbar_style">GTK_TOOLBAR_BOTH</property>
+             <property name="tooltips">True</property>
+             <property name="show_arrow">True</property>
+
+             <child>
+               <widget class="GtkToolButton" id="button1">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Goes up of one level (single view)</property>
+                 <property name="label" translatable="yes">Back</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-undo</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_back_clicked"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolItem" id="toolitem1">
+                 <property name="visible">True</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+
+                 <child>
+                   <widget class="GtkVSeparator" id="vseparator1">
+                     <property name="visible">True</property>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button2">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Load a config file</property>
+                 <property name="label" translatable="yes">Load</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-open</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_load_clicked"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button3">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Save a config file</property>
+                 <property name="label" translatable="yes">Save</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-save</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_save_activate"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolItem" id="toolitem2">
+                 <property name="visible">True</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+
+                 <child>
+                   <widget class="GtkVSeparator" id="vseparator2">
+                     <property name="visible">True</property>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button4">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Single view</property>
+                 <property name="label" translatable="yes">Single</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-missing-image</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_single_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:39 GMT"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button5">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Split view</property>
+                 <property name="label" translatable="yes">Split</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-missing-image</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_split_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:45 GMT"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button6">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Full view</property>
+                 <property name="label" translatable="yes">Full</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-missing-image</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_full_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:50 GMT"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolItem" id="toolitem3">
+                 <property name="visible">True</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+
+                 <child>
+                   <widget class="GtkVSeparator" id="vseparator3">
+                     <property name="visible">True</property>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button7">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Collapse the whole tree in the right frame</property>
+                 <property name="label" translatable="yes">Collapse</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-remove</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_collapse_clicked"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button8">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Expand the whole tree in the right frame</property>
+                 <property name="label" translatable="yes">Expand</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-add</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_expand_clicked"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">False</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkHPaned" id="hpaned1">
+         <property name="width_request">1</property>
+         <property name="visible">True</property>
+         <property name="can_focus">True</property>
+         <property name="position">0</property>
+
+         <child>
+           <widget class="GtkScrolledWindow" id="scrolledwindow1">
+             <property name="visible">True</property>
+             <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+             <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+             <property name="shadow_type">GTK_SHADOW_IN</property>
+             <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+             <child>
+               <widget class="GtkTreeView" id="treeview1">
+                 <property name="visible">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="headers_visible">True</property>
+                 <property name="rules_hint">False</property>
+                 <property name="reorderable">False</property>
+                 <property name="enable_search">True</property>
+                 <signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:58:22 GMT"/>
+                 <signal name="button_press_event" handler="on_treeview1_button_press_event" last_modification_time="Sun, 12 Jan 2003 16:03:52 GMT"/>
+                 <signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 16:11:44 GMT"/>
+               </widget>
+             </child>
+           </widget>
+           <packing>
+             <property name="shrink">True</property>
+             <property name="resize">False</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkVPaned" id="vpaned1">
+             <property name="visible">True</property>
+             <property name="can_focus">True</property>
+             <property name="position">0</property>
+
+             <child>
+               <widget class="GtkScrolledWindow" id="scrolledwindow2">
+                 <property name="visible">True</property>
+                 <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                 <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                 <property name="shadow_type">GTK_SHADOW_IN</property>
+                 <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+                 <child>
+                   <widget class="GtkTreeView" id="treeview2">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="has_focus">True</property>
+                     <property name="headers_visible">True</property>
+                     <property name="rules_hint">False</property>
+                     <property name="reorderable">False</property>
+                     <property name="enable_search">True</property>
+                     <signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:57:55 GMT"/>
+                     <signal name="button_press_event" handler="on_treeview2_button_press_event" last_modification_time="Sun, 12 Jan 2003 15:57:58 GMT"/>
+                     <signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 15:58:01 GMT"/>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="shrink">True</property>
+                 <property name="resize">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkScrolledWindow" id="scrolledwindow3">
+                 <property name="visible">True</property>
+                 <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+                 <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                 <property name="shadow_type">GTK_SHADOW_IN</property>
+                 <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+                 <child>
+                   <widget class="GtkTextView" id="textview3">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="editable">False</property>
+                     <property name="overwrite">False</property>
+                     <property name="accepts_tab">True</property>
+                     <property name="justification">GTK_JUSTIFY_LEFT</property>
+                     <property name="wrap_mode">GTK_WRAP_WORD</property>
+                     <property name="cursor_visible">True</property>
+                     <property name="pixels_above_lines">0</property>
+                     <property name="pixels_below_lines">0</property>
+                     <property name="pixels_inside_wrap">0</property>
+                     <property name="left_margin">0</property>
+                     <property name="right_margin">0</property>
+                     <property name="indent">0</property>
+                     <property name="text" translatable="yes">Sorry, no help available for this option yet.</property>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="shrink">True</property>
+                 <property name="resize">True</property>
+               </packing>
+             </child>
+           </widget>
+           <packing>
+             <property name="shrink">True</property>
+             <property name="resize">True</property>
+           </packing>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">True</property>
+         <property name="fill">True</property>
+       </packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+</glade-interface>
diff --git a/bin/kconfig/images.c b/bin/kconfig/images.c
new file mode 100644 (file)
index 0000000..d4f84bd
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+static const char *xpm_load[] = {
+"22 22 5 1",
+". c None",
+"# c #000000",
+"c c #838100",
+"a c #ffff00",
+"b c #ffffff",
+"......................",
+"......................",
+"......................",
+"............####....#.",
+"...........#....##.##.",
+"..................###.",
+".................####.",
+".####...........#####.",
+"#abab##########.......",
+"#babababababab#.......",
+"#ababababababa#.......",
+"#babababababab#.......",
+"#ababab###############",
+"#babab##cccccccccccc##",
+"#abab##cccccccccccc##.",
+"#bab##cccccccccccc##..",
+"#ab##cccccccccccc##...",
+"#b##cccccccccccc##....",
+"###cccccccccccc##.....",
+"##cccccccccccc##......",
+"###############.......",
+"......................"};
+
+static const char *xpm_save[] = {
+"22 22 5 1",
+". c None",
+"# c #000000",
+"a c #838100",
+"b c #c5c2c5",
+"c c #cdb6d5",
+"......................",
+".####################.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbcbb####.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aaa############aaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaa#############aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+"..##################..",
+"......................"};
+
+static const char *xpm_back[] = {
+"22 22 3 1",
+". c None",
+"# c #000083",
+"a c #838183",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................",
+"...........######a....",
+"..#......##########...",
+"..##...####......##a..",
+"..###.###.........##..",
+"..######..........##..",
+"..#####...........##..",
+"..######..........##..",
+"..#######.........##..",
+"..########.......##a..",
+"...............a###...",
+"...............###....",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................"};
+
+static const char *xpm_tree_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......................",
+"......................"};
+
+static const char *xpm_single_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"......................",
+"......................"};
+
+static const char *xpm_split_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......................",
+"......................"};
+
+static const char *xpm_symbol_no[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_symbol_mod[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .        . ",
+" .   ..   . ",
+" .  ....  . ",
+" .  ....  . ",
+" .   ..   . ",
+" .        . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_symbol_yes[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .        . ",
+" .      . . ",
+" .     .. . ",
+" . .  ..  . ",
+" . ....   . ",
+" .  ..    . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_choice_no[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+"    ....    ",
+"  ..    ..  ",
+"  .      .  ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+"  .      .  ",
+"  ..    ..  ",
+"    ....    ",
+"            "};
+
+static const char *xpm_choice_yes[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+"    ....    ",
+"  ..    ..  ",
+"  .      .  ",
+" .   ..   . ",
+" .  ....  . ",
+" .  ....  . ",
+" .   ..   . ",
+"  .      .  ",
+"  ..    ..  ",
+"    ....    ",
+"            "};
+
+static const char *xpm_menu[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" . ..     . ",
+" . ....   . ",
+" . ...... . ",
+" . ...... . ",
+" . ....   . ",
+" . ..     . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_menu_inv[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .......... ",
+" ..  ...... ",
+" ..    .... ",
+" ..      .. ",
+" ..      .. ",
+" ..    .... ",
+" ..  ...... ",
+" .......... ",
+" .......... ",
+"            "};
+
+static const char *xpm_menuback[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .     .. . ",
+" .   .... . ",
+" . ...... . ",
+" . ...... . ",
+" .   .... . ",
+" .     .. . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_void[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            "};
diff --git a/bin/kconfig/kconfig_load.c b/bin/kconfig/kconfig_load.c
new file mode 100644 (file)
index 0000000..dbdcaad
--- /dev/null
@@ -0,0 +1,35 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "lkc.h"
+
+#define P(name,type,arg)       type (*name ## _p) arg
+#include "lkc_proto.h"
+#undef P
+
+void kconfig_load(void)
+{
+       void *handle;
+       char *error;
+
+       handle = dlopen("./libkconfig.so", RTLD_LAZY);
+       if (!handle) {
+               handle = dlopen("./scripts/kconfig/libkconfig.so", RTLD_LAZY);
+               if (!handle) {
+                       fprintf(stderr, "%s\n", dlerror());
+                       exit(1);
+               }
+       }
+
+#define P(name,type,arg)                       \
+{                                              \
+       name ## _p = dlsym(handle, #name);      \
+        if ((error = dlerror()))  {            \
+                fprintf(stderr, "%s\n", error);        \
+               exit(1);                        \
+       }                                       \
+}
+#include "lkc_proto.h"
+#undef P
+}
diff --git a/bin/kconfig/kxgettext.c b/bin/kconfig/kxgettext.c
new file mode 100644 (file)
index 0000000..6eb72a7
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2005
+ *
+ * Released under the terms of the GNU GPL v2.0
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static char *escape(const char* text, char *bf, int len)
+{
+       char *bfp = bf;
+       int multiline = strchr(text, '\n') != NULL;
+       int eol = 0;
+       int textlen = strlen(text);
+
+       if ((textlen > 0) && (text[textlen-1] == '\n'))
+               eol = 1;
+
+       *bfp++ = '"';
+       --len;
+
+       if (multiline) {
+               *bfp++ = '"';
+               *bfp++ = '\n';
+               *bfp++ = '"';
+               len -= 3;
+       }
+
+       while (*text != '\0' && len > 1) {
+               if (*text == '"')
+                       *bfp++ = '\\';
+               else if (*text == '\n') {
+                       *bfp++ = '\\';
+                       *bfp++ = 'n';
+                       *bfp++ = '"';
+                       *bfp++ = '\n';
+                       *bfp++ = '"';
+                       len -= 5;
+                       ++text;
+                       goto next;
+               }
+               *bfp++ = *text++;
+next:
+               --len;
+       }
+
+       if (multiline && eol)
+               bfp -= 3;
+
+       *bfp++ = '"';
+       *bfp = '\0';
+
+       return bf;
+}
+
+struct file_line {
+       struct file_line *next;
+       char*            file;
+       int              lineno;
+};
+
+static struct file_line *file_line__new(char *file, int lineno)
+{
+       struct file_line *self = malloc(sizeof(*self));
+
+       if (self == NULL)
+               goto out;
+
+       self->file   = file;
+       self->lineno = lineno;
+       self->next   = NULL;
+out:
+       return self;
+}
+
+struct message {
+       const char       *msg;
+       const char       *option;
+       struct message   *next;
+       struct file_line *files;
+};
+
+static struct message *message__list;
+
+static struct message *message__new(const char *msg, char *option, char *file, int lineno)
+{
+       struct message *self = malloc(sizeof(*self));
+
+       if (self == NULL)
+               goto out;
+
+       self->files = file_line__new(file, lineno);
+       if (self->files == NULL)
+               goto out_fail;
+
+       self->msg = strdup(msg);
+       if (self->msg == NULL)
+               goto out_fail_msg;
+
+       self->option = option;
+       self->next = NULL;
+out:
+       return self;
+out_fail_msg:
+       free(self->files);
+out_fail:
+       free(self);
+       self = NULL;
+       goto out;
+}
+
+static struct message *mesage__find(const char *msg)
+{
+       struct message *m = message__list;
+
+       while (m != NULL) {
+               if (strcmp(m->msg, msg) == 0)
+                       break;
+               m = m->next;
+       }
+
+       return m;
+}
+
+static int message__add_file_line(struct message *self, char *file, int lineno)
+{
+       int rc = -1;
+       struct file_line *fl = file_line__new(file, lineno);
+
+       if (fl == NULL)
+               goto out;
+
+       fl->next    = self->files;
+       self->files = fl;
+       rc = 0;
+out:
+       return rc;
+}
+
+static int message__add(const char *msg, char *option, char *file, int lineno)
+{
+       int rc = 0;
+       char bf[16384];
+       char *escaped = escape(msg, bf, sizeof(bf));
+       struct message *m = mesage__find(escaped);
+
+       if (m != NULL)
+               rc = message__add_file_line(m, file, lineno);
+       else {
+               m = message__new(escaped, option, file, lineno);
+
+               if (m != NULL) {
+                       m->next       = message__list;
+                       message__list = m;
+               } else
+                       rc = -1;
+       }
+       return rc;
+}
+
+void menu_build_message_list(struct menu *menu)
+{
+       struct menu *child;
+
+       message__add(menu_get_prompt(menu), NULL,
+                    menu->file == NULL ? "Root Menu" : menu->file->name,
+                    menu->lineno);
+
+       if (menu->sym != NULL && menu_has_help(menu))
+               message__add(menu_get_help(menu), menu->sym->name,
+                            menu->file == NULL ? "Root Menu" : menu->file->name,
+                            menu->lineno);
+
+       for (child = menu->list; child != NULL; child = child->next)
+               if (child->prompt != NULL)
+                       menu_build_message_list(child);
+}
+
+static void message__print_file_lineno(struct message *self)
+{
+       struct file_line *fl = self->files;
+
+       putchar('\n');
+       if (self->option != NULL)
+               printf("# %s:00000\n", self->option);
+
+       printf("#: %s:%d", fl->file, fl->lineno);
+       fl = fl->next;
+
+       while (fl != NULL) {
+               printf(", %s:%d", fl->file, fl->lineno);
+               fl = fl->next;
+       }
+
+       putchar('\n');
+}
+
+static void message__print_gettext_msgid_msgstr(struct message *self)
+{
+       message__print_file_lineno(self);
+
+       printf("msgid %s\n"
+              "msgstr \"\"\n", self->msg);
+}
+
+void menu__xgettext(void)
+{
+       struct message *m = message__list;
+
+       while (m != NULL) {
+               /* skip empty lines ("") */
+               if (strlen(m->msg) > sizeof("\"\""))
+                       message__print_gettext_msgid_msgstr(m);
+               m = m->next;
+       }
+}
+
+int main(int ac, char **av)
+{
+       conf_parse(av[1]);
+
+       menu_build_message_list(menu_get_root_menu(NULL));
+       menu__xgettext();
+       return 0;
+}
diff --git a/bin/kconfig/lex.zconf.c_shipped b/bin/kconfig/lex.zconf.c_shipped
new file mode 100644 (file)
index 0000000..6a61cee
--- /dev/null
@@ -0,0 +1,2355 @@
+
+#line 3 "scripts/kconfig/lex.zconf.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 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
+
+/* 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)
+
+/* 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 (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 (((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 zconfrestart(zconfin  )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#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
+
+extern int zconfleng;
+
+extern FILE *zconfin, *zconfout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up zconftext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+               *yy_cp = (yy_hold_char); \
+               YY_RESTORE_YY_MORE_OFFSET \
+               (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+               YY_DO_BEFORE_ACTION; /* set up zconftext again */ \
+               } \
+       while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+/* 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;
+
+#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 zconfrestart()), so that the user can continue scanning by
+        * just pointing zconfin at a new input file.
+        */
+#define YY_BUFFER_EOF_PENDING 2
+
+       };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* 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 ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(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 (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when zconftext is formed. */
+static char yy_hold_char;
+static int yy_n_chars;         /* number of characters read into yy_ch_buf */
+int zconfleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0;                /* whether we need to initialize */
+static int yy_start = 0;       /* start state number */
+
+/* Flag which is used to allow zconfwrap()'s to do buffer switches
+ * instead of setting up a fresh zconfin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void zconfrestart (FILE *input_file  );
+void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size  );
+void zconf_delete_buffer (YY_BUFFER_STATE b  );
+void zconf_flush_buffer (YY_BUFFER_STATE b  );
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer  );
+void zconfpop_buffer_state (void );
+
+static void zconfensure_buffer_stack (void );
+static void zconf_load_buffer_state (void );
+static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,int len  );
+
+void *zconfalloc (yy_size_t  );
+void *zconfrealloc (void *,yy_size_t  );
+void zconffree (void *  );
+
+#define yy_new_buffer zconf_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+       { \
+       if ( ! YY_CURRENT_BUFFER ){ \
+        zconfensure_buffer_stack (); \
+               YY_CURRENT_BUFFER_LVALUE =    \
+            zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+       } \
+       YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+       }
+
+#define yy_set_bol(at_bol) \
+       { \
+       if ( ! YY_CURRENT_BUFFER ){\
+        zconfensure_buffer_stack (); \
+               YY_CURRENT_BUFFER_LVALUE =    \
+            zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+       } \
+       YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+       }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define zconfwrap() 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int zconflineno;
+
+int zconflineno = 1;
+
+extern char *zconftext;
+#define yytext_ptr zconftext
+static yyconst flex_int16_t yy_nxt[][17] =
+    {
+    {
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0
+    },
+
+    {
+       11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12
+    },
+
+    {
+       11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12
+    },
+
+    {
+       11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   18,   16,   16,   16
+    },
+
+    {
+       11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   18,   16,   16,   16
+
+    },
+
+    {
+       11,   19,   20,   21,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19
+    },
+
+    {
+       11,   19,   20,   21,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19
+    },
+
+    {
+       11,   22,   22,   23,   22,   24,   22,   22,   24,   22,
+       22,   22,   22,   22,   22,   25,   22
+    },
+
+    {
+       11,   22,   22,   23,   22,   24,   22,   22,   24,   22,
+       22,   22,   22,   22,   22,   25,   22
+    },
+
+    {
+       11,   26,   26,   27,   28,   29,   30,   31,   29,   32,
+       33,   34,   35,   35,   36,   37,   38
+
+    },
+
+    {
+       11,   26,   26,   27,   28,   29,   30,   31,   29,   32,
+       33,   34,   35,   35,   36,   37,   38
+    },
+
+    {
+      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,
+      -11,  -11,  -11,  -11,  -11,  -11,  -11
+    },
+
+    {
+       11,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,
+      -12,  -12,  -12,  -12,  -12,  -12,  -12
+    },
+
+    {
+       11,  -13,   39,   40,  -13,  -13,   41,  -13,  -13,  -13,
+      -13,  -13,  -13,  -13,  -13,  -13,  -13
+    },
+
+    {
+       11,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,
+      -14,  -14,  -14,  -14,  -14,  -14,  -14
+
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,
+      -16,  -16,  -16,  -16,  -16,  -16,  -16
+    },
+
+    {
+       11,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,
+      -17,  -17,  -17,  -17,  -17,  -17,  -17
+    },
+
+    {
+       11,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,
+      -18,  -18,  -18,   44,  -18,  -18,  -18
+    },
+
+    {
+       11,   45,   45,  -19,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45
+
+    },
+
+    {
+       11,  -20,   46,   47,  -20,  -20,  -20,  -20,  -20,  -20,
+      -20,  -20,  -20,  -20,  -20,  -20,  -20
+    },
+
+    {
+       11,   48,  -21,  -21,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48
+    },
+
+    {
+       11,   49,   49,   50,   49,  -22,   49,   49,  -22,   49,
+       49,   49,   49,   49,   49,  -22,   49
+    },
+
+    {
+       11,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,
+      -23,  -23,  -23,  -23,  -23,  -23,  -23
+    },
+
+    {
+       11,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,
+      -24,  -24,  -24,  -24,  -24,  -24,  -24
+
+    },
+
+    {
+       11,   51,   51,   52,   51,   51,   51,   51,   51,   51,
+       51,   51,   51,   51,   51,   51,   51
+    },
+
+    {
+       11,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,
+      -26,  -26,  -26,  -26,  -26,  -26,  -26
+    },
+
+    {
+       11,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,
+      -27,  -27,  -27,  -27,  -27,  -27,  -27
+    },
+
+    {
+       11,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,
+      -28,  -28,  -28,  -28,   53,  -28,  -28
+    },
+
+    {
+       11,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,
+      -29,  -29,  -29,  -29,  -29,  -29,  -29
+
+    },
+
+    {
+       11,   54,   54,  -30,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54
+    },
+
+    {
+       11,  -31,  -31,  -31,  -31,  -31,  -31,   55,  -31,  -31,
+      -31,  -31,  -31,  -31,  -31,  -31,  -31
+    },
+
+    {
+       11,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,
+      -32,  -32,  -32,  -32,  -32,  -32,  -32
+    },
+
+    {
+       11,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,
+      -33,  -33,  -33,  -33,  -33,  -33,  -33
+    },
+
+    {
+       11,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,
+      -34,   56,   57,   57,  -34,  -34,  -34
+
+    },
+
+    {
+       11,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,
+      -35,   57,   57,   57,  -35,  -35,  -35
+    },
+
+    {
+       11,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,
+      -36,  -36,  -36,  -36,  -36,  -36,  -36
+    },
+
+    {
+       11,  -37,  -37,   58,  -37,  -37,  -37,  -37,  -37,  -37,
+      -37,  -37,  -37,  -37,  -37,  -37,  -37
+    },
+
+    {
+       11,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,
+      -38,  -38,  -38,  -38,  -38,  -38,   59
+    },
+
+    {
+       11,  -39,   39,   40,  -39,  -39,   41,  -39,  -39,  -39,
+      -39,  -39,  -39,  -39,  -39,  -39,  -39
+
+    },
+
+    {
+       11,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,
+      -40,  -40,  -40,  -40,  -40,  -40,  -40
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,
+      -43,  -43,  -43,  -43,  -43,  -43,  -43
+    },
+
+    {
+       11,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,
+      -44,  -44,  -44,   44,  -44,  -44,  -44
+
+    },
+
+    {
+       11,   45,   45,  -45,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45
+    },
+
+    {
+       11,  -46,   46,   47,  -46,  -46,  -46,  -46,  -46,  -46,
+      -46,  -46,  -46,  -46,  -46,  -46,  -46
+    },
+
+    {
+       11,   48,  -47,  -47,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48
+    },
+
+    {
+       11,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,
+      -48,  -48,  -48,  -48,  -48,  -48,  -48
+    },
+
+    {
+       11,   49,   49,   50,   49,  -49,   49,   49,  -49,   49,
+       49,   49,   49,   49,   49,  -49,   49
+
+    },
+
+    {
+       11,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,
+      -50,  -50,  -50,  -50,  -50,  -50,  -50
+    },
+
+    {
+       11,  -51,  -51,   52,  -51,  -51,  -51,  -51,  -51,  -51,
+      -51,  -51,  -51,  -51,  -51,  -51,  -51
+    },
+
+    {
+       11,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,
+      -52,  -52,  -52,  -52,  -52,  -52,  -52
+    },
+
+    {
+       11,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,
+      -53,  -53,  -53,  -53,  -53,  -53,  -53
+    },
+
+    {
+       11,   54,   54,  -54,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54
+
+    },
+
+    {
+       11,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,
+      -55,  -55,  -55,  -55,  -55,  -55,  -55
+    },
+
+    {
+       11,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,
+      -56,   60,   57,   57,  -56,  -56,  -56
+    },
+
+    {
+       11,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,
+      -57,   57,   57,   57,  -57,  -57,  -57
+    },
+
+    {
+       11,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,
+      -58,  -58,  -58,  -58,  -58,  -58,  -58
+    },
+
+    {
+       11,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,
+      -59,  -59,  -59,  -59,  -59,  -59,  -59
+
+    },
+
+    {
+       11,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,
+      -60,   57,   57,   57,  -60,  -60,  -60
+    },
+
+    } ;
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up zconftext.
+ */
+#define YY_DO_BEFORE_ACTION \
+       (yytext_ptr) = yy_bp; \
+       zconfleng = (size_t) (yy_cp - yy_bp); \
+       (yy_hold_char) = *yy_cp; \
+       *yy_cp = '\0'; \
+       (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 33
+#define YY_END_OF_BUFFER 34
+/* 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[61] =
+    {   0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+       34,    5,    4,    2,    3,    7,    8,    6,   32,   29,
+       31,   24,   28,   27,   26,   22,   17,   13,   16,   20,
+       22,   11,   12,   19,   19,   14,   22,   22,    4,    2,
+        3,    3,    1,    6,   32,   29,   31,   30,   24,   23,
+       26,   25,   15,   20,    9,   19,   19,   21,   10,   18
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    4,    5,    6,    1,    1,    7,    8,    9,
+       10,    1,    1,    1,   11,   12,   12,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,    1,    1,    1,
+       14,    1,    1,    1,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+        1,   15,    1,    1,   13,    1,   13,   13,   13,   13,
+
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,    1,   16,    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,    1
+    } ;
+
+extern int zconf_flex_debug;
+int zconf_flex_debug = 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
+char *zconftext;
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define START_STRSIZE  16
+
+static struct {
+       struct file *file;
+       int lineno;
+} current_pos;
+
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+        struct buffer *parent;
+        YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+void new_string(void)
+{
+       text = malloc(START_STRSIZE);
+       text_asize = START_STRSIZE;
+       text_size = 0;
+       *text = 0;
+}
+
+void append_string(const char *str, int size)
+{
+       int new_size = text_size + size + 1;
+       if (new_size > text_asize) {
+               new_size += START_STRSIZE - 1;
+               new_size &= -START_STRSIZE;
+               text = realloc(text, new_size);
+               text_asize = new_size;
+       }
+       memcpy(text + text_size, str, size);
+       text_size += size;
+       text[text_size] = 0;
+}
+
+void alloc_string(const char *str, int size)
+{
+       text = malloc(size + 1);
+       memcpy(text, str, size);
+       text[size] = 0;
+}
+
+#define INITIAL 0
+#define COMMAND 1
+#define HELP 2
+#define STRING 3
+#define PARAM 4
+
+#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
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int zconfwrap (void );
+#else
+extern int zconfwrap (void );
+#endif
+#endif
+
+    static void yyunput (int c,char *buf_ptr  );
+    
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#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 (void) fwrite( zconftext, zconfleng, 1, zconfout )
+#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) \
+       errno=0; \
+       while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \
+       { \
+               if( errno != EINTR) \
+               { \
+                       YY_FATAL_ERROR( "input in flex scanner failed" ); \
+                       break; \
+               } \
+               errno=0; \
+               clearerr(zconfin); \
+       }\
+\
+
+#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 )
+#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 zconflex (void);
+
+#define YY_DECL int zconflex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after zconftext and zconfleng
+ * 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 \
+       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;
+    
+       int str = 0;
+       int ts, i;
+
+       if ( !(yy_init) )
+               {
+               (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+               YY_USER_INIT;
+#endif
+
+               if ( ! (yy_start) )
+                       (yy_start) = 1; /* first start state */
+
+               if ( ! zconfin )
+                       zconfin = stdin;
+
+               if ( ! zconfout )
+                       zconfout = stdout;
+
+               if ( ! YY_CURRENT_BUFFER ) {
+                       zconfensure_buffer_stack ();
+                       YY_CURRENT_BUFFER_LVALUE =
+                               zconf_create_buffer(zconfin,YY_BUF_SIZE );
+               }
+
+               zconf_load_buffer_state( );
+               }
+
+       while ( 1 )             /* loops until end-of-file is reached */
+               {
+               yy_cp = (yy_c_buf_p);
+
+               /* Support of zconftext. */
+               *yy_cp = (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 = (yy_start);
+yy_match:
+               while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)]  ]) > 0 )
+                       ++yy_cp;
+
+               yy_current_state = -yy_current_state;
+
+yy_find_action:
+               yy_act = yy_accept[yy_current_state];
+
+               YY_DO_BEFORE_ACTION;
+
+do_action:     /* This label is used only to access EOF actions. */
+
+               switch ( yy_act )
+       { /* beginning of action switch */
+case 1:
+/* rule 1 can match eol */
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+{
+       current_file->lineno++;
+       return T_EOL;
+}
+       YY_BREAK
+case 3:
+YY_RULE_SETUP
+
+       YY_BREAK
+case 4:
+YY_RULE_SETUP
+{
+       BEGIN(COMMAND);
+}
+       YY_BREAK
+case 5:
+YY_RULE_SETUP
+{
+       unput(zconftext[0]);
+       BEGIN(COMMAND);
+}
+       YY_BREAK
+
+case 6:
+YY_RULE_SETUP
+{
+               struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+               BEGIN(PARAM);
+               current_pos.file = current_file;
+               current_pos.lineno = current_file->lineno;
+               if (id && id->flags & TF_COMMAND) {
+                       zconflval.id = id;
+                       return id->token;
+               }
+               alloc_string(zconftext, zconfleng);
+               zconflval.string = text;
+               return T_WORD;
+       }
+       YY_BREAK
+case 7:
+YY_RULE_SETUP
+
+       YY_BREAK
+case 8:
+/* rule 8 can match eol */
+YY_RULE_SETUP
+{
+               BEGIN(INITIAL);
+               current_file->lineno++;
+               return T_EOL;
+       }
+       YY_BREAK
+
+case 9:
+YY_RULE_SETUP
+return T_AND;
+       YY_BREAK
+case 10:
+YY_RULE_SETUP
+return T_OR;
+       YY_BREAK
+case 11:
+YY_RULE_SETUP
+return T_OPEN_PAREN;
+       YY_BREAK
+case 12:
+YY_RULE_SETUP
+return T_CLOSE_PAREN;
+       YY_BREAK
+case 13:
+YY_RULE_SETUP
+return T_NOT;
+       YY_BREAK
+case 14:
+YY_RULE_SETUP
+return T_EQUAL;
+       YY_BREAK
+case 15:
+YY_RULE_SETUP
+return T_UNEQUAL;
+       YY_BREAK
+case 16:
+YY_RULE_SETUP
+{
+               str = zconftext[0];
+               new_string();
+               BEGIN(STRING);
+       }
+       YY_BREAK
+case 17:
+/* rule 17 can match eol */
+YY_RULE_SETUP
+BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+       YY_BREAK
+case 18:
+YY_RULE_SETUP
+/* ignore */
+       YY_BREAK
+case 19:
+YY_RULE_SETUP
+{
+               struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+               if (id && id->flags & TF_PARAM) {
+                       zconflval.id = id;
+                       return id->token;
+               }
+               alloc_string(zconftext, zconfleng);
+               zconflval.string = text;
+               return T_WORD;
+       }
+       YY_BREAK
+case 20:
+YY_RULE_SETUP
+/* comment */
+       YY_BREAK
+case 21:
+/* rule 21 can match eol */
+YY_RULE_SETUP
+current_file->lineno++;
+       YY_BREAK
+case 22:
+YY_RULE_SETUP
+
+       YY_BREAK
+case YY_STATE_EOF(PARAM):
+{
+               BEGIN(INITIAL);
+       }
+       YY_BREAK
+
+case 23:
+/* rule 23 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+               append_string(zconftext, zconfleng);
+               zconflval.string = text;
+               return T_WORD_QUOTE;
+       }
+       YY_BREAK
+case 24:
+YY_RULE_SETUP
+{
+               append_string(zconftext, zconfleng);
+       }
+       YY_BREAK
+case 25:
+/* rule 25 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+               append_string(zconftext + 1, zconfleng - 1);
+               zconflval.string = text;
+               return T_WORD_QUOTE;
+       }
+       YY_BREAK
+case 26:
+YY_RULE_SETUP
+{
+               append_string(zconftext + 1, zconfleng - 1);
+       }
+       YY_BREAK
+case 27:
+YY_RULE_SETUP
+{
+               if (str == zconftext[0]) {
+                       BEGIN(PARAM);
+                       zconflval.string = text;
+                       return T_WORD_QUOTE;
+               } else
+                       append_string(zconftext, 1);
+       }
+       YY_BREAK
+case 28:
+/* rule 28 can match eol */
+YY_RULE_SETUP
+{
+               printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+               current_file->lineno++;
+               BEGIN(INITIAL);
+               return T_EOL;
+       }
+       YY_BREAK
+case YY_STATE_EOF(STRING):
+{
+               BEGIN(INITIAL);
+       }
+       YY_BREAK
+
+case 29:
+YY_RULE_SETUP
+{
+               ts = 0;
+               for (i = 0; i < zconfleng; i++) {
+                       if (zconftext[i] == '\t')
+                               ts = (ts & ~7) + 8;
+                       else
+                               ts++;
+               }
+               last_ts = ts;
+               if (first_ts) {
+                       if (ts < first_ts) {
+                               zconf_endhelp();
+                               return T_HELPTEXT;
+                       }
+                       ts -= first_ts;
+                       while (ts > 8) {
+                               append_string("        ", 8);
+                               ts -= 8;
+                       }
+                       append_string("        ", ts);
+               }
+       }
+       YY_BREAK
+case 30:
+/* rule 30 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+               current_file->lineno++;
+               zconf_endhelp();
+               return T_HELPTEXT;
+       }
+       YY_BREAK
+case 31:
+/* rule 31 can match eol */
+YY_RULE_SETUP
+{
+               current_file->lineno++;
+               append_string("\n", 1);
+       }
+       YY_BREAK
+case 32:
+YY_RULE_SETUP
+{
+               while (zconfleng) {
+                       if ((zconftext[zconfleng-1] != ' ') && (zconftext[zconfleng-1] != '\t'))
+                               break;
+                       zconfleng--;
+               }
+               append_string(zconftext, zconfleng);
+               if (!first_ts)
+                       first_ts = last_ts;
+       }
+       YY_BREAK
+case YY_STATE_EOF(HELP):
+{
+               zconf_endhelp();
+               return T_HELPTEXT;
+       }
+       YY_BREAK
+
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(COMMAND):
+{
+       if (current_file) {
+               zconf_endfile();
+               return T_EOL;
+       }
+       fclose(zconfin);
+       yyterminate();
+}
+       YY_BREAK
+case 33:
+YY_RULE_SETUP
+YY_FATAL_ERROR( "flex scanner jammed" );
+       YY_BREAK
+
+       case YY_END_OF_BUFFER:
+               {
+               /* Amount of text matched not including the EOB char. */
+               int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+               /* Undo the effects of YY_DO_BEFORE_ACTION. */
+               *yy_cp = (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 zconfin at a new source and called
+                        * zconflex().  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.
+                        */
+                       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+                       YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin;
+                       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 ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+                       { /* This was really a NUL. */
+                       yy_state_type yy_next_state;
+
+                       (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+                       yy_current_state = yy_get_previous_state(  );
+
+                       /* 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 );
+
+                       yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+                       if ( yy_next_state )
+                               {
+                               /* Consume the NUL. */
+                               yy_cp = ++(yy_c_buf_p);
+                               yy_current_state = yy_next_state;
+                               goto yy_match;
+                               }
+
+                       else
+                               {
+                               yy_cp = (yy_c_buf_p);
+                               goto yy_find_action;
+                               }
+                       }
+
+               else switch ( yy_get_next_buffer(  ) )
+                       {
+                       case EOB_ACT_END_OF_FILE:
+                               {
+                               (yy_did_buffer_switch_on_eof) = 0;
+
+                               if ( zconfwrap( ) )
+                                       {
+                                       /* Note: because we've taken care in
+                                        * yy_get_next_buffer() to have set up
+                                        * zconftext, 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.
+                                        */
+                                       (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+                                       yy_act = YY_STATE_EOF(YY_START);
+                                       goto do_action;
+                                       }
+
+                               else
+                                       {
+                                       if ( ! (yy_did_buffer_switch_on_eof) )
+                                               YY_NEW_FILE;
+                                       }
+                               break;
+                               }
+
+                       case EOB_ACT_CONTINUE_SCAN:
+                               (yy_c_buf_p) =
+                                       (yytext_ptr) + yy_amount_of_matched_text;
+
+                               yy_current_state = yy_get_previous_state(  );
+
+                               yy_cp = (yy_c_buf_p);
+                               yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+                               goto yy_match;
+
+                       case EOB_ACT_LAST_MATCH:
+                               (yy_c_buf_p) =
+                               &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+                               yy_current_state = yy_get_previous_state(  );
+
+                               yy_cp = (yy_c_buf_p);
+                               yy_bp = (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 zconflex */
+
+/* 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 (void)
+{
+       register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+       register char *source = (yytext_ptr);
+       register int number_to_move, i;
+       int ret_val;
+
+       if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(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 ( (yy_c_buf_p) - (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) ((yy_c_buf_p) - (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 = (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) ((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. */
+                                       zconfrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );
+                               }
+                       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" );
+
+                       (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]),
+                       (yy_n_chars), (size_t) num_to_read );
+
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+               }
+
+       if ( (yy_n_chars) == 0 )
+               {
+               if ( number_to_move == YY_MORE_ADJ )
+                       {
+                       ret_val = EOB_ACT_END_OF_FILE;
+                       zconfrestart(zconfin  );
+                       }
+
+               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;
+
+       (yy_n_chars) += number_to_move;
+       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+       (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 (void)
+{
+       register yy_state_type yy_current_state;
+       register char *yy_cp;
+    
+       yy_current_state = (yy_start);
+
+       for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+               {
+               yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)];
+               }
+
+       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 )
+{
+       register int yy_is_jam;
+    
+       yy_current_state = yy_nxt[yy_current_state][1];
+       yy_is_jam = (yy_current_state <= 0);
+
+       return yy_is_jam ? 0 : yy_current_state;
+}
+
+    static void yyunput (int c, register char * yy_bp )
+{
+       register char *yy_cp;
+    
+    yy_cp = (yy_c_buf_p);
+
+       /* undo effects of setting up zconftext */
+       *yy_cp = (yy_hold_char);
+
+       if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+               { /* need to shift things up to make room */
+               /* +2 for EOB chars. */
+               register int number_to_move = (yy_n_chars) + 2;
+               register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+                                       YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+               register char *source =
+                               &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+               while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+                       *--dest = *--source;
+
+               yy_cp += (int) (dest - source);
+               yy_bp += (int) (dest - source);
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+                       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+               if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+                       YY_FATAL_ERROR( "flex scanner push-back overflow" );
+               }
+
+       *--yy_cp = (char) c;
+
+       (yytext_ptr) = yy_bp;
+       (yy_hold_char) = *yy_cp;
+       (yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+       int c;
+    
+       *(yy_c_buf_p) = (yy_hold_char);
+
+       if ( *(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 ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+                       /* This was really a NUL. */
+                       *(yy_c_buf_p) = '\0';
+
+               else
+                       { /* need more input */
+                       int offset = (yy_c_buf_p) - (yytext_ptr);
+                       ++(yy_c_buf_p);
+
+                       switch ( yy_get_next_buffer(  ) )
+                               {
+                               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. */
+                                       zconfrestart(zconfin );
+
+                                       /*FALLTHROUGH*/
+
+                               case EOB_ACT_END_OF_FILE:
+                                       {
+                                       if ( zconfwrap( ) )
+                                               return EOF;
+
+                                       if ( ! (yy_did_buffer_switch_on_eof) )
+                                               YY_NEW_FILE;
+#ifdef __cplusplus
+                                       return yyinput();
+#else
+                                       return input();
+#endif
+                                       }
+
+                               case EOB_ACT_CONTINUE_SCAN:
+                                       (yy_c_buf_p) = (yytext_ptr) + offset;
+                                       break;
+                               }
+                       }
+               }
+
+       c = *(unsigned char *) (yy_c_buf_p);    /* cast for 8-bit char's */
+       *(yy_c_buf_p) = '\0';   /* preserve zconftext */
+       (yy_hold_char) = *++(yy_c_buf_p);
+
+       return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void zconfrestart  (FILE * input_file )
+{
+    
+       if ( ! YY_CURRENT_BUFFER ){
+        zconfensure_buffer_stack ();
+               YY_CURRENT_BUFFER_LVALUE =
+            zconf_create_buffer(zconfin,YY_BUF_SIZE );
+       }
+
+       zconf_init_buffer(YY_CURRENT_BUFFER,input_file );
+       zconf_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void zconf_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+       /* TODO. We should be able to replace this entire function body
+        * with
+        *              zconfpop_buffer_state();
+        *              zconfpush_buffer_state(new_buffer);
+     */
+       zconfensure_buffer_stack ();
+       if ( YY_CURRENT_BUFFER == new_buffer )
+               return;
+
+       if ( YY_CURRENT_BUFFER )
+               {
+               /* Flush out information for old buffer. */
+               *(yy_c_buf_p) = (yy_hold_char);
+               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+               }
+
+       YY_CURRENT_BUFFER_LVALUE = new_buffer;
+       zconf_load_buffer_state( );
+
+       /* We don't actually know whether we did this switch during
+        * EOF (zconfwrap()) processing, but the only time this flag
+        * is looked at is after zconfwrap() is called, so it's safe
+        * to go ahead and always set it.
+        */
+       (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void zconf_load_buffer_state  (void)
+{
+       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+       (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+       zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+       (yy_hold_char) = *(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.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE zconf_create_buffer  (FILE * file, int  size )
+{
+       YY_BUFFER_STATE b;
+    
+       b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state )  );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in zconf_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 *) zconfalloc(b->yy_buf_size + 2  );
+       if ( ! b->yy_ch_buf )
+               YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
+
+       b->yy_is_our_buffer = 1;
+
+       zconf_init_buffer(b,file );
+
+       return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with zconf_create_buffer()
+ * 
+ */
+    void zconf_delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+       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 )
+               zconffree((void *) b->yy_ch_buf  );
+
+       zconffree((void *) b  );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a zconfrestart() or at EOF.
+ */
+    static void zconf_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+       int oerrno = errno;
+    
+       zconf_flush_buffer(b );
+
+       b->yy_input_file = file;
+       b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then zconf_init_buffer was _probably_
+     * called from zconfrestart() 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 = 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.
+ * 
+ */
+    void zconf_flush_buffer (YY_BUFFER_STATE  b )
+{
+       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 )
+               zconf_load_buffer_state( );
+}
+
+/** 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.
+ *  
+ */
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+       if (new_buffer == NULL)
+               return;
+
+       zconfensure_buffer_stack();
+
+       /* This block is copied from zconf_switch_to_buffer. */
+       if ( YY_CURRENT_BUFFER )
+               {
+               /* Flush out information for old buffer. */
+               *(yy_c_buf_p) = (yy_hold_char);
+               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+               }
+
+       /* Only push if top exists. Otherwise, replace top. */
+       if (YY_CURRENT_BUFFER)
+               (yy_buffer_stack_top)++;
+       YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+       /* copied from zconf_switch_to_buffer. */
+       zconf_load_buffer_state( );
+       (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void zconfpop_buffer_state (void)
+{
+       if (!YY_CURRENT_BUFFER)
+               return;
+
+       zconf_delete_buffer(YY_CURRENT_BUFFER );
+       YY_CURRENT_BUFFER_LVALUE = NULL;
+       if ((yy_buffer_stack_top) > 0)
+               --(yy_buffer_stack_top);
+
+       if (YY_CURRENT_BUFFER) {
+               zconf_load_buffer_state( );
+               (yy_did_buffer_switch_on_eof) = 1;
+       }
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void zconfensure_buffer_stack (void)
+{
+       int num_to_alloc;
+    
+       if (!(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;
+               (yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc
+                                                               (num_to_alloc * sizeof(struct yy_buffer_state*)
+                                                               );
+               
+               memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+                               
+               (yy_buffer_stack_max) = num_to_alloc;
+               (yy_buffer_stack_top) = 0;
+               return;
+       }
+
+       if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+               /* Increase the buffer to prepare for a possible push. */
+               int grow_size = 8 /* arbitrary grow size */;
+
+               num_to_alloc = (yy_buffer_stack_max) + grow_size;
+               (yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc
+                                                               ((yy_buffer_stack),
+                                                               num_to_alloc * sizeof(struct yy_buffer_state*)
+                                                               );
+
+               /* zero only the new slots.*/
+               memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+               (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
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE zconf_scan_buffer  (char * base, yy_size_t  size )
+{
+       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) zconfalloc(sizeof( struct yy_buffer_state )  );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in zconf_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;
+
+       zconf_switch_to_buffer(b  );
+
+       return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to zconflex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       zconf_scan_bytes() instead.
+ */
+YY_BUFFER_STATE zconf_scan_string (yyconst char * yystr )
+{
+    
+       return zconf_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to zconflex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE zconf_scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
+{
+       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 *) zconfalloc(n  );
+       if ( ! buf )
+               YY_FATAL_ERROR( "out of dynamic memory in zconf_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 = zconf_scan_buffer(buf,n );
+       if ( ! b )
+               YY_FATAL_ERROR( "bad buffer in zconf_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 )
+{
+       (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 zconftext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+               zconftext[zconfleng] = (yy_hold_char); \
+               (yy_c_buf_p) = zconftext + yyless_macro_arg; \
+               (yy_hold_char) = *(yy_c_buf_p); \
+               *(yy_c_buf_p) = '\0'; \
+               zconfleng = yyless_macro_arg; \
+               } \
+       while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ * 
+ */
+int zconfget_lineno  (void)
+{
+        
+    return zconflineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *zconfget_in  (void)
+{
+        return zconfin;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *zconfget_out  (void)
+{
+        return zconfout;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+int zconfget_leng  (void)
+{
+        return zconfleng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *zconfget_text  (void)
+{
+        return zconftext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void zconfset_lineno (int  line_number )
+{
+    
+    zconflineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see zconf_switch_to_buffer
+ */
+void zconfset_in (FILE *  in_str )
+{
+        zconfin = in_str ;
+}
+
+void zconfset_out (FILE *  out_str )
+{
+        zconfout = out_str ;
+}
+
+int zconfget_debug  (void)
+{
+        return zconf_flex_debug;
+}
+
+void zconfset_debug (int  bdebug )
+{
+        zconf_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from zconflex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    zconfin = stdin;
+    zconfout = stdout;
+#else
+    zconfin = (FILE *) 0;
+    zconfout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * zconflex_init()
+     */
+    return 0;
+}
+
+/* zconflex_destroy is for both reentrant and non-reentrant scanners. */
+int zconflex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+       while(YY_CURRENT_BUFFER){
+               zconf_delete_buffer(YY_CURRENT_BUFFER  );
+               YY_CURRENT_BUFFER_LVALUE = NULL;
+               zconfpop_buffer_state();
+       }
+
+       /* Destroy the stack itself. */
+       zconffree((yy_buffer_stack) );
+       (yy_buffer_stack) = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * zconflex() is called, initialization will occur. */
+    yy_init_globals( );
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+       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 )
+{
+       register int n;
+       for ( n = 0; s[n]; ++n )
+               ;
+
+       return n;
+}
+#endif
+
+void *zconfalloc (yy_size_t  size )
+{
+       return (void *) malloc( size );
+}
+
+void *zconfrealloc  (void * ptr, yy_size_t  size )
+{
+       /* 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 zconffree (void * ptr )
+{
+       free( (char *) ptr );   /* see zconfrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+void zconf_starthelp(void)
+{
+       new_string();
+       last_ts = first_ts = 0;
+       BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+       zconflval.string = text;
+       BEGIN(INITIAL);
+}
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+       char *env, fullname[PATH_MAX+1];
+       FILE *f;
+
+       f = fopen(name, "r");
+       if (!f && name != NULL && name[0] != '/') {
+               env = getenv(SRCTREE);
+               if (env) {
+                       sprintf(fullname, "%s/%s", env, name);
+                       f = fopen(fullname, "r");
+               }
+       }
+       return f;
+}
+
+void zconf_initscan(const char *name)
+{
+       zconfin = zconf_fopen(name);
+       if (!zconfin) {
+               printf("can't find file %s\n", name);
+               exit(1);
+       }
+
+       current_buf = malloc(sizeof(*current_buf));
+       memset(current_buf, 0, sizeof(*current_buf));
+
+       current_file = file_lookup(name);
+       current_file->lineno = 1;
+       current_file->flags = FILE_BUSY;
+}
+
+void zconf_nextfile(const char *name)
+{
+       struct file *file = file_lookup(name);
+       struct buffer *buf = malloc(sizeof(*buf));
+       memset(buf, 0, sizeof(*buf));
+
+       current_buf->state = YY_CURRENT_BUFFER;
+       zconfin = zconf_fopen(name);
+       if (!zconfin) {
+               printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name);
+               exit(1);
+       }
+       zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE));
+       buf->parent = current_buf;
+       current_buf = buf;
+
+       if (file->flags & FILE_BUSY) {
+               printf("recursive scan (%s)?\n", name);
+               exit(1);
+       }
+       if (file->flags & FILE_SCANNED) {
+               printf("file %s already scanned?\n", name);
+               exit(1);
+       }
+       file->flags |= FILE_BUSY;
+       file->lineno = 1;
+       file->parent = current_file;
+       current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+       struct buffer *parent;
+
+       current_file->flags |= FILE_SCANNED;
+       current_file->flags &= ~FILE_BUSY;
+       current_file = current_file->parent;
+
+       parent = current_buf->parent;
+       if (parent) {
+               fclose(zconfin);
+               zconf_delete_buffer(YY_CURRENT_BUFFER);
+               zconf_switch_to_buffer(parent->state);
+       }
+       free(current_buf);
+       current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+       return current_pos.lineno;
+}
+
+char *zconf_curname(void)
+{
+       return current_pos.file ? current_pos.file->name : "<none>";
+}
+
diff --git a/bin/kconfig/lkc.h b/bin/kconfig/lkc.h
new file mode 100644 (file)
index 0000000..96521cb
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef LKC_H
+#define LKC_H
+
+#include "expr.h"
+
+#ifndef KBUILD_NO_NLS
+# include <libintl.h>
+#else
+static inline const char *gettext(const char *txt) { return txt; }
+static inline void textdomain(const char *domainname) {}
+static inline void bindtextdomain(const char *name, const char *dir) {}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef LKC_DIRECT_LINK
+#define P(name,type,arg)       extern type name arg
+#else
+#include "lkc_defs.h"
+#define P(name,type,arg)       extern type (*name ## _p) arg
+#endif
+#include "lkc_proto.h"
+#undef P
+
+#define SRCTREE "srctree"
+
+#define PACKAGE "linux"
+#define LOCALEDIR "/usr/share/locale"
+
+#define _(text) gettext(text)
+#define N_(text) (text)
+
+
+#define TF_COMMAND     0x0001
+#define TF_PARAM       0x0002
+#define TF_OPTION      0x0004
+
+#define T_OPT_MODULES          1
+#define T_OPT_DEFCONFIG_LIST   2
+#define T_OPT_ENV              3
+
+struct kconf_id {
+       int name;
+       int token;
+       unsigned int flags;
+       enum symbol_type stype;
+};
+
+int zconfparse(void);
+void zconfdump(FILE *out);
+
+extern int zconfdebug;
+void zconf_starthelp(void);
+FILE *zconf_fopen(const char *name);
+void zconf_initscan(const char *name);
+void zconf_nextfile(const char *name);
+int zconf_lineno(void);
+char *zconf_curname(void);
+
+/* confdata.c */
+const char *conf_get_configname(void);
+char *conf_get_default_confname(void);
+void sym_set_change_count(int count);
+void sym_add_change_count(int count);
+
+/* kconfig_load.c */
+void kconfig_load(void);
+
+/* menu.c */
+void menu_init(void);
+void menu_warn(struct menu *menu, const char *fmt, ...);
+struct menu *menu_add_menu(void);
+void menu_end_menu(void);
+void menu_add_entry(struct symbol *sym);
+void menu_end_entry(void);
+void menu_add_dep(struct expr *dep);
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
+void menu_add_option(int token, char *arg);
+void menu_finalize(struct menu *parent);
+void menu_set_type(int type);
+
+/* util.c */
+struct file *file_lookup(const char *name);
+int file_write_dep(const char *name);
+
+struct gstr {
+       size_t len;
+       char  *s;
+};
+struct gstr str_new(void);
+struct gstr str_assign(const char *s);
+void str_free(struct gstr *gs);
+void str_append(struct gstr *gs, const char *s);
+void str_printf(struct gstr *gs, const char *fmt, ...);
+const char *str_get(struct gstr *gs);
+
+/* symbol.c */
+extern struct expr *sym_env_list;
+
+void sym_init(void);
+void sym_clear_all_valid(void);
+void sym_set_all_changed(void);
+void sym_set_changed(struct symbol *sym);
+struct symbol *sym_check_deps(struct symbol *sym);
+struct property *prop_alloc(enum prop_type type, struct symbol *sym);
+struct symbol *prop_get_symbol(struct property *prop);
+struct property *sym_get_env_prop(struct symbol *sym);
+
+static inline tristate sym_get_tristate_value(struct symbol *sym)
+{
+       return sym->curr.tri;
+}
+
+
+static inline struct symbol *sym_get_choice_value(struct symbol *sym)
+{
+       return (struct symbol *)sym->curr.val;
+}
+
+static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval)
+{
+       return sym_set_tristate_value(chval, yes);
+}
+
+static inline bool sym_is_choice(struct symbol *sym)
+{
+       return sym->flags & SYMBOL_CHOICE ? true : false;
+}
+
+static inline bool sym_is_choice_value(struct symbol *sym)
+{
+       return sym->flags & SYMBOL_CHOICEVAL ? true : false;
+}
+
+static inline bool sym_is_optional(struct symbol *sym)
+{
+       return sym->flags & SYMBOL_OPTIONAL ? true : false;
+}
+
+static inline bool sym_has_value(struct symbol *sym)
+{
+       return sym->flags & SYMBOL_DEF_USER ? true : false;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LKC_H */
diff --git a/bin/kconfig/lkc_proto.h b/bin/kconfig/lkc_proto.h
new file mode 100644 (file)
index 0000000..8e69461
--- /dev/null
@@ -0,0 +1,45 @@
+
+/* confdata.c */
+P(conf_parse,void,(const char *name));
+P(conf_read,int,(const char *name));
+P(conf_read_simple,int,(const char *name, int));
+P(conf_write,int,(const char *name));
+P(conf_write_autoconf,int,(void));
+P(conf_get_changed,bool,(void));
+P(conf_set_changed_callback, void,(void (*fn)(void)));
+
+/* menu.c */
+P(rootmenu,struct menu,);
+
+P(menu_is_visible,bool,(struct menu *menu));
+P(menu_get_prompt,const char *,(struct menu *menu));
+P(menu_get_root_menu,struct menu *,(struct menu *menu));
+P(menu_get_parent_menu,struct menu *,(struct menu *menu));
+P(menu_has_help,bool,(struct menu *menu));
+P(menu_get_help,const char *,(struct menu *menu));
+
+/* symbol.c */
+P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
+
+P(sym_lookup,struct symbol *,(const char *name, int flags));
+P(sym_find,struct symbol *,(const char *name));
+P(sym_re_search,struct symbol **,(const char *pattern));
+P(sym_type_name,const char *,(enum symbol_type type));
+P(sym_calc_value,void,(struct symbol *sym));
+P(sym_get_type,enum symbol_type,(struct symbol *sym));
+P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri));
+P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri));
+P(sym_toggle_tristate_value,tristate,(struct symbol *sym));
+P(sym_string_valid,bool,(struct symbol *sym, const char *newval));
+P(sym_string_within_range,bool,(struct symbol *sym, const char *str));
+P(sym_set_string_value,bool,(struct symbol *sym, const char *newval));
+P(sym_is_changable,bool,(struct symbol *sym));
+P(sym_get_choice_prop,struct property *,(struct symbol *sym));
+P(sym_get_default_prop,struct property *,(struct symbol *sym));
+P(sym_get_string_value,const char *,(struct symbol *sym));
+
+P(prop_get_type_name,const char *,(enum prop_type type));
+
+/* expr.c */
+P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2));
+P(expr_print,void,(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken));
diff --git a/bin/kconfig/lxdialog/.gitignore b/bin/kconfig/lxdialog/.gitignore
new file mode 100644 (file)
index 0000000..90b08ff
--- /dev/null
@@ -0,0 +1,4 @@
+#
+# Generated files
+#
+lxdialog
diff --git a/bin/kconfig/lxdialog/BIG.FAT.WARNING b/bin/kconfig/lxdialog/BIG.FAT.WARNING
new file mode 100644 (file)
index 0000000..cbc154b
--- /dev/null
@@ -0,0 +1,4 @@
+This is NOT the official version of dialog.  This version has been
+significantly modified from the original for use in the Linux kernel
+and firmly.0cpm configuration scripts.  Please do not bother Savio Lam
+with questions about this program.
diff --git a/bin/kconfig/lxdialog/check-lxdialog.sh b/bin/kconfig/lxdialog/check-lxdialog.sh
new file mode 100644 (file)
index 0000000..5552154
--- /dev/null
@@ -0,0 +1,82 @@
+#!/bin/sh
+# Check ncurses compatibility
+
+# What library to link
+ldflags()
+{
+       for ext in so a dylib ; do
+               for lib in ncursesw ncurses curses ; do
+                       $cc -print-file-name=lib${lib}.${ext} | grep -q /
+                       if [ $? -eq 0 ]; then
+                               echo "-l${lib}"
+                               exit
+                       fi
+               done
+       done
+       exit 1
+}
+
+# Where is ncurses.h?
+ccflags()
+{
+       if [ -f /usr/include/ncurses/ncurses.h ]; then
+               echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"'
+       elif [ -f /usr/include/ncurses/curses.h ]; then
+               echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"'
+       elif [ -f /usr/include/ncurses.h ]; then
+               echo '-DCURSES_LOC="<ncurses.h>"'
+       else
+               echo '-DCURSES_LOC="<curses.h>"'
+       fi
+}
+
+# Temp file, try to clean up after us
+tmp=.lxdialog.tmp
+trap "rm -f $tmp" 0 1 2 3 15
+
+# Check if we can link to ncurses
+check() {
+        $cc -xc - -o $tmp 2>/dev/null <<'EOF'
+#include CURSES_LOC
+main() {}
+EOF
+       if [ $? != 0 ]; then
+           echo " *** Unable to find the ncurses libraries or the"       1>&2
+           echo " *** required header files."                            1>&2
+           echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2
+           echo " *** "                                                  1>&2
+           echo " *** Install ncurses (ncurses-devel) and try again."    1>&2
+           echo " *** "                                                  1>&2
+           exit 1
+       fi
+}
+
+usage() {
+       printf "Usage: $0 [-check compiler options|-header|-library]\n"
+}
+
+if [ $# -eq 0 ]; then
+       usage
+       exit 1
+fi
+
+cc=""
+case "$1" in
+       "-check")
+               shift
+               cc="$@"
+               check
+               ;;
+       "-ccflags")
+               ccflags
+               ;;
+       "-ldflags")
+               shift
+               cc="$@"
+               ldflags
+               ;;
+       "*")
+               usage
+               exit 1
+               ;;
+esac
diff --git a/bin/kconfig/lxdialog/checklist.c b/bin/kconfig/lxdialog/checklist.c
new file mode 100644 (file)
index 0000000..b2a878c
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ *  checklist.c -- implements the checklist box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *     Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
+ *     Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  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, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+static int list_width, check_x, item_x;
+
+/*
+ * Print list item
+ */
+static void print_item(WINDOW * win, int choice, int selected)
+{
+       int i;
+
+       /* Clear 'residue' of last item */
+       wattrset(win, dlg.menubox.atr);
+       wmove(win, choice, 0);
+       for (i = 0; i < list_width; i++)
+               waddch(win, ' ');
+
+       wmove(win, choice, check_x);
+       wattrset(win, selected ? dlg.check_selected.atr
+                : dlg.check.atr);
+       wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
+
+       wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
+       mvwaddch(win, choice, item_x, item_str()[0]);
+       wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+       waddstr(win, (char *)item_str() + 1);
+       if (selected) {
+               wmove(win, choice, check_x + 1);
+               wrefresh(win);
+       }
+}
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
+            int y, int x, int height)
+{
+       wmove(win, y, x);
+
+       if (scroll > 0) {
+               wattrset(win, dlg.uarrow.atr);
+               waddch(win, ACS_UARROW);
+               waddstr(win, "(-)");
+       } else {
+               wattrset(win, dlg.menubox.atr);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+       }
+
+       y = y + height + 1;
+       wmove(win, y, x);
+
+       if ((height < item_no) && (scroll + choice < item_no - 1)) {
+               wattrset(win, dlg.darrow.atr);
+               waddch(win, ACS_DARROW);
+               waddstr(win, "(+)");
+       } else {
+               wattrset(win, dlg.menubox_border.atr);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+       }
+}
+
+/*
+ *  Display the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+       int x = width / 2 - 11;
+       int y = height - 2;
+
+       print_button(dialog, gettext("Select"), y, x, selected == 0);
+       print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
+
+       wmove(dialog, y, x + 1 + 14 * selected);
+       wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with a list of options that can be turned on or off
+ * in the style of radiolist (only one option turned on at a time).
+ */
+int dialog_checklist(const char *title, const char *prompt, int height,
+                    int width, int list_height)
+{
+       int i, x, y, box_x, box_y;
+       int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
+       WINDOW *dialog, *list;
+
+       /* which item to highlight */
+       item_foreach() {
+               if (item_is_tag('X'))
+                       choice = item_n();
+               if (item_is_selected()) {
+                       choice = item_n();
+                       break;
+               }
+       }
+
+do_resize:
+       if (getmaxy(stdscr) < (height + 6))
+               return -ERRDISPLAYTOOSMALL;
+       if (getmaxx(stdscr) < (width + 6))
+               return -ERRDISPLAYTOOSMALL;
+
+       max_choice = MIN(list_height, item_count());
+
+       /* center dialog box on screen */
+       x = (COLS - width) / 2;
+       y = (LINES - height) / 2;
+
+       draw_shadow(stdscr, y, x, height, width);
+
+       dialog = newwin(height, width, y, x);
+       keypad(dialog, TRUE);
+
+       draw_box(dialog, 0, 0, height, width,
+                dlg.dialog.atr, dlg.border.atr);
+       wattrset(dialog, dlg.border.atr);
+       mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+       for (i = 0; i < width - 2; i++)
+               waddch(dialog, ACS_HLINE);
+       wattrset(dialog, dlg.dialog.atr);
+       waddch(dialog, ACS_RTEE);
+
+       print_title(dialog, title, width);
+
+       wattrset(dialog, dlg.dialog.atr);
+       print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+       list_width = width - 6;
+       box_y = height - list_height - 5;
+       box_x = (width - list_width) / 2 - 1;
+
+       /* create new window for the list */
+       list = subwin(dialog, list_height, list_width, y + box_y + 1,
+                     x + box_x + 1);
+
+       keypad(list, TRUE);
+
+       /* draw a box around the list items */
+       draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
+                dlg.menubox_border.atr, dlg.menubox.atr);
+
+       /* Find length of longest item in order to center checklist */
+       check_x = 0;
+       item_foreach()
+               check_x = MAX(check_x, strlen(item_str()) + 4);
+
+       check_x = (list_width - check_x) / 2;
+       item_x = check_x + 4;
+
+       if (choice >= list_height) {
+               scroll = choice - list_height + 1;
+               choice -= scroll;
+       }
+
+       /* Print the list */
+       for (i = 0; i < max_choice; i++) {
+               item_set(scroll + i);
+               print_item(list, i, i == choice);
+       }
+
+       print_arrows(dialog, choice, item_count(), scroll,
+                    box_y, box_x + check_x + 5, list_height);
+
+       print_buttons(dialog, height, width, 0);
+
+       wnoutrefresh(dialog);
+       wnoutrefresh(list);
+       doupdate();
+
+       while (key != KEY_ESC) {
+               key = wgetch(dialog);
+
+               for (i = 0; i < max_choice; i++) {
+                       item_set(i + scroll);
+                       if (toupper(key) == toupper(item_str()[0]))
+                               break;
+               }
+
+               if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
+                   key == '+' || key == '-') {
+                       if (key == KEY_UP || key == '-') {
+                               if (!choice) {
+                                       if (!scroll)
+                                               continue;
+                                       /* Scroll list down */
+                                       if (list_height > 1) {
+                                               /* De-highlight current first item */
+                                               item_set(scroll);
+                                               print_item(list, 0, FALSE);
+                                               scrollok(list, TRUE);
+                                               wscrl(list, -1);
+                                               scrollok(list, FALSE);
+                                       }
+                                       scroll--;
+                                       item_set(scroll);
+                                       print_item(list, 0, TRUE);
+                                       print_arrows(dialog, choice, item_count(),
+                                                    scroll, box_y, box_x + check_x + 5, list_height);
+
+                                       wnoutrefresh(dialog);
+                                       wrefresh(list);
+
+                                       continue;       /* wait for another key press */
+                               } else
+                                       i = choice - 1;
+                       } else if (key == KEY_DOWN || key == '+') {
+                               if (choice == max_choice - 1) {
+                                       if (scroll + choice >= item_count() - 1)
+                                               continue;
+                                       /* Scroll list up */
+                                       if (list_height > 1) {
+                                               /* De-highlight current last item before scrolling up */
+                                               item_set(scroll + max_choice - 1);
+                                               print_item(list,
+                                                           max_choice - 1,
+                                                           FALSE);
+                                               scrollok(list, TRUE);
+                                               wscrl(list, 1);
+                                               scrollok(list, FALSE);
+                                       }
+                                       scroll++;
+                                       item_set(scroll + max_choice - 1);
+                                       print_item(list, max_choice - 1, TRUE);
+
+                                       print_arrows(dialog, choice, item_count(),
+                                                    scroll, box_y, box_x + check_x + 5, list_height);
+
+                                       wnoutrefresh(dialog);
+                                       wrefresh(list);
+
+                                       continue;       /* wait for another key press */
+                               } else
+                                       i = choice + 1;
+                       }
+                       if (i != choice) {
+                               /* De-highlight current item */
+                               item_set(scroll + choice);
+                               print_item(list, choice, FALSE);
+                               /* Highlight new item */
+                               choice = i;
+                               item_set(scroll + choice);
+                               print_item(list, choice, TRUE);
+                               wnoutrefresh(dialog);
+                               wrefresh(list);
+                       }
+                       continue;       /* wait for another key press */
+               }
+               switch (key) {
+               case 'H':
+               case 'h':
+               case '?':
+                       button = 1;
+                       /* fall-through */
+               case 'S':
+               case 's':
+               case ' ':
+               case '\n':
+                       item_foreach()
+                               item_set_selected(0);
+                       item_set(scroll + choice);
+                       item_set_selected(1);
+                       delwin(list);
+                       delwin(dialog);
+                       return button;
+               case TAB:
+               case KEY_LEFT:
+               case KEY_RIGHT:
+                       button = ((key == KEY_LEFT ? --button : ++button) < 0)
+                           ? 1 : (button > 1 ? 0 : button);
+
+                       print_buttons(dialog, height, width, button);
+                       wrefresh(dialog);
+                       break;
+               case 'X':
+               case 'x':
+                       key = KEY_ESC;
+                       break;
+               case KEY_ESC:
+                       key = on_key_esc(dialog);
+                       break;
+               case KEY_RESIZE:
+                       delwin(list);
+                       delwin(dialog);
+                       on_key_resize();
+                       goto do_resize;
+               }
+
+               /* Now, update everything... */
+               doupdate();
+       }
+       delwin(list);
+       delwin(dialog);
+       return key;             /* ESC pressed */
+}
diff --git a/bin/kconfig/lxdialog/dialog.h b/bin/kconfig/lxdialog/dialog.h
new file mode 100644 (file)
index 0000000..b5211fc
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ *  dialog.h -- common declarations for all dialog modules
+ *
+ *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  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, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#ifndef KBUILD_NO_NLS
+# include <libintl.h>
+#else
+# define gettext(Msgid) ((const char *) (Msgid))
+#endif
+
+#ifdef __sun__
+#define CURS_MACROS
+#endif
+#include CURSES_LOC
+
+/*
+ * Colors in ncurses 1.9.9e do not work properly since foreground and
+ * background colors are OR'd rather than separately masked.  This version
+ * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
+ * with standard curses.  The simplest fix (to make this work with standard
+ * curses) uses the wbkgdset() function, not used in the original hack.
+ * Turn it off if we're building with 1.9.9e, since it just confuses things.
+ */
+#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
+#define OLD_NCURSES 1
+#undef  wbkgdset
+#define wbkgdset(w,p)          /*nothing */
+#else
+#define OLD_NCURSES 0
+#endif
+
+#define TR(params) _tracef params
+
+#define KEY_ESC 27
+#define TAB 9
+#define MAX_LEN 2048
+#define BUF_SIZE (10*1024)
+#define MIN(x,y) (x < y ? x : y)
+#define MAX(x,y) (x > y ? x : y)
+
+#ifndef ACS_ULCORNER
+#define ACS_ULCORNER '+'
+#endif
+#ifndef ACS_LLCORNER
+#define ACS_LLCORNER '+'
+#endif
+#ifndef ACS_URCORNER
+#define ACS_URCORNER '+'
+#endif
+#ifndef ACS_LRCORNER
+#define ACS_LRCORNER '+'
+#endif
+#ifndef ACS_HLINE
+#define ACS_HLINE '-'
+#endif
+#ifndef ACS_VLINE
+#define ACS_VLINE '|'
+#endif
+#ifndef ACS_LTEE
+#define ACS_LTEE '+'
+#endif
+#ifndef ACS_RTEE
+#define ACS_RTEE '+'
+#endif
+#ifndef ACS_UARROW
+#define ACS_UARROW '^'
+#endif
+#ifndef ACS_DARROW
+#define ACS_DARROW 'v'
+#endif
+
+/* error return codes */
+#define ERRDISPLAYTOOSMALL (KEY_MAX + 1)
+
+/*
+ *   Color definitions
+ */
+struct dialog_color {
+       chtype atr;     /* Color attribute */
+       int fg;         /* foreground */
+       int bg;         /* background */
+       int hl;         /* highlight this item */
+};
+
+struct dialog_info {
+       const char *backtitle;
+       struct dialog_color screen;
+       struct dialog_color shadow;
+       struct dialog_color dialog;
+       struct dialog_color title;
+       struct dialog_color border;
+       struct dialog_color button_active;
+       struct dialog_color button_inactive;
+       struct dialog_color button_key_active;
+       struct dialog_color button_key_inactive;
+       struct dialog_color button_label_active;
+       struct dialog_color button_label_inactive;
+       struct dialog_color inputbox;
+       struct dialog_color inputbox_border;
+       struct dialog_color searchbox;
+       struct dialog_color searchbox_title;
+       struct dialog_color searchbox_border;
+       struct dialog_color position_indicator;
+       struct dialog_color menubox;
+       struct dialog_color menubox_border;
+       struct dialog_color item;
+       struct dialog_color item_selected;
+       struct dialog_color tag;
+       struct dialog_color tag_selected;
+       struct dialog_color tag_key;
+       struct dialog_color tag_key_selected;
+       struct dialog_color check;
+       struct dialog_color check_selected;
+       struct dialog_color uarrow;
+       struct dialog_color darrow;
+};
+
+/*
+ * Global variables
+ */
+extern struct dialog_info dlg;
+extern char dialog_input_result[];
+
+/*
+ * Function prototypes
+ */
+
+/* item list as used by checklist and menubox */
+void item_reset(void);
+void item_make(const char *fmt, ...);
+void item_add_str(const char *fmt, ...);
+void item_set_tag(char tag);
+void item_set_data(void *p);
+void item_set_selected(int val);
+int item_activate_selected(void);
+void *item_data(void);
+char item_tag(void);
+
+/* item list manipulation for lxdialog use */
+#define MAXITEMSTR 200
+struct dialog_item {
+       char str[MAXITEMSTR];   /* promtp displayed */
+       char tag;
+       void *data;     /* pointer to menu item - used by menubox+checklist */
+       int selected;   /* Set to 1 by dialog_*() function if selected. */
+};
+
+/* list of lialog_items */
+struct dialog_list {
+       struct dialog_item node;
+       struct dialog_list *next;
+};
+
+extern struct dialog_list *item_cur;
+extern struct dialog_list item_nil;
+extern struct dialog_list *item_head;
+
+int item_count(void);
+void item_set(int n);
+int item_n(void);
+const char *item_str(void);
+int item_is_selected(void);
+int item_is_tag(char tag);
+#define item_foreach() \
+       for (item_cur = item_head ? item_head: item_cur; \
+            item_cur && (item_cur != &item_nil); item_cur = item_cur->next)
+
+/* generic key handlers */
+int on_key_esc(WINDOW *win);
+int on_key_resize(void);
+
+int init_dialog(const char *backtitle);
+void set_dialog_backtitle(const char *backtitle);
+void end_dialog(int x, int y);
+void attr_clear(WINDOW * win, int height, int width, chtype attr);
+void dialog_clear(void);
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
+void print_button(WINDOW * win, const char *label, int y, int x, int selected);
+void print_title(WINDOW *dialog, const char *title, int width);
+void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box,
+             chtype border);
+void draw_shadow(WINDOW * win, int y, int x, int height, int width);
+
+int first_alpha(const char *string, const char *exempt);
+int dialog_yesno(const char *title, const char *prompt, int height, int width);
+int dialog_msgbox(const char *title, const char *prompt, int height,
+                 int width, int pause);
+int dialog_textbox(const char *title, const char *file, int height, int width);
+int dialog_menu(const char *title, const char *prompt,
+               const void *selected, int *s_scroll);
+int dialog_checklist(const char *title, const char *prompt, int height,
+                    int width, int list_height);
+extern char dialog_input_result[];
+int dialog_inputbox(const char *title, const char *prompt, int height,
+                   int width, const char *init);
+
+/*
+ * This is the base for fictitious keys, which activate
+ * the buttons.
+ *
+ * Mouse-generated keys are the following:
+ *   -- the first 32 are used as numbers, in addition to '0'-'9'
+ *   -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
+ *   -- uppercase chars are used to invoke the button (M_EVENT + 'O')
+ */
+#define M_EVENT (KEY_MAX+1)
diff --git a/bin/kconfig/lxdialog/inputbox.c b/bin/kconfig/lxdialog/inputbox.c
new file mode 100644 (file)
index 0000000..616c601
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ *  inputbox.c -- implements the input box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  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, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+char dialog_input_result[MAX_LEN + 1];
+
+/*
+ *  Print the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+       int x = width / 2 - 11;
+       int y = height - 2;
+
+       print_button(dialog, gettext("  Ok  "), y, x, selected == 0);
+       print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
+
+       wmove(dialog, y, x + 1 + 14 * selected);
+       wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box for inputing a string
+ */
+int dialog_inputbox(const char *title, const char *prompt, int height, int width,
+                    const char *init)
+{
+       int i, x, y, box_y, box_x, box_width;
+       int input_x = 0, scroll = 0, key = 0, button = -1;
+       char *instr = dialog_input_result;
+       WINDOW *dialog;
+
+       if (!init)
+               instr[0] = '\0';
+       else
+               strcpy(instr, init);
+
+do_resize:
+       if (getmaxy(stdscr) <= (height - 2))
+               return -ERRDISPLAYTOOSMALL;
+       if (getmaxx(stdscr) <= (width - 2))
+               return -ERRDISPLAYTOOSMALL;
+
+       /* center dialog box on screen */
+       x = (COLS - width) / 2;
+       y = (LINES - height) / 2;
+
+       draw_shadow(stdscr, y, x, height, width);
+
+       dialog = newwin(height, width, y, x);
+       keypad(dialog, TRUE);
+
+       draw_box(dialog, 0, 0, height, width,
+                dlg.dialog.atr, dlg.border.atr);
+       wattrset(dialog, dlg.border.atr);
+       mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+       for (i = 0; i < width - 2; i++)
+               waddch(dialog, ACS_HLINE);
+       wattrset(dialog, dlg.dialog.atr);
+       waddch(dialog, ACS_RTEE);
+
+       print_title(dialog, title, width);
+
+       wattrset(dialog, dlg.dialog.atr);
+       print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+       /* Draw the input field box */
+       box_width = width - 6;
+       getyx(dialog, y, x);
+       box_y = y + 2;
+       box_x = (width - box_width) / 2;
+       draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
+                dlg.dialog.atr, dlg.border.atr);
+
+       print_buttons(dialog, height, width, 0);
+
+       /* Set up the initial value */
+       wmove(dialog, box_y, box_x);
+       wattrset(dialog, dlg.inputbox.atr);
+
+       input_x = strlen(instr);
+
+       if (input_x >= box_width) {
+               scroll = input_x - box_width + 1;
+               input_x = box_width - 1;
+               for (i = 0; i < box_width - 1; i++)
+                       waddch(dialog, instr[scroll + i]);
+       } else {
+               waddstr(dialog, instr);
+       }
+
+       wmove(dialog, box_y, box_x + input_x);
+
+       wrefresh(dialog);
+
+       while (key != KEY_ESC) {
+               key = wgetch(dialog);
+
+               if (button == -1) {     /* Input box selected */
+                       switch (key) {
+                       case TAB:
+                       case KEY_UP:
+                       case KEY_DOWN:
+                               break;
+                       case KEY_LEFT:
+                               continue;
+                       case KEY_RIGHT:
+                               continue;
+                       case KEY_BACKSPACE:
+                       case 127:
+                               if (input_x || scroll) {
+                                       wattrset(dialog, dlg.inputbox.atr);
+                                       if (!input_x) {
+                                               scroll = scroll < box_width - 1 ? 0 : scroll - (box_width - 1);
+                                               wmove(dialog, box_y, box_x);
+                                               for (i = 0; i < box_width; i++)
+                                                       waddch(dialog,
+                                                              instr[scroll + input_x + i] ?
+                                                              instr[scroll + input_x + i] : ' ');
+                                               input_x = strlen(instr) - scroll;
+                                       } else
+                                               input_x--;
+                                       instr[scroll + input_x] = '\0';
+                                       mvwaddch(dialog, box_y, input_x + box_x, ' ');
+                                       wmove(dialog, box_y, input_x + box_x);
+                                       wrefresh(dialog);
+                               }
+                               continue;
+                       default:
+                               if (key < 0x100 && isprint(key)) {
+                                       if (scroll + input_x < MAX_LEN) {
+                                               wattrset(dialog, dlg.inputbox.atr);
+                                               instr[scroll + input_x] = key;
+                                               instr[scroll + input_x + 1] = '\0';
+                                               if (input_x == box_width - 1) {
+                                                       scroll++;
+                                                       wmove(dialog, box_y, box_x);
+                                                       for (i = 0; i < box_width - 1; i++)
+                                                               waddch(dialog, instr [scroll + i]);
+                                               } else {
+                                                       wmove(dialog, box_y, input_x++ + box_x);
+                                                       waddch(dialog, key);
+                                               }
+                                               wrefresh(dialog);
+                                       } else
+                                               flash();        /* Alarm user about overflow */
+                                       continue;
+                               }
+                       }
+               }
+               switch (key) {
+               case 'O':
+               case 'o':
+                       delwin(dialog);
+                       return 0;
+               case 'H':
+               case 'h':
+                       delwin(dialog);
+                       return 1;
+               case KEY_UP:
+               case KEY_LEFT:
+                       switch (button) {
+                       case -1:
+                               button = 1;     /* Indicates "Cancel" button is selected */
+                               print_buttons(dialog, height, width, 1);
+                               break;
+                       case 0:
+                               button = -1;    /* Indicates input box is selected */
+                               print_buttons(dialog, height, width, 0);
+                               wmove(dialog, box_y, box_x + input_x);
+                               wrefresh(dialog);
+                               break;
+                       case 1:
+                               button = 0;     /* Indicates "OK" button is selected */
+                               print_buttons(dialog, height, width, 0);
+                               break;
+                       }
+                       break;
+               case TAB:
+               case KEY_DOWN:
+               case KEY_RIGHT:
+                       switch (button) {
+                       case -1:
+                               button = 0;     /* Indicates "OK" button is selected */
+                               print_buttons(dialog, height, width, 0);
+                               break;
+                       case 0:
+                               button = 1;     /* Indicates "Cancel" button is selected */
+                               print_buttons(dialog, height, width, 1);
+                               break;
+                       case 1:
+                               button = -1;    /* Indicates input box is selected */
+                               print_buttons(dialog, height, width, 0);
+                               wmove(dialog, box_y, box_x + input_x);
+                               wrefresh(dialog);
+                               break;
+                       }
+                       break;
+               case ' ':
+               case '\n':
+                       delwin(dialog);
+                       return (button == -1 ? 0 : button);
+               case 'X':
+               case 'x':
+                       key = KEY_ESC;
+                       break;
+               case KEY_ESC:
+                       key = on_key_esc(dialog);
+                       break;
+               case KEY_RESIZE:
+                       delwin(dialog);
+                       on_key_resize();
+                       goto do_resize;
+               }
+       }
+
+       delwin(dialog);
+       return KEY_ESC;         /* ESC pressed */
+}
diff --git a/bin/kconfig/lxdialog/menubox.c b/bin/kconfig/lxdialog/menubox.c
new file mode 100644 (file)
index 0000000..fa9d633
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ *  menubox.c -- implements the menu box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  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, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *  Changes by Clifford Wolf (god@clifford.at)
+ *
+ *  [ 1998-06-13 ]
+ *
+ *    *)  A bugfix for the Page-Down problem
+ *
+ *    *)  Formerly when I used Page Down and Page Up, the cursor would be set 
+ *        to the first position in the menu box.  Now lxdialog is a bit
+ *        smarter and works more like other menu systems (just have a look at
+ *        it).
+ *
+ *    *)  Formerly if I selected something my scrolling would be broken because
+ *        lxdialog is re-invoked by the Menuconfig shell script, can't
+ *        remember the last scrolling position, and just sets it so that the
+ *        cursor is at the bottom of the box.  Now it writes the temporary file
+ *        lxdialog.scrltmp which contains this information. The file is
+ *        deleted by lxdialog if the user leaves a submenu or enters a new
+ *        one, but it would be nice if Menuconfig could make another "rm -f"
+ *        just to be sure.  Just try it out - you will recognise a difference!
+ *
+ *  [ 1998-06-14 ]
+ *
+ *    *)  Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files
+ *        and menus change their size on the fly.
+ *
+ *    *)  If for some reason the last scrolling position is not saved by
+ *        lxdialog, it sets the scrolling so that the selected item is in the
+ *        middle of the menu box, not at the bottom.
+ *
+ * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
+ * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
+ * This fixes a bug in Menuconfig where using ' ' to descend into menus
+ * would leave mis-synchronized lxdialog.scrltmp files lying around,
+ * fscanf would read in 'scroll', and eventually that value would get used.
+ */
+
+#include "dialog.h"
+
+static int menu_width, item_x;
+
+/*
+ * Print menu item
+ */
+static void do_print_item(WINDOW * win, const char *item, int line_y,
+                          int selected, int hotkey)
+{
+       int j;
+       char *menu_item = malloc(menu_width + 1);
+
+       strncpy(menu_item, item, menu_width - item_x);
+       menu_item[menu_width - item_x] = '\0';
+       j = first_alpha(menu_item, "YyNnMmHh");
+
+       /* Clear 'residue' of last item */
+       wattrset(win, dlg.menubox.atr);
+       wmove(win, line_y, 0);
+#if OLD_NCURSES
+       {
+               int i;
+               for (i = 0; i < menu_width; i++)
+                       waddch(win, ' ');
+       }
+#else
+       wclrtoeol(win);
+#endif
+       wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+       mvwaddstr(win, line_y, item_x, menu_item);
+       if (hotkey) {
+               wattrset(win, selected ? dlg.tag_key_selected.atr
+                        : dlg.tag_key.atr);
+               mvwaddch(win, line_y, item_x + j, menu_item[j]);
+       }
+       if (selected) {
+               wmove(win, line_y, item_x + 1);
+       }
+       free(menu_item);
+       wrefresh(win);
+}
+
+#define print_item(index, choice, selected)                            \
+do {                                                                   \
+       item_set(index);                                                \
+       do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \
+} while (0)
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
+                        int height)
+{
+       int cur_y, cur_x;
+
+       getyx(win, cur_y, cur_x);
+
+       wmove(win, y, x);
+
+       if (scroll > 0) {
+               wattrset(win, dlg.uarrow.atr);
+               waddch(win, ACS_UARROW);
+               waddstr(win, "(-)");
+       } else {
+               wattrset(win, dlg.menubox.atr);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+       }
+
+       y = y + height + 1;
+       wmove(win, y, x);
+       wrefresh(win);
+
+       if ((height < item_no) && (scroll + height < item_no)) {
+               wattrset(win, dlg.darrow.atr);
+               waddch(win, ACS_DARROW);
+               waddstr(win, "(+)");
+       } else {
+               wattrset(win, dlg.menubox_border.atr);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+       }
+
+       wmove(win, cur_y, cur_x);
+       wrefresh(win);
+}
+
+/*
+ * Display the termination buttons.
+ */
+static void print_buttons(WINDOW * win, int height, int width, int selected)
+{
+       int x = width / 2 - 16;
+       int y = height - 2;
+
+       print_button(win, gettext("Select"), y, x, selected == 0);
+       print_button(win, gettext(" Exit "), y, x + 12, selected == 1);
+       print_button(win, gettext(" Help "), y, x + 24, selected == 2);
+
+       wmove(win, y, x + 1 + 12 * selected);
+       wrefresh(win);
+}
+
+/* scroll up n lines (n may be negative) */
+static void do_scroll(WINDOW *win, int *scroll, int n)
+{
+       /* Scroll menu up */
+       scrollok(win, TRUE);
+       wscrl(win, n);
+       scrollok(win, FALSE);
+       *scroll = *scroll + n;
+       wrefresh(win);
+}
+
+/*
+ * Display a menu for choosing among a number of options
+ */
+int dialog_menu(const char *title, const char *prompt,
+                const void *selected, int *s_scroll)
+{
+       int i, j, x, y, box_x, box_y;
+       int height, width, menu_height;
+       int key = 0, button = 0, scroll = 0, choice = 0;
+       int first_item =  0, max_choice;
+       WINDOW *dialog, *menu;
+
+do_resize:
+       height = getmaxy(stdscr);
+       width = getmaxx(stdscr);
+       if (height < 15 || width < 65)
+               return -ERRDISPLAYTOOSMALL;
+
+       height -= 4;
+       width  -= 5;
+       menu_height = height - 10;
+
+       max_choice = MIN(menu_height, item_count());
+
+       /* center dialog box on screen */
+       x = (COLS - width) / 2;
+       y = (LINES - height) / 2;
+
+       draw_shadow(stdscr, y, x, height, width);
+
+       dialog = newwin(height, width, y, x);
+       keypad(dialog, TRUE);
+
+       draw_box(dialog, 0, 0, height, width,
+                dlg.dialog.atr, dlg.border.atr);
+       wattrset(dialog, dlg.border.atr);
+       mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+       for (i = 0; i < width - 2; i++)
+               waddch(dialog, ACS_HLINE);
+       wattrset(dialog, dlg.dialog.atr);
+       wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+       waddch(dialog, ACS_RTEE);
+
+       print_title(dialog, title, width);
+
+       wattrset(dialog, dlg.dialog.atr);
+       print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+       menu_width = width - 6;
+       box_y = height - menu_height - 5;
+       box_x = (width - menu_width) / 2 - 1;
+
+       /* create new window for the menu */
+       menu = subwin(dialog, menu_height, menu_width,
+                     y + box_y + 1, x + box_x + 1);
+       keypad(menu, TRUE);
+
+       /* draw a box around the menu items */
+       draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
+                dlg.menubox_border.atr, dlg.menubox.atr);
+
+       if (menu_width >= 80)
+               item_x = (menu_width - 70) / 2;
+       else
+               item_x = 4;
+
+       /* Set choice to default item */
+       item_foreach()
+               if (selected && (selected == item_data()))
+                       choice = item_n();
+       /* get the saved scroll info */
+       scroll = *s_scroll;
+       if ((scroll <= choice) && (scroll + max_choice > choice) &&
+          (scroll >= 0) && (scroll + max_choice <= item_count())) {
+               first_item = scroll;
+               choice = choice - scroll;
+       } else {
+               scroll = 0;
+       }
+       if ((choice >= max_choice)) {
+               if (choice >= item_count() - max_choice / 2)
+                       scroll = first_item = item_count() - max_choice;
+               else
+                       scroll = first_item = choice - max_choice / 2;
+               choice = choice - scroll;
+       }
+
+       /* Print the menu */
+       for (i = 0; i < max_choice; i++) {
+               print_item(first_item + i, i, i == choice);
+       }
+
+       wnoutrefresh(menu);
+
+       print_arrows(dialog, item_count(), scroll,
+                    box_y, box_x + item_x + 1, menu_height);
+
+       print_buttons(dialog, height, width, 0);
+       wmove(menu, choice, item_x + 1);
+       wrefresh(menu);
+
+       while (key != KEY_ESC) {
+               key = wgetch(menu);
+
+               if (key < 256 && isalpha(key))
+                       key = tolower(key);
+
+               if (strchr("ynmh", key))
+                       i = max_choice;
+               else {
+                       for (i = choice + 1; i < max_choice; i++) {
+                               item_set(scroll + i);
+                               j = first_alpha(item_str(), "YyNnMmHh");
+                               if (key == tolower(item_str()[j]))
+                                       break;
+                       }
+                       if (i == max_choice)
+                               for (i = 0; i < max_choice; i++) {
+                                       item_set(scroll + i);
+                                       j = first_alpha(item_str(), "YyNnMmHh");
+                                       if (key == tolower(item_str()[j]))
+                                               break;
+                               }
+               }
+
+               if (i < max_choice ||
+                   key == KEY_UP || key == KEY_DOWN ||
+                   key == '-' || key == '+' ||
+                   key == KEY_PPAGE || key == KEY_NPAGE) {
+                       /* Remove highligt of current item */
+                       print_item(scroll + choice, choice, FALSE);
+
+                       if (key == KEY_UP || key == '-') {
+                               if (choice < 2 && scroll) {
+                                       /* Scroll menu down */
+                                       do_scroll(menu, &scroll, -1);
+
+                                       print_item(scroll, 0, FALSE);
+                               } else
+                                       choice = MAX(choice - 1, 0);
+
+                       } else if (key == KEY_DOWN || key == '+') {
+                               print_item(scroll+choice, choice, FALSE);
+
+                               if ((choice > max_choice - 3) &&
+                                   (scroll + max_choice < item_count())) {
+                                       /* Scroll menu up */
+                                       do_scroll(menu, &scroll, 1);
+
+                                       print_item(scroll+max_choice - 1,
+                                                  max_choice - 1, FALSE);
+                               } else
+                                       choice = MIN(choice + 1, max_choice - 1);
+
+                       } else if (key == KEY_PPAGE) {
+                               scrollok(menu, TRUE);
+                               for (i = 0; (i < max_choice); i++) {
+                                       if (scroll > 0) {
+                                               do_scroll(menu, &scroll, -1);
+                                               print_item(scroll, 0, FALSE);
+                                       } else {
+                                               if (choice > 0)
+                                                       choice--;
+                                       }
+                               }
+
+                       } else if (key == KEY_NPAGE) {
+                               for (i = 0; (i < max_choice); i++) {
+                                       if (scroll + max_choice < item_count()) {
+                                               do_scroll(menu, &scroll, 1);
+                                               print_item(scroll+max_choice-1,
+                                                          max_choice - 1, FALSE);
+                                       } else {
+                                               if (choice + 1 < max_choice)
+                                                       choice++;
+                                       }
+                               }
+                       } else
+                               choice = i;
+
+                       print_item(scroll + choice, choice, TRUE);
+
+                       print_arrows(dialog, item_count(), scroll,
+                                    box_y, box_x + item_x + 1, menu_height);
+
+                       wnoutrefresh(dialog);
+                       wrefresh(menu);
+
+                       continue;       /* wait for another key press */
+               }
+
+               switch (key) {
+               case KEY_LEFT:
+               case TAB:
+               case KEY_RIGHT:
+                       button = ((key == KEY_LEFT ? --button : ++button) < 0)
+                           ? 2 : (button > 2 ? 0 : button);
+
+                       print_buttons(dialog, height, width, button);
+                       wrefresh(menu);
+                       break;
+               case ' ':
+               case 's':
+               case 'y':
+               case 'n':
+               case 'm':
+               case '/':
+                       /* save scroll info */
+                       *s_scroll = scroll;
+                       delwin(menu);
+                       delwin(dialog);
+                       item_set(scroll + choice);
+                       item_set_selected(1);
+                       switch (key) {
+                       case 's':
+                               return 3;
+                       case 'y':
+                               return 3;
+                       case 'n':
+                               return 4;
+                       case 'm':
+                               return 5;
+                       case ' ':
+                               return 6;
+                       case '/':
+                               return 7;
+                       }
+                       return 0;
+               case 'h':
+               case '?':
+                       button = 2;
+               case '\n':
+                       *s_scroll = scroll;
+                       delwin(menu);
+                       delwin(dialog);
+                       item_set(scroll + choice);
+                       item_set_selected(1);
+                       return button;
+               case 'e':
+               case 'x':
+                       key = KEY_ESC;
+                       break;
+               case KEY_ESC:
+                       key = on_key_esc(menu);
+                       break;
+               case KEY_RESIZE:
+                       on_key_resize();
+                       delwin(menu);
+                       delwin(dialog);
+                       goto do_resize;
+               }
+       }
+       delwin(menu);
+       delwin(dialog);
+       return key;             /* ESC pressed */
+}
diff --git a/bin/kconfig/lxdialog/textbox.c b/bin/kconfig/lxdialog/textbox.c
new file mode 100644 (file)
index 0000000..c704712
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ *  textbox.c -- implements the text box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  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, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+static void back_lines(int n);
+static void print_page(WINDOW * win, int height, int width);
+static void print_line(WINDOW * win, int row, int width);
+static char *get_line(void);
+static void print_position(WINDOW * win);
+
+static int hscroll;
+static int begin_reached, end_reached, page_length;
+static const char *buf;
+static const char *page;
+
+/*
+ * refresh window content
+ */
+static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
+                                                         int cur_y, int cur_x)
+{
+       print_page(box, boxh, boxw);
+       print_position(dialog);
+       wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
+       wrefresh(dialog);
+}
+
+
+/*
+ * Display text from a file in a dialog box.
+ */
+int dialog_textbox(const char *title, const char *tbuf,
+                  int initial_height, int initial_width)
+{
+       int i, x, y, cur_x, cur_y, key = 0;
+       int height, width, boxh, boxw;
+       int passed_end;
+       WINDOW *dialog, *box;
+
+       begin_reached = 1;
+       end_reached = 0;
+       page_length = 0;
+       hscroll = 0;
+       buf = tbuf;
+       page = buf;     /* page is pointer to start of page to be displayed */
+
+do_resize:
+       getmaxyx(stdscr, height, width);
+       if (height < 8 || width < 8)
+               return -ERRDISPLAYTOOSMALL;
+       if (initial_height != 0)
+               height = initial_height;
+       else
+               if (height > 4)
+                       height -= 4;
+               else
+                       height = 0;
+       if (initial_width != 0)
+               width = initial_width;
+       else
+               if (width > 5)
+                       width -= 5;
+               else
+                       width = 0;
+
+       /* center dialog box on screen */
+       x = (COLS - width) / 2;
+       y = (LINES - height) / 2;
+
+       draw_shadow(stdscr, y, x, height, width);
+
+       dialog = newwin(height, width, y, x);
+       keypad(dialog, TRUE);
+
+       /* Create window for box region, used for scrolling text */
+       boxh = height - 4;
+       boxw = width - 2;
+       box = subwin(dialog, boxh, boxw, y + 1, x + 1);
+       wattrset(box, dlg.dialog.atr);
+       wbkgdset(box, dlg.dialog.atr & A_COLOR);
+
+       keypad(box, TRUE);
+
+       /* register the new window, along with its borders */
+       draw_box(dialog, 0, 0, height, width,
+                dlg.dialog.atr, dlg.border.atr);
+
+       wattrset(dialog, dlg.border.atr);
+       mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+       for (i = 0; i < width - 2; i++)
+               waddch(dialog, ACS_HLINE);
+       wattrset(dialog, dlg.dialog.atr);
+       wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+       waddch(dialog, ACS_RTEE);
+
+       print_title(dialog, title, width);
+
+       print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE);
+       wnoutrefresh(dialog);
+       getyx(dialog, cur_y, cur_x);    /* Save cursor position */
+
+       /* Print first page of text */
+       attr_clear(box, boxh, boxw, dlg.dialog.atr);
+       refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
+
+       while ((key != KEY_ESC) && (key != '\n')) {
+               key = wgetch(dialog);
+               switch (key) {
+               case 'E':       /* Exit */
+               case 'e':
+               case 'X':
+               case 'x':
+                       delwin(box);
+                       delwin(dialog);
+                       return 0;
+               case 'g':       /* First page */
+               case KEY_HOME:
+                       if (!begin_reached) {
+                               begin_reached = 1;
+                               page = buf;
+                               refresh_text_box(dialog, box, boxh, boxw,
+                                                cur_y, cur_x);
+                       }
+                       break;
+               case 'G':       /* Last page */
+               case KEY_END:
+
+                       end_reached = 1;
+                       /* point to last char in buf */
+                       page = buf + strlen(buf);
+                       back_lines(boxh);
+                       refresh_text_box(dialog, box, boxh, boxw,
+                                        cur_y, cur_x);
+                       break;
+               case 'K':       /* Previous line */
+               case 'k':
+               case KEY_UP:
+                       if (!begin_reached) {
+                               back_lines(page_length + 1);
+
+                               /* We don't call print_page() here but use
+                                * scrolling to ensure faster screen update.
+                                * However, 'end_reached' and 'page_length'
+                                * should still be updated, and 'page' should
+                                * point to start of next page. This is done
+                                * by calling get_line() in the following
+                                * 'for' loop. */
+                               scrollok(box, TRUE);
+                               wscrl(box, -1); /* Scroll box region down one line */
+                               scrollok(box, FALSE);
+                               page_length = 0;
+                               passed_end = 0;
+                               for (i = 0; i < boxh; i++) {
+                                       if (!i) {
+                                               /* print first line of page */
+                                               print_line(box, 0, boxw);
+                                               wnoutrefresh(box);
+                                       } else
+                                               /* Called to update 'end_reached' and 'page' */
+                                               get_line();
+                                       if (!passed_end)
+                                               page_length++;
+                                       if (end_reached && !passed_end)
+                                               passed_end = 1;
+                               }
+
+                               print_position(dialog);
+                               wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
+                               wrefresh(dialog);
+                       }
+                       break;
+               case 'B':       /* Previous page */
+               case 'b':
+               case KEY_PPAGE:
+                       if (begin_reached)
+                               break;
+                       back_lines(page_length + boxh);
+                       refresh_text_box(dialog, box, boxh, boxw,
+                                        cur_y, cur_x);
+                       break;
+               case 'J':       /* Next line */
+               case 'j':
+               case KEY_DOWN:
+                       if (!end_reached) {
+                               begin_reached = 0;
+                               scrollok(box, TRUE);
+                               scroll(box);    /* Scroll box region up one line */
+                               scrollok(box, FALSE);
+                               print_line(box, boxh - 1, boxw);
+                               wnoutrefresh(box);
+                               print_position(dialog);
+                               wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
+                               wrefresh(dialog);
+                       }
+                       break;
+               case KEY_NPAGE: /* Next page */
+               case ' ':
+                       if (end_reached)
+                               break;
+
+                       begin_reached = 0;
+                       refresh_text_box(dialog, box, boxh, boxw,
+                                        cur_y, cur_x);
+                       break;
+               case '0':       /* Beginning of line */
+               case 'H':       /* Scroll left */
+               case 'h':
+               case KEY_LEFT:
+                       if (hscroll <= 0)
+                               break;
+
+                       if (key == '0')
+                               hscroll = 0;
+                       else
+                               hscroll--;
+                       /* Reprint current page to scroll horizontally */
+                       back_lines(page_length);
+                       refresh_text_box(dialog, box, boxh, boxw,
+                                        cur_y, cur_x);
+                       break;
+               case 'L':       /* Scroll right */
+               case 'l':
+               case KEY_RIGHT:
+                       if (hscroll >= MAX_LEN)
+                               break;
+                       hscroll++;
+                       /* Reprint current page to scroll horizontally */
+                       back_lines(page_length);
+                       refresh_text_box(dialog, box, boxh, boxw,
+                                        cur_y, cur_x);
+                       break;
+               case KEY_ESC:
+                       key = on_key_esc(dialog);
+                       break;
+               case KEY_RESIZE:
+                       back_lines(height);
+                       delwin(box);
+                       delwin(dialog);
+                       on_key_resize();
+                       goto do_resize;
+               }
+       }
+       delwin(box);
+       delwin(dialog);
+       return key;             /* ESC pressed */
+}
+
+/*
+ * Go back 'n' lines in text. Called by dialog_textbox().
+ * 'page' will be updated to point to the desired line in 'buf'.
+ */
+static void back_lines(int n)
+{
+       int i;
+
+       begin_reached = 0;
+       /* Go back 'n' lines */
+       for (i = 0; i < n; i++) {
+               if (*page == '\0') {
+                       if (end_reached) {
+                               end_reached = 0;
+                               continue;
+                       }
+               }
+               if (page == buf) {
+                       begin_reached = 1;
+                       return;
+               }
+               page--;
+               do {
+                       if (page == buf) {
+                               begin_reached = 1;
+                               return;
+                       }
+                       page--;
+               } while (*page != '\n');
+               page++;
+       }
+}
+
+/*
+ * Print a new page of text. Called by dialog_textbox().
+ */
+static void print_page(WINDOW * win, int height, int width)
+{
+       int i, passed_end = 0;
+
+       page_length = 0;
+       for (i = 0; i < height; i++) {
+               print_line(win, i, width);
+               if (!passed_end)
+                       page_length++;
+               if (end_reached && !passed_end)
+                       passed_end = 1;
+       }
+       wnoutrefresh(win);
+}
+
+/*
+ * Print a new line of text. Called by dialog_textbox() and print_page().
+ */
+static void print_line(WINDOW * win, int row, int width)
+{
+       int y, x;
+       char *line;
+
+       line = get_line();
+       line += MIN(strlen(line), hscroll);     /* Scroll horizontally */
+       wmove(win, row, 0);     /* move cursor to correct line */
+       waddch(win, ' ');
+       waddnstr(win, line, MIN(strlen(line), width - 2));
+
+       getyx(win, y, x);
+       /* Clear 'residue' of previous line */
+#if OLD_NCURSES
+       {
+               int i;
+               for (i = 0; i < width - x; i++)
+                       waddch(win, ' ');
+       }
+#else
+       wclrtoeol(win);
+#endif
+}
+
+/*
+ * Return current line of text. Called by dialog_textbox() and print_line().
+ * 'page' should point to start of current line before calling, and will be
+ * updated to point to start of next line.
+ */
+static char *get_line(void)
+{
+       int i = 0;
+       static char line[MAX_LEN + 1];
+
+       end_reached = 0;
+       while (*page != '\n') {
+               if (*page == '\0') {
+                       if (!end_reached) {
+                               end_reached = 1;
+                               break;
+                       }
+               } else if (i < MAX_LEN)
+                       line[i++] = *(page++);
+               else {
+                       /* Truncate lines longer than MAX_LEN characters */
+                       if (i == MAX_LEN)
+                               line[i++] = '\0';
+                       page++;
+               }
+       }
+       if (i <= MAX_LEN)
+               line[i] = '\0';
+       if (!end_reached)
+               page++;         /* move pass '\n' */
+
+       return line;
+}
+
+/*
+ * Print current position
+ */
+static void print_position(WINDOW * win)
+{
+       int percent;
+
+       wattrset(win, dlg.position_indicator.atr);
+       wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
+       percent = (page - buf) * 100 / strlen(buf);
+       wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
+       wprintw(win, "(%3d%%)", percent);
+}
diff --git a/bin/kconfig/lxdialog/util.c b/bin/kconfig/lxdialog/util.c
new file mode 100644 (file)
index 0000000..86d95cc
--- /dev/null
@@ -0,0 +1,655 @@
+/*
+ *  util.c
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  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, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+struct dialog_info dlg;
+
+static void set_mono_theme(void)
+{
+       dlg.screen.atr = A_NORMAL;
+       dlg.shadow.atr = A_NORMAL;
+       dlg.dialog.atr = A_NORMAL;
+       dlg.title.atr = A_BOLD;
+       dlg.border.atr = A_NORMAL;
+       dlg.button_active.atr = A_REVERSE;
+       dlg.button_inactive.atr = A_DIM;
+       dlg.button_key_active.atr = A_REVERSE;
+       dlg.button_key_inactive.atr = A_BOLD;
+       dlg.button_label_active.atr = A_REVERSE;
+       dlg.button_label_inactive.atr = A_NORMAL;
+       dlg.inputbox.atr = A_NORMAL;
+       dlg.inputbox_border.atr = A_NORMAL;
+       dlg.searchbox.atr = A_NORMAL;
+       dlg.searchbox_title.atr = A_BOLD;
+       dlg.searchbox_border.atr = A_NORMAL;
+       dlg.position_indicator.atr = A_BOLD;
+       dlg.menubox.atr = A_NORMAL;
+       dlg.menubox_border.atr = A_NORMAL;
+       dlg.item.atr = A_NORMAL;
+       dlg.item_selected.atr = A_REVERSE;
+       dlg.tag.atr = A_BOLD;
+       dlg.tag_selected.atr = A_REVERSE;
+       dlg.tag_key.atr = A_BOLD;
+       dlg.tag_key_selected.atr = A_REVERSE;
+       dlg.check.atr = A_BOLD;
+       dlg.check_selected.atr = A_REVERSE;
+       dlg.uarrow.atr = A_BOLD;
+       dlg.darrow.atr = A_BOLD;
+}
+
+#define DLG_COLOR(dialog, f, b, h) \
+do {                               \
+       dlg.dialog.fg = (f);       \
+       dlg.dialog.bg = (b);       \
+       dlg.dialog.hl = (h);       \
+} while (0)
+
+static void set_classic_theme(void)
+{
+       DLG_COLOR(screen,                COLOR_CYAN,   COLOR_BLUE,   true);
+       DLG_COLOR(shadow,                COLOR_BLACK,  COLOR_BLACK,  true);
+       DLG_COLOR(dialog,                COLOR_BLACK,  COLOR_WHITE,  false);
+       DLG_COLOR(title,                 COLOR_YELLOW, COLOR_WHITE,  true);
+       DLG_COLOR(border,                COLOR_WHITE,  COLOR_WHITE,  true);
+       DLG_COLOR(button_active,         COLOR_WHITE,  COLOR_BLUE,   true);
+       DLG_COLOR(button_inactive,       COLOR_BLACK,  COLOR_WHITE,  false);
+       DLG_COLOR(button_key_active,     COLOR_WHITE,  COLOR_BLUE,   true);
+       DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_WHITE,  false);
+       DLG_COLOR(button_label_active,   COLOR_YELLOW, COLOR_BLUE,   true);
+       DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_WHITE,  true);
+       DLG_COLOR(inputbox,              COLOR_BLACK,  COLOR_WHITE,  false);
+       DLG_COLOR(inputbox_border,       COLOR_BLACK,  COLOR_WHITE,  false);
+       DLG_COLOR(searchbox,             COLOR_BLACK,  COLOR_WHITE,  false);
+       DLG_COLOR(searchbox_title,       COLOR_YELLOW, COLOR_WHITE,  true);
+       DLG_COLOR(searchbox_border,      COLOR_WHITE,  COLOR_WHITE,  true);
+       DLG_COLOR(position_indicator,    COLOR_YELLOW, COLOR_WHITE,  true);
+       DLG_COLOR(menubox,               COLOR_BLACK,  COLOR_WHITE,  false);
+       DLG_COLOR(menubox_border,        COLOR_WHITE,  COLOR_WHITE,  true);
+       DLG_COLOR(item,                  COLOR_BLACK,  COLOR_WHITE,  false);
+       DLG_COLOR(item_selected,         COLOR_WHITE,  COLOR_BLUE,   true);
+       DLG_COLOR(tag,                   COLOR_YELLOW, COLOR_WHITE,  true);
+       DLG_COLOR(tag_selected,          COLOR_YELLOW, COLOR_BLUE,   true);
+       DLG_COLOR(tag_key,               COLOR_YELLOW, COLOR_WHITE,  true);
+       DLG_COLOR(tag_key_selected,      COLOR_YELLOW, COLOR_BLUE,   true);
+       DLG_COLOR(check,                 COLOR_BLACK,  COLOR_WHITE,  false);
+       DLG_COLOR(check_selected,        COLOR_WHITE,  COLOR_BLUE,   true);
+       DLG_COLOR(uarrow,                COLOR_GREEN,  COLOR_WHITE,  true);
+       DLG_COLOR(darrow,                COLOR_GREEN,  COLOR_WHITE,  true);
+}
+
+static void set_blackbg_theme(void)
+{
+       DLG_COLOR(screen, COLOR_RED,   COLOR_BLACK, true);
+       DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
+       DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
+       DLG_COLOR(title,  COLOR_RED,   COLOR_BLACK, false);
+       DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
+
+       DLG_COLOR(button_active,         COLOR_YELLOW, COLOR_RED,   false);
+       DLG_COLOR(button_inactive,       COLOR_YELLOW, COLOR_BLACK, false);
+       DLG_COLOR(button_key_active,     COLOR_YELLOW, COLOR_RED,   true);
+       DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_BLACK, false);
+       DLG_COLOR(button_label_active,   COLOR_WHITE,  COLOR_RED,   false);
+       DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_BLACK, true);
+
+       DLG_COLOR(inputbox,         COLOR_YELLOW, COLOR_BLACK, false);
+       DLG_COLOR(inputbox_border,  COLOR_YELLOW, COLOR_BLACK, false);
+
+       DLG_COLOR(searchbox,        COLOR_YELLOW, COLOR_BLACK, false);
+       DLG_COLOR(searchbox_title,  COLOR_YELLOW, COLOR_BLACK, true);
+       DLG_COLOR(searchbox_border, COLOR_BLACK,  COLOR_BLACK, true);
+
+       DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK,  false);
+
+       DLG_COLOR(menubox,          COLOR_YELLOW, COLOR_BLACK, false);
+       DLG_COLOR(menubox_border,   COLOR_BLACK,  COLOR_BLACK, true);
+
+       DLG_COLOR(item,             COLOR_WHITE, COLOR_BLACK, false);
+       DLG_COLOR(item_selected,    COLOR_WHITE, COLOR_RED,   false);
+
+       DLG_COLOR(tag,              COLOR_RED,    COLOR_BLACK, false);
+       DLG_COLOR(tag_selected,     COLOR_YELLOW, COLOR_RED,   true);
+       DLG_COLOR(tag_key,          COLOR_RED,    COLOR_BLACK, false);
+       DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED,   true);
+
+       DLG_COLOR(check,            COLOR_YELLOW, COLOR_BLACK, false);
+       DLG_COLOR(check_selected,   COLOR_YELLOW, COLOR_RED,   true);
+
+       DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
+       DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
+}
+
+static void set_bluetitle_theme(void)
+{
+       set_classic_theme();
+       DLG_COLOR(title,               COLOR_BLUE,   COLOR_WHITE, true);
+       DLG_COLOR(button_key_active,   COLOR_YELLOW, COLOR_BLUE,  true);
+       DLG_COLOR(button_label_active, COLOR_WHITE,  COLOR_BLUE,  true);
+       DLG_COLOR(searchbox_title,     COLOR_BLUE,   COLOR_WHITE, true);
+       DLG_COLOR(position_indicator,  COLOR_BLUE,   COLOR_WHITE, true);
+       DLG_COLOR(tag,                 COLOR_BLUE,   COLOR_WHITE, true);
+       DLG_COLOR(tag_key,             COLOR_BLUE,   COLOR_WHITE, true);
+
+}
+
+/*
+ * Select color theme
+ */
+static int set_theme(const char *theme)
+{
+       int use_color = 1;
+       if (!theme)
+               set_bluetitle_theme();
+       else if (strcmp(theme, "classic") == 0)
+               set_classic_theme();
+       else if (strcmp(theme, "bluetitle") == 0)
+               set_bluetitle_theme();
+       else if (strcmp(theme, "blackbg") == 0)
+               set_blackbg_theme();
+       else if (strcmp(theme, "mono") == 0)
+               use_color = 0;
+
+       return use_color;
+}
+
+static void init_one_color(struct dialog_color *color)
+{
+       static int pair = 0;
+
+       pair++;
+       init_pair(pair, color->fg, color->bg);
+       if (color->hl)
+               color->atr = A_BOLD | COLOR_PAIR(pair);
+       else
+               color->atr = COLOR_PAIR(pair);
+}
+
+static void init_dialog_colors(void)
+{
+       init_one_color(&dlg.screen);
+       init_one_color(&dlg.shadow);
+       init_one_color(&dlg.dialog);
+       init_one_color(&dlg.title);
+       init_one_color(&dlg.border);
+       init_one_color(&dlg.button_active);
+       init_one_color(&dlg.button_inactive);
+       init_one_color(&dlg.button_key_active);
+       init_one_color(&dlg.button_key_inactive);
+       init_one_color(&dlg.button_label_active);
+       init_one_color(&dlg.button_label_inactive);
+       init_one_color(&dlg.inputbox);
+       init_one_color(&dlg.inputbox_border);
+       init_one_color(&dlg.searchbox);
+       init_one_color(&dlg.searchbox_title);
+       init_one_color(&dlg.searchbox_border);
+       init_one_color(&dlg.position_indicator);
+       init_one_color(&dlg.menubox);
+       init_one_color(&dlg.menubox_border);
+       init_one_color(&dlg.item);
+       init_one_color(&dlg.item_selected);
+       init_one_color(&dlg.tag);
+       init_one_color(&dlg.tag_selected);
+       init_one_color(&dlg.tag_key);
+       init_one_color(&dlg.tag_key_selected);
+       init_one_color(&dlg.check);
+       init_one_color(&dlg.check_selected);
+       init_one_color(&dlg.uarrow);
+       init_one_color(&dlg.darrow);
+}
+
+/*
+ * Setup for color display
+ */
+static void color_setup(const char *theme)
+{
+       int use_color;
+
+       use_color = set_theme(theme);
+       if (use_color && has_colors()) {
+               start_color();
+               init_dialog_colors();
+       } else
+               set_mono_theme();
+}
+
+/*
+ * Set window to attribute 'attr'
+ */
+void attr_clear(WINDOW * win, int height, int width, chtype attr)
+{
+       int i, j;
+
+       wattrset(win, attr);
+       for (i = 0; i < height; i++) {
+               wmove(win, i, 0);
+               for (j = 0; j < width; j++)
+                       waddch(win, ' ');
+       }
+       touchwin(win);
+}
+
+void dialog_clear(void)
+{
+       attr_clear(stdscr, LINES, COLS, dlg.screen.atr);
+       /* Display background title if it exists ... - SLH */
+       if (dlg.backtitle != NULL) {
+               int i;
+
+               wattrset(stdscr, dlg.screen.atr);
+               mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
+               wmove(stdscr, 1, 1);
+               for (i = 1; i < COLS - 1; i++)
+                       waddch(stdscr, ACS_HLINE);
+       }
+       wnoutrefresh(stdscr);
+}
+
+/*
+ * Do some initialization for dialog
+ */
+int init_dialog(const char *backtitle)
+{
+       int height, width;
+
+       initscr();              /* Init curses */
+       getmaxyx(stdscr, height, width);
+       if (height < 19 || width < 80) {
+               endwin();
+               return -ERRDISPLAYTOOSMALL;
+       }
+
+       dlg.backtitle = backtitle;
+       color_setup(getenv("MENUCONFIG_COLOR"));
+
+       keypad(stdscr, TRUE);
+       cbreak();
+       noecho();
+       dialog_clear();
+
+       return 0;
+}
+
+void set_dialog_backtitle(const char *backtitle)
+{
+       dlg.backtitle = backtitle;
+}
+
+/*
+ * End using dialog functions.
+ */
+void end_dialog(int x, int y)
+{
+       /* move cursor back to original position */
+       move(y, x);
+       refresh();
+       endwin();
+}
+
+/* Print the title of the dialog. Center the title and truncate
+ * tile if wider than dialog (- 2 chars).
+ **/
+void print_title(WINDOW *dialog, const char *title, int width)
+{
+       if (title) {
+               int tlen = MIN(width - 2, strlen(title));
+               wattrset(dialog, dlg.title.atr);
+               mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
+               mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
+               waddch(dialog, ' ');
+       }
+}
+
+/*
+ * Print a string of text in a window, automatically wrap around to the
+ * next line if the string is too long to fit on one line. Newline
+ * characters '\n' are replaced by spaces.  We start on a new line
+ * if there is no room for at least 4 nonblanks following a double-space.
+ */
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
+{
+       int newl, cur_x, cur_y;
+       int i, prompt_len, room, wlen;
+       char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
+
+       strcpy(tempstr, prompt);
+
+       prompt_len = strlen(tempstr);
+
+       /*
+        * Remove newlines
+        */
+       for (i = 0; i < prompt_len; i++) {
+               if (tempstr[i] == '\n')
+                       tempstr[i] = ' ';
+       }
+
+       if (prompt_len <= width - x * 2) {      /* If prompt is short */
+               wmove(win, y, (width - prompt_len) / 2);
+               waddstr(win, tempstr);
+       } else {
+               cur_x = x;
+               cur_y = y;
+               newl = 1;
+               word = tempstr;
+               while (word && *word) {
+                       sp = strchr(word, ' ');
+                       if (sp)
+                               *sp++ = 0;
+
+                       /* Wrap to next line if either the word does not fit,
+                          or it is the first word of a new sentence, and it is
+                          short, and the next word does not fit. */
+                       room = width - cur_x;
+                       wlen = strlen(word);
+                       if (wlen > room ||
+                           (newl && wlen < 4 && sp
+                            && wlen + 1 + strlen(sp) > room
+                            && (!(sp2 = strchr(sp, ' '))
+                                || wlen + 1 + (sp2 - sp) > room))) {
+                               cur_y++;
+                               cur_x = x;
+                       }
+                       wmove(win, cur_y, cur_x);
+                       waddstr(win, word);
+                       getyx(win, cur_y, cur_x);
+                       cur_x++;
+                       if (sp && *sp == ' ') {
+                               cur_x++;        /* double space */
+                               while (*++sp == ' ') ;
+                               newl = 1;
+                       } else
+                               newl = 0;
+                       word = sp;
+               }
+       }
+}
+
+/*
+ * Print a button
+ */
+void print_button(WINDOW * win, const char *label, int y, int x, int selected)
+{
+       int i, temp;
+
+       wmove(win, y, x);
+       wattrset(win, selected ? dlg.button_active.atr
+                : dlg.button_inactive.atr);
+       waddstr(win, "<");
+       temp = strspn(label, " ");
+       label += temp;
+       wattrset(win, selected ? dlg.button_label_active.atr
+                : dlg.button_label_inactive.atr);
+       for (i = 0; i < temp; i++)
+               waddch(win, ' ');
+       wattrset(win, selected ? dlg.button_key_active.atr
+                : dlg.button_key_inactive.atr);
+       waddch(win, label[0]);
+       wattrset(win, selected ? dlg.button_label_active.atr
+                : dlg.button_label_inactive.atr);
+       waddstr(win, (char *)label + 1);
+       wattrset(win, selected ? dlg.button_active.atr
+                : dlg.button_inactive.atr);
+       waddstr(win, ">");
+       wmove(win, y, x + temp + 1);
+}
+
+/*
+ * Draw a rectangular box with line drawing characters
+ */
+void
+draw_box(WINDOW * win, int y, int x, int height, int width,
+        chtype box, chtype border)
+{
+       int i, j;
+
+       wattrset(win, 0);
+       for (i = 0; i < height; i++) {
+               wmove(win, y + i, x);
+               for (j = 0; j < width; j++)
+                       if (!i && !j)
+                               waddch(win, border | ACS_ULCORNER);
+                       else if (i == height - 1 && !j)
+                               waddch(win, border | ACS_LLCORNER);
+                       else if (!i && j == width - 1)
+                               waddch(win, box | ACS_URCORNER);
+                       else if (i == height - 1 && j == width - 1)
+                               waddch(win, box | ACS_LRCORNER);
+                       else if (!i)
+                               waddch(win, border | ACS_HLINE);
+                       else if (i == height - 1)
+                               waddch(win, box | ACS_HLINE);
+                       else if (!j)
+                               waddch(win, border | ACS_VLINE);
+                       else if (j == width - 1)
+                               waddch(win, box | ACS_VLINE);
+                       else
+                               waddch(win, box | ' ');
+       }
+}
+
+/*
+ * Draw shadows along the right and bottom edge to give a more 3D look
+ * to the boxes
+ */
+void draw_shadow(WINDOW * win, int y, int x, int height, int width)
+{
+       int i;
+
+       if (has_colors()) {     /* Whether terminal supports color? */
+               wattrset(win, dlg.shadow.atr);
+               wmove(win, y + height, x + 2);
+               for (i = 0; i < width; i++)
+                       waddch(win, winch(win) & A_CHARTEXT);
+               for (i = y + 1; i < y + height + 1; i++) {
+                       wmove(win, i, x + width);
+                       waddch(win, winch(win) & A_CHARTEXT);
+                       waddch(win, winch(win) & A_CHARTEXT);
+               }
+               wnoutrefresh(win);
+       }
+}
+
+/*
+ *  Return the position of the first alphabetic character in a string.
+ */
+int first_alpha(const char *string, const char *exempt)
+{
+       int i, in_paren = 0, c;
+
+       for (i = 0; i < strlen(string); i++) {
+               c = tolower(string[i]);
+
+               if (strchr("<[(", c))
+                       ++in_paren;
+               if (strchr(">])", c) && in_paren > 0)
+                       --in_paren;
+
+               if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
+                       return i;
+       }
+
+       return 0;
+}
+
+/*
+ * ncurses uses ESC to detect escaped char sequences. This resutl in
+ * a small timeout before ESC is actually delivered to the application.
+ * lxdialog suggest <ESC> <ESC> which is correctly translated to two
+ * times esc. But then we need to ignore the second esc to avoid stepping
+ * out one menu too much. Filter away all escaped key sequences since
+ * keypad(FALSE) turn off ncurses support for escape sequences - and thats
+ * needed to make notimeout() do as expected.
+ */
+int on_key_esc(WINDOW *win)
+{
+       int key;
+       int key2;
+       int key3;
+
+       nodelay(win, TRUE);
+       keypad(win, FALSE);
+       key = wgetch(win);
+       key2 = wgetch(win);
+       do {
+               key3 = wgetch(win);
+       } while (key3 != ERR);
+       nodelay(win, FALSE);
+       keypad(win, TRUE);
+       if (key == KEY_ESC && key2 == ERR)
+               return KEY_ESC;
+       else if (key != ERR && key != KEY_ESC && key2 == ERR)
+               ungetch(key);
+
+       return -1;
+}
+
+/* redraw screen in new size */
+int on_key_resize(void)
+{
+       dialog_clear();
+       return KEY_RESIZE;
+}
+
+struct dialog_list *item_cur;
+struct dialog_list item_nil;
+struct dialog_list *item_head;
+
+void item_reset(void)
+{
+       struct dialog_list *p, *next;
+
+       for (p = item_head; p; p = next) {
+               next = p->next;
+               free(p);
+       }
+       item_head = NULL;
+       item_cur = &item_nil;
+}
+
+void item_make(const char *fmt, ...)
+{
+       va_list ap;
+       struct dialog_list *p = malloc(sizeof(*p));
+
+       if (item_head)
+               item_cur->next = p;
+       else
+               item_head = p;
+       item_cur = p;
+       memset(p, 0, sizeof(*p));
+
+       va_start(ap, fmt);
+       vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
+       va_end(ap);
+}
+
+void item_add_str(const char *fmt, ...)
+{
+       va_list ap;
+        size_t avail;
+
+       avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
+
+       va_start(ap, fmt);
+       vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
+                 avail, fmt, ap);
+       item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
+       va_end(ap);
+}
+
+void item_set_tag(char tag)
+{
+       item_cur->node.tag = tag;
+}
+void item_set_data(void *ptr)
+{
+       item_cur->node.data = ptr;
+}
+
+void item_set_selected(int val)
+{
+       item_cur->node.selected = val;
+}
+
+int item_activate_selected(void)
+{
+       item_foreach()
+               if (item_is_selected())
+                       return 1;
+       return 0;
+}
+
+void *item_data(void)
+{
+       return item_cur->node.data;
+}
+
+char item_tag(void)
+{
+       return item_cur->node.tag;
+}
+
+int item_count(void)
+{
+       int n = 0;
+       struct dialog_list *p;
+
+       for (p = item_head; p; p = p->next)
+               n++;
+       return n;
+}
+
+void item_set(int n)
+{
+       int i = 0;
+       item_foreach()
+               if (i++ == n)
+                       return;
+}
+
+int item_n(void)
+{
+       int n = 0;
+       struct dialog_list *p;
+
+       for (p = item_head; p; p = p->next) {
+               if (p == item_cur)
+                       return n;
+               n++;
+       }
+       return 0;
+}
+
+const char *item_str(void)
+{
+       return item_cur->node.str;
+}
+
+int item_is_selected(void)
+{
+       return (item_cur->node.selected != 0);
+}
+
+int item_is_tag(char tag)
+{
+       return (item_cur->node.tag == tag);
+}
diff --git a/bin/kconfig/lxdialog/yesno.c b/bin/kconfig/lxdialog/yesno.c
new file mode 100644 (file)
index 0000000..4e6e809
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ *  yesno.c -- implements the yes/no box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  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, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+/*
+ * Display termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+       int x = width / 2 - 10;
+       int y = height - 2;
+
+       print_button(dialog, gettext(" Yes "), y, x, selected == 0);
+       print_button(dialog, gettext("  No  "), y, x + 13, selected == 1);
+
+       wmove(dialog, y, x + 1 + 13 * selected);
+       wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with two buttons - Yes and No
+ */
+int dialog_yesno(const char *title, const char *prompt, int height, int width)
+{
+       int i, x, y, key = 0, button = 0;
+       WINDOW *dialog;
+
+do_resize:
+       if (getmaxy(stdscr) < (height + 4))
+               return -ERRDISPLAYTOOSMALL;
+       if (getmaxx(stdscr) < (width + 4))
+               return -ERRDISPLAYTOOSMALL;
+
+       /* center dialog box on screen */
+       x = (COLS - width) / 2;
+       y = (LINES - height) / 2;
+
+       draw_shadow(stdscr, y, x, height, width);
+
+       dialog = newwin(height, width, y, x);
+       keypad(dialog, TRUE);
+
+       draw_box(dialog, 0, 0, height, width,
+                dlg.dialog.atr, dlg.border.atr);
+       wattrset(dialog, dlg.border.atr);
+       mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+       for (i = 0; i < width - 2; i++)
+               waddch(dialog, ACS_HLINE);
+       wattrset(dialog, dlg.dialog.atr);
+       waddch(dialog, ACS_RTEE);
+
+       print_title(dialog, title, width);
+
+       wattrset(dialog, dlg.dialog.atr);
+       print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+       print_buttons(dialog, height, width, 0);
+
+       while (key != KEY_ESC) {
+               key = wgetch(dialog);
+               switch (key) {
+               case 'Y':
+               case 'y':
+                       delwin(dialog);
+                       return 0;
+               case 'N':
+               case 'n':
+                       delwin(dialog);
+                       return 1;
+
+               case TAB:
+               case KEY_LEFT:
+               case KEY_RIGHT:
+                       button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button);
+
+                       print_buttons(dialog, height, width, button);
+                       wrefresh(dialog);
+                       break;
+               case ' ':
+               case '\n':
+                       delwin(dialog);
+                       return button;
+               case KEY_ESC:
+                       key = on_key_esc(dialog);
+                       break;
+               case KEY_RESIZE:
+                       delwin(dialog);
+                       on_key_resize();
+                       goto do_resize;
+               }
+       }
+
+       delwin(dialog);
+       return key;             /* ESC pressed */
+}
diff --git a/bin/kconfig/mconf.c b/bin/kconfig/mconf.c
new file mode 100644 (file)
index 0000000..598ce2c
--- /dev/null
@@ -0,0 +1,928 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Introduced single menu mode (show all sub-menus in one large tree).
+ * 2002-11-06 Petr Baudis <pasky@ucw.cz>
+ *
+ * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <locale.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+#include "lxdialog/dialog.h"
+
+static const char mconf_readme[] = N_(
+"Overview\n"
+"--------\n"
+"Some kernel features may be built directly into the kernel.\n"
+"Some may be made into loadable runtime modules.  Some features\n"
+"may be completely removed altogether.  There are also certain\n"
+"kernel parameters which are not really features, but must be\n"
+"entered in as decimal or hexadecimal numbers or possibly text.\n"
+"\n"
+"Menu items beginning with following braces represent features that\n"
+"  [ ] can be built in or removed\n"
+"  < > can be built in, modularized or removed\n"
+"  { } can be built in or modularized (selected by other feature)\n"
+"  - - are selected by other feature,\n"
+"while *, M or whitespace inside braces means to build in, build as\n"
+"a module or to exclude the feature respectively.\n"
+"\n"
+"To change any of these features, highlight it with the cursor\n"
+"keys and press <Y> to build it in, <M> to make it a module or\n"
+"<N> to removed it.  You may also press the <Space Bar> to cycle\n"
+"through the available options (ie. Y->N->M->Y).\n"
+"\n"
+"Some additional keyboard hints:\n"
+"\n"
+"Menus\n"
+"----------\n"
+"o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
+"   you wish to change or submenu wish to select and press <Enter>.\n"
+"   Submenus are designated by \"--->\".\n"
+"\n"
+"   Shortcut: Press the option's highlighted letter (hotkey).\n"
+"             Pressing a hotkey more than once will sequence\n"
+"             through all visible items which use that hotkey.\n"
+"\n"
+"   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
+"   unseen options into view.\n"
+"\n"
+"o  To exit a menu use the cursor keys to highlight the <Exit> button\n"
+"   and press <ENTER>.\n"
+"\n"
+"   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
+"             using those letters.  You may press a single <ESC>, but\n"
+"             there is a delayed response which you may find annoying.\n"
+"\n"
+"   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
+"   <Exit> and <Help>\n"
+"\n"
+"o  To get help with an item, use the cursor keys to highlight <Help>\n"
+"   and Press <ENTER>.\n"
+"\n"
+"   Shortcut: Press <H> or <?>.\n"
+"\n"
+"\n"
+"Radiolists  (Choice lists)\n"
+"-----------\n"
+"o  Use the cursor keys to select the option you wish to set and press\n"
+"   <S> or the <SPACE BAR>.\n"
+"\n"
+"   Shortcut: Press the first letter of the option you wish to set then\n"
+"             press <S> or <SPACE BAR>.\n"
+"\n"
+"o  To see available help for the item, use the cursor keys to highlight\n"
+"   <Help> and Press <ENTER>.\n"
+"\n"
+"   Shortcut: Press <H> or <?>.\n"
+"\n"
+"   Also, the <TAB> and cursor keys will cycle between <Select> and\n"
+"   <Help>\n"
+"\n"
+"\n"
+"Data Entry\n"
+"-----------\n"
+"o  Enter the requested information and press <ENTER>\n"
+"   If you are entering hexadecimal values, it is not necessary to\n"
+"   add the '0x' prefix to the entry.\n"
+"\n"
+"o  For help, use the <TAB> or cursor keys to highlight the help option\n"
+"   and press <ENTER>.  You can try <TAB><H> as well.\n"
+"\n"
+"\n"
+"Text Box    (Help Window)\n"
+"--------\n"
+"o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
+"   keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
+"   who are familiar with less and lynx.\n"
+"\n"
+"o  Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
+"\n"
+"\n"
+"Alternate Configuration Files\n"
+"-----------------------------\n"
+"Menuconfig supports the use of alternate configuration files for\n"
+"those who, for various reasons, find it necessary to switch\n"
+"between different kernel configurations.\n"
+"\n"
+"At the end of the main menu you will find two options.  One is\n"
+"for saving the current configuration to a file of your choosing.\n"
+"The other option is for loading a previously saved alternate\n"
+"configuration.\n"
+"\n"
+"Even if you don't use alternate configuration files, but you\n"
+"find during a Menuconfig session that you have completely messed\n"
+"up your settings, you may use the \"Load Alternate...\" option to\n"
+"restore your previously saved settings from \".config\" without\n"
+"restarting Menuconfig.\n"
+"\n"
+"Other information\n"
+"-----------------\n"
+"If you use Menuconfig in an XTERM window make sure you have your\n"
+"$TERM variable set to point to a xterm definition which supports color.\n"
+"Otherwise, Menuconfig will look rather bad.  Menuconfig will not\n"
+"display correctly in a RXVT window because rxvt displays only one\n"
+"intensity of color, bright.\n"
+"\n"
+"Menuconfig will display larger menus on screens or xterms which are\n"
+"set to display more than the standard 25 row by 80 column geometry.\n"
+"In order for this to work, the \"stty size\" command must be able to\n"
+"display the screen's current row and column geometry.  I STRONGLY\n"
+"RECOMMEND that you make sure you do NOT have the shell variables\n"
+"LINES and COLUMNS exported into your environment.  Some distributions\n"
+"export those variables via /etc/profile.  Some ncurses programs can\n"
+"become confused when those variables (LINES & COLUMNS) don't reflect\n"
+"the true screen size.\n"
+"\n"
+"Optional personality available\n"
+"------------------------------\n"
+"If you prefer to have all of the kernel options listed in a single\n"
+"menu, rather than the default multimenu hierarchy, run the menuconfig\n"
+"with MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
+"\n"
+"make MENUCONFIG_MODE=single_menu menuconfig\n"
+"\n"
+"<Enter> will then unroll the appropriate category, or enfold it if it\n"
+"is already unrolled.\n"
+"\n"
+"Note that this mode can eventually be a little more CPU expensive\n"
+"(especially with a larger number of unrolled categories) than the\n"
+"default mode.\n"
+"\n"
+"Different color themes available\n"
+"--------------------------------\n"
+"It is possible to select different color themes using the variable\n"
+"MENUCONFIG_COLOR. To select a theme use:\n"
+"\n"
+"make MENUCONFIG_COLOR=<theme> menuconfig\n"
+"\n"
+"Available themes are\n"
+" mono       => selects colors suitable for monochrome displays\n"
+" blackbg    => selects a color scheme with black background\n"
+" classic    => theme with blue background. The classic look\n"
+" bluetitle  => a LCD friendly version of classic. (default)\n"
+"\n"),
+menu_instructions[] = N_(
+       "Arrow keys navigate the menu.  "
+       "<Enter> selects submenus --->.  "
+       "Highlighted letters are hotkeys.  "
+       "Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
+       "Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
+       "Legend: [*] built-in  [ ] excluded  <M> module  < > module capable"),
+radiolist_instructions[] = N_(
+       "Use the arrow keys to navigate this window or "
+       "press the hotkey of the item you wish to select "
+       "followed by the <SPACE BAR>. "
+       "Press <?> for additional information about this option."),
+inputbox_instructions_int[] = N_(
+       "Please enter a decimal value. "
+       "Fractions will not be accepted.  "
+       "Use the <TAB> key to move from the input field to the buttons below it."),
+inputbox_instructions_hex[] = N_(
+       "Please enter a hexadecimal value. "
+       "Use the <TAB> key to move from the input field to the buttons below it."),
+inputbox_instructions_string[] = N_(
+       "Please enter a string value. "
+       "Use the <TAB> key to move from the input field to the buttons below it."),
+setmod_text[] = N_(
+       "This feature depends on another which has been configured as a module.\n"
+       "As a result, this feature will be built as a module."),
+nohelp_text[] = N_(
+       "There is no help available for this kernel option.\n"),
+load_config_text[] = N_(
+       "Enter the name of the configuration file you wish to load.  "
+       "Accept the name shown to restore the configuration you "
+       "last retrieved.  Leave blank to abort."),
+load_config_help[] = N_(
+       "\n"
+       "For various reasons, one may wish to keep several different kernel\n"
+       "configurations available on a single machine.\n"
+       "\n"
+       "If you have saved a previous configuration in a file other than the\n"
+       "kernel's default, entering the name of the file here will allow you\n"
+       "to modify that configuration.\n"
+       "\n"
+       "If you are uncertain, then you have probably never used alternate\n"
+       "configuration files.  You should therefor leave this blank to abort.\n"),
+save_config_text[] = N_(
+       "Enter a filename to which this configuration should be saved "
+       "as an alternate.  Leave blank to abort."),
+save_config_help[] = N_(
+       "\n"
+       "For various reasons, one may wish to keep different kernel\n"
+       "configurations available on a single machine.\n"
+       "\n"
+       "Entering a file name here will allow you to later retrieve, modify\n"
+       "and use the current configuration as an alternate to whatever\n"
+       "configuration options you have selected at that time.\n"
+       "\n"
+       "If you are uncertain what all this means then you should probably\n"
+       "leave this blank.\n"),
+search_help[] = N_(
+       "\n"
+       "Search for CONFIG_ symbols and display their relations.\n"
+       "Regular expressions are allowed.\n"
+       "Example: search for \"^FOO\"\n"
+       "Result:\n"
+       "-----------------------------------------------------------------\n"
+       "Symbol: FOO [=m]\n"
+       "Prompt: Foo bus is used to drive the bar HW\n"
+       "Defined at drivers/pci/Kconfig:47\n"
+       "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
+       "Location:\n"
+       "  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
+       "    -> PCI support (PCI [=y])\n"
+       "      -> PCI access mode (<choice> [=y])\n"
+       "Selects: LIBCRC32\n"
+       "Selected by: BAR\n"
+       "-----------------------------------------------------------------\n"
+       "o The line 'Prompt:' shows the text used in the menu structure for\n"
+       "  this CONFIG_ symbol\n"
+       "o The 'Defined at' line tell at what file / line number the symbol\n"
+       "  is defined\n"
+       "o The 'Depends on:' line tell what symbols needs to be defined for\n"
+       "  this symbol to be visible in the menu (selectable)\n"
+       "o The 'Location:' lines tell where in the menu structure this symbol\n"
+       "  is located\n"
+       "    A location followed by a [=y] indicate that this is a selectable\n"
+       "    menu item - and current value is displayed inside brackets.\n"
+       "o The 'Selects:' line tell what symbol will be automatically\n"
+       "  selected if this symbol is selected (y or m)\n"
+       "o The 'Selected by' line tell what symbol has selected this symbol\n"
+       "\n"
+       "Only relevant lines are shown.\n"
+       "\n\n"
+       "Search examples:\n"
+       "Examples: USB  => find all CONFIG_ symbols containing USB\n"
+       "          ^USB => find all CONFIG_ symbols starting with USB\n"
+       "          USB$ => find all CONFIG_ symbols ending with USB\n"
+       "\n");
+
+static int indent;
+static struct menu *current_menu;
+static int child_count;
+static int single_menu_mode;
+
+static void conf(struct menu *menu);
+static void conf_choice(struct menu *menu);
+static void conf_string(struct menu *menu);
+static void conf_load(void);
+static void conf_save(void);
+static void show_textbox(const char *title, const char *text, int r, int c);
+static void show_helptext(const char *title, const char *text);
+static void show_help(struct menu *menu);
+
+static void get_prompt_str(struct gstr *r, struct property *prop)
+{
+       int i, j;
+       struct menu *submenu[8], *menu;
+
+       str_printf(r, _("Prompt: %s\n"), _(prop->text));
+       str_printf(r, _("  Defined at %s:%d\n"), prop->menu->file->name,
+               prop->menu->lineno);
+       if (!expr_is_yes(prop->visible.expr)) {
+               str_append(r, _("  Depends on: "));
+               expr_gstr_print(prop->visible.expr, r);
+               str_append(r, "\n");
+       }
+       menu = prop->menu->parent;
+       for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
+               submenu[i++] = menu;
+       if (i > 0) {
+               str_printf(r, _("  Location:\n"));
+               for (j = 4; --i >= 0; j += 2) {
+                       menu = submenu[i];
+                       str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu)));
+                       if (menu->sym) {
+                               str_printf(r, " (%s [=%s])", menu->sym->name ?
+                                       menu->sym->name : _("<choice>"),
+                                       sym_get_string_value(menu->sym));
+                       }
+                       str_append(r, "\n");
+               }
+       }
+}
+
+static void get_symbol_str(struct gstr *r, struct symbol *sym)
+{
+       bool hit;
+       struct property *prop;
+
+       if (sym && sym->name)
+               str_printf(r, "Symbol: %s [=%s]\n", sym->name,
+                                                   sym_get_string_value(sym));
+       for_all_prompts(sym, prop)
+               get_prompt_str(r, prop);
+       hit = false;
+       for_all_properties(sym, prop, P_SELECT) {
+               if (!hit) {
+                       str_append(r, "  Selects: ");
+                       hit = true;
+               } else
+                       str_printf(r, " && ");
+               expr_gstr_print(prop->expr, r);
+       }
+       if (hit)
+               str_append(r, "\n");
+       if (sym->rev_dep.expr) {
+               str_append(r, _("  Selected by: "));
+               expr_gstr_print(sym->rev_dep.expr, r);
+               str_append(r, "\n");
+       }
+       str_append(r, "\n\n");
+}
+
+static struct gstr get_relations_str(struct symbol **sym_arr)
+{
+       struct symbol *sym;
+       struct gstr res = str_new();
+       int i;
+
+       for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
+               get_symbol_str(&res, sym);
+       if (!i)
+               str_append(&res, _("No matches found.\n"));
+       return res;
+}
+
+static char filename[PATH_MAX+1];
+static void set_config_filename(const char *config_filename)
+{
+       static char menu_backtitle[PATH_MAX+128];
+       int size;
+       struct symbol *sym;
+
+       sym = sym_lookup("KERNELVERSION", 0);
+       sym_calc_value(sym);
+       size = snprintf(menu_backtitle, sizeof(menu_backtitle),
+                       _("%s - firmly.0cpm v%s Configuration"),
+                       config_filename, sym_get_string_value(sym));
+       if (size >= sizeof(menu_backtitle))
+               menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
+       set_dialog_backtitle(menu_backtitle);
+
+       size = snprintf(filename, sizeof(filename), "%s", config_filename);
+       if (size >= sizeof(filename))
+               filename[sizeof(filename)-1] = '\0';
+}
+
+
+static void search_conf(void)
+{
+       struct symbol **sym_arr;
+       struct gstr res;
+       char *dialog_input;
+       int dres;
+again:
+       dialog_clear();
+       dres = dialog_inputbox(_("Search Configuration Parameter"),
+                             _("Enter CONFIG_ (sub)string to search for "
+                               "(with or without \"CONFIG\")"),
+                             10, 75, "");
+       switch (dres) {
+       case 0:
+               break;
+       case 1:
+               show_helptext(_("Search Configuration"), search_help);
+               goto again;
+       default:
+               return;
+       }
+
+       /* strip CONFIG_ if necessary */
+       dialog_input = dialog_input_result;
+       if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0)
+               dialog_input += 7;
+
+       sym_arr = sym_re_search(dialog_input);
+       res = get_relations_str(sym_arr);
+       free(sym_arr);
+       show_textbox(_("Search Results"), str_get(&res), 0, 0);
+       str_free(&res);
+}
+
+static void build_conf(struct menu *menu)
+{
+       struct symbol *sym;
+       struct property *prop;
+       struct menu *child;
+       int type, tmp, doint = 2;
+       tristate val;
+       char ch;
+
+       if (!menu_is_visible(menu))
+               return;
+
+       sym = menu->sym;
+       prop = menu->prompt;
+       if (!sym) {
+               if (prop && menu != current_menu) {
+                       const char *prompt = menu_get_prompt(menu);
+                       switch (prop->type) {
+                       case P_MENU:
+                               child_count++;
+                               prompt = _(prompt);
+                               if (single_menu_mode) {
+                                       item_make("%s%*c%s",
+                                                 menu->data ? "-->" : "++>",
+                                                 indent + 1, ' ', prompt);
+                               } else
+                                       item_make("   %*c%s  --->", indent + 1, ' ', prompt);
+
+                               item_set_tag('m');
+                               item_set_data(menu);
+                               if (single_menu_mode && menu->data)
+                                       goto conf_childs;
+                               return;
+                       case P_COMMENT:
+                               if (prompt) {
+                                       child_count++;
+                                       item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
+                                       item_set_tag(':');
+                                       item_set_data(menu);
+                               }
+                               break;
+                       default:
+                               if (prompt) {
+                                       child_count++;
+                                       item_make("---%*c%s", indent + 1, ' ', _(prompt));
+                                       item_set_tag(':');
+                                       item_set_data(menu);
+                               }
+                       }
+               } else
+                       doint = 0;
+               goto conf_childs;
+       }
+
+       type = sym_get_type(sym);
+       if (sym_is_choice(sym)) {
+               struct symbol *def_sym = sym_get_choice_value(sym);
+               struct menu *def_menu = NULL;
+
+               child_count++;
+               for (child = menu->list; child; child = child->next) {
+                       if (menu_is_visible(child) && child->sym == def_sym)
+                               def_menu = child;
+               }
+
+               val = sym_get_tristate_value(sym);
+               if (sym_is_changable(sym)) {
+                       switch (type) {
+                       case S_BOOLEAN:
+                               item_make("[%c]", val == no ? ' ' : '*');
+                               break;
+                       case S_TRISTATE:
+                               switch (val) {
+                               case yes: ch = '*'; break;
+                               case mod: ch = 'M'; break;
+                               default:  ch = ' '; break;
+                               }
+                               item_make("<%c>", ch);
+                               break;
+                       }
+                       item_set_tag('t');
+                       item_set_data(menu);
+               } else {
+                       item_make("   ");
+                       item_set_tag(def_menu ? 't' : ':');
+                       item_set_data(menu);
+               }
+
+               item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
+               if (val == yes) {
+                       if (def_menu) {
+                               item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
+                               item_add_str("  --->");
+                               if (def_menu->list) {
+                                       indent += 2;
+                                       build_conf(def_menu);
+                                       indent -= 2;
+                               }
+                       }
+                       return;
+               }
+       } else {
+               if (menu == current_menu) {
+                       item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
+                       item_set_tag(':');
+                       item_set_data(menu);
+                       goto conf_childs;
+               }
+               child_count++;
+               val = sym_get_tristate_value(sym);
+               if (sym_is_choice_value(sym) && val == yes) {
+                       item_make("   ");
+                       item_set_tag(':');
+                       item_set_data(menu);
+               } else {
+                       switch (type) {
+                       case S_BOOLEAN:
+                               if (sym_is_changable(sym))
+                                       item_make("[%c]", val == no ? ' ' : '*');
+                               else
+                                       item_make("-%c-", val == no ? ' ' : '*');
+                               item_set_tag('t');
+                               item_set_data(menu);
+                               break;
+                       case S_TRISTATE:
+                               switch (val) {
+                               case yes: ch = '*'; break;
+                               case mod: ch = 'M'; break;
+                               default:  ch = ' '; break;
+                               }
+                               if (sym_is_changable(sym)) {
+                                       if (sym->rev_dep.tri == mod)
+                                               item_make("{%c}", ch);
+                                       else
+                                               item_make("<%c>", ch);
+                               } else
+                                       item_make("-%c-", ch);
+                               item_set_tag('t');
+                               item_set_data(menu);
+                               break;
+                       default:
+                               tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
+                               item_make("(%s)", sym_get_string_value(sym));
+                               tmp = indent - tmp + 4;
+                               if (tmp < 0)
+                                       tmp = 0;
+                               item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
+                                            (sym_has_value(sym) || !sym_is_changable(sym)) ?
+                                            "" : _(" (NEW)"));
+                               item_set_tag('s');
+                               item_set_data(menu);
+                               goto conf_childs;
+                       }
+               }
+               item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
+                         (sym_has_value(sym) || !sym_is_changable(sym)) ?
+                         "" : _(" (NEW)"));
+               if (menu->prompt->type == P_MENU) {
+                       item_add_str("  --->");
+                       return;
+               }
+       }
+
+conf_childs:
+       indent += doint;
+       for (child = menu->list; child; child = child->next)
+               build_conf(child);
+       indent -= doint;
+}
+
+static void conf(struct menu *menu)
+{
+       struct menu *submenu;
+       const char *prompt = menu_get_prompt(menu);
+       struct symbol *sym;
+       struct menu *active_menu = NULL;
+       int res;
+       int s_scroll = 0;
+
+       while (1) {
+               item_reset();
+               current_menu = menu;
+               build_conf(menu);
+               if (!child_count)
+                       break;
+               if (menu == &rootmenu) {
+                       item_make("--- ");
+                       item_set_tag(':');
+                       item_make(_("    Load an Alternate Configuration File"));
+                       item_set_tag('L');
+                       item_make(_("    Save an Alternate Configuration File"));
+                       item_set_tag('S');
+               }
+               dialog_clear();
+               res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
+                                 _(menu_instructions),
+                                 active_menu, &s_scroll);
+               if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
+                       break;
+               if (!item_activate_selected())
+                       continue;
+               if (!item_tag())
+                       continue;
+
+               submenu = item_data();
+               active_menu = item_data();
+               if (submenu)
+                       sym = submenu->sym;
+               else
+                       sym = NULL;
+
+               switch (res) {
+               case 0:
+                       switch (item_tag()) {
+                       case 'm':
+                               if (single_menu_mode)
+                                       submenu->data = (void *) (long) !submenu->data;
+                               else
+                                       conf(submenu);
+                               break;
+                       case 't':
+                               if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
+                                       conf_choice(submenu);
+                               else if (submenu->prompt->type == P_MENU)
+                                       conf(submenu);
+                               break;
+                       case 's':
+                               conf_string(submenu);
+                               break;
+                       case 'L':
+                               conf_load();
+                               break;
+                       case 'S':
+                               conf_save();
+                               break;
+                       }
+                       break;
+               case 2:
+                       if (sym)
+                               show_help(submenu);
+                       else
+                               show_helptext(_("README"), _(mconf_readme));
+                       break;
+               case 3:
+                       if (item_is_tag('t')) {
+                               if (sym_set_tristate_value(sym, yes))
+                                       break;
+                               if (sym_set_tristate_value(sym, mod))
+                                       show_textbox(NULL, setmod_text, 6, 74);
+                       }
+                       break;
+               case 4:
+                       if (item_is_tag('t'))
+                               sym_set_tristate_value(sym, no);
+                       break;
+               case 5:
+                       if (item_is_tag('t'))
+                               sym_set_tristate_value(sym, mod);
+                       break;
+               case 6:
+                       if (item_is_tag('t'))
+                               sym_toggle_tristate_value(sym);
+                       else if (item_is_tag('m'))
+                               conf(submenu);
+                       break;
+               case 7:
+                       search_conf();
+                       break;
+               }
+       }
+}
+
+static void show_textbox(const char *title, const char *text, int r, int c)
+{
+       dialog_clear();
+       dialog_textbox(title, text, r, c);
+}
+
+static void show_helptext(const char *title, const char *text)
+{
+       show_textbox(title, text, 0, 0);
+}
+
+static void show_help(struct menu *menu)
+{
+       struct gstr help = str_new();
+       struct symbol *sym = menu->sym;
+
+       if (menu_has_help(menu))
+       {
+               if (sym->name) {
+                       str_printf(&help, "CONFIG_%s:\n\n", sym->name);
+                       str_append(&help, _(menu_get_help(menu)));
+                       str_append(&help, "\n");
+               }
+       } else {
+               str_append(&help, nohelp_text);
+       }
+       get_symbol_str(&help, sym);
+       show_helptext(_(menu_get_prompt(menu)), str_get(&help));
+       str_free(&help);
+}
+
+static void conf_choice(struct menu *menu)
+{
+       const char *prompt = _(menu_get_prompt(menu));
+       struct menu *child;
+       struct symbol *active;
+
+       active = sym_get_choice_value(menu->sym);
+       while (1) {
+               int res;
+               int selected;
+               item_reset();
+
+               current_menu = menu;
+               for (child = menu->list; child; child = child->next) {
+                       if (!menu_is_visible(child))
+                               continue;
+                       item_make("%s", _(menu_get_prompt(child)));
+                       item_set_data(child);
+                       if (child->sym == active)
+                               item_set_selected(1);
+                       if (child->sym == sym_get_choice_value(menu->sym))
+                               item_set_tag('X');
+               }
+               dialog_clear();
+               res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
+                                       _(radiolist_instructions),
+                                        15, 70, 6);
+               selected = item_activate_selected();
+               switch (res) {
+               case 0:
+                       if (selected) {
+                               child = item_data();
+                               sym_set_tristate_value(child->sym, yes);
+                       }
+                       return;
+               case 1:
+                       if (selected) {
+                               child = item_data();
+                               show_help(child);
+                               active = child->sym;
+                       } else
+                               show_help(menu);
+                       break;
+               case KEY_ESC:
+                       return;
+               case -ERRDISPLAYTOOSMALL:
+                       return;
+               }
+       }
+}
+
+static void conf_string(struct menu *menu)
+{
+       const char *prompt = menu_get_prompt(menu);
+
+       while (1) {
+               int res;
+               const char *heading;
+
+               switch (sym_get_type(menu->sym)) {
+               case S_INT:
+                       heading = _(inputbox_instructions_int);
+                       break;
+               case S_HEX:
+                       heading = _(inputbox_instructions_hex);
+                       break;
+               case S_STRING:
+                       heading = _(inputbox_instructions_string);
+                       break;
+               default:
+                       heading = _("Internal mconf error!");
+               }
+               dialog_clear();
+               res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
+                                     heading, 10, 75,
+                                     sym_get_string_value(menu->sym));
+               switch (res) {
+               case 0:
+                       if (sym_set_string_value(menu->sym, dialog_input_result))
+                               return;
+                       show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
+                       break;
+               case 1:
+                       show_help(menu);
+                       break;
+               case KEY_ESC:
+                       return;
+               }
+       }
+}
+
+static void conf_load(void)
+{
+
+       while (1) {
+               int res;
+               dialog_clear();
+               res = dialog_inputbox(NULL, load_config_text,
+                                     11, 55, filename);
+               switch(res) {
+               case 0:
+                       if (!dialog_input_result[0])
+                               return;
+                       if (!conf_read(dialog_input_result)) {
+                               set_config_filename(dialog_input_result);
+                               sym_set_change_count(1);
+                               return;
+                       }
+                       show_textbox(NULL, _("File does not exist!"), 5, 38);
+                       break;
+               case 1:
+                       show_helptext(_("Load Alternate Configuration"), load_config_help);
+                       break;
+               case KEY_ESC:
+                       return;
+               }
+       }
+}
+
+static void conf_save(void)
+{
+       while (1) {
+               int res;
+               dialog_clear();
+               res = dialog_inputbox(NULL, save_config_text,
+                                     11, 55, filename);
+               switch(res) {
+               case 0:
+                       if (!dialog_input_result[0])
+                               return;
+                       if (!conf_write(dialog_input_result)) {
+                               set_config_filename(dialog_input_result);
+                               return;
+                       }
+                       show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
+                       break;
+               case 1:
+                       show_helptext(_("Save Alternate Configuration"), save_config_help);
+                       break;
+               case KEY_ESC:
+                       return;
+               }
+       }
+}
+
+int main(int ac, char **av)
+{
+       int saved_x, saved_y;
+       char *mode;
+       int res;
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       conf_parse(av[1]);
+       conf_read(NULL);
+
+       mode = getenv("MENUCONFIG_MODE");
+       if (mode) {
+               if (!strcasecmp(mode, "single_menu"))
+                       single_menu_mode = 1;
+       }
+
+       getyx(stdscr, saved_y, saved_x);
+       if (init_dialog(NULL)) {
+               fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
+               fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
+               return 1;
+       }
+
+       set_config_filename(conf_get_configname());
+       do {
+               conf(&rootmenu);
+               dialog_clear();
+               if (conf_get_changed())
+                       res = dialog_yesno(NULL,
+                                          _("Do you wish to save your "
+                                            "new kernel configuration?\n"
+                                            "<ESC><ESC> to continue."),
+                                          6, 60);
+               else
+                       res = -1;
+       } while (res == KEY_ESC);
+       end_dialog(saved_x, saved_y);
+
+       switch (res) {
+       case 0:
+               if (conf_write(filename)) {
+                       fprintf(stderr, _("\n\n"
+                               "Error during writing of the kernel configuration.\n"
+                               "Your kernel configuration changes were NOT saved."
+                               "\n\n"));
+                       return 1;
+               }
+       case -1:
+               printf(_("\n\n"
+                       "*** End of firmly.0cpm configuration.\n"
+                       "*** Execute 'make' to build the kernel or try 'make help'."
+                       "\n\n"));
+               break;
+       default:
+               fprintf(stderr, _("\n\n"
+                       "Your kernel configuration changes were NOT saved."
+                       "\n\n"));
+       }
+
+       return 0;
+}
+
diff --git a/bin/kconfig/menu.c b/bin/kconfig/menu.c
new file mode 100644 (file)
index 0000000..07ff8d1
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+struct menu rootmenu;
+static struct menu **last_entry_ptr;
+
+struct file *file_list;
+struct file *current_file;
+
+void menu_warn(struct menu *menu, const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
+       vfprintf(stderr, fmt, ap);
+       fprintf(stderr, "\n");
+       va_end(ap);
+}
+
+static void prop_warn(struct property *prop, const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
+       vfprintf(stderr, fmt, ap);
+       fprintf(stderr, "\n");
+       va_end(ap);
+}
+
+void menu_init(void)
+{
+       current_entry = current_menu = &rootmenu;
+       last_entry_ptr = &rootmenu.list;
+}
+
+void menu_add_entry(struct symbol *sym)
+{
+       struct menu *menu;
+
+       menu = malloc(sizeof(*menu));
+       memset(menu, 0, sizeof(*menu));
+       menu->sym = sym;
+       menu->parent = current_menu;
+       menu->file = current_file;
+       menu->lineno = zconf_lineno();
+
+       *last_entry_ptr = menu;
+       last_entry_ptr = &menu->next;
+       current_entry = menu;
+}
+
+void menu_end_entry(void)
+{
+}
+
+struct menu *menu_add_menu(void)
+{
+       menu_end_entry();
+       last_entry_ptr = &current_entry->list;
+       return current_menu = current_entry;
+}
+
+void menu_end_menu(void)
+{
+       last_entry_ptr = &current_menu->next;
+       current_menu = current_menu->parent;
+}
+
+struct expr *menu_check_dep(struct expr *e)
+{
+       if (!e)
+               return e;
+
+       switch (e->type) {
+       case E_NOT:
+               e->left.expr = menu_check_dep(e->left.expr);
+               break;
+       case E_OR:
+       case E_AND:
+               e->left.expr = menu_check_dep(e->left.expr);
+               e->right.expr = menu_check_dep(e->right.expr);
+               break;
+       case E_SYMBOL:
+               /* change 'm' into 'm' && MODULES */
+               if (e->left.sym == &symbol_mod)
+                       return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
+               break;
+       default:
+               break;
+       }
+       return e;
+}
+
+void menu_add_dep(struct expr *dep)
+{
+       current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
+}
+
+void menu_set_type(int type)
+{
+       struct symbol *sym = current_entry->sym;
+
+       if (sym->type == type)
+               return;
+       if (sym->type == S_UNKNOWN) {
+               sym->type = type;
+               return;
+       }
+       menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'",
+           sym->name ? sym->name : "<choice>",
+           sym_type_name(sym->type), sym_type_name(type));
+}
+
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
+{
+       struct property *prop = prop_alloc(type, current_entry->sym);
+
+       prop->menu = current_entry;
+       prop->expr = expr;
+       prop->visible.expr = menu_check_dep(dep);
+
+       if (prompt) {
+               if (isspace(*prompt)) {
+                       prop_warn(prop, "leading whitespace ignored");
+                       while (isspace(*prompt))
+                               prompt++;
+               }
+               if (current_entry->prompt)
+                       prop_warn(prop, "prompt redefined");
+               current_entry->prompt = prop;
+       }
+       prop->text = prompt;
+
+       return prop;
+}
+
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
+{
+       return menu_add_prop(type, prompt, NULL, dep);
+}
+
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
+{
+       menu_add_prop(type, NULL, expr, dep);
+}
+
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
+{
+       menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
+}
+
+void menu_add_option(int token, char *arg)
+{
+       struct property *prop;
+
+       switch (token) {
+       case T_OPT_MODULES:
+               prop = prop_alloc(P_DEFAULT, modules_sym);
+               prop->expr = expr_alloc_symbol(current_entry->sym);
+               break;
+       case T_OPT_DEFCONFIG_LIST:
+               if (!sym_defconfig_list)
+                       sym_defconfig_list = current_entry->sym;
+               else if (sym_defconfig_list != current_entry->sym)
+                       zconf_error("trying to redefine defconfig symbol");
+               break;
+       case T_OPT_ENV:
+               prop_add_env(arg);
+               break;
+       }
+}
+
+static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2)
+{
+       return sym2->type == S_INT || sym2->type == S_HEX ||
+              (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
+}
+
+void sym_check_prop(struct symbol *sym)
+{
+       struct property *prop;
+       struct symbol *sym2;
+       for (prop = sym->prop; prop; prop = prop->next) {
+               switch (prop->type) {
+               case P_DEFAULT:
+                       if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
+                           prop->expr->type != E_SYMBOL)
+                               prop_warn(prop,
+                                   "default for config symbol '%'"
+                                   " must be a single symbol", sym->name);
+                       break;
+               case P_SELECT:
+                       sym2 = prop_get_symbol(prop);
+                       if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
+                               prop_warn(prop,
+                                   "config symbol '%s' uses select, but is "
+                                   "not boolean or tristate", sym->name);
+                       else if (sym2->type != S_UNKNOWN &&
+                                sym2->type != S_BOOLEAN &&
+                                sym2->type != S_TRISTATE)
+                               prop_warn(prop,
+                                   "'%s' has wrong type. 'select' only "
+                                   "accept arguments of boolean and "
+                                   "tristate type", sym2->name);
+                       break;
+               case P_RANGE:
+                       if (sym->type != S_INT && sym->type != S_HEX)
+                               prop_warn(prop, "range is only allowed "
+                                               "for int or hex symbols");
+                       if (!menu_range_valid_sym(sym, prop->expr->left.sym) ||
+                           !menu_range_valid_sym(sym, prop->expr->right.sym))
+                               prop_warn(prop, "range is invalid");
+                       break;
+               default:
+                       ;
+               }
+       }
+}
+
+void menu_finalize(struct menu *parent)
+{
+       struct menu *menu, *last_menu;
+       struct symbol *sym;
+       struct property *prop;
+       struct expr *parentdep, *basedep, *dep, *dep2, **ep;
+
+       sym = parent->sym;
+       if (parent->list) {
+               if (sym && sym_is_choice(sym)) {
+                       if (sym->type == S_UNKNOWN) {
+                               /* find the first choice value to find out choice type */
+                               current_entry = parent;
+                               for (menu = parent->list; menu; menu = menu->next) {
+                                       if (menu->sym && menu->sym->type != S_UNKNOWN) {
+                                               menu_set_type(menu->sym->type);
+                                               break;
+                                       }
+                               }
+                       }
+                       /* set the type of the remaining choice values */
+                       for (menu = parent->list; menu; menu = menu->next) {
+                               current_entry = menu;
+                               if (menu->sym && menu->sym->type == S_UNKNOWN)
+                                       menu_set_type(sym->type);
+                       }
+                       parentdep = expr_alloc_symbol(sym);
+               } else if (parent->prompt)
+                       parentdep = parent->prompt->visible.expr;
+               else
+                       parentdep = parent->dep;
+
+               for (menu = parent->list; menu; menu = menu->next) {
+                       basedep = expr_transform(menu->dep);
+                       basedep = expr_alloc_and(expr_copy(parentdep), basedep);
+                       basedep = expr_eliminate_dups(basedep);
+                       menu->dep = basedep;
+                       if (menu->sym)
+                               prop = menu->sym->prop;
+                       else
+                               prop = menu->prompt;
+                       for (; prop; prop = prop->next) {
+                               if (prop->menu != menu)
+                                       continue;
+                               dep = expr_transform(prop->visible.expr);
+                               dep = expr_alloc_and(expr_copy(basedep), dep);
+                               dep = expr_eliminate_dups(dep);
+                               if (menu->sym && menu->sym->type != S_TRISTATE)
+                                       dep = expr_trans_bool(dep);
+                               prop->visible.expr = dep;
+                               if (prop->type == P_SELECT) {
+                                       struct symbol *es = prop_get_symbol(prop);
+                                       es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
+                                                       expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
+                               }
+                       }
+               }
+               for (menu = parent->list; menu; menu = menu->next)
+                       menu_finalize(menu);
+       } else if (sym) {
+               basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
+               basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
+               basedep = expr_eliminate_dups(expr_transform(basedep));
+               last_menu = NULL;
+               for (menu = parent->next; menu; menu = menu->next) {
+                       dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
+                       if (!expr_contains_symbol(dep, sym))
+                               break;
+                       if (expr_depends_symbol(dep, sym))
+                               goto next;
+                       dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
+                       dep = expr_eliminate_dups(expr_transform(dep));
+                       dep2 = expr_copy(basedep);
+                       expr_eliminate_eq(&dep, &dep2);
+                       expr_free(dep);
+                       if (!expr_is_yes(dep2)) {
+                               expr_free(dep2);
+                               break;
+                       }
+                       expr_free(dep2);
+               next:
+                       menu_finalize(menu);
+                       menu->parent = parent;
+                       last_menu = menu;
+               }
+               if (last_menu) {
+                       parent->list = parent->next;
+                       parent->next = last_menu->next;
+                       last_menu->next = NULL;
+               }
+       }
+       for (menu = parent->list; menu; menu = menu->next) {
+               if (sym && sym_is_choice(sym) &&
+                   menu->sym && !sym_is_choice_value(menu->sym)) {
+                       current_entry = menu;
+                       menu->sym->flags |= SYMBOL_CHOICEVAL;
+                       if (!menu->prompt)
+                               menu_warn(menu, "choice value must have a prompt");
+                       for (prop = menu->sym->prop; prop; prop = prop->next) {
+                               if (prop->type == P_DEFAULT)
+                                       prop_warn(prop, "defaults for choice "
+                                                 "values not supported");
+                               if (prop->menu == menu)
+                                       continue;
+                               if (prop->type == P_PROMPT &&
+                                   prop->menu->parent->sym != sym)
+                                       prop_warn(prop, "choice value used outside its choice group");
+                       }
+                       /* Non-tristate choice values of tristate choices must
+                        * depend on the choice being set to Y. The choice
+                        * values' dependencies were propagated to their
+                        * properties above, so the change here must be re-
+                        * propagated.
+                        */
+                       if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
+                               basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
+                               menu->dep = expr_alloc_and(basedep, menu->dep);
+                               for (prop = menu->sym->prop; prop; prop = prop->next) {
+                                       if (prop->menu != menu)
+                                               continue;
+                                       prop->visible.expr = expr_alloc_and(expr_copy(basedep),
+                                                                           prop->visible.expr);
+                               }
+                       }
+                       menu_add_symbol(P_CHOICE, sym, NULL);
+                       prop = sym_get_choice_prop(sym);
+                       for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
+                               ;
+                       *ep = expr_alloc_one(E_LIST, NULL);
+                       (*ep)->right.sym = menu->sym;
+               }
+               if (menu->list && (!menu->prompt || !menu->prompt->text)) {
+                       for (last_menu = menu->list; ; last_menu = last_menu->next) {
+                               last_menu->parent = parent;
+                               if (!last_menu->next)
+                                       break;
+                       }
+                       last_menu->next = menu->next;
+                       menu->next = menu->list;
+                       menu->list = NULL;
+               }
+       }
+
+       if (sym && !(sym->flags & SYMBOL_WARNED)) {
+               if (sym->type == S_UNKNOWN)
+                       menu_warn(parent, "config symbol defined without type");
+
+               if (sym_is_choice(sym) && !parent->prompt)
+                       menu_warn(parent, "choice must have a prompt");
+
+               /* Check properties connected to this symbol */
+               sym_check_prop(sym);
+               sym->flags |= SYMBOL_WARNED;
+       }
+
+       if (sym && !sym_is_optional(sym) && parent->prompt) {
+               sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
+                               expr_alloc_and(parent->prompt->visible.expr,
+                                       expr_alloc_symbol(&symbol_mod)));
+       }
+}
+
+bool menu_is_visible(struct menu *menu)
+{
+       struct menu *child;
+       struct symbol *sym;
+       tristate visible;
+
+       if (!menu->prompt)
+               return false;
+       sym = menu->sym;
+       if (sym) {
+               sym_calc_value(sym);
+               visible = menu->prompt->visible.tri;
+       } else
+               visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
+
+       if (visible != no)
+               return true;
+       if (!sym || sym_get_tristate_value(menu->sym) == no)
+               return false;
+
+       for (child = menu->list; child; child = child->next)
+               if (menu_is_visible(child))
+                       return true;
+       return false;
+}
+
+const char *menu_get_prompt(struct menu *menu)
+{
+       if (menu->prompt)
+               return menu->prompt->text;
+       else if (menu->sym)
+               return menu->sym->name;
+       return NULL;
+}
+
+struct menu *menu_get_root_menu(struct menu *menu)
+{
+       return &rootmenu;
+}
+
+struct menu *menu_get_parent_menu(struct menu *menu)
+{
+       enum prop_type type;
+
+       for (; menu != &rootmenu; menu = menu->parent) {
+               type = menu->prompt ? menu->prompt->type : 0;
+               if (type == P_MENU)
+                       break;
+       }
+       return menu;
+}
+
+bool menu_has_help(struct menu *menu)
+{
+       return menu->help != NULL;
+}
+
+const char *menu_get_help(struct menu *menu)
+{
+       if (menu->help)
+               return menu->help;
+       else
+               return "";
+}
diff --git a/bin/kconfig/qconf.cc b/bin/kconfig/qconf.cc
new file mode 100644 (file)
index 0000000..72b5ad8
--- /dev/null
@@ -0,0 +1,1759 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <qapplication.h>
+#include <qmainwindow.h>
+#include <qtoolbar.h>
+#include <qlayout.h>
+#include <qvbox.h>
+#include <qsplitter.h>
+#include <qlistview.h>
+#include <qtextbrowser.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qmenubar.h>
+#include <qmessagebox.h>
+#include <qaction.h>
+#include <qheader.h>
+#include <qfiledialog.h>
+#include <qdragobject.h>
+#include <qregexp.h>
+
+#include <stdlib.h>
+
+#include "lkc.h"
+#include "qconf.h"
+
+#include "qconf.moc"
+#include "images.c"
+
+#ifdef _
+# undef _
+# define _ qgettext
+#endif
+
+static QApplication *configApp;
+static ConfigSettings *configSettings;
+
+QAction *ConfigMainWindow::saveAction;
+
+static inline QString qgettext(const char* str)
+{
+       return QString::fromLocal8Bit(gettext(str));
+}
+
+static inline QString qgettext(const QString& str)
+{
+       return QString::fromLocal8Bit(gettext(str.latin1()));
+}
+
+/**
+ * Reads a list of integer values from the application settings.
+ */
+QValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
+{
+       QValueList<int> result;
+       QStringList entryList = readListEntry(key, ok);
+       if (ok) {
+               QStringList::Iterator it;
+               for (it = entryList.begin(); it != entryList.end(); ++it)
+                       result.push_back((*it).toInt());
+       }
+
+       return result;
+}
+
+/**
+ * Writes a list of integer values to the application settings.
+ */
+bool ConfigSettings::writeSizes(const QString& key, const QValueList<int>& value)
+{
+       QStringList stringList;
+       QValueList<int>::ConstIterator it;
+
+       for (it = value.begin(); it != value.end(); ++it)
+               stringList.push_back(QString::number(*it));
+       return writeEntry(key, stringList);
+}
+
+
+#if QT_VERSION >= 300
+/*
+ * set the new data
+ * TODO check the value
+ */
+void ConfigItem::okRename(int col)
+{
+       Parent::okRename(col);
+       sym_set_string_value(menu->sym, text(dataColIdx).latin1());
+       listView()->updateList(this);
+}
+#endif
+
+/*
+ * update the displayed of a menu entry
+ */
+void ConfigItem::updateMenu(void)
+{
+       ConfigList* list;
+       struct symbol* sym;
+       struct property *prop;
+       QString prompt;
+       int type;
+       tristate expr;
+
+       list = listView();
+       if (goParent) {
+               setPixmap(promptColIdx, list->menuBackPix);
+               prompt = "..";
+               goto set_prompt;
+       }
+
+       sym = menu->sym;
+       prop = menu->prompt;
+       prompt = _(menu_get_prompt(menu));
+
+       if (prop) switch (prop->type) {
+       case P_MENU:
+               if (list->mode == singleMode || list->mode == symbolMode) {
+                       /* a menuconfig entry is displayed differently
+                        * depending whether it's at the view root or a child.
+                        */
+                       if (sym && list->rootEntry == menu)
+                               break;
+                       setPixmap(promptColIdx, list->menuPix);
+               } else {
+                       if (sym)
+                               break;
+                       setPixmap(promptColIdx, 0);
+               }
+               goto set_prompt;
+       case P_COMMENT:
+               setPixmap(promptColIdx, 0);
+               goto set_prompt;
+       default:
+               ;
+       }
+       if (!sym)
+               goto set_prompt;
+
+       setText(nameColIdx, QString::fromLocal8Bit(sym->name));
+
+       type = sym_get_type(sym);
+       switch (type) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               char ch;
+
+               if (!sym_is_changable(sym) && !list->showAll) {
+                       setPixmap(promptColIdx, 0);
+                       setText(noColIdx, QString::null);
+                       setText(modColIdx, QString::null);
+                       setText(yesColIdx, QString::null);
+                       break;
+               }
+               expr = sym_get_tristate_value(sym);
+               switch (expr) {
+               case yes:
+                       if (sym_is_choice_value(sym) && type == S_BOOLEAN)
+                               setPixmap(promptColIdx, list->choiceYesPix);
+                       else
+                               setPixmap(promptColIdx, list->symbolYesPix);
+                       setText(yesColIdx, "Y");
+                       ch = 'Y';
+                       break;
+               case mod:
+                       setPixmap(promptColIdx, list->symbolModPix);
+                       setText(modColIdx, "M");
+                       ch = 'M';
+                       break;
+               default:
+                       if (sym_is_choice_value(sym) && type == S_BOOLEAN)
+                               setPixmap(promptColIdx, list->choiceNoPix);
+                       else
+                               setPixmap(promptColIdx, list->symbolNoPix);
+                       setText(noColIdx, "N");
+                       ch = 'N';
+                       break;
+               }
+               if (expr != no)
+                       setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0);
+               if (expr != mod)
+                       setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0);
+               if (expr != yes)
+                       setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0);
+
+               setText(dataColIdx, QChar(ch));
+               break;
+       case S_INT:
+       case S_HEX:
+       case S_STRING:
+               const char* data;
+
+               data = sym_get_string_value(sym);
+
+#if QT_VERSION >= 300
+               int i = list->mapIdx(dataColIdx);
+               if (i >= 0)
+                       setRenameEnabled(i, TRUE);
+#endif
+               setText(dataColIdx, data);
+               if (type == S_STRING)
+                       prompt = QString("%1: %2").arg(prompt).arg(data);
+               else
+                       prompt = QString("(%2) %1").arg(prompt).arg(data);
+               break;
+       }
+       if (!sym_has_value(sym) && visible)
+               prompt += _(" (NEW)");
+set_prompt:
+       setText(promptColIdx, prompt);
+}
+
+void ConfigItem::testUpdateMenu(bool v)
+{
+       ConfigItem* i;
+
+       visible = v;
+       if (!menu)
+               return;
+
+       sym_calc_value(menu->sym);
+       if (menu->flags & MENU_CHANGED) {
+               /* the menu entry changed, so update all list items */
+               menu->flags &= ~MENU_CHANGED;
+               for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
+                       i->updateMenu();
+       } else if (listView()->updateAll)
+               updateMenu();
+}
+
+void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align)
+{
+       ConfigList* list = listView();
+
+       if (visible) {
+               if (isSelected() && !list->hasFocus() && list->mode == menuMode)
+                       Parent::paintCell(p, list->inactivedColorGroup, column, width, align);
+               else
+                       Parent::paintCell(p, cg, column, width, align);
+       } else
+               Parent::paintCell(p, list->disabledColorGroup, column, width, align);
+}
+
+/*
+ * construct a menu entry
+ */
+void ConfigItem::init(void)
+{
+       if (menu) {
+               ConfigList* list = listView();
+               nextItem = (ConfigItem*)menu->data;
+               menu->data = this;
+
+               if (list->mode != fullMode)
+                       setOpen(TRUE);
+               sym_calc_value(menu->sym);
+       }
+       updateMenu();
+}
+
+/*
+ * destruct a menu entry
+ */
+ConfigItem::~ConfigItem(void)
+{
+       if (menu) {
+               ConfigItem** ip = (ConfigItem**)&menu->data;
+               for (; *ip; ip = &(*ip)->nextItem) {
+                       if (*ip == this) {
+                               *ip = nextItem;
+                               break;
+                       }
+               }
+       }
+}
+
+ConfigLineEdit::ConfigLineEdit(ConfigView* parent)
+       : Parent(parent)
+{
+       connect(this, SIGNAL(lostFocus()), SLOT(hide()));
+}
+
+void ConfigLineEdit::show(ConfigItem* i)
+{
+       item = i;
+       if (sym_get_string_value(item->menu->sym))
+               setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym)));
+       else
+               setText(QString::null);
+       Parent::show();
+       setFocus();
+}
+
+void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
+{
+       switch (e->key()) {
+       case Key_Escape:
+               break;
+       case Key_Return:
+       case Key_Enter:
+               sym_set_string_value(item->menu->sym, text().latin1());
+               parent()->updateList(item);
+               break;
+       default:
+               Parent::keyPressEvent(e);
+               return;
+       }
+       e->accept();
+       parent()->list->setFocus();
+       hide();
+}
+
+ConfigList::ConfigList(ConfigView* p, const char *name)
+       : Parent(p, name),
+         updateAll(false),
+         symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
+         choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
+         menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
+         showAll(false), showName(false), showRange(false), showData(false),
+         rootEntry(0), headerPopup(0)
+{
+       int i;
+
+       setSorting(-1);
+       setRootIsDecorated(TRUE);
+       disabledColorGroup = palette().active();
+       disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text());
+       inactivedColorGroup = palette().active();
+       inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight());
+
+       connect(this, SIGNAL(selectionChanged(void)),
+               SLOT(updateSelection(void)));
+
+       if (name) {
+               configSettings->beginGroup(name);
+               showAll = configSettings->readBoolEntry("/showAll", false);
+               showName = configSettings->readBoolEntry("/showName", false);
+               showRange = configSettings->readBoolEntry("/showRange", false);
+               showData = configSettings->readBoolEntry("/showData", false);
+               configSettings->endGroup();
+               connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
+       }
+
+       for (i = 0; i < colNr; i++)
+               colMap[i] = colRevMap[i] = -1;
+       addColumn(promptColIdx, _("Option"));
+
+       reinit();
+}
+
+void ConfigList::reinit(void)
+{
+       removeColumn(dataColIdx);
+       removeColumn(yesColIdx);
+       removeColumn(modColIdx);
+       removeColumn(noColIdx);
+       removeColumn(nameColIdx);
+
+       if (showName)
+               addColumn(nameColIdx, _("Name"));
+       if (showRange) {
+               addColumn(noColIdx, "N");
+               addColumn(modColIdx, "M");
+               addColumn(yesColIdx, "Y");
+       }
+       if (showData)
+               addColumn(dataColIdx, _("Value"));
+
+       updateListAll();
+}
+
+void ConfigList::saveSettings(void)
+{
+       if (name()) {
+               configSettings->beginGroup(name());
+               configSettings->writeEntry("/showName", showName);
+               configSettings->writeEntry("/showRange", showRange);
+               configSettings->writeEntry("/showData", showData);
+               configSettings->writeEntry("/showAll", showAll);
+               configSettings->endGroup();
+       }
+}
+
+ConfigItem* ConfigList::findConfigItem(struct menu *menu)
+{
+       ConfigItem* item = (ConfigItem*)menu->data;
+
+       for (; item; item = item->nextItem) {
+               if (this == item->listView())
+                       break;
+       }
+
+       return item;
+}
+
+void ConfigList::updateSelection(void)
+{
+       struct menu *menu;
+       enum prop_type type;
+
+       ConfigItem* item = (ConfigItem*)selectedItem();
+       if (!item)
+               return;
+
+       menu = item->menu;
+       emit menuChanged(menu);
+       if (!menu)
+               return;
+       type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+       if (mode == menuMode && type == P_MENU)
+               emit menuSelected(menu);
+}
+
+void ConfigList::updateList(ConfigItem* item)
+{
+       ConfigItem* last = 0;
+
+       if (!rootEntry) {
+               if (mode != listMode)
+                       goto update;
+               QListViewItemIterator it(this);
+               ConfigItem* item;
+
+               for (; it.current(); ++it) {
+                       item = (ConfigItem*)it.current();
+                       if (!item->menu)
+                               continue;
+                       item->testUpdateMenu(menu_is_visible(item->menu));
+               }
+               return;
+       }
+
+       if (rootEntry != &rootmenu && (mode == singleMode ||
+           (mode == symbolMode && rootEntry->parent != &rootmenu))) {
+               item = firstChild();
+               if (!item)
+                       item = new ConfigItem(this, 0, true);
+               last = item;
+       }
+       if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
+           rootEntry->sym && rootEntry->prompt) {
+               item = last ? last->nextSibling() : firstChild();
+               if (!item)
+                       item = new ConfigItem(this, last, rootEntry, true);
+               else
+                       item->testUpdateMenu(true);
+
+               updateMenuList(item, rootEntry);
+               triggerUpdate();
+               return;
+       }
+update:
+       updateMenuList(this, rootEntry);
+       triggerUpdate();
+}
+
+void ConfigList::setValue(ConfigItem* item, tristate val)
+{
+       struct symbol* sym;
+       int type;
+       tristate oldval;
+
+       sym = item->menu ? item->menu->sym : 0;
+       if (!sym)
+               return;
+
+       type = sym_get_type(sym);
+       switch (type) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               oldval = sym_get_tristate_value(sym);
+
+               if (!sym_set_tristate_value(sym, val))
+                       return;
+               if (oldval == no && item->menu->list)
+                       item->setOpen(TRUE);
+               parent()->updateList(item);
+               break;
+       }
+}
+
+void ConfigList::changeValue(ConfigItem* item)
+{
+       struct symbol* sym;
+       struct menu* menu;
+       int type, oldexpr, newexpr;
+
+       menu = item->menu;
+       if (!menu)
+               return;
+       sym = menu->sym;
+       if (!sym) {
+               if (item->menu->list)
+                       item->setOpen(!item->isOpen());
+               return;
+       }
+
+       type = sym_get_type(sym);
+       switch (type) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               oldexpr = sym_get_tristate_value(sym);
+               newexpr = sym_toggle_tristate_value(sym);
+               if (item->menu->list) {
+                       if (oldexpr == newexpr)
+                               item->setOpen(!item->isOpen());
+                       else if (oldexpr == no)
+                               item->setOpen(TRUE);
+               }
+               if (oldexpr != newexpr)
+                       parent()->updateList(item);
+               break;
+       case S_INT:
+       case S_HEX:
+       case S_STRING:
+#if QT_VERSION >= 300
+               if (colMap[dataColIdx] >= 0)
+                       item->startRename(colMap[dataColIdx]);
+               else
+#endif
+                       parent()->lineEdit->show(item);
+               break;
+       }
+}
+
+void ConfigList::setRootMenu(struct menu *menu)
+{
+       enum prop_type type;
+
+       if (rootEntry == menu)
+               return;
+       type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
+       if (type != P_MENU)
+               return;
+       updateMenuList(this, 0);
+       rootEntry = menu;
+       updateListAll();
+       setSelected(currentItem(), hasFocus());
+       ensureItemVisible(currentItem());
+}
+
+void ConfigList::setParentMenu(void)
+{
+       ConfigItem* item;
+       struct menu *oldroot;
+
+       oldroot = rootEntry;
+       if (rootEntry == &rootmenu)
+               return;
+       setRootMenu(menu_get_parent_menu(rootEntry->parent));
+
+       QListViewItemIterator it(this);
+       for (; (item = (ConfigItem*)it.current()); it++) {
+               if (item->menu == oldroot) {
+                       setCurrentItem(item);
+                       ensureItemVisible(item);
+                       break;
+               }
+       }
+}
+
+/*
+ * update all the children of a menu entry
+ *   removes/adds the entries from the parent widget as necessary
+ *
+ * parent: either the menu list widget or a menu entry widget
+ * menu: entry to be updated
+ */
+template <class P>
+void ConfigList::updateMenuList(P* parent, struct menu* menu)
+{
+       struct menu* child;
+       ConfigItem* item;
+       ConfigItem* last;
+       bool visible;
+       enum prop_type type;
+
+       if (!menu) {
+               while ((item = parent->firstChild()))
+                       delete item;
+               return;
+       }
+
+       last = parent->firstChild();
+       if (last && !last->goParent)
+               last = 0;
+       for (child = menu->list; child; child = child->next) {
+               item = last ? last->nextSibling() : parent->firstChild();
+               type = child->prompt ? child->prompt->type : P_UNKNOWN;
+
+               switch (mode) {
+               case menuMode:
+                       if (!(child->flags & MENU_ROOT))
+                               goto hide;
+                       break;
+               case symbolMode:
+                       if (child->flags & MENU_ROOT)
+                               goto hide;
+                       break;
+               default:
+                       break;
+               }
+
+               visible = menu_is_visible(child);
+               if (showAll || visible) {
+                       if (!child->sym && !child->list && !child->prompt)
+                               continue;
+                       if (!item || item->menu != child)
+                               item = new ConfigItem(parent, last, child, visible);
+                       else
+                               item->testUpdateMenu(visible);
+
+                       if (mode == fullMode || mode == menuMode || type != P_MENU)
+                               updateMenuList(item, child);
+                       else
+                               updateMenuList(item, 0);
+                       last = item;
+                       continue;
+               }
+       hide:
+               if (item && item->menu == child) {
+                       last = parent->firstChild();
+                       if (last == item)
+                               last = 0;
+                       else while (last->nextSibling() != item)
+                               last = last->nextSibling();
+                       delete item;
+               }
+       }
+}
+
+void ConfigList::keyPressEvent(QKeyEvent* ev)
+{
+       QListViewItem* i = currentItem();
+       ConfigItem* item;
+       struct menu *menu;
+       enum prop_type type;
+
+       if (ev->key() == Key_Escape && mode != fullMode && mode != listMode) {
+               emit parentSelected();
+               ev->accept();
+               return;
+       }
+
+       if (!i) {
+               Parent::keyPressEvent(ev);
+               return;
+       }
+       item = (ConfigItem*)i;
+
+       switch (ev->key()) {
+       case Key_Return:
+       case Key_Enter:
+               if (item->goParent) {
+                       emit parentSelected();
+                       break;
+               }
+               menu = item->menu;
+               if (!menu)
+                       break;
+               type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+               if (type == P_MENU && rootEntry != menu &&
+                   mode != fullMode && mode != menuMode) {
+                       emit menuSelected(menu);
+                       break;
+               }
+       case Key_Space:
+               changeValue(item);
+               break;
+       case Key_N:
+               setValue(item, no);
+               break;
+       case Key_M:
+               setValue(item, mod);
+               break;
+       case Key_Y:
+               setValue(item, yes);
+               break;
+       default:
+               Parent::keyPressEvent(ev);
+               return;
+       }
+       ev->accept();
+}
+
+void ConfigList::contentsMousePressEvent(QMouseEvent* e)
+{
+       //QPoint p(contentsToViewport(e->pos()));
+       //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
+       Parent::contentsMousePressEvent(e);
+}
+
+void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e)
+{
+       QPoint p(contentsToViewport(e->pos()));
+       ConfigItem* item = (ConfigItem*)itemAt(p);
+       struct menu *menu;
+       enum prop_type ptype;
+       const QPixmap* pm;
+       int idx, x;
+
+       if (!item)
+               goto skip;
+
+       menu = item->menu;
+       x = header()->offset() + p.x();
+       idx = colRevMap[header()->sectionAt(x)];
+       switch (idx) {
+       case promptColIdx:
+               pm = item->pixmap(promptColIdx);
+               if (pm) {
+                       int off = header()->sectionPos(0) + itemMargin() +
+                               treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0));
+                       if (x >= off && x < off + pm->width()) {
+                               if (item->goParent) {
+                                       emit parentSelected();
+                                       break;
+                               } else if (!menu)
+                                       break;
+                               ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+                               if (ptype == P_MENU && rootEntry != menu &&
+                                   mode != fullMode && mode != menuMode)
+                                       emit menuSelected(menu);
+                               else
+                                       changeValue(item);
+                       }
+               }
+               break;
+       case noColIdx:
+               setValue(item, no);
+               break;
+       case modColIdx:
+               setValue(item, mod);
+               break;
+       case yesColIdx:
+               setValue(item, yes);
+               break;
+       case dataColIdx:
+               changeValue(item);
+               break;
+       }
+
+skip:
+       //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
+       Parent::contentsMouseReleaseEvent(e);
+}
+
+void ConfigList::contentsMouseMoveEvent(QMouseEvent* e)
+{
+       //QPoint p(contentsToViewport(e->pos()));
+       //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
+       Parent::contentsMouseMoveEvent(e);
+}
+
+void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e)
+{
+       QPoint p(contentsToViewport(e->pos()));
+       ConfigItem* item = (ConfigItem*)itemAt(p);
+       struct menu *menu;
+       enum prop_type ptype;
+
+       if (!item)
+               goto skip;
+       if (item->goParent) {
+               emit parentSelected();
+               goto skip;
+       }
+       menu = item->menu;
+       if (!menu)
+               goto skip;
+       ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+       if (ptype == P_MENU && (mode == singleMode || mode == symbolMode))
+               emit menuSelected(menu);
+       else if (menu->sym)
+               changeValue(item);
+
+skip:
+       //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
+       Parent::contentsMouseDoubleClickEvent(e);
+}
+
+void ConfigList::focusInEvent(QFocusEvent *e)
+{
+       struct menu *menu = NULL;
+
+       Parent::focusInEvent(e);
+
+       ConfigItem* item = (ConfigItem *)currentItem();
+       if (item) {
+               setSelected(item, TRUE);
+               menu = item->menu;
+       }
+       emit gotFocus(menu);
+}
+
+void ConfigList::contextMenuEvent(QContextMenuEvent *e)
+{
+       if (e->y() <= header()->geometry().bottom()) {
+               if (!headerPopup) {
+                       QAction *action;
+
+                       headerPopup = new QPopupMenu(this);
+                       action = new QAction(NULL, _("Show Name"), 0, this);
+                         action->setToggleAction(TRUE);
+                         connect(action, SIGNAL(toggled(bool)),
+                                 parent(), SLOT(setShowName(bool)));
+                         connect(parent(), SIGNAL(showNameChanged(bool)),
+                                 action, SLOT(setOn(bool)));
+                         action->setOn(showName);
+                         action->addTo(headerPopup);
+                       action = new QAction(NULL, _("Show Range"), 0, this);
+                         action->setToggleAction(TRUE);
+                         connect(action, SIGNAL(toggled(bool)),
+                                 parent(), SLOT(setShowRange(bool)));
+                         connect(parent(), SIGNAL(showRangeChanged(bool)),
+                                 action, SLOT(setOn(bool)));
+                         action->setOn(showRange);
+                         action->addTo(headerPopup);
+                       action = new QAction(NULL, _("Show Data"), 0, this);
+                         action->setToggleAction(TRUE);
+                         connect(action, SIGNAL(toggled(bool)),
+                                 parent(), SLOT(setShowData(bool)));
+                         connect(parent(), SIGNAL(showDataChanged(bool)),
+                                 action, SLOT(setOn(bool)));
+                         action->setOn(showData);
+                         action->addTo(headerPopup);
+               }
+               headerPopup->exec(e->globalPos());
+               e->accept();
+       } else
+               e->ignore();
+}
+
+ConfigView* ConfigView::viewList;
+
+ConfigView::ConfigView(QWidget* parent, const char *name)
+       : Parent(parent, name)
+{
+       list = new ConfigList(this, name);
+       lineEdit = new ConfigLineEdit(this);
+       lineEdit->hide();
+
+       this->nextView = viewList;
+       viewList = this;
+}
+
+ConfigView::~ConfigView(void)
+{
+       ConfigView** vp;
+
+       for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
+               if (*vp == this) {
+                       *vp = nextView;
+                       break;
+               }
+       }
+}
+
+void ConfigView::setShowAll(bool b)
+{
+       if (list->showAll != b) {
+               list->showAll = b;
+               list->updateListAll();
+               emit showAllChanged(b);
+       }
+}
+
+void ConfigView::setShowName(bool b)
+{
+       if (list->showName != b) {
+               list->showName = b;
+               list->reinit();
+               emit showNameChanged(b);
+       }
+}
+
+void ConfigView::setShowRange(bool b)
+{
+       if (list->showRange != b) {
+               list->showRange = b;
+               list->reinit();
+               emit showRangeChanged(b);
+       }
+}
+
+void ConfigView::setShowData(bool b)
+{
+       if (list->showData != b) {
+               list->showData = b;
+               list->reinit();
+               emit showDataChanged(b);
+       }
+}
+
+void ConfigList::setAllOpen(bool open)
+{
+       QListViewItemIterator it(this);
+
+       for (; it.current(); it++)
+               it.current()->setOpen(open);
+}
+
+void ConfigView::updateList(ConfigItem* item)
+{
+       ConfigView* v;
+
+       for (v = viewList; v; v = v->nextView)
+               v->list->updateList(item);
+}
+
+void ConfigView::updateListAll(void)
+{
+       ConfigView* v;
+
+       for (v = viewList; v; v = v->nextView)
+               v->list->updateListAll();
+}
+
+ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
+       : Parent(parent, name), menu(0), sym(0)
+{
+       if (name) {
+               configSettings->beginGroup(name);
+               _showDebug = configSettings->readBoolEntry("/showDebug", false);
+               configSettings->endGroup();
+               connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
+       }
+}
+
+void ConfigInfoView::saveSettings(void)
+{
+       if (name()) {
+               configSettings->beginGroup(name());
+               configSettings->writeEntry("/showDebug", showDebug());
+               configSettings->endGroup();
+       }
+}
+
+void ConfigInfoView::setShowDebug(bool b)
+{
+       if (_showDebug != b) {
+               _showDebug = b;
+               if (menu)
+                       menuInfo();
+               else if (sym)
+                       symbolInfo();
+               emit showDebugChanged(b);
+       }
+}
+
+void ConfigInfoView::setInfo(struct menu *m)
+{
+       if (menu == m)
+               return;
+       menu = m;
+       sym = NULL;
+       if (!menu)
+               clear();
+       else
+               menuInfo();
+}
+
+void ConfigInfoView::setSource(const QString& name)
+{
+       const char *p = name.latin1();
+
+       menu = NULL;
+       sym = NULL;
+
+       switch (p[0]) {
+       case 'm':
+               struct menu *m;
+
+               if (sscanf(p, "m%p", &m) == 1 && menu != m) {
+                       menu = m;
+                       menuInfo();
+                       emit menuSelected(menu);
+               }
+               break;
+       case 's':
+               struct symbol *s;
+
+               if (sscanf(p, "s%p", &s) == 1 && sym != s) {
+                       sym = s;
+                       symbolInfo();
+               }
+               break;
+       }
+}
+
+void ConfigInfoView::symbolInfo(void)
+{
+       QString str;
+
+       str += "<big>Symbol: <b>";
+       str += print_filter(sym->name);
+       str += "</b></big><br><br>value: ";
+       str += print_filter(sym_get_string_value(sym));
+       str += "<br>visibility: ";
+       str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
+       str += "<br>";
+       str += debug_info(sym);
+
+       setText(str);
+}
+
+void ConfigInfoView::menuInfo(void)
+{
+       struct symbol* sym;
+       QString head, debug, help;
+
+       sym = menu->sym;
+       if (sym) {
+               if (menu->prompt) {
+                       head += "<big><b>";
+                       head += print_filter(_(menu->prompt->text));
+                       head += "</b></big>";
+                       if (sym->name) {
+                               head += " (";
+                               if (showDebug())
+                                       head += QString().sprintf("<a href=\"s%p\">", sym);
+                               head += print_filter(sym->name);
+                               if (showDebug())
+                                       head += "</a>";
+                               head += ")";
+                       }
+               } else if (sym->name) {
+                       head += "<big><b>";
+                       if (showDebug())
+                               head += QString().sprintf("<a href=\"s%p\">", sym);
+                       head += print_filter(sym->name);
+                       if (showDebug())
+                               head += "</a>";
+                       head += "</b></big>";
+               }
+               head += "<br><br>";
+
+               if (showDebug())
+                       debug = debug_info(sym);
+
+               help = menu_get_help(menu);
+               /* Gettextize if the help text not empty */
+               if (help.isEmpty())
+                       help = print_filter(menu_get_help(menu));
+               else
+                       help = print_filter(_(menu_get_help(menu)));
+       } else if (menu->prompt) {
+               head += "<big><b>";
+               head += print_filter(_(menu->prompt->text));
+               head += "</b></big><br><br>";
+               if (showDebug()) {
+                       if (menu->prompt->visible.expr) {
+                               debug += "&nbsp;&nbsp;dep: ";
+                               expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
+                               debug += "<br><br>";
+                       }
+               }
+       }
+       if (showDebug())
+               debug += QString().sprintf("defined at %s:%d<br><br>", menu->file->name, menu->lineno);
+
+       setText(head + debug + help);
+}
+
+QString ConfigInfoView::debug_info(struct symbol *sym)
+{
+       QString debug;
+
+       debug += "type: ";
+       debug += print_filter(sym_type_name(sym->type));
+       if (sym_is_choice(sym))
+               debug += " (choice)";
+       debug += "<br>";
+       if (sym->rev_dep.expr) {
+               debug += "reverse dep: ";
+               expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
+               debug += "<br>";
+       }
+       for (struct property *prop = sym->prop; prop; prop = prop->next) {
+               switch (prop->type) {
+               case P_PROMPT:
+               case P_MENU:
+                       debug += QString().sprintf("prompt: <a href=\"m%p\">", prop->menu);
+                       debug += print_filter(_(prop->text));
+                       debug += "</a><br>";
+                       break;
+               case P_DEFAULT:
+               case P_SELECT:
+               case P_RANGE:
+               case P_ENV:
+                       debug += prop_get_type_name(prop->type);
+                       debug += ": ";
+                       expr_print(prop->expr, expr_print_help, &debug, E_NONE);
+                       debug += "<br>";
+                       break;
+               case P_CHOICE:
+                       if (sym_is_choice(sym)) {
+                               debug += "choice: ";
+                               expr_print(prop->expr, expr_print_help, &debug, E_NONE);
+                               debug += "<br>";
+                       }
+                       break;
+               default:
+                       debug += "unknown property: ";
+                       debug += prop_get_type_name(prop->type);
+                       debug += "<br>";
+               }
+               if (prop->visible.expr) {
+                       debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
+                       expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
+                       debug += "<br>";
+               }
+       }
+       debug += "<br>";
+
+       return debug;
+}
+
+QString ConfigInfoView::print_filter(const QString &str)
+{
+       QRegExp re("[<>&\"\\n]");
+       QString res = str;
+       for (int i = 0; (i = res.find(re, i)) >= 0;) {
+               switch (res[i].latin1()) {
+               case '<':
+                       res.replace(i, 1, "&lt;");
+                       i += 4;
+                       break;
+               case '>':
+                       res.replace(i, 1, "&gt;");
+                       i += 4;
+                       break;
+               case '&':
+                       res.replace(i, 1, "&amp;");
+                       i += 5;
+                       break;
+               case '"':
+                       res.replace(i, 1, "&quot;");
+                       i += 6;
+                       break;
+               case '\n':
+                       res.replace(i, 1, "<br>");
+                       i += 4;
+                       break;
+               }
+       }
+       return res;
+}
+
+void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
+{
+       QString* text = reinterpret_cast<QString*>(data);
+       QString str2 = print_filter(str);
+
+       if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
+               *text += QString().sprintf("<a href=\"s%p\">", sym);
+               *text += str2;
+               *text += "</a>";
+       } else
+               *text += str2;
+}
+
+QPopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos)
+{
+       QPopupMenu* popup = Parent::createPopupMenu(pos);
+       QAction* action = new QAction(NULL, _("Show Debug Info"), 0, popup);
+         action->setToggleAction(TRUE);
+         connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
+         connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
+         action->setOn(showDebug());
+       popup->insertSeparator();
+       action->addTo(popup);
+       return popup;
+}
+
+void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e)
+{
+       Parent::contentsContextMenuEvent(e);
+}
+
+ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name)
+       : Parent(parent, name), result(NULL)
+{
+       setCaption("Search Config");
+
+       QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6);
+       QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6);
+       layout2->addWidget(new QLabel(_("Find:"), this));
+       editField = new QLineEdit(this);
+       connect(editField, SIGNAL(returnPressed()), SLOT(search()));
+       layout2->addWidget(editField);
+       searchButton = new QPushButton(_("Search"), this);
+       searchButton->setAutoDefault(FALSE);
+       connect(searchButton, SIGNAL(clicked()), SLOT(search()));
+       layout2->addWidget(searchButton);
+       layout1->addLayout(layout2);
+
+       split = new QSplitter(this);
+       split->setOrientation(QSplitter::Vertical);
+       list = new ConfigView(split, name);
+       list->list->mode = listMode;
+       info = new ConfigInfoView(split, name);
+       connect(list->list, SIGNAL(menuChanged(struct menu *)),
+               info, SLOT(setInfo(struct menu *)));
+       connect(list->list, SIGNAL(menuChanged(struct menu *)),
+               parent, SLOT(setMenuLink(struct menu *)));
+
+       layout1->addWidget(split);
+
+       if (name) {
+               int x, y, width, height;
+               bool ok;
+
+               configSettings->beginGroup(name);
+               width = configSettings->readNumEntry("/window width", parent->width() / 2);
+               height = configSettings->readNumEntry("/window height", parent->height() / 2);
+               resize(width, height);
+               x = configSettings->readNumEntry("/window x", 0, &ok);
+               if (ok)
+                       y = configSettings->readNumEntry("/window y", 0, &ok);
+               if (ok)
+                       move(x, y);
+               QValueList<int> sizes = configSettings->readSizes("/split", &ok);
+               if (ok)
+                       split->setSizes(sizes);
+               configSettings->endGroup();
+               connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
+       }
+}
+
+void ConfigSearchWindow::saveSettings(void)
+{
+       if (name()) {
+               configSettings->beginGroup(name());
+               configSettings->writeEntry("/window x", pos().x());
+               configSettings->writeEntry("/window y", pos().y());
+               configSettings->writeEntry("/window width", size().width());
+               configSettings->writeEntry("/window height", size().height());
+               configSettings->writeSizes("/split", split->sizes());
+               configSettings->endGroup();
+       }
+}
+
+void ConfigSearchWindow::search(void)
+{
+       struct symbol **p;
+       struct property *prop;
+       ConfigItem *lastItem = NULL;
+
+       free(result);
+       list->list->clear();
+       info->clear();
+
+       result = sym_re_search(editField->text().latin1());
+       if (!result)
+               return;
+       for (p = result; *p; p++) {
+               for_all_prompts((*p), prop)
+                       lastItem = new ConfigItem(list->list, lastItem, prop->menu,
+                                                 menu_is_visible(prop->menu));
+       }
+}
+
+/*
+ * Construct the complete config widget
+ */
+ConfigMainWindow::ConfigMainWindow(void)
+       : searchWindow(0)
+{
+       QMenuBar* menu;
+       bool ok;
+       int x, y, width, height;
+       char title[256];
+
+       QWidget *d = configApp->desktop();
+       snprintf(title, sizeof(title), _("firmly.0cpm v%s Configuration"),
+               getenv("KERNELVERSION"));
+       setCaption(title);
+
+       width = configSettings->readNumEntry("/window width", d->width() - 64);
+       height = configSettings->readNumEntry("/window height", d->height() - 64);
+       resize(width, height);
+       x = configSettings->readNumEntry("/window x", 0, &ok);
+       if (ok)
+               y = configSettings->readNumEntry("/window y", 0, &ok);
+       if (ok)
+               move(x, y);
+
+       split1 = new QSplitter(this);
+       split1->setOrientation(QSplitter::Horizontal);
+       setCentralWidget(split1);
+
+       menuView = new ConfigView(split1, "menu");
+       menuList = menuView->list;
+
+       split2 = new QSplitter(split1);
+       split2->setOrientation(QSplitter::Vertical);
+
+       // create config tree
+       configView = new ConfigView(split2, "config");
+       configList = configView->list;
+
+       helpText = new ConfigInfoView(split2, "help");
+       helpText->setTextFormat(Qt::RichText);
+
+       setTabOrder(configList, helpText);
+       configList->setFocus();
+
+       menu = menuBar();
+       toolBar = new QToolBar("Tools", this);
+
+       backAction = new QAction("Back", QPixmap(xpm_back), _("Back"), 0, this);
+         connect(backAction, SIGNAL(activated()), SLOT(goBack()));
+         backAction->setEnabled(FALSE);
+       QAction *quitAction = new QAction("Quit", _("&Quit"), CTRL+Key_Q, this);
+         connect(quitAction, SIGNAL(activated()), SLOT(close()));
+       QAction *loadAction = new QAction("Load", QPixmap(xpm_load), _("&Load"), CTRL+Key_L, this);
+         connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
+       saveAction = new QAction("Save", QPixmap(xpm_save), _("&Save"), CTRL+Key_S, this);
+         connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
+       conf_set_changed_callback(conf_changed);
+       // Set saveAction's initial state
+       conf_changed();
+       QAction *saveAsAction = new QAction("Save As...", _("Save &As..."), 0, this);
+         connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
+       QAction *searchAction = new QAction("Find", _("&Find"), CTRL+Key_F, this);
+         connect(searchAction, SIGNAL(activated()), SLOT(searchConfig()));
+       QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this);
+         connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
+       QAction *splitViewAction = new QAction("Split View", QPixmap(xpm_split_view), _("Split View"), 0, this);
+         connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
+       QAction *fullViewAction = new QAction("Full View", QPixmap(xpm_tree_view), _("Full View"), 0, this);
+         connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
+
+       QAction *showNameAction = new QAction(NULL, _("Show Name"), 0, this);
+         showNameAction->setToggleAction(TRUE);
+         connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
+         connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool)));
+         showNameAction->setOn(configView->showName());
+       QAction *showRangeAction = new QAction(NULL, _("Show Range"), 0, this);
+         showRangeAction->setToggleAction(TRUE);
+         connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
+         connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool)));
+         showRangeAction->setOn(configList->showRange);
+       QAction *showDataAction = new QAction(NULL, _("Show Data"), 0, this);
+         showDataAction->setToggleAction(TRUE);
+         connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
+         connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool)));
+         showDataAction->setOn(configList->showData);
+       QAction *showAllAction = new QAction(NULL, _("Show All Options"), 0, this);
+         showAllAction->setToggleAction(TRUE);
+         connect(showAllAction, SIGNAL(toggled(bool)), configView, SLOT(setShowAll(bool)));
+         connect(showAllAction, SIGNAL(toggled(bool)), menuView, SLOT(setShowAll(bool)));
+         showAllAction->setOn(configList->showAll);
+       QAction *showDebugAction = new QAction(NULL, _("Show Debug Info"), 0, this);
+         showDebugAction->setToggleAction(TRUE);
+         connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
+         connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool)));
+         showDebugAction->setOn(helpText->showDebug());
+
+       QAction *showIntroAction = new QAction(NULL, _("Introduction"), 0, this);
+         connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
+       QAction *showAboutAction = new QAction(NULL, _("About"), 0, this);
+         connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
+
+       // init tool bar
+       backAction->addTo(toolBar);
+       toolBar->addSeparator();
+       loadAction->addTo(toolBar);
+       saveAction->addTo(toolBar);
+       toolBar->addSeparator();
+       singleViewAction->addTo(toolBar);
+       splitViewAction->addTo(toolBar);
+       fullViewAction->addTo(toolBar);
+
+       // create config menu
+       QPopupMenu* config = new QPopupMenu(this);
+       menu->insertItem(_("&File"), config);
+       loadAction->addTo(config);
+       saveAction->addTo(config);
+       saveAsAction->addTo(config);
+       config->insertSeparator();
+       quitAction->addTo(config);
+
+       // create edit menu
+       QPopupMenu* editMenu = new QPopupMenu(this);
+       menu->insertItem(_("&Edit"), editMenu);
+       searchAction->addTo(editMenu);
+
+       // create options menu
+       QPopupMenu* optionMenu = new QPopupMenu(this);
+       menu->insertItem(_("&Option"), optionMenu);
+       showNameAction->addTo(optionMenu);
+       showRangeAction->addTo(optionMenu);
+       showDataAction->addTo(optionMenu);
+       optionMenu->insertSeparator();
+       showAllAction->addTo(optionMenu);
+       showDebugAction->addTo(optionMenu);
+
+       // create help menu
+       QPopupMenu* helpMenu = new QPopupMenu(this);
+       menu->insertSeparator();
+       menu->insertItem(_("&Help"), helpMenu);
+       showIntroAction->addTo(helpMenu);
+       showAboutAction->addTo(helpMenu);
+
+       connect(configList, SIGNAL(menuChanged(struct menu *)),
+               helpText, SLOT(setInfo(struct menu *)));
+       connect(configList, SIGNAL(menuSelected(struct menu *)),
+               SLOT(changeMenu(struct menu *)));
+       connect(configList, SIGNAL(parentSelected()),
+               SLOT(goBack()));
+       connect(menuList, SIGNAL(menuChanged(struct menu *)),
+               helpText, SLOT(setInfo(struct menu *)));
+       connect(menuList, SIGNAL(menuSelected(struct menu *)),
+               SLOT(changeMenu(struct menu *)));
+
+       connect(configList, SIGNAL(gotFocus(struct menu *)),
+               helpText, SLOT(setInfo(struct menu *)));
+       connect(menuList, SIGNAL(gotFocus(struct menu *)),
+               helpText, SLOT(setInfo(struct menu *)));
+       connect(menuList, SIGNAL(gotFocus(struct menu *)),
+               SLOT(listFocusChanged(void)));
+       connect(helpText, SIGNAL(menuSelected(struct menu *)),
+               SLOT(setMenuLink(struct menu *)));
+
+       QString listMode = configSettings->readEntry("/listMode", "symbol");
+       if (listMode == "single")
+               showSingleView();
+       else if (listMode == "full")
+               showFullView();
+       else /*if (listMode == "split")*/
+               showSplitView();
+
+       // UI setup done, restore splitter positions
+       QValueList<int> sizes = configSettings->readSizes("/split1", &ok);
+       if (ok)
+               split1->setSizes(sizes);
+
+       sizes = configSettings->readSizes("/split2", &ok);
+       if (ok)
+               split2->setSizes(sizes);
+}
+
+void ConfigMainWindow::loadConfig(void)
+{
+       QString s = QFileDialog::getOpenFileName(".config", NULL, this);
+       if (s.isNull())
+               return;
+       if (conf_read(QFile::encodeName(s)))
+               QMessageBox::information(this, "qconf", _("Unable to load configuration!"));
+       ConfigView::updateListAll();
+}
+
+void ConfigMainWindow::saveConfig(void)
+{
+       if (conf_write(NULL))
+               QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+}
+
+void ConfigMainWindow::saveConfigAs(void)
+{
+       QString s = QFileDialog::getSaveFileName(".config", NULL, this);
+       if (s.isNull())
+               return;
+       if (conf_write(QFile::encodeName(s)))
+               QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+}
+
+void ConfigMainWindow::searchConfig(void)
+{
+       if (!searchWindow)
+               searchWindow = new ConfigSearchWindow(this, "search");
+       searchWindow->show();
+}
+
+void ConfigMainWindow::changeMenu(struct menu *menu)
+{
+       configList->setRootMenu(menu);
+       if (configList->rootEntry->parent == &rootmenu)
+               backAction->setEnabled(FALSE);
+       else
+               backAction->setEnabled(TRUE);
+}
+
+void ConfigMainWindow::setMenuLink(struct menu *menu)
+{
+       struct menu *parent;
+       ConfigList* list = NULL;
+       ConfigItem* item;
+
+       if (!menu_is_visible(menu) && !configView->showAll())
+               return;
+
+       switch (configList->mode) {
+       case singleMode:
+               list = configList;
+               parent = menu_get_parent_menu(menu);
+               if (!parent)
+                       return;
+               list->setRootMenu(parent);
+               break;
+       case symbolMode:
+               if (menu->flags & MENU_ROOT) {
+                       configList->setRootMenu(menu);
+                       configList->clearSelection();
+                       list = menuList;
+               } else {
+                       list = configList;
+                       parent = menu_get_parent_menu(menu->parent);
+                       if (!parent)
+                               return;
+                       item = menuList->findConfigItem(parent);
+                       if (item) {
+                               menuList->setSelected(item, TRUE);
+                               menuList->ensureItemVisible(item);
+                       }
+                       list->setRootMenu(parent);
+               }
+               break;
+       case fullMode:
+               list = configList;
+               break;
+       }
+
+       if (list) {
+               item = list->findConfigItem(menu);
+               if (item) {
+                       list->setSelected(item, TRUE);
+                       list->ensureItemVisible(item);
+                       list->setFocus();
+               }
+       }
+}
+
+void ConfigMainWindow::listFocusChanged(void)
+{
+       if (menuList->mode == menuMode)
+               configList->clearSelection();
+}
+
+void ConfigMainWindow::goBack(void)
+{
+       ConfigItem* item;
+
+       configList->setParentMenu();
+       if (configList->rootEntry == &rootmenu)
+               backAction->setEnabled(FALSE);
+       item = (ConfigItem*)menuList->selectedItem();
+       while (item) {
+               if (item->menu == configList->rootEntry) {
+                       menuList->setSelected(item, TRUE);
+                       break;
+               }
+               item = (ConfigItem*)item->parent();
+       }
+}
+
+void ConfigMainWindow::showSingleView(void)
+{
+       menuView->hide();
+       menuList->setRootMenu(0);
+       configList->mode = singleMode;
+       if (configList->rootEntry == &rootmenu)
+               configList->updateListAll();
+       else
+               configList->setRootMenu(&rootmenu);
+       configList->setAllOpen(TRUE);
+       configList->setFocus();
+}
+
+void ConfigMainWindow::showSplitView(void)
+{
+       configList->mode = symbolMode;
+       if (configList->rootEntry == &rootmenu)
+               configList->updateListAll();
+       else
+               configList->setRootMenu(&rootmenu);
+       configList->setAllOpen(TRUE);
+       configApp->processEvents();
+       menuList->mode = menuMode;
+       menuList->setRootMenu(&rootmenu);
+       menuList->setAllOpen(TRUE);
+       menuView->show();
+       menuList->setFocus();
+}
+
+void ConfigMainWindow::showFullView(void)
+{
+       menuView->hide();
+       menuList->setRootMenu(0);
+       configList->mode = fullMode;
+       if (configList->rootEntry == &rootmenu)
+               configList->updateListAll();
+       else
+               configList->setRootMenu(&rootmenu);
+       configList->setAllOpen(FALSE);
+       configList->setFocus();
+}
+
+/*
+ * ask for saving configuration before quitting
+ * TODO ask only when something changed
+ */
+void ConfigMainWindow::closeEvent(QCloseEvent* e)
+{
+       if (!conf_get_changed()) {
+               e->accept();
+               return;
+       }
+       QMessageBox mb("qconf", _("Save configuration?"), QMessageBox::Warning,
+                       QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
+       mb.setButtonText(QMessageBox::Yes, _("&Save Changes"));
+       mb.setButtonText(QMessageBox::No, _("&Discard Changes"));
+       mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
+       switch (mb.exec()) {
+       case QMessageBox::Yes:
+               conf_write(NULL);
+       case QMessageBox::No:
+               e->accept();
+               break;
+       case QMessageBox::Cancel:
+               e->ignore();
+               break;
+       }
+}
+
+void ConfigMainWindow::showIntro(void)
+{
+       static const QString str = _("Welcome to the qconf graphical kernel configuration tool for firmly.0cpm.\n\n"
+               "For each option, a blank box indicates the feature is disabled, a check\n"
+               "indicates it is enabled, and a dot indicates that it is to be compiled\n"
+               "as a module.  Clicking on the box will cycle through the three states.\n\n"
+               "If you do not see an option (e.g., a device driver) that you believe\n"
+               "should be present, try turning on Show All Options under the Options menu.\n"
+               "Although there is no cross reference yet to help you figure out what other\n"
+               "options must be enabled to support the option you are interested in, you can\n"
+               "still view the help of a grayed-out option.\n\n"
+               "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
+               "which you can then match by examining other options.\n\n");
+
+       QMessageBox::information(this, "qconf", str);
+}
+
+void ConfigMainWindow::showAbout(void)
+{
+       static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n\n"
+               "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n");
+
+       QMessageBox::information(this, "qconf", str);
+}
+
+void ConfigMainWindow::saveSettings(void)
+{
+       configSettings->writeEntry("/window x", pos().x());
+       configSettings->writeEntry("/window y", pos().y());
+       configSettings->writeEntry("/window width", size().width());
+       configSettings->writeEntry("/window height", size().height());
+
+       QString entry;
+       switch(configList->mode) {
+       case singleMode :
+               entry = "single";
+               break;
+
+       case symbolMode :
+               entry = "split";
+               break;
+
+       case fullMode :
+               entry = "full";
+               break;
+       }
+       configSettings->writeEntry("/listMode", entry);
+
+       configSettings->writeSizes("/split1", split1->sizes());
+       configSettings->writeSizes("/split2", split2->sizes());
+}
+
+void ConfigMainWindow::conf_changed(void)
+{
+       if (saveAction)
+               saveAction->setEnabled(conf_get_changed());
+}
+
+void fixup_rootmenu(struct menu *menu)
+{
+       struct menu *child;
+       static int menu_cnt = 0;
+
+       menu->flags |= MENU_ROOT;
+       for (child = menu->list; child; child = child->next) {
+               if (child->prompt && child->prompt->type == P_MENU) {
+                       menu_cnt++;
+                       fixup_rootmenu(child);
+                       menu_cnt--;
+               } else if (!menu_cnt)
+                       fixup_rootmenu(child);
+       }
+}
+
+static const char *progname;
+
+static void usage(void)
+{
+       printf(_("%s <config>\n"), progname);
+       exit(0);
+}
+
+int main(int ac, char** av)
+{
+       ConfigMainWindow* v;
+       const char *name;
+
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+#ifndef LKC_DIRECT_LINK
+       kconfig_load();
+#endif
+
+       progname = av[0];
+       configApp = new QApplication(ac, av);
+       if (ac > 1 && av[1][0] == '-') {
+               switch (av[1][1]) {
+               case 'h':
+               case '?':
+                       usage();
+               }
+               name = av[2];
+       } else
+               name = av[1];
+       if (!name)
+               usage();
+
+       conf_parse(name);
+       fixup_rootmenu(&rootmenu);
+       conf_read(NULL);
+       //zconfdump(stdout);
+
+       configSettings = new ConfigSettings();
+       configSettings->beginGroup("/kconfig/qconf");
+       v = new ConfigMainWindow();
+
+       //zconfdump(stdout);
+       configApp->setMainWidget(v);
+       configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
+       configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
+       v->show();
+       configApp->exec();
+
+       configSettings->endGroup();
+       delete configSettings;
+
+       return 0;
+}
diff --git a/bin/kconfig/qconf.h b/bin/kconfig/qconf.h
new file mode 100644 (file)
index 0000000..b3b5657
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <qlistview.h>
+#if QT_VERSION >= 300
+#include <qsettings.h>
+#else
+class QSettings {
+public:
+       void beginGroup(const QString& group) { }
+       void endGroup(void) { }
+       bool readBoolEntry(const QString& key, bool def = FALSE, bool* ok = 0) const
+       { if (ok) *ok = FALSE; return def; }
+       int readNumEntry(const QString& key, int def = 0, bool* ok = 0) const
+       { if (ok) *ok = FALSE; return def; }
+       QString readEntry(const QString& key, const QString& def = QString::null, bool* ok = 0) const
+       { if (ok) *ok = FALSE; return def; }
+       QStringList readListEntry(const QString& key, bool* ok = 0) const
+       { if (ok) *ok = FALSE; return QStringList(); }
+       template <class t>
+       bool writeEntry(const QString& key, t value)
+       { return TRUE; }
+};
+#endif
+
+class ConfigView;
+class ConfigList;
+class ConfigItem;
+class ConfigLineEdit;
+class ConfigMainWindow;
+
+
+class ConfigSettings : public QSettings {
+public:
+       QValueList<int> readSizes(const QString& key, bool *ok);
+       bool writeSizes(const QString& key, const QValueList<int>& value);
+};
+
+enum colIdx {
+       promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx, colNr
+};
+enum listMode {
+       singleMode, menuMode, symbolMode, fullMode, listMode
+};
+
+class ConfigList : public QListView {
+       Q_OBJECT
+       typedef class QListView Parent;
+public:
+       ConfigList(ConfigView* p, const char *name = 0);
+       void reinit(void);
+       ConfigView* parent(void) const
+       {
+               return (ConfigView*)Parent::parent();
+       }
+       ConfigItem* findConfigItem(struct menu *);
+
+protected:
+       void keyPressEvent(QKeyEvent *e);
+       void contentsMousePressEvent(QMouseEvent *e);
+       void contentsMouseReleaseEvent(QMouseEvent *e);
+       void contentsMouseMoveEvent(QMouseEvent *e);
+       void contentsMouseDoubleClickEvent(QMouseEvent *e);
+       void focusInEvent(QFocusEvent *e);
+       void contextMenuEvent(QContextMenuEvent *e);
+
+public slots:
+       void setRootMenu(struct menu *menu);
+
+       void updateList(ConfigItem *item);
+       void setValue(ConfigItem* item, tristate val);
+       void changeValue(ConfigItem* item);
+       void updateSelection(void);
+       void saveSettings(void);
+signals:
+       void menuChanged(struct menu *menu);
+       void menuSelected(struct menu *menu);
+       void parentSelected(void);
+       void gotFocus(struct menu *);
+
+public:
+       void updateListAll(void)
+       {
+               updateAll = true;
+               updateList(NULL);
+               updateAll = false;
+       }
+       ConfigList* listView()
+       {
+               return this;
+       }
+       ConfigItem* firstChild() const
+       {
+               return (ConfigItem *)Parent::firstChild();
+       }
+       int mapIdx(colIdx idx)
+       {
+               return colMap[idx];
+       }
+       void addColumn(colIdx idx, const QString& label)
+       {
+               colMap[idx] = Parent::addColumn(label);
+               colRevMap[colMap[idx]] = idx;
+       }
+       void removeColumn(colIdx idx)
+       {
+               int col = colMap[idx];
+               if (col >= 0) {
+                       Parent::removeColumn(col);
+                       colRevMap[col] = colMap[idx] = -1;
+               }
+       }
+       void setAllOpen(bool open);
+       void setParentMenu(void);
+
+       template <class P>
+       void updateMenuList(P*, struct menu*);
+
+       bool updateAll;
+
+       QPixmap symbolYesPix, symbolModPix, symbolNoPix;
+       QPixmap choiceYesPix, choiceNoPix;
+       QPixmap menuPix, menuInvPix, menuBackPix, voidPix;
+
+       bool showAll, showName, showRange, showData;
+       enum listMode mode;
+       struct menu *rootEntry;
+       QColorGroup disabledColorGroup;
+       QColorGroup inactivedColorGroup;
+       QPopupMenu* headerPopup;
+
+private:
+       int colMap[colNr];
+       int colRevMap[colNr];
+};
+
+class ConfigItem : public QListViewItem {
+       typedef class QListViewItem Parent;
+public:
+       ConfigItem(QListView *parent, ConfigItem *after, struct menu *m, bool v)
+       : Parent(parent, after), menu(m), visible(v), goParent(false)
+       {
+               init();
+       }
+       ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v)
+       : Parent(parent, after), menu(m), visible(v), goParent(false)
+       {
+               init();
+       }
+       ConfigItem(QListView *parent, ConfigItem *after, bool v)
+       : Parent(parent, after), menu(0), visible(v), goParent(true)
+       {
+               init();
+       }
+       ~ConfigItem(void);
+       void init(void);
+#if QT_VERSION >= 300
+       void okRename(int col);
+#endif
+       void updateMenu(void);
+       void testUpdateMenu(bool v);
+       ConfigList* listView() const
+       {
+               return (ConfigList*)Parent::listView();
+       }
+       ConfigItem* firstChild() const
+       {
+               return (ConfigItem *)Parent::firstChild();
+       }
+       ConfigItem* nextSibling() const
+       {
+               return (ConfigItem *)Parent::nextSibling();
+       }
+       void setText(colIdx idx, const QString& text)
+       {
+               Parent::setText(listView()->mapIdx(idx), text);
+       }
+       QString text(colIdx idx) const
+       {
+               return Parent::text(listView()->mapIdx(idx));
+       }
+       void setPixmap(colIdx idx, const QPixmap& pm)
+       {
+               Parent::setPixmap(listView()->mapIdx(idx), pm);
+       }
+       const QPixmap* pixmap(colIdx idx) const
+       {
+               return Parent::pixmap(listView()->mapIdx(idx));
+       }
+       void paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align);
+
+       ConfigItem* nextItem;
+       struct menu *menu;
+       bool visible;
+       bool goParent;
+};
+
+class ConfigLineEdit : public QLineEdit {
+       Q_OBJECT
+       typedef class QLineEdit Parent;
+public:
+       ConfigLineEdit(ConfigView* parent);
+       ConfigView* parent(void) const
+       {
+               return (ConfigView*)Parent::parent();
+       }
+       void show(ConfigItem *i);
+       void keyPressEvent(QKeyEvent *e);
+
+public:
+       ConfigItem *item;
+};
+
+class ConfigView : public QVBox {
+       Q_OBJECT
+       typedef class QVBox Parent;
+public:
+       ConfigView(QWidget* parent, const char *name = 0);
+       ~ConfigView(void);
+       static void updateList(ConfigItem* item);
+       static void updateListAll(void);
+
+       bool showAll(void) const { return list->showAll; }
+       bool showName(void) const { return list->showName; }
+       bool showRange(void) const { return list->showRange; }
+       bool showData(void) const { return list->showData; }
+public slots:
+       void setShowAll(bool);
+       void setShowName(bool);
+       void setShowRange(bool);
+       void setShowData(bool);
+signals:
+       void showAllChanged(bool);
+       void showNameChanged(bool);
+       void showRangeChanged(bool);
+       void showDataChanged(bool);
+public:
+       ConfigList* list;
+       ConfigLineEdit* lineEdit;
+
+       static ConfigView* viewList;
+       ConfigView* nextView;
+};
+
+class ConfigInfoView : public QTextBrowser {
+       Q_OBJECT
+       typedef class QTextBrowser Parent;
+public:
+       ConfigInfoView(QWidget* parent, const char *name = 0);
+       bool showDebug(void) const { return _showDebug; }
+
+public slots:
+       void setInfo(struct menu *menu);
+       void saveSettings(void);
+       void setSource(const QString& name);
+       void setShowDebug(bool);
+
+signals:
+       void showDebugChanged(bool);
+       void menuSelected(struct menu *);
+
+protected:
+       void symbolInfo(void);
+       void menuInfo(void);
+       QString debug_info(struct symbol *sym);
+       static QString print_filter(const QString &str);
+       static void expr_print_help(void *data, struct symbol *sym, const char *str);
+       QPopupMenu* createPopupMenu(const QPoint& pos);
+       void contentsContextMenuEvent(QContextMenuEvent *e);
+
+       struct symbol *sym;
+       struct menu *menu;
+       bool _showDebug;
+};
+
+class ConfigSearchWindow : public QDialog {
+       Q_OBJECT
+       typedef class QDialog Parent;
+public:
+       ConfigSearchWindow(ConfigMainWindow* parent, const char *name = 0);
+
+public slots:
+       void saveSettings(void);
+       void search(void);
+
+protected:
+       QLineEdit* editField;
+       QPushButton* searchButton;
+       QSplitter* split;
+       ConfigView* list;
+       ConfigInfoView* info;
+
+       struct symbol **result;
+};
+
+class ConfigMainWindow : public QMainWindow {
+       Q_OBJECT
+
+       static QAction *saveAction;
+       static void conf_changed(void);
+public:
+       ConfigMainWindow(void);
+public slots:
+       void changeMenu(struct menu *);
+       void setMenuLink(struct menu *);
+       void listFocusChanged(void);
+       void goBack(void);
+       void loadConfig(void);
+       void saveConfig(void);
+       void saveConfigAs(void);
+       void searchConfig(void);
+       void showSingleView(void);
+       void showSplitView(void);
+       void showFullView(void);
+       void showIntro(void);
+       void showAbout(void);
+       void saveSettings(void);
+
+protected:
+       void closeEvent(QCloseEvent *e);
+
+       ConfigSearchWindow *searchWindow;
+       ConfigView *menuView;
+       ConfigList *menuList;
+       ConfigView *configView;
+       ConfigList *configList;
+       ConfigInfoView *helpText;
+       QToolBar *toolBar;
+       QAction *backAction;
+       QSplitter* split1;
+       QSplitter* split2;
+};
diff --git a/bin/kconfig/symbol.c b/bin/kconfig/symbol.c
new file mode 100644 (file)
index 0000000..18f3e5c
--- /dev/null
@@ -0,0 +1,973 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <regex.h>
+#include <sys/utsname.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+struct symbol symbol_yes = {
+       .name = "y",
+       .curr = { "y", yes },
+       .flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_mod = {
+       .name = "m",
+       .curr = { "m", mod },
+       .flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_no = {
+       .name = "n",
+       .curr = { "n", no },
+       .flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_empty = {
+       .name = "",
+       .curr = { "", no },
+       .flags = SYMBOL_VALID,
+};
+
+struct symbol *sym_defconfig_list;
+struct symbol *modules_sym;
+tristate modules_val;
+
+struct expr *sym_env_list;
+
+void sym_add_default(struct symbol *sym, const char *def)
+{
+       struct property *prop = prop_alloc(P_DEFAULT, sym);
+
+       prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST));
+}
+
+void sym_init(void)
+{
+       struct symbol *sym;
+       struct utsname uts;
+       static bool inited = false;
+
+       if (inited)
+               return;
+       inited = true;
+
+       uname(&uts);
+
+       sym = sym_lookup("UNAME_RELEASE", 0);
+       sym->type = S_STRING;
+       sym->flags |= SYMBOL_AUTO;
+       sym_add_default(sym, uts.release);
+}
+
+enum symbol_type sym_get_type(struct symbol *sym)
+{
+       enum symbol_type type = sym->type;
+
+       if (type == S_TRISTATE) {
+               if (sym_is_choice_value(sym) && sym->visible == yes)
+                       type = S_BOOLEAN;
+               else if (modules_val == no)
+                       type = S_BOOLEAN;
+       }
+       return type;
+}
+
+const char *sym_type_name(enum symbol_type type)
+{
+       switch (type) {
+       case S_BOOLEAN:
+               return "boolean";
+       case S_TRISTATE:
+               return "tristate";
+       case S_INT:
+               return "integer";
+       case S_HEX:
+               return "hex";
+       case S_STRING:
+               return "string";
+       case S_UNKNOWN:
+               return "unknown";
+       case S_OTHER:
+               break;
+       }
+       return "???";
+}
+
+struct property *sym_get_choice_prop(struct symbol *sym)
+{
+       struct property *prop;
+
+       for_all_choices(sym, prop)
+               return prop;
+       return NULL;
+}
+
+struct property *sym_get_env_prop(struct symbol *sym)
+{
+       struct property *prop;
+
+       for_all_properties(sym, prop, P_ENV)
+               return prop;
+       return NULL;
+}
+
+struct property *sym_get_default_prop(struct symbol *sym)
+{
+       struct property *prop;
+
+       for_all_defaults(sym, prop) {
+               prop->visible.tri = expr_calc_value(prop->visible.expr);
+               if (prop->visible.tri != no)
+                       return prop;
+       }
+       return NULL;
+}
+
+struct property *sym_get_range_prop(struct symbol *sym)
+{
+       struct property *prop;
+
+       for_all_properties(sym, prop, P_RANGE) {
+               prop->visible.tri = expr_calc_value(prop->visible.expr);
+               if (prop->visible.tri != no)
+                       return prop;
+       }
+       return NULL;
+}
+
+static int sym_get_range_val(struct symbol *sym, int base)
+{
+       sym_calc_value(sym);
+       switch (sym->type) {
+       case S_INT:
+               base = 10;
+               break;
+       case S_HEX:
+               base = 16;
+               break;
+       default:
+               break;
+       }
+       return strtol(sym->curr.val, NULL, base);
+}
+
+static void sym_validate_range(struct symbol *sym)
+{
+       struct property *prop;
+       int base, val, val2;
+       char str[64];
+
+       switch (sym->type) {
+       case S_INT:
+               base = 10;
+               break;
+       case S_HEX:
+               base = 16;
+               break;
+       default:
+               return;
+       }
+       prop = sym_get_range_prop(sym);
+       if (!prop)
+               return;
+       val = strtol(sym->curr.val, NULL, base);
+       val2 = sym_get_range_val(prop->expr->left.sym, base);
+       if (val >= val2) {
+               val2 = sym_get_range_val(prop->expr->right.sym, base);
+               if (val <= val2)
+                       return;
+       }
+       if (sym->type == S_INT)
+               sprintf(str, "%d", val2);
+       else
+               sprintf(str, "0x%x", val2);
+       sym->curr.val = strdup(str);
+}
+
+static void sym_calc_visibility(struct symbol *sym)
+{
+       struct property *prop;
+       tristate tri;
+
+       /* any prompt visible? */
+       tri = no;
+       for_all_prompts(sym, prop) {
+               prop->visible.tri = expr_calc_value(prop->visible.expr);
+               tri = EXPR_OR(tri, prop->visible.tri);
+       }
+       if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
+               tri = yes;
+       if (sym->visible != tri) {
+               sym->visible = tri;
+               sym_set_changed(sym);
+       }
+       if (sym_is_choice_value(sym))
+               return;
+       tri = no;
+       if (sym->rev_dep.expr)
+               tri = expr_calc_value(sym->rev_dep.expr);
+       if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
+               tri = yes;
+       if (sym->rev_dep.tri != tri) {
+               sym->rev_dep.tri = tri;
+               sym_set_changed(sym);
+       }
+}
+
+static struct symbol *sym_calc_choice(struct symbol *sym)
+{
+       struct symbol *def_sym;
+       struct property *prop;
+       struct expr *e;
+
+       /* is the user choice visible? */
+       def_sym = sym->def[S_DEF_USER].val;
+       if (def_sym) {
+               sym_calc_visibility(def_sym);
+               if (def_sym->visible != no)
+                       return def_sym;
+       }
+
+       /* any of the defaults visible? */
+       for_all_defaults(sym, prop) {
+               prop->visible.tri = expr_calc_value(prop->visible.expr);
+               if (prop->visible.tri == no)
+                       continue;
+               def_sym = prop_get_symbol(prop);
+               sym_calc_visibility(def_sym);
+               if (def_sym->visible != no)
+                       return def_sym;
+       }
+
+       /* just get the first visible value */
+       prop = sym_get_choice_prop(sym);
+       expr_list_for_each_sym(prop->expr, e, def_sym) {
+               sym_calc_visibility(def_sym);
+               if (def_sym->visible != no)
+                       return def_sym;
+       }
+
+       /* no choice? reset tristate value */
+       sym->curr.tri = no;
+       return NULL;
+}
+
+void sym_calc_value(struct symbol *sym)
+{
+       struct symbol_value newval, oldval;
+       struct property *prop;
+       struct expr *e;
+
+       if (!sym)
+               return;
+
+       if (sym->flags & SYMBOL_VALID)
+               return;
+       sym->flags |= SYMBOL_VALID;
+
+       oldval = sym->curr;
+
+       switch (sym->type) {
+       case S_INT:
+       case S_HEX:
+       case S_STRING:
+               newval = symbol_empty.curr;
+               break;
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               newval = symbol_no.curr;
+               break;
+       default:
+               sym->curr.val = sym->name;
+               sym->curr.tri = no;
+               return;
+       }
+       if (!sym_is_choice_value(sym))
+               sym->flags &= ~SYMBOL_WRITE;
+
+       sym_calc_visibility(sym);
+
+       /* set default if recursively called */
+       sym->curr = newval;
+
+       switch (sym_get_type(sym)) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               if (sym_is_choice_value(sym) && sym->visible == yes) {
+                       prop = sym_get_choice_prop(sym);
+                       newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
+               } else {
+                       if (sym->visible != no) {
+                               /* if the symbol is visible use the user value
+                                * if available, otherwise try the default value
+                                */
+                               sym->flags |= SYMBOL_WRITE;
+                               if (sym_has_value(sym)) {
+                                       newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
+                                                             sym->visible);
+                                       goto calc_newval;
+                               }
+                       }
+                       if (sym->rev_dep.tri != no)
+                               sym->flags |= SYMBOL_WRITE;
+                       if (!sym_is_choice(sym)) {
+                               prop = sym_get_default_prop(sym);
+                               if (prop) {
+                                       sym->flags |= SYMBOL_WRITE;
+                                       newval.tri = EXPR_AND(expr_calc_value(prop->expr),
+                                                             prop->visible.tri);
+                               }
+                       }
+               calc_newval:
+                       newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
+               }
+               if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
+                       newval.tri = yes;
+               break;
+       case S_STRING:
+       case S_HEX:
+       case S_INT:
+               if (sym->visible != no) {
+                       sym->flags |= SYMBOL_WRITE;
+                       if (sym_has_value(sym)) {
+                               newval.val = sym->def[S_DEF_USER].val;
+                               break;
+                       }
+               }
+               prop = sym_get_default_prop(sym);
+               if (prop) {
+                       struct symbol *ds = prop_get_symbol(prop);
+                       if (ds) {
+                               sym->flags |= SYMBOL_WRITE;
+                               sym_calc_value(ds);
+                               newval.val = ds->curr.val;
+                       }
+               }
+               break;
+       default:
+               ;
+       }
+
+       sym->curr = newval;
+       if (sym_is_choice(sym) && newval.tri == yes)
+               sym->curr.val = sym_calc_choice(sym);
+       sym_validate_range(sym);
+
+       if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
+               sym_set_changed(sym);
+               if (modules_sym == sym) {
+                       sym_set_all_changed();
+                       modules_val = modules_sym->curr.tri;
+               }
+       }
+
+       if (sym_is_choice(sym)) {
+               struct symbol *choice_sym;
+               int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
+
+               prop = sym_get_choice_prop(sym);
+               expr_list_for_each_sym(prop->expr, e, choice_sym) {
+                       choice_sym->flags |= flags;
+                       if (flags & SYMBOL_CHANGED)
+                               sym_set_changed(choice_sym);
+               }
+       }
+
+       if (sym->flags & SYMBOL_AUTO)
+               sym->flags &= ~SYMBOL_WRITE;
+}
+
+void sym_clear_all_valid(void)
+{
+       struct symbol *sym;
+       int i;
+
+       for_all_symbols(i, sym)
+               sym->flags &= ~SYMBOL_VALID;
+       sym_add_change_count(1);
+       if (modules_sym)
+               sym_calc_value(modules_sym);
+}
+
+void sym_set_changed(struct symbol *sym)
+{
+       struct property *prop;
+
+       sym->flags |= SYMBOL_CHANGED;
+       for (prop = sym->prop; prop; prop = prop->next) {
+               if (prop->menu)
+                       prop->menu->flags |= MENU_CHANGED;
+       }
+}
+
+void sym_set_all_changed(void)
+{
+       struct symbol *sym;
+       int i;
+
+       for_all_symbols(i, sym)
+               sym_set_changed(sym);
+}
+
+bool sym_tristate_within_range(struct symbol *sym, tristate val)
+{
+       int type = sym_get_type(sym);
+
+       if (sym->visible == no)
+               return false;
+
+       if (type != S_BOOLEAN && type != S_TRISTATE)
+               return false;
+
+       if (type == S_BOOLEAN && val == mod)
+               return false;
+       if (sym->visible <= sym->rev_dep.tri)
+               return false;
+       if (sym_is_choice_value(sym) && sym->visible == yes)
+               return val == yes;
+       return val >= sym->rev_dep.tri && val <= sym->visible;
+}
+
+bool sym_set_tristate_value(struct symbol *sym, tristate val)
+{
+       tristate oldval = sym_get_tristate_value(sym);
+
+       if (oldval != val && !sym_tristate_within_range(sym, val))
+               return false;
+
+       if (!(sym->flags & SYMBOL_DEF_USER)) {
+               sym->flags |= SYMBOL_DEF_USER;
+               sym_set_changed(sym);
+       }
+       /*
+        * setting a choice value also resets the new flag of the choice
+        * symbol and all other choice values.
+        */
+       if (sym_is_choice_value(sym) && val == yes) {
+               struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+               struct property *prop;
+               struct expr *e;
+
+               cs->def[S_DEF_USER].val = sym;
+               cs->flags |= SYMBOL_DEF_USER;
+               prop = sym_get_choice_prop(cs);
+               for (e = prop->expr; e; e = e->left.expr) {
+                       if (e->right.sym->visible != no)
+                               e->right.sym->flags |= SYMBOL_DEF_USER;
+               }
+       }
+
+       sym->def[S_DEF_USER].tri = val;
+       if (oldval != val)
+               sym_clear_all_valid();
+
+       return true;
+}
+
+tristate sym_toggle_tristate_value(struct symbol *sym)
+{
+       tristate oldval, newval;
+
+       oldval = newval = sym_get_tristate_value(sym);
+       do {
+               switch (newval) {
+               case no:
+                       newval = mod;
+                       break;
+               case mod:
+                       newval = yes;
+                       break;
+               case yes:
+                       newval = no;
+                       break;
+               }
+               if (sym_set_tristate_value(sym, newval))
+                       break;
+       } while (oldval != newval);
+       return newval;
+}
+
+bool sym_string_valid(struct symbol *sym, const char *str)
+{
+       signed char ch;
+
+       switch (sym->type) {
+       case S_STRING:
+               return true;
+       case S_INT:
+               ch = *str++;
+               if (ch == '-')
+                       ch = *str++;
+               if (!isdigit(ch))
+                       return false;
+               if (ch == '0' && *str != 0)
+                       return false;
+               while ((ch = *str++)) {
+                       if (!isdigit(ch))
+                               return false;
+               }
+               return true;
+       case S_HEX:
+               if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
+                       str += 2;
+               ch = *str++;
+               do {
+                       if (!isxdigit(ch))
+                               return false;
+               } while ((ch = *str++));
+               return true;
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               switch (str[0]) {
+               case 'y': case 'Y':
+               case 'm': case 'M':
+               case 'n': case 'N':
+                       return true;
+               }
+               return false;
+       default:
+               return false;
+       }
+}
+
+bool sym_string_within_range(struct symbol *sym, const char *str)
+{
+       struct property *prop;
+       int val;
+
+       switch (sym->type) {
+       case S_STRING:
+               return sym_string_valid(sym, str);
+       case S_INT:
+               if (!sym_string_valid(sym, str))
+                       return false;
+               prop = sym_get_range_prop(sym);
+               if (!prop)
+                       return true;
+               val = strtol(str, NULL, 10);
+               return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
+                      val <= sym_get_range_val(prop->expr->right.sym, 10);
+       case S_HEX:
+               if (!sym_string_valid(sym, str))
+                       return false;
+               prop = sym_get_range_prop(sym);
+               if (!prop)
+                       return true;
+               val = strtol(str, NULL, 16);
+               return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
+                      val <= sym_get_range_val(prop->expr->right.sym, 16);
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               switch (str[0]) {
+               case 'y': case 'Y':
+                       return sym_tristate_within_range(sym, yes);
+               case 'm': case 'M':
+                       return sym_tristate_within_range(sym, mod);
+               case 'n': case 'N':
+                       return sym_tristate_within_range(sym, no);
+               }
+               return false;
+       default:
+               return false;
+       }
+}
+
+bool sym_set_string_value(struct symbol *sym, const char *newval)
+{
+       const char *oldval;
+       char *val;
+       int size;
+
+       switch (sym->type) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               switch (newval[0]) {
+               case 'y': case 'Y':
+                       return sym_set_tristate_value(sym, yes);
+               case 'm': case 'M':
+                       return sym_set_tristate_value(sym, mod);
+               case 'n': case 'N':
+                       return sym_set_tristate_value(sym, no);
+               }
+               return false;
+       default:
+               ;
+       }
+
+       if (!sym_string_within_range(sym, newval))
+               return false;
+
+       if (!(sym->flags & SYMBOL_DEF_USER)) {
+               sym->flags |= SYMBOL_DEF_USER;
+               sym_set_changed(sym);
+       }
+
+       oldval = sym->def[S_DEF_USER].val;
+       size = strlen(newval) + 1;
+       if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
+               size += 2;
+               sym->def[S_DEF_USER].val = val = malloc(size);
+               *val++ = '0';
+               *val++ = 'x';
+       } else if (!oldval || strcmp(oldval, newval))
+               sym->def[S_DEF_USER].val = val = malloc(size);
+       else
+               return true;
+
+       strcpy(val, newval);
+       free((void *)oldval);
+       sym_clear_all_valid();
+
+       return true;
+}
+
+const char *sym_get_string_value(struct symbol *sym)
+{
+       tristate val;
+
+       switch (sym->type) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               val = sym_get_tristate_value(sym);
+               switch (val) {
+               case no:
+                       return "n";
+               case mod:
+                       return "m";
+               case yes:
+                       return "y";
+               }
+               break;
+       default:
+               ;
+       }
+       return (const char *)sym->curr.val;
+}
+
+bool sym_is_changable(struct symbol *sym)
+{
+       return sym->visible > sym->rev_dep.tri;
+}
+
+struct symbol *sym_lookup(const char *name, int flags)
+{
+       struct symbol *symbol;
+       const char *ptr;
+       char *new_name;
+       int hash = 0;
+
+       if (name) {
+               if (name[0] && !name[1]) {
+                       switch (name[0]) {
+                       case 'y': return &symbol_yes;
+                       case 'm': return &symbol_mod;
+                       case 'n': return &symbol_no;
+                       }
+               }
+               for (ptr = name; *ptr; ptr++)
+                       hash += *ptr;
+               hash &= 0xff;
+
+               for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+                       if (!strcmp(symbol->name, name) &&
+                           (flags ? symbol->flags & flags
+                                  : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
+                               return symbol;
+               }
+               new_name = strdup(name);
+       } else {
+               new_name = NULL;
+               hash = 256;
+       }
+
+       symbol = malloc(sizeof(*symbol));
+       memset(symbol, 0, sizeof(*symbol));
+       symbol->name = new_name;
+       symbol->type = S_UNKNOWN;
+       symbol->flags |= flags;
+
+       symbol->next = symbol_hash[hash];
+       symbol_hash[hash] = symbol;
+
+       return symbol;
+}
+
+struct symbol *sym_find(const char *name)
+{
+       struct symbol *symbol = NULL;
+       const char *ptr;
+       int hash = 0;
+
+       if (!name)
+               return NULL;
+
+       if (name[0] && !name[1]) {
+               switch (name[0]) {
+               case 'y': return &symbol_yes;
+               case 'm': return &symbol_mod;
+               case 'n': return &symbol_no;
+               }
+       }
+       for (ptr = name; *ptr; ptr++)
+               hash += *ptr;
+       hash &= 0xff;
+
+       for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+               if (!strcmp(symbol->name, name) &&
+                   !(symbol->flags & SYMBOL_CONST))
+                               break;
+       }
+
+       return symbol;
+}
+
+struct symbol **sym_re_search(const char *pattern)
+{
+       struct symbol *sym, **sym_arr = NULL;
+       int i, cnt, size;
+       regex_t re;
+
+       cnt = size = 0;
+       /* Skip if empty */
+       if (strlen(pattern) == 0)
+               return NULL;
+       if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
+               return NULL;
+
+       for_all_symbols(i, sym) {
+               if (sym->flags & SYMBOL_CONST || !sym->name)
+                       continue;
+               if (regexec(&re, sym->name, 0, NULL, 0))
+                       continue;
+               if (cnt + 1 >= size) {
+                       void *tmp = sym_arr;
+                       size += 16;
+                       sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
+                       if (!sym_arr) {
+                               free(tmp);
+                               return NULL;
+                       }
+               }
+               sym_arr[cnt++] = sym;
+       }
+       if (sym_arr)
+               sym_arr[cnt] = NULL;
+       regfree(&re);
+
+       return sym_arr;
+}
+
+
+static struct symbol *sym_check_expr_deps(struct expr *e)
+{
+       struct symbol *sym;
+
+       if (!e)
+               return NULL;
+       switch (e->type) {
+       case E_OR:
+       case E_AND:
+               sym = sym_check_expr_deps(e->left.expr);
+               if (sym)
+                       return sym;
+               return sym_check_expr_deps(e->right.expr);
+       case E_NOT:
+               return sym_check_expr_deps(e->left.expr);
+       case E_EQUAL:
+       case E_UNEQUAL:
+               sym = sym_check_deps(e->left.sym);
+               if (sym)
+                       return sym;
+               return sym_check_deps(e->right.sym);
+       case E_SYMBOL:
+               return sym_check_deps(e->left.sym);
+       default:
+               break;
+       }
+       printf("Oops! How to check %d?\n", e->type);
+       return NULL;
+}
+
+/* return NULL when dependencies are OK */
+static struct symbol *sym_check_sym_deps(struct symbol *sym)
+{
+       struct symbol *sym2;
+       struct property *prop;
+
+       sym2 = sym_check_expr_deps(sym->rev_dep.expr);
+       if (sym2)
+               return sym2;
+
+       for (prop = sym->prop; prop; prop = prop->next) {
+               if (prop->type == P_CHOICE || prop->type == P_SELECT)
+                       continue;
+               sym2 = sym_check_expr_deps(prop->visible.expr);
+               if (sym2)
+                       break;
+               if (prop->type != P_DEFAULT || sym_is_choice(sym))
+                       continue;
+               sym2 = sym_check_expr_deps(prop->expr);
+               if (sym2)
+                       break;
+       }
+
+       return sym2;
+}
+
+static struct symbol *sym_check_choice_deps(struct symbol *choice)
+{
+       struct symbol *sym, *sym2;
+       struct property *prop;
+       struct expr *e;
+
+       prop = sym_get_choice_prop(choice);
+       expr_list_for_each_sym(prop->expr, e, sym)
+               sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+
+       choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+       sym2 = sym_check_sym_deps(choice);
+       choice->flags &= ~SYMBOL_CHECK;
+       if (sym2)
+               goto out;
+
+       expr_list_for_each_sym(prop->expr, e, sym) {
+               sym2 = sym_check_sym_deps(sym);
+               if (sym2) {
+                       fprintf(stderr, " -> %s", sym->name);
+                       break;
+               }
+       }
+out:
+       expr_list_for_each_sym(prop->expr, e, sym)
+               sym->flags &= ~SYMBOL_CHECK;
+
+       if (sym2 && sym_is_choice_value(sym2) &&
+           prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
+               sym2 = choice;
+
+       return sym2;
+}
+
+struct symbol *sym_check_deps(struct symbol *sym)
+{
+       struct symbol *sym2;
+       struct property *prop;
+
+       if (sym->flags & SYMBOL_CHECK) {
+               fprintf(stderr, "%s:%d:error: found recursive dependency: %s",
+                       sym->prop->file->name, sym->prop->lineno,
+                       sym->name ? sym->name : "<choice>");
+               return sym;
+       }
+       if (sym->flags & SYMBOL_CHECKED)
+               return NULL;
+
+       if (sym_is_choice_value(sym)) {
+               /* for choice groups start the check with main choice symbol */
+               prop = sym_get_choice_prop(sym);
+               sym2 = sym_check_deps(prop_get_symbol(prop));
+       } else if (sym_is_choice(sym)) {
+               sym2 = sym_check_choice_deps(sym);
+       } else {
+               sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+               sym2 = sym_check_sym_deps(sym);
+               sym->flags &= ~SYMBOL_CHECK;
+       }
+
+       if (sym2) {
+               fprintf(stderr, " -> %s", sym->name ? sym->name : "<choice>");
+               if (sym2 == sym) {
+                       fprintf(stderr, "\n");
+                       zconfnerrs++;
+                       sym2 = NULL;
+               }
+       }
+
+       return sym2;
+}
+
+struct property *prop_alloc(enum prop_type type, struct symbol *sym)
+{
+       struct property *prop;
+       struct property **propp;
+
+       prop = malloc(sizeof(*prop));
+       memset(prop, 0, sizeof(*prop));
+       prop->type = type;
+       prop->sym = sym;
+       prop->file = current_file;
+       prop->lineno = zconf_lineno();
+
+       /* append property to the prop list of symbol */
+       if (sym) {
+               for (propp = &sym->prop; *propp; propp = &(*propp)->next)
+                       ;
+               *propp = prop;
+       }
+
+       return prop;
+}
+
+struct symbol *prop_get_symbol(struct property *prop)
+{
+       if (prop->expr && (prop->expr->type == E_SYMBOL ||
+                          prop->expr->type == E_LIST))
+               return prop->expr->left.sym;
+       return NULL;
+}
+
+const char *prop_get_type_name(enum prop_type type)
+{
+       switch (type) {
+       case P_PROMPT:
+               return "prompt";
+       case P_ENV:
+               return "env";
+       case P_COMMENT:
+               return "comment";
+       case P_MENU:
+               return "menu";
+       case P_DEFAULT:
+               return "default";
+       case P_CHOICE:
+               return "choice";
+       case P_SELECT:
+               return "select";
+       case P_RANGE:
+               return "range";
+       case P_UNKNOWN:
+               break;
+       }
+       return "unknown";
+}
+
+void prop_add_env(const char *env)
+{
+       struct symbol *sym, *sym2;
+       struct property *prop;
+       char *p;
+
+       sym = current_entry->sym;
+       sym->flags |= SYMBOL_AUTO;
+       for_all_properties(sym, prop, P_ENV) {
+               sym2 = prop_get_symbol(prop);
+               if (strcmp(sym2->name, env))
+                       menu_warn(current_entry, "redefining environment symbol from %s",
+                                 sym2->name);
+               return;
+       }
+
+       prop = prop_alloc(P_ENV, sym);
+       prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST));
+
+       sym_env_list = expr_alloc_one(E_LIST, sym_env_list);
+       sym_env_list->right.sym = sym;
+
+       p = getenv(env);
+       if (p)
+               sym_add_default(sym, p);
+       else
+               menu_warn(current_entry, "environment variable %s undefined", env);
+}
diff --git a/bin/kconfig/util.c b/bin/kconfig/util.c
new file mode 100644 (file)
index 0000000..3cc9f93
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2002-2005 Roman Zippel <zippel@linux-m68k.org>
+ * Copyright (C) 2002-2005 Sam Ravnborg <sam@ravnborg.org>
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <string.h>
+#include "lkc.h"
+
+/* file already present in list? If not add it */
+struct file *file_lookup(const char *name)
+{
+       struct file *file;
+
+       for (file = file_list; file; file = file->next) {
+               if (!strcmp(name, file->name))
+                       return file;
+       }
+
+       file = malloc(sizeof(*file));
+       memset(file, 0, sizeof(*file));
+       file->name = strdup(name);
+       file->next = file_list;
+       file_list = file;
+       return file;
+}
+
+/* write a dependency file as used by kbuild to track dependencies */
+int file_write_dep(const char *name)
+{
+       struct symbol *sym, *env_sym;
+       struct expr *e;
+       struct file *file;
+       FILE *out;
+
+       if (!name)
+               name = ".kconfig.d";
+       out = fopen("..config.tmp", "w");
+       if (!out)
+               return 1;
+       fprintf(out, "deps_config := \\\n");
+       for (file = file_list; file; file = file->next) {
+               if (file->next)
+                       fprintf(out, "\t%s \\\n", file->name);
+               else
+                       fprintf(out, "\t%s\n", file->name);
+       }
+       fprintf(out, "\ninclude/config/auto.conf: \\\n"
+                    "\t$(deps_config)\n\n");
+
+       expr_list_for_each_sym(sym_env_list, e, sym) {
+               struct property *prop;
+               const char *value;
+
+               prop = sym_get_env_prop(sym);
+               env_sym = prop_get_symbol(prop);
+               if (!env_sym)
+                       continue;
+               value = getenv(env_sym->name);
+               if (!value)
+                       value = "";
+               fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value);
+               fprintf(out, "include/config/auto.conf: FORCE\n");
+               fprintf(out, "endif\n");
+       }
+
+       fprintf(out, "\n$(deps_config): ;\n");
+       fclose(out);
+       rename("..config.tmp", name);
+       return 0;
+}
+
+
+/* Allocate initial growable sting */
+struct gstr str_new(void)
+{
+       struct gstr gs;
+       gs.s = malloc(sizeof(char) * 64);
+       gs.len = 64;
+       strcpy(gs.s, "\0");
+       return gs;
+}
+
+/* Allocate and assign growable string */
+struct gstr str_assign(const char *s)
+{
+       struct gstr gs;
+       gs.s = strdup(s);
+       gs.len = strlen(s) + 1;
+       return gs;
+}
+
+/* Free storage for growable string */
+void str_free(struct gstr *gs)
+{
+       if (gs->s)
+               free(gs->s);
+       gs->s = NULL;
+       gs->len = 0;
+}
+
+/* Append to growable string */
+void str_append(struct gstr *gs, const char *s)
+{
+       size_t l;
+       if (s) {
+               l = strlen(gs->s) + strlen(s) + 1;
+               if (l > gs->len) {
+                       gs->s   = realloc(gs->s, l);
+                       gs->len = l;
+               }
+               strcat(gs->s, s);
+       }
+}
+
+/* Append printf formatted string to growable string */
+void str_printf(struct gstr *gs, const char *fmt, ...)
+{
+       va_list ap;
+       char s[10000]; /* big enough... */
+       va_start(ap, fmt);
+       vsnprintf(s, sizeof(s), fmt, ap);
+       str_append(gs, s);
+       va_end(ap);
+}
+
+/* Retrieve value of growable string */
+const char *str_get(struct gstr *gs)
+{
+       return gs->s;
+}
+
diff --git a/bin/kconfig/zconf.gperf b/bin/kconfig/zconf.gperf
new file mode 100644 (file)
index 0000000..25ef5d0
--- /dev/null
@@ -0,0 +1,44 @@
+%language=ANSI-C
+%define hash-function-name kconf_id_hash
+%define lookup-function-name kconf_id_lookup
+%define string-pool-name kconf_id_strings
+%compare-strncmp
+%enum
+%pic
+%struct-type
+
+struct kconf_id;
+
+%%
+mainmenu,      T_MAINMENU,     TF_COMMAND
+menu,          T_MENU,         TF_COMMAND
+endmenu,       T_ENDMENU,      TF_COMMAND
+source,                T_SOURCE,       TF_COMMAND
+choice,                T_CHOICE,       TF_COMMAND
+endchoice,     T_ENDCHOICE,    TF_COMMAND
+comment,       T_COMMENT,      TF_COMMAND
+config,                T_CONFIG,       TF_COMMAND
+menuconfig,    T_MENUCONFIG,   TF_COMMAND
+help,          T_HELP,         TF_COMMAND
+if,            T_IF,           TF_COMMAND|TF_PARAM
+endif,         T_ENDIF,        TF_COMMAND
+depends,       T_DEPENDS,      TF_COMMAND
+optional,      T_OPTIONAL,     TF_COMMAND
+default,       T_DEFAULT,      TF_COMMAND, S_UNKNOWN
+prompt,                T_PROMPT,       TF_COMMAND
+tristate,      T_TYPE,         TF_COMMAND, S_TRISTATE
+def_tristate,  T_DEFAULT,      TF_COMMAND, S_TRISTATE
+bool,          T_TYPE,         TF_COMMAND, S_BOOLEAN
+boolean,       T_TYPE,         TF_COMMAND, S_BOOLEAN
+def_bool,      T_DEFAULT,      TF_COMMAND, S_BOOLEAN
+int,           T_TYPE,         TF_COMMAND, S_INT
+hex,           T_TYPE,         TF_COMMAND, S_HEX
+string,                T_TYPE,         TF_COMMAND, S_STRING
+select,                T_SELECT,       TF_COMMAND
+range,         T_RANGE,        TF_COMMAND
+option,                T_OPTION,       TF_COMMAND
+on,            T_ON,           TF_PARAM
+modules,       T_OPT_MODULES,  TF_OPTION
+defconfig_list,        T_OPT_DEFCONFIG_LIST,TF_OPTION
+env,           T_OPT_ENV,      TF_OPTION
+%%
diff --git a/bin/kconfig/zconf.hash.c_shipped b/bin/kconfig/zconf.hash.c_shipped
new file mode 100644 (file)
index 0000000..5c73d51
--- /dev/null
@@ -0,0 +1,237 @@
+/* ANSI-C code produced by gperf version 3.0.3 */
+/* Command-line: gperf  */
+/* Computed positions: -k'1,3' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+struct kconf_id;
+/* maximum key range = 47, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+kconf_id_hash (register const char *str, register unsigned int len)
+{
+  static unsigned char asso_values[] =
+    {
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 11,  5,
+       0,  0,  5, 49,  5, 20, 49, 49,  5, 20,
+       5,  0, 30, 49,  0, 15,  0, 10,  0, 49,
+      25, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49
+    };
+  register int hval = len;
+
+  switch (hval)
+    {
+      default:
+        hval += asso_values[(unsigned char)str[2]];
+      /*FALLTHROUGH*/
+      case 2:
+      case 1:
+        hval += asso_values[(unsigned char)str[0]];
+        break;
+    }
+  return hval;
+}
+
+struct kconf_id_strings_t
+  {
+    char kconf_id_strings_str2[sizeof("on")];
+    char kconf_id_strings_str3[sizeof("env")];
+    char kconf_id_strings_str5[sizeof("endif")];
+    char kconf_id_strings_str6[sizeof("option")];
+    char kconf_id_strings_str7[sizeof("endmenu")];
+    char kconf_id_strings_str8[sizeof("optional")];
+    char kconf_id_strings_str9[sizeof("endchoice")];
+    char kconf_id_strings_str10[sizeof("range")];
+    char kconf_id_strings_str11[sizeof("choice")];
+    char kconf_id_strings_str12[sizeof("default")];
+    char kconf_id_strings_str13[sizeof("def_bool")];
+    char kconf_id_strings_str14[sizeof("help")];
+    char kconf_id_strings_str15[sizeof("bool")];
+    char kconf_id_strings_str16[sizeof("config")];
+    char kconf_id_strings_str17[sizeof("def_tristate")];
+    char kconf_id_strings_str18[sizeof("boolean")];
+    char kconf_id_strings_str19[sizeof("defconfig_list")];
+    char kconf_id_strings_str21[sizeof("string")];
+    char kconf_id_strings_str22[sizeof("if")];
+    char kconf_id_strings_str23[sizeof("int")];
+    char kconf_id_strings_str26[sizeof("select")];
+    char kconf_id_strings_str27[sizeof("modules")];
+    char kconf_id_strings_str28[sizeof("tristate")];
+    char kconf_id_strings_str29[sizeof("menu")];
+    char kconf_id_strings_str31[sizeof("source")];
+    char kconf_id_strings_str32[sizeof("comment")];
+    char kconf_id_strings_str33[sizeof("hex")];
+    char kconf_id_strings_str35[sizeof("menuconfig")];
+    char kconf_id_strings_str36[sizeof("prompt")];
+    char kconf_id_strings_str37[sizeof("depends")];
+    char kconf_id_strings_str48[sizeof("mainmenu")];
+  };
+static struct kconf_id_strings_t kconf_id_strings_contents =
+  {
+    "on",
+    "env",
+    "endif",
+    "option",
+    "endmenu",
+    "optional",
+    "endchoice",
+    "range",
+    "choice",
+    "default",
+    "def_bool",
+    "help",
+    "bool",
+    "config",
+    "def_tristate",
+    "boolean",
+    "defconfig_list",
+    "string",
+    "if",
+    "int",
+    "select",
+    "modules",
+    "tristate",
+    "menu",
+    "source",
+    "comment",
+    "hex",
+    "menuconfig",
+    "prompt",
+    "depends",
+    "mainmenu"
+  };
+#define kconf_id_strings ((const char *) &kconf_id_strings_contents)
+#ifdef __GNUC__
+__inline
+#ifdef __GNUC_STDC_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
+#endif
+struct kconf_id *
+kconf_id_lookup (register const char *str, register unsigned int len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 31,
+      MIN_WORD_LENGTH = 2,
+      MAX_WORD_LENGTH = 14,
+      MIN_HASH_VALUE = 2,
+      MAX_HASH_VALUE = 48
+    };
+
+  static struct kconf_id wordlist[] =
+    {
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2,            T_ON,           TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3,            T_OPT_ENV,      TF_OPTION},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5,            T_ENDIF,        TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6,            T_OPTION,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7,    T_ENDMENU,      TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8,    T_OPTIONAL,     TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9,    T_ENDCHOICE,    TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10,           T_RANGE,        TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11,           T_CHOICE,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12,   T_DEFAULT,      TF_COMMAND, S_UNKNOWN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13,   T_DEFAULT,      TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14,           T_HELP,         TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str15,           T_TYPE,         TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16,           T_CONFIG,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17,   T_DEFAULT,      TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18,   T_TYPE,         TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str19,   T_OPT_DEFCONFIG_LIST,TF_OPTION},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21,           T_TYPE,         TF_COMMAND, S_STRING},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22,           T_IF,           TF_COMMAND|TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23,           T_TYPE,         TF_COMMAND, S_INT},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26,           T_SELECT,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27,   T_OPT_MODULES,  TF_OPTION},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28,   T_TYPE,         TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29,           T_MENU,         TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31,           T_SOURCE,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32,   T_COMMENT,      TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33,           T_TYPE,         TF_COMMAND, S_HEX},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35,   T_MENUCONFIG,   TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36,           T_PROMPT,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37,   T_DEPENDS,      TF_COMMAND},
+      {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str48,   T_MAINMENU,     TF_COMMAND}
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      register int key = kconf_id_hash (str, len);
+
+      if (key <= MAX_HASH_VALUE && key >= 0)
+        {
+          register int o = wordlist[key].name;
+          if (o >= 0)
+            {
+              register const char *s = o + kconf_id_strings;
+
+              if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
+                return &wordlist[key];
+            }
+        }
+    }
+  return 0;
+}
+
diff --git a/bin/kconfig/zconf.l b/bin/kconfig/zconf.l
new file mode 100644 (file)
index 0000000..4cea5c8
--- /dev/null
@@ -0,0 +1,355 @@
+%option backup nostdinit noyywrap never-interactive full ecs
+%option 8bit backup nodefault perf-report perf-report
+%x COMMAND HELP STRING PARAM
+%{
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define START_STRSIZE  16
+
+static struct {
+       struct file *file;
+       int lineno;
+} current_pos;
+
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+        struct buffer *parent;
+        YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+void new_string(void)
+{
+       text = malloc(START_STRSIZE);
+       text_asize = START_STRSIZE;
+       text_size = 0;
+       *text = 0;
+}
+
+void append_string(const char *str, int size)
+{
+       int new_size = text_size + size + 1;
+       if (new_size > text_asize) {
+               new_size += START_STRSIZE - 1;
+               new_size &= -START_STRSIZE;
+               text = realloc(text, new_size);
+               text_asize = new_size;
+       }
+       memcpy(text + text_size, str, size);
+       text_size += size;
+       text[text_size] = 0;
+}
+
+void alloc_string(const char *str, int size)
+{
+       text = malloc(size + 1);
+       memcpy(text, str, size);
+       text[size] = 0;
+}
+%}
+
+ws     [ \n\t]
+n      [A-Za-z0-9_]
+
+%%
+       int str = 0;
+       int ts, i;
+
+[ \t]*#.*\n    |
+[ \t]*\n       {
+       current_file->lineno++;
+       return T_EOL;
+}
+[ \t]*#.*
+
+
+[ \t]+ {
+       BEGIN(COMMAND);
+}
+
+.      {
+       unput(yytext[0]);
+       BEGIN(COMMAND);
+}
+
+
+<COMMAND>{
+       {n}+    {
+               struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+               BEGIN(PARAM);
+               current_pos.file = current_file;
+               current_pos.lineno = current_file->lineno;
+               if (id && id->flags & TF_COMMAND) {
+                       zconflval.id = id;
+                       return id->token;
+               }
+               alloc_string(yytext, yyleng);
+               zconflval.string = text;
+               return T_WORD;
+       }
+       .
+       \n      {
+               BEGIN(INITIAL);
+               current_file->lineno++;
+               return T_EOL;
+       }
+}
+
+<PARAM>{
+       "&&"    return T_AND;
+       "||"    return T_OR;
+       "("     return T_OPEN_PAREN;
+       ")"     return T_CLOSE_PAREN;
+       "!"     return T_NOT;
+       "="     return T_EQUAL;
+       "!="    return T_UNEQUAL;
+       \"|\'   {
+               str = yytext[0];
+               new_string();
+               BEGIN(STRING);
+       }
+       \n      BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+       ---     /* ignore */
+       ({n}|[-/.])+    {
+               struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+               if (id && id->flags & TF_PARAM) {
+                       zconflval.id = id;
+                       return id->token;
+               }
+               alloc_string(yytext, yyleng);
+               zconflval.string = text;
+               return T_WORD;
+       }
+       #.*     /* comment */
+       \\\n    current_file->lineno++;
+       .
+       <<EOF>> {
+               BEGIN(INITIAL);
+       }
+}
+
+<STRING>{
+       [^'"\\\n]+/\n   {
+               append_string(yytext, yyleng);
+               zconflval.string = text;
+               return T_WORD_QUOTE;
+       }
+       [^'"\\\n]+      {
+               append_string(yytext, yyleng);
+       }
+       \\.?/\n {
+               append_string(yytext + 1, yyleng - 1);
+               zconflval.string = text;
+               return T_WORD_QUOTE;
+       }
+       \\.?    {
+               append_string(yytext + 1, yyleng - 1);
+       }
+       \'|\"   {
+               if (str == yytext[0]) {
+                       BEGIN(PARAM);
+                       zconflval.string = text;
+                       return T_WORD_QUOTE;
+               } else
+                       append_string(yytext, 1);
+       }
+       \n      {
+               printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+               current_file->lineno++;
+               BEGIN(INITIAL);
+               return T_EOL;
+       }
+       <<EOF>> {
+               BEGIN(INITIAL);
+       }
+}
+
+<HELP>{
+       [ \t]+  {
+               ts = 0;
+               for (i = 0; i < yyleng; i++) {
+                       if (yytext[i] == '\t')
+                               ts = (ts & ~7) + 8;
+                       else
+                               ts++;
+               }
+               last_ts = ts;
+               if (first_ts) {
+                       if (ts < first_ts) {
+                               zconf_endhelp();
+                               return T_HELPTEXT;
+                       }
+                       ts -= first_ts;
+                       while (ts > 8) {
+                               append_string("        ", 8);
+                               ts -= 8;
+                       }
+                       append_string("        ", ts);
+               }
+       }
+       [ \t]*\n/[^ \t\n] {
+               current_file->lineno++;
+               zconf_endhelp();
+               return T_HELPTEXT;
+       }
+       [ \t]*\n        {
+               current_file->lineno++;
+               append_string("\n", 1);
+       }
+       [^ \t\n].* {
+               while (yyleng) {
+                       if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
+                               break;
+                       yyleng--;
+               }
+               append_string(yytext, yyleng);
+               if (!first_ts)
+                       first_ts = last_ts;
+       }
+       <<EOF>> {
+               zconf_endhelp();
+               return T_HELPTEXT;
+       }
+}
+
+<<EOF>>        {
+       if (current_file) {
+               zconf_endfile();
+               return T_EOL;
+       }
+       fclose(yyin);
+       yyterminate();
+}
+
+%%
+void zconf_starthelp(void)
+{
+       new_string();
+       last_ts = first_ts = 0;
+       BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+       zconflval.string = text;
+       BEGIN(INITIAL);
+}
+
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+       char *env, fullname[PATH_MAX+1];
+       FILE *f;
+
+       f = fopen(name, "r");
+       if (!f && name != NULL && name[0] != '/') {
+               env = getenv(SRCTREE);
+               if (env) {
+                       sprintf(fullname, "%s/%s", env, name);
+                       f = fopen(fullname, "r");
+               }
+       }
+       return f;
+}
+
+void zconf_initscan(const char *name)
+{
+       yyin = zconf_fopen(name);
+       if (!yyin) {
+               printf("can't find file %s\n", name);
+               exit(1);
+       }
+
+       current_buf = malloc(sizeof(*current_buf));
+       memset(current_buf, 0, sizeof(*current_buf));
+
+       current_file = file_lookup(name);
+       current_file->lineno = 1;
+       current_file->flags = FILE_BUSY;
+}
+
+void zconf_nextfile(const char *name)
+{
+       struct file *file = file_lookup(name);
+       struct buffer *buf = malloc(sizeof(*buf));
+       memset(buf, 0, sizeof(*buf));
+
+       current_buf->state = YY_CURRENT_BUFFER;
+       yyin = zconf_fopen(name);
+       if (!yyin) {
+               printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name);
+               exit(1);
+       }
+       yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+       buf->parent = current_buf;
+       current_buf = buf;
+
+       if (file->flags & FILE_BUSY) {
+               printf("recursive scan (%s)?\n", name);
+               exit(1);
+       }
+       if (file->flags & FILE_SCANNED) {
+               printf("file %s already scanned?\n", name);
+               exit(1);
+       }
+       file->flags |= FILE_BUSY;
+       file->lineno = 1;
+       file->parent = current_file;
+       current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+       struct buffer *parent;
+
+       current_file->flags |= FILE_SCANNED;
+       current_file->flags &= ~FILE_BUSY;
+       current_file = current_file->parent;
+
+       parent = current_buf->parent;
+       if (parent) {
+               fclose(yyin);
+               yy_delete_buffer(YY_CURRENT_BUFFER);
+               yy_switch_to_buffer(parent->state);
+       }
+       free(current_buf);
+       current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+       return current_pos.lineno;
+}
+
+char *zconf_curname(void)
+{
+       return current_pos.file ? current_pos.file->name : "<none>";
+}
diff --git a/bin/kconfig/zconf.tab.c_shipped b/bin/kconfig/zconf.tab.c_shipped
new file mode 100644 (file)
index 0000000..e77ed67
--- /dev/null
@@ -0,0 +1,2490 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* 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 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+/* 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.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names.  */
+#define yyparse zconfparse
+#define yylex   zconflex
+#define yyerror zconferror
+#define yylval  zconflval
+#define yychar  zconfchar
+#define yydebug zconfdebug
+#define yynerrs zconfnerrs
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     T_MAINMENU = 258,
+     T_MENU = 259,
+     T_ENDMENU = 260,
+     T_SOURCE = 261,
+     T_CHOICE = 262,
+     T_ENDCHOICE = 263,
+     T_COMMENT = 264,
+     T_CONFIG = 265,
+     T_MENUCONFIG = 266,
+     T_HELP = 267,
+     T_HELPTEXT = 268,
+     T_IF = 269,
+     T_ENDIF = 270,
+     T_DEPENDS = 271,
+     T_OPTIONAL = 272,
+     T_PROMPT = 273,
+     T_TYPE = 274,
+     T_DEFAULT = 275,
+     T_SELECT = 276,
+     T_RANGE = 277,
+     T_OPTION = 278,
+     T_ON = 279,
+     T_WORD = 280,
+     T_WORD_QUOTE = 281,
+     T_UNEQUAL = 282,
+     T_CLOSE_PAREN = 283,
+     T_OPEN_PAREN = 284,
+     T_EOL = 285,
+     T_OR = 286,
+     T_AND = 287,
+     T_EQUAL = 288,
+     T_NOT = 289
+   };
+#endif
+/* Tokens.  */
+#define T_MAINMENU 258
+#define T_MENU 259
+#define T_ENDMENU 260
+#define T_SOURCE 261
+#define T_CHOICE 262
+#define T_ENDCHOICE 263
+#define T_COMMENT 264
+#define T_CONFIG 265
+#define T_MENUCONFIG 266
+#define T_HELP 267
+#define T_HELPTEXT 268
+#define T_IF 269
+#define T_ENDIF 270
+#define T_DEPENDS 271
+#define T_OPTIONAL 272
+#define T_PROMPT 273
+#define T_TYPE 274
+#define T_DEFAULT 275
+#define T_SELECT 276
+#define T_RANGE 277
+#define T_OPTION 278
+#define T_ON 279
+#define T_WORD 280
+#define T_WORD_QUOTE 281
+#define T_UNEQUAL 282
+#define T_CLOSE_PAREN 283
+#define T_OPEN_PAREN 284
+#define T_EOL 285
+#define T_OR 286
+#define T_AND 287
+#define T_EQUAL 288
+#define T_NOT 289
+
+
+
+
+/* Copy the first part of user declarations.  */
+
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#include "zconf.hash.c"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD         0x0001
+#define DEBUG_PARSE    0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[257];
+
+static struct menu *current_menu, *current_entry;
+
+#define YYDEBUG 0
+#if YYDEBUG
+#define YYERROR_VERBOSE
+#endif
+
+
+/* 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
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+
+{
+       char *string;
+       struct file *file;
+       struct symbol *symbol;
+       struct expr *expr;
+       struct menu *menu;
+       struct kconf_id *id;
+}
+/* Line 187 of yacc.c.  */
+
+       YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 216 of yacc.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 i)
+#else
+static int
+YYID (i)
+    int i;
+#endif
+{
+  return i;
+}
+#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;
+  YYSTYPE yyvs;
+  };
+
+/* 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)                                       \
+    do                                                                 \
+      {                                                                        \
+       YYSIZE_T yynewbytes;                                            \
+       YYCOPY (&yyptr->Stack, Stack, yysize);                          \
+       Stack = &yyptr->Stack;                                          \
+       yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+       yyptr += yynewbytes / sizeof (*yyptr);                          \
+      }                                                                        \
+    while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  3
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   259
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  35
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  46
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  110
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  180
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   289
+
+#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,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint16 yyprhs[] =
+{
+       0,     0,     3,     5,     6,     9,    12,    15,    20,    23,
+      28,    33,    37,    39,    41,    43,    45,    47,    49,    51,
+      53,    55,    57,    59,    61,    63,    67,    70,    74,    77,
+      81,    84,    85,    88,    91,    94,    97,   100,   103,   107,
+     112,   117,   122,   128,   132,   133,   137,   138,   141,   145,
+     148,   150,   154,   155,   158,   161,   164,   167,   170,   175,
+     179,   182,   187,   188,   191,   195,   197,   201,   202,   205,
+     208,   211,   215,   218,   220,   224,   225,   228,   231,   234,
+     238,   242,   245,   248,   251,   252,   255,   258,   261,   266,
+     267,   270,   272,   274,   277,   280,   283,   285,   288,   289,
+     292,   294,   298,   302,   306,   309,   313,   317,   319,   321,
+     322
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      36,     0,    -1,    37,    -1,    -1,    37,    39,    -1,    37,
+      53,    -1,    37,    64,    -1,    37,     3,    74,    76,    -1,
+      37,    75,    -1,    37,    25,     1,    30,    -1,    37,    38,
+       1,    30,    -1,    37,     1,    30,    -1,    16,    -1,    18,
+      -1,    19,    -1,    21,    -1,    17,    -1,    22,    -1,    20,
+      -1,    30,    -1,    59,    -1,    68,    -1,    42,    -1,    44,
+      -1,    66,    -1,    25,     1,    30,    -1,     1,    30,    -1,
+      10,    25,    30,    -1,    41,    45,    -1,    11,    25,    30,
+      -1,    43,    45,    -1,    -1,    45,    46,    -1,    45,    47,
+      -1,    45,    72,    -1,    45,    70,    -1,    45,    40,    -1,
+      45,    30,    -1,    19,    73,    30,    -1,    18,    74,    77,
+      30,    -1,    20,    78,    77,    30,    -1,    21,    25,    77,
+      30,    -1,    22,    79,    79,    77,    30,    -1,    23,    48,
+      30,    -1,    -1,    48,    25,    49,    -1,    -1,    33,    74,
+      -1,     7,    80,    30,    -1,    50,    54,    -1,    75,    -1,
+      51,    56,    52,    -1,    -1,    54,    55,    -1,    54,    72,
+      -1,    54,    70,    -1,    54,    30,    -1,    54,    40,    -1,
+      18,    74,    77,    30,    -1,    19,    73,    30,    -1,    17,
+      30,    -1,    20,    25,    77,    30,    -1,    -1,    56,    39,
+      -1,    14,    78,    76,    -1,    75,    -1,    57,    60,    58,
+      -1,    -1,    60,    39,    -1,    60,    64,    -1,    60,    53,
+      -1,     4,    74,    30,    -1,    61,    71,    -1,    75,    -1,
+      62,    65,    63,    -1,    -1,    65,    39,    -1,    65,    64,
+      -1,    65,    53,    -1,     6,    74,    30,    -1,     9,    74,
+      30,    -1,    67,    71,    -1,    12,    30,    -1,    69,    13,
+      -1,    -1,    71,    72,    -1,    71,    30,    -1,    71,    40,
+      -1,    16,    24,    78,    30,    -1,    -1,    74,    77,    -1,
+      25,    -1,    26,    -1,     5,    30,    -1,     8,    30,    -1,
+      15,    30,    -1,    30,    -1,    76,    30,    -1,    -1,    14,
+      78,    -1,    79,    -1,    79,    33,    79,    -1,    79,    27,
+      79,    -1,    29,    78,    28,    -1,    34,    78,    -1,    78,
+      31,    78,    -1,    78,    32,    78,    -1,    25,    -1,    26,
+      -1,    -1,    25,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,   104,   104,   106,   108,   109,   110,   111,   112,   113,
+     114,   118,   122,   122,   122,   122,   122,   122,   122,   126,
+     127,   128,   129,   130,   131,   135,   136,   142,   150,   156,
+     164,   174,   176,   177,   178,   179,   180,   181,   184,   192,
+     198,   208,   214,   220,   223,   225,   236,   237,   242,   251,
+     256,   264,   267,   269,   270,   271,   272,   273,   276,   282,
+     293,   299,   309,   311,   316,   324,   332,   335,   337,   338,
+     339,   344,   351,   356,   364,   367,   369,   370,   371,   374,
+     382,   389,   396,   402,   409,   411,   412,   413,   416,   424,
+     426,   431,   432,   435,   436,   437,   441,   442,   445,   446,
+     449,   450,   451,   452,   453,   454,   455,   458,   459,   462,
+     463
+};
+#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", "T_MAINMENU", "T_MENU", "T_ENDMENU",
+  "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG",
+  "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS",
+  "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_RANGE",
+  "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL",
+  "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL",
+  "T_NOT", "$accept", "input", "stmt_list", "option_name", "common_stmt",
+  "option_error", "config_entry_start", "config_stmt",
+  "menuconfig_entry_start", "menuconfig_stmt", "config_option_list",
+  "config_option", "symbol_option", "symbol_option_list",
+  "symbol_option_arg", "choice", "choice_entry", "choice_end",
+  "choice_stmt", "choice_option_list", "choice_option", "choice_block",
+  "if_entry", "if_end", "if_stmt", "if_block", "menu", "menu_entry",
+  "menu_end", "menu_stmt", "menu_block", "source_stmt", "comment",
+  "comment_stmt", "help_start", "help", "depends_list", "depends",
+  "prompt_stmt_opt", "prompt", "end", "nl", "if_expr", "expr", "symbol",
+  "word_opt", 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,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287,   288,   289
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    35,    36,    37,    37,    37,    37,    37,    37,    37,
+      37,    37,    38,    38,    38,    38,    38,    38,    38,    39,
+      39,    39,    39,    39,    39,    40,    40,    41,    42,    43,
+      44,    45,    45,    45,    45,    45,    45,    45,    46,    46,
+      46,    46,    46,    47,    48,    48,    49,    49,    50,    51,
+      52,    53,    54,    54,    54,    54,    54,    54,    55,    55,
+      55,    55,    56,    56,    57,    58,    59,    60,    60,    60,
+      60,    61,    62,    63,    64,    65,    65,    65,    65,    66,
+      67,    68,    69,    70,    71,    71,    71,    71,    72,    73,
+      73,    74,    74,    75,    75,    75,    76,    76,    77,    77,
+      78,    78,    78,    78,    78,    78,    78,    79,    79,    80,
+      80
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     1,     0,     2,     2,     2,     4,     2,     4,
+       4,     3,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     3,     2,     3,     2,     3,
+       2,     0,     2,     2,     2,     2,     2,     2,     3,     4,
+       4,     4,     5,     3,     0,     3,     0,     2,     3,     2,
+       1,     3,     0,     2,     2,     2,     2,     2,     4,     3,
+       2,     4,     0,     2,     3,     1,     3,     0,     2,     2,
+       2,     3,     2,     1,     3,     0,     2,     2,     2,     3,
+       3,     2,     2,     2,     0,     2,     2,     2,     4,     0,
+       2,     1,     1,     2,     2,     2,     1,     2,     0,     2,
+       1,     3,     3,     3,     2,     3,     3,     1,     1,     0,
+       1
+};
+
+/* 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[] =
+{
+       3,     0,     0,     1,     0,     0,     0,     0,     0,   109,
+       0,     0,     0,     0,     0,     0,    12,    16,    13,    14,
+      18,    15,    17,     0,    19,     0,     4,    31,    22,    31,
+      23,    52,    62,     5,    67,    20,    84,    75,     6,    24,
+      84,    21,     8,    11,    91,    92,     0,     0,    93,     0,
+     110,     0,    94,     0,     0,     0,   107,   108,     0,     0,
+       0,   100,    95,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,    96,     7,    71,    79,    48,    80,    27,
+      29,     0,   104,     0,     0,    64,     0,     0,     9,    10,
+       0,     0,     0,     0,    89,     0,     0,     0,    44,     0,
+      37,    36,    32,    33,     0,    35,    34,     0,     0,    89,
+       0,    56,    57,    53,    55,    54,    63,    51,    50,    68,
+      70,    66,    69,    65,    86,    87,    85,    76,    78,    74,
+      77,    73,    97,   103,   105,   106,   102,   101,    26,    82,
+       0,    98,     0,    98,    98,    98,     0,     0,     0,    83,
+      60,    98,     0,    98,     0,     0,     0,    38,    90,     0,
+       0,    98,    46,    43,    25,     0,    59,     0,    88,    99,
+      39,    40,    41,     0,     0,    45,    58,    61,    42,    47
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int16 yydefgoto[] =
+{
+      -1,     1,     2,    25,    26,   101,    27,    28,    29,    30,
+      65,   102,   103,   147,   175,    31,    32,   117,    33,    67,
+     113,    68,    34,   121,    35,    69,    36,    37,   129,    38,
+      71,    39,    40,    41,   104,   105,    70,   106,   142,   143,
+      42,    74,   156,    60,    61,    51
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -80
+static const yytype_int16 yypact[] =
+{
+     -80,     2,   132,   -80,   -13,    -1,    -1,    -2,    -1,     9,
+      33,    -1,    27,    40,    -3,    38,   -80,   -80,   -80,   -80,
+     -80,   -80,   -80,    71,   -80,    77,   -80,   -80,   -80,   -80,
+     -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,
+     -80,   -80,   -80,   -80,   -80,   -80,    57,    61,   -80,    63,
+     -80,    76,   -80,    87,   101,   133,   -80,   -80,    -3,    -3,
+     195,    -6,   -80,   136,   149,    39,   104,    65,   150,     5,
+     194,     5,   167,   -80,   176,   -80,   -80,   -80,   -80,   -80,
+     -80,    68,   -80,    -3,    -3,   176,    72,    72,   -80,   -80,
+     177,   187,    78,    -1,    -1,    -3,   196,    72,   -80,   222,
+     -80,   -80,   -80,   -80,   221,   -80,   -80,   205,    -1,    -1,
+     211,   -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,
+     -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,
+     -80,   -80,   -80,   -80,   206,   -80,   -80,   -80,   -80,   -80,
+      -3,   223,   209,   223,   197,   223,    72,     7,   210,   -80,
+     -80,   223,   212,   223,   201,    -3,   213,   -80,   -80,   214,
+     215,   223,   208,   -80,   -80,   216,   -80,   217,   -80,   113,
+     -80,   -80,   -80,   218,    -1,   -80,   -80,   -80,   -80,   -80
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int16 yypgoto[] =
+{
+     -80,   -80,   -80,   -80,   122,   -34,   -80,   -80,   -80,   -80,
+     220,   -80,   -80,   -80,   -80,   -80,   -80,   -80,    59,   -80,
+     -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,   125,
+     -80,   -80,   -80,   -80,   -80,   183,   219,    22,   142,    -5,
+     147,   192,    69,   -54,   -79,   -80
+};
+
+/* 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 -82
+static const yytype_int16 yytable[] =
+{
+      46,    47,     3,    49,    81,    82,    53,   136,   137,     6,
+       7,     8,     9,    10,    11,    12,    13,    43,   146,    14,
+      15,    86,    56,    57,    44,    45,    58,    87,    48,   134,
+     135,    59,   162,   112,    50,    24,   125,   163,   125,   -28,
+      90,   144,   -28,   -28,   -28,   -28,   -28,   -28,   -28,   -28,
+     -28,    91,    54,   -28,   -28,    92,   -28,    93,    94,    95,
+      96,    97,    98,    52,    99,    55,    90,   161,    62,   100,
+     -49,   -49,    63,   -49,   -49,   -49,   -49,    91,    64,   -49,
+     -49,    92,   107,   108,   109,   110,   154,    73,   141,   115,
+      99,    75,   126,    76,   126,   111,   133,    56,    57,    83,
+      84,   169,   140,   151,   -30,    90,    77,   -30,   -30,   -30,
+     -30,   -30,   -30,   -30,   -30,   -30,    91,    78,   -30,   -30,
+      92,   -30,    93,    94,    95,    96,    97,    98,   120,    99,
+     128,    79,    -2,     4,   100,     5,     6,     7,     8,     9,
+      10,    11,    12,    13,    83,    84,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,     7,     8,    23,    10,    11,
+      12,    13,    24,    80,    14,    15,    88,   -81,    90,   179,
+     -81,   -81,   -81,   -81,   -81,   -81,   -81,   -81,   -81,    89,
+      24,   -81,   -81,    92,   -81,   -81,   -81,   -81,   -81,   -81,
+     116,   119,    99,   127,   122,    90,   130,   124,   -72,   -72,
+     -72,   -72,   -72,   -72,   -72,   -72,   132,   138,   -72,   -72,
+      92,   155,   158,   159,   160,   118,   123,   139,   131,    99,
+     165,   145,   167,   148,   124,    73,    83,    84,    83,    84,
+     173,   168,    83,    84,   149,   150,   153,   155,    84,   157,
+     164,   174,   166,   170,   171,   172,   176,   177,   178,    66,
+     114,   152,    85,     0,     0,     0,     0,     0,     0,    72
+};
+
+static const yytype_int16 yycheck[] =
+{
+       5,     6,     0,     8,    58,    59,    11,    86,    87,     4,
+       5,     6,     7,     8,     9,    10,    11,    30,    97,    14,
+      15,    27,    25,    26,    25,    26,    29,    33,    30,    83,
+      84,    34,    25,    67,    25,    30,    70,    30,    72,     0,
+       1,    95,     3,     4,     5,     6,     7,     8,     9,    10,
+      11,    12,    25,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,    23,    30,    25,    25,     1,   146,    30,    30,
+       5,     6,     1,     8,     9,    10,    11,    12,     1,    14,
+      15,    16,    17,    18,    19,    20,   140,    30,    93,    67,
+      25,    30,    70,    30,    72,    30,    28,    25,    26,    31,
+      32,   155,    24,   108,     0,     1,    30,     3,     4,     5,
+       6,     7,     8,     9,    10,    11,    12,    30,    14,    15,
+      16,    17,    18,    19,    20,    21,    22,    23,    69,    25,
+      71,    30,     0,     1,    30,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    31,    32,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,     5,     6,    25,     8,     9,
+      10,    11,    30,    30,    14,    15,    30,     0,     1,   174,
+       3,     4,     5,     6,     7,     8,     9,    10,    11,    30,
+      30,    14,    15,    16,    17,    18,    19,    20,    21,    22,
+      68,    69,    25,    71,    69,     1,    71,    30,     4,     5,
+       6,     7,     8,     9,    10,    11,    30,    30,    14,    15,
+      16,    14,   143,   144,   145,    68,    69,    30,    71,    25,
+     151,    25,   153,     1,    30,    30,    31,    32,    31,    32,
+     161,    30,    31,    32,    13,    30,    25,    14,    32,    30,
+      30,    33,    30,    30,    30,    30,    30,    30,    30,    29,
+      67,   109,    60,    -1,    -1,    -1,    -1,    -1,    -1,    40
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,    36,    37,     0,     1,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    14,    15,    16,    17,    18,    19,
+      20,    21,    22,    25,    30,    38,    39,    41,    42,    43,
+      44,    50,    51,    53,    57,    59,    61,    62,    64,    66,
+      67,    68,    75,    30,    25,    26,    74,    74,    30,    74,
+      25,    80,    30,    74,    25,    25,    25,    26,    29,    34,
+      78,    79,    30,     1,     1,    45,    45,    54,    56,    60,
+      71,    65,    71,    30,    76,    30,    30,    30,    30,    30,
+      30,    78,    78,    31,    32,    76,    27,    33,    30,    30,
+       1,    12,    16,    18,    19,    20,    21,    22,    23,    25,
+      30,    40,    46,    47,    69,    70,    72,    17,    18,    19,
+      20,    30,    40,    55,    70,    72,    39,    52,    75,    39,
+      53,    58,    64,    75,    30,    40,    72,    39,    53,    63,
+      64,    75,    30,    28,    78,    78,    79,    79,    30,    30,
+      24,    74,    73,    74,    78,    25,    79,    48,     1,    13,
+      30,    74,    73,    25,    78,    14,    77,    30,    77,    77,
+      77,    79,    25,    30,    30,    77,    30,    77,    30,    78,
+      30,    30,    30,    77,    33,    49,    30,    30,    30,    74
+};
+
+#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 (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 (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#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); \
+      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)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (!yyvaluep)
+    return;
+# 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)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+  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 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    yytype_int16 *bottom;
+    yytype_int16 *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  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)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+    YYSTYPE *yyvsp;
+    int yyrule;
+#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++)
+    {
+      fprintf (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+                      &(yyvsp[(yyi + 1) - (yynrhs)])
+                                      );
+      fprintf (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)         \
+do {                                   \
+  if (yydebug)                         \
+    yy_reduce_print (yyvsp, Rule); \
+} 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
+
+\f
+
+#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 */
+\f
+
+/*-----------------------------------------------.
+| 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)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  YYUSE (yyvaluep);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+      case 51: /* "choice_entry" */
+
+       {
+       fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+               (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+       if (current_menu == (yyvaluep->menu))
+               menu_end_menu();
+};
+
+       break;
+      case 57: /* "if_entry" */
+
+       {
+       fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+               (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+       if (current_menu == (yyvaluep->menu))
+               menu_end_menu();
+};
+
+       break;
+      case 62: /* "menu_entry" */
+
+       {
+       fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+               (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+       if (current_menu == (yyvaluep->menu))
+               menu_end_menu();
+};
+
+       break;
+
+      default:
+       break;
+    }
+}
+\f
+
+/* 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);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol.  */
+int yychar;
+
+/* The semantic value of the look-ahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#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)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+  
+  int yystate;
+  int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Look-ahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack.  */
+  yytype_int16 yyssa[YYINITDEPTH];
+  yytype_int16 *yyss = yyssa;
+  yytype_int16 *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  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);
+       YYSTACK_RELOCATE (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));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     look-ahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to look-ahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a look-ahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead 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;
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token unless it is eof.  */
+  if (yychar != YYEOF)
+    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 8:
+
+    { zconf_error("unexpected end statement"); ;}
+    break;
+
+  case 9:
+
+    { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); ;}
+    break;
+
+  case 10:
+
+    {
+       zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[(2) - (4)].id)->name);
+;}
+    break;
+
+  case 11:
+
+    { zconf_error("invalid statement"); ;}
+    break;
+
+  case 25:
+
+    { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); ;}
+    break;
+
+  case 26:
+
+    { zconf_error("invalid option"); ;}
+    break;
+
+  case 27:
+
+    {
+       struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0);
+       sym->flags |= SYMBOL_OPTIONAL;
+       menu_add_entry(sym);
+       printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+;}
+    break;
+
+  case 28:
+
+    {
+       menu_end_entry();
+       printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 29:
+
+    {
+       struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0);
+       sym->flags |= SYMBOL_OPTIONAL;
+       menu_add_entry(sym);
+       printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+;}
+    break;
+
+  case 30:
+
+    {
+       if (current_entry->prompt)
+               current_entry->prompt->type = P_MENU;
+       else
+               zconfprint("warning: menuconfig statement without prompt");
+       menu_end_entry();
+       printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 38:
+
+    {
+       menu_set_type((yyvsp[(1) - (3)].id)->stype);
+       printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+               zconf_curname(), zconf_lineno(),
+               (yyvsp[(1) - (3)].id)->stype);
+;}
+    break;
+
+  case 39:
+
+    {
+       menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
+       printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 40:
+
+    {
+       menu_add_expr(P_DEFAULT, (yyvsp[(2) - (4)].expr), (yyvsp[(3) - (4)].expr));
+       if ((yyvsp[(1) - (4)].id)->stype != S_UNKNOWN)
+               menu_set_type((yyvsp[(1) - (4)].id)->stype);
+       printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+               zconf_curname(), zconf_lineno(),
+               (yyvsp[(1) - (4)].id)->stype);
+;}
+    break;
+
+  case 41:
+
+    {
+       menu_add_symbol(P_SELECT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr));
+       printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 42:
+
+    {
+       menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr));
+       printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 45:
+
+    {
+       struct kconf_id *id = kconf_id_lookup((yyvsp[(2) - (3)].string), strlen((yyvsp[(2) - (3)].string)));
+       if (id && id->flags & TF_OPTION)
+               menu_add_option(id->token, (yyvsp[(3) - (3)].string));
+       else
+               zconfprint("warning: ignoring unknown option %s", (yyvsp[(2) - (3)].string));
+       free((yyvsp[(2) - (3)].string));
+;}
+    break;
+
+  case 46:
+
+    { (yyval.string) = NULL; ;}
+    break;
+
+  case 47:
+
+    { (yyval.string) = (yyvsp[(2) - (2)].string); ;}
+    break;
+
+  case 48:
+
+    {
+       struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), SYMBOL_CHOICE);
+       sym->flags |= SYMBOL_AUTO;
+       menu_add_entry(sym);
+       menu_add_expr(P_CHOICE, NULL, NULL);
+       printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 49:
+
+    {
+       (yyval.menu) = menu_add_menu();
+;}
+    break;
+
+  case 50:
+
+    {
+       if (zconf_endtoken((yyvsp[(1) - (1)].id), T_CHOICE, T_ENDCHOICE)) {
+               menu_end_menu();
+               printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+       }
+;}
+    break;
+
+  case 58:
+
+    {
+       menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
+       printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 59:
+
+    {
+       if ((yyvsp[(1) - (3)].id)->stype == S_BOOLEAN || (yyvsp[(1) - (3)].id)->stype == S_TRISTATE) {
+               menu_set_type((yyvsp[(1) - (3)].id)->stype);
+               printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+                       zconf_curname(), zconf_lineno(),
+                       (yyvsp[(1) - (3)].id)->stype);
+       } else
+               YYERROR;
+;}
+    break;
+
+  case 60:
+
+    {
+       current_entry->sym->flags |= SYMBOL_OPTIONAL;
+       printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 61:
+
+    {
+       if ((yyvsp[(1) - (4)].id)->stype == S_UNKNOWN) {
+               menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr));
+               printd(DEBUG_PARSE, "%s:%d:default\n",
+                       zconf_curname(), zconf_lineno());
+       } else
+               YYERROR;
+;}
+    break;
+
+  case 64:
+
+    {
+       printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+       menu_add_entry(NULL);
+       menu_add_dep((yyvsp[(2) - (3)].expr));
+       (yyval.menu) = menu_add_menu();
+;}
+    break;
+
+  case 65:
+
+    {
+       if (zconf_endtoken((yyvsp[(1) - (1)].id), T_IF, T_ENDIF)) {
+               menu_end_menu();
+               printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+       }
+;}
+    break;
+
+  case 71:
+
+    {
+       menu_add_entry(NULL);
+       menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL);
+       printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 72:
+
+    {
+       (yyval.menu) = menu_add_menu();
+;}
+    break;
+
+  case 73:
+
+    {
+       if (zconf_endtoken((yyvsp[(1) - (1)].id), T_MENU, T_ENDMENU)) {
+               menu_end_menu();
+               printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+       }
+;}
+    break;
+
+  case 79:
+
+    {
+       printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+       zconf_nextfile((yyvsp[(2) - (3)].string));
+;}
+    break;
+
+  case 80:
+
+    {
+       menu_add_entry(NULL);
+       menu_add_prompt(P_COMMENT, (yyvsp[(2) - (3)].string), NULL);
+       printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 81:
+
+    {
+       menu_end_entry();
+;}
+    break;
+
+  case 82:
+
+    {
+       printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+       zconf_starthelp();
+;}
+    break;
+
+  case 83:
+
+    {
+       current_entry->help = (yyvsp[(2) - (2)].string);
+;}
+    break;
+
+  case 88:
+
+    {
+       menu_add_dep((yyvsp[(3) - (4)].expr));
+       printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 90:
+
+    {
+       menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr));
+;}
+    break;
+
+  case 93:
+
+    { (yyval.id) = (yyvsp[(1) - (2)].id); ;}
+    break;
+
+  case 94:
+
+    { (yyval.id) = (yyvsp[(1) - (2)].id); ;}
+    break;
+
+  case 95:
+
+    { (yyval.id) = (yyvsp[(1) - (2)].id); ;}
+    break;
+
+  case 98:
+
+    { (yyval.expr) = NULL; ;}
+    break;
+
+  case 99:
+
+    { (yyval.expr) = (yyvsp[(2) - (2)].expr); ;}
+    break;
+
+  case 100:
+
+    { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); ;}
+    break;
+
+  case 101:
+
+    { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
+    break;
+
+  case 102:
+
+    { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
+    break;
+
+  case 103:
+
+    { (yyval.expr) = (yyvsp[(2) - (3)].expr); ;}
+    break;
+
+  case 104:
+
+    { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); ;}
+    break;
+
+  case 105:
+
+    { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
+    break;
+
+  case 106:
+
+    { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
+    break;
+
+  case 107:
+
+    { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); ;}
+    break;
+
+  case 108:
+
+    { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); ;}
+    break;
+
+  case 109:
+
+    { (yyval.string) = NULL; ;}
+    break;
+
+
+/* Line 1267 of yacc.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 (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 (yymsg);
+         }
+       else
+         {
+           yyerror (YY_("syntax error"));
+           if (yysize != 0)
+             goto yyexhaustedlab;
+         }
+      }
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse look-ahead 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);
+         yychar = YYEMPTY;
+       }
+    }
+
+  /* Else will try to reuse look-ahead 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);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  *++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;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEOF && yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+                yytoken, &yylval);
+  /* 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);
+      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);
+}
+
+
+
+
+
+void conf_parse(const char *name)
+{
+       struct symbol *sym;
+       int i;
+
+       zconf_initscan(name);
+
+       sym_init();
+       menu_init();
+       modules_sym = sym_lookup(NULL, 0);
+       modules_sym->type = S_BOOLEAN;
+       modules_sym->flags |= SYMBOL_AUTO;
+       rootmenu.prompt = menu_add_prompt(P_MENU, "firmly.0cpm Configuration", NULL);
+
+#if YYDEBUG
+       if (getenv("ZCONF_DEBUG"))
+               zconfdebug = 1;
+#endif
+       zconfparse();
+       if (zconfnerrs)
+               exit(1);
+       if (!modules_sym->prop) {
+               struct property *prop;
+
+               prop = prop_alloc(P_DEFAULT, modules_sym);
+               prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
+       }
+       menu_finalize(&rootmenu);
+       for_all_symbols(i, sym) {
+               if (sym_check_deps(sym))
+                       zconfnerrs++;
+        }
+       if (zconfnerrs)
+               exit(1);
+       sym_set_change_count(1);
+}
+
+const char *zconf_tokenname(int token)
+{
+       switch (token) {
+       case T_MENU:            return "menu";
+       case T_ENDMENU:         return "endmenu";
+       case T_CHOICE:          return "choice";
+       case T_ENDCHOICE:       return "endchoice";
+       case T_IF:              return "if";
+       case T_ENDIF:           return "endif";
+       case T_DEPENDS:         return "depends";
+       }
+       return "<token>";
+}
+
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
+{
+       if (id->token != endtoken) {
+               zconf_error("unexpected '%s' within %s block",
+                       kconf_id_strings + id->name, zconf_tokenname(starttoken));
+               zconfnerrs++;
+               return false;
+       }
+       if (current_menu->file != current_file) {
+               zconf_error("'%s' in different file than '%s'",
+                       kconf_id_strings + id->name, zconf_tokenname(starttoken));
+               fprintf(stderr, "%s:%d: location of the '%s'\n",
+                       current_menu->file->name, current_menu->lineno,
+                       zconf_tokenname(starttoken));
+               zconfnerrs++;
+               return false;
+       }
+       return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+       va_list ap;
+
+       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+       va_start(ap, err);
+       vfprintf(stderr, err, ap);
+       va_end(ap);
+       fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+       va_list ap;
+
+       zconfnerrs++;
+       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+       va_start(ap, err);
+       vfprintf(stderr, err, ap);
+       va_end(ap);
+       fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+#if YYDEBUG
+       fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
+}
+
+void print_quoted_string(FILE *out, const char *str)
+{
+       const char *p;
+       int len;
+
+       putc('"', out);
+       while ((p = strchr(str, '"'))) {
+               len = p - str;
+               if (len)
+                       fprintf(out, "%.*s", len, str);
+               fputs("\\\"", out);
+               str = p + 1;
+       }
+       fputs(str, out);
+       putc('"', out);
+}
+
+void print_symbol(FILE *out, struct menu *menu)
+{
+       struct symbol *sym = menu->sym;
+       struct property *prop;
+
+       if (sym_is_choice(sym))
+               fprintf(out, "choice\n");
+       else
+               fprintf(out, "config %s\n", sym->name);
+       switch (sym->type) {
+       case S_BOOLEAN:
+               fputs("  boolean\n", out);
+               break;
+       case S_TRISTATE:
+               fputs("  tristate\n", out);
+               break;
+       case S_STRING:
+               fputs("  string\n", out);
+               break;
+       case S_INT:
+               fputs("  integer\n", out);
+               break;
+       case S_HEX:
+               fputs("  hex\n", out);
+               break;
+       default:
+               fputs("  ???\n", out);
+               break;
+       }
+       for (prop = sym->prop; prop; prop = prop->next) {
+               if (prop->menu != menu)
+                       continue;
+               switch (prop->type) {
+               case P_PROMPT:
+                       fputs("  prompt ", out);
+                       print_quoted_string(out, prop->text);
+                       if (!expr_is_yes(prop->visible.expr)) {
+                               fputs(" if ", out);
+                               expr_fprint(prop->visible.expr, out);
+                       }
+                       fputc('\n', out);
+                       break;
+               case P_DEFAULT:
+                       fputs( "  default ", out);
+                       expr_fprint(prop->expr, out);
+                       if (!expr_is_yes(prop->visible.expr)) {
+                               fputs(" if ", out);
+                               expr_fprint(prop->visible.expr, out);
+                       }
+                       fputc('\n', out);
+                       break;
+               case P_CHOICE:
+                       fputs("  #choice value\n", out);
+                       break;
+               default:
+                       fprintf(out, "  unknown prop %d!\n", prop->type);
+                       break;
+               }
+       }
+       if (menu->help) {
+               int len = strlen(menu->help);
+               while (menu->help[--len] == '\n')
+                       menu->help[len] = 0;
+               fprintf(out, "  help\n%s\n", menu->help);
+       }
+       fputc('\n', out);
+}
+
+void zconfdump(FILE *out)
+{
+       struct property *prop;
+       struct symbol *sym;
+       struct menu *menu;
+
+       menu = rootmenu.list;
+       while (menu) {
+               if ((sym = menu->sym))
+                       print_symbol(out, menu);
+               else if ((prop = menu->prompt)) {
+                       switch (prop->type) {
+                       case P_COMMENT:
+                               fputs("\ncomment ", out);
+                               print_quoted_string(out, prop->text);
+                               fputs("\n", out);
+                               break;
+                       case P_MENU:
+                               fputs("\nmenu ", out);
+                               print_quoted_string(out, prop->text);
+                               fputs("\n", out);
+                               break;
+                       default:
+                               ;
+                       }
+                       if (!expr_is_yes(prop->visible.expr)) {
+                               fputs("  depends ", out);
+                               expr_fprint(prop->visible.expr, out);
+                               fputc('\n', out);
+                       }
+                       fputs("\n", out);
+               }
+
+               if (menu->list)
+                       menu = menu->list;
+               else if (menu->next)
+                       menu = menu->next;
+               else while ((menu = menu->parent)) {
+                       if (menu->prompt && menu->prompt->type == P_MENU)
+                               fputs("\nendmenu\n", out);
+                       if (menu->next) {
+                               menu = menu->next;
+                               break;
+                       }
+               }
+       }
+}
+
+#include "lex.zconf.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
+
diff --git a/bin/kconfig/zconf.y b/bin/kconfig/zconf.y
new file mode 100644 (file)
index 0000000..39d0335
--- /dev/null
@@ -0,0 +1,706 @@
+%{
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#include "zconf.hash.c"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD         0x0001
+#define DEBUG_PARSE    0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[257];
+
+static struct menu *current_menu, *current_entry;
+
+#define YYDEBUG 0
+#if YYDEBUG
+#define YYERROR_VERBOSE
+#endif
+%}
+%expect 26
+
+%union
+{
+       char *string;
+       struct file *file;
+       struct symbol *symbol;
+       struct expr *expr;
+       struct menu *menu;
+       struct kconf_id *id;
+}
+
+%token <id>T_MAINMENU
+%token <id>T_MENU
+%token <id>T_ENDMENU
+%token <id>T_SOURCE
+%token <id>T_CHOICE
+%token <id>T_ENDCHOICE
+%token <id>T_COMMENT
+%token <id>T_CONFIG
+%token <id>T_MENUCONFIG
+%token <id>T_HELP
+%token <string> T_HELPTEXT
+%token <id>T_IF
+%token <id>T_ENDIF
+%token <id>T_DEPENDS
+%token <id>T_OPTIONAL
+%token <id>T_PROMPT
+%token <id>T_TYPE
+%token <id>T_DEFAULT
+%token <id>T_SELECT
+%token <id>T_RANGE
+%token <id>T_OPTION
+%token <id>T_ON
+%token <string> T_WORD
+%token <string> T_WORD_QUOTE
+%token T_UNEQUAL
+%token T_CLOSE_PAREN
+%token T_OPEN_PAREN
+%token T_EOL
+
+%left T_OR
+%left T_AND
+%left T_EQUAL T_UNEQUAL
+%nonassoc T_NOT
+
+%type <string> prompt
+%type <symbol> symbol
+%type <expr> expr
+%type <expr> if_expr
+%type <id> end
+%type <id> option_name
+%type <menu> if_entry menu_entry choice_entry
+%type <string> symbol_option_arg word_opt
+
+%destructor {
+       fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+               $$->file->name, $$->lineno);
+       if (current_menu == $$)
+               menu_end_menu();
+} if_entry menu_entry choice_entry
+
+%%
+input: stmt_list;
+
+stmt_list:
+         /* empty */
+       | stmt_list common_stmt
+       | stmt_list choice_stmt
+       | stmt_list menu_stmt
+       | stmt_list T_MAINMENU prompt nl
+       | stmt_list end                 { zconf_error("unexpected end statement"); }
+       | stmt_list T_WORD error T_EOL  { zconf_error("unknown statement \"%s\"", $2); }
+       | stmt_list option_name error T_EOL
+{
+       zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name);
+}
+       | stmt_list error T_EOL         { zconf_error("invalid statement"); }
+;
+
+option_name:
+       T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT
+;
+
+common_stmt:
+         T_EOL
+       | if_stmt
+       | comment_stmt
+       | config_stmt
+       | menuconfig_stmt
+       | source_stmt
+;
+
+option_error:
+         T_WORD error T_EOL            { zconf_error("unknown option \"%s\"", $1); }
+       | error T_EOL                   { zconf_error("invalid option"); }
+;
+
+
+/* config/menuconfig entry */
+
+config_entry_start: T_CONFIG T_WORD T_EOL
+{
+       struct symbol *sym = sym_lookup($2, 0);
+       sym->flags |= SYMBOL_OPTIONAL;
+       menu_add_entry(sym);
+       printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+config_stmt: config_entry_start config_option_list
+{
+       menu_end_entry();
+       printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+};
+
+menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL
+{
+       struct symbol *sym = sym_lookup($2, 0);
+       sym->flags |= SYMBOL_OPTIONAL;
+       menu_add_entry(sym);
+       printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+menuconfig_stmt: menuconfig_entry_start config_option_list
+{
+       if (current_entry->prompt)
+               current_entry->prompt->type = P_MENU;
+       else
+               zconfprint("warning: menuconfig statement without prompt");
+       menu_end_entry();
+       printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+};
+
+config_option_list:
+         /* empty */
+       | config_option_list config_option
+       | config_option_list symbol_option
+       | config_option_list depends
+       | config_option_list help
+       | config_option_list option_error
+       | config_option_list T_EOL
+;
+
+config_option: T_TYPE prompt_stmt_opt T_EOL
+{
+       menu_set_type($1->stype);
+       printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+               zconf_curname(), zconf_lineno(),
+               $1->stype);
+};
+
+config_option: T_PROMPT prompt if_expr T_EOL
+{
+       menu_add_prompt(P_PROMPT, $2, $3);
+       printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_DEFAULT expr if_expr T_EOL
+{
+       menu_add_expr(P_DEFAULT, $2, $3);
+       if ($1->stype != S_UNKNOWN)
+               menu_set_type($1->stype);
+       printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+               zconf_curname(), zconf_lineno(),
+               $1->stype);
+};
+
+config_option: T_SELECT T_WORD if_expr T_EOL
+{
+       menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3);
+       printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_RANGE symbol symbol if_expr T_EOL
+{
+       menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
+       printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+};
+
+symbol_option: T_OPTION symbol_option_list T_EOL
+;
+
+symbol_option_list:
+         /* empty */
+       | symbol_option_list T_WORD symbol_option_arg
+{
+       struct kconf_id *id = kconf_id_lookup($2, strlen($2));
+       if (id && id->flags & TF_OPTION)
+               menu_add_option(id->token, $3);
+       else
+               zconfprint("warning: ignoring unknown option %s", $2);
+       free($2);
+};
+
+symbol_option_arg:
+         /* empty */           { $$ = NULL; }
+       | T_EQUAL prompt        { $$ = $2; }
+;
+
+/* choice entry */
+
+choice: T_CHOICE word_opt T_EOL
+{
+       struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE);
+       sym->flags |= SYMBOL_AUTO;
+       menu_add_entry(sym);
+       menu_add_expr(P_CHOICE, NULL, NULL);
+       printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+};
+
+choice_entry: choice choice_option_list
+{
+       $$ = menu_add_menu();
+};
+
+choice_end: end
+{
+       if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) {
+               menu_end_menu();
+               printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+       }
+};
+
+choice_stmt: choice_entry choice_block choice_end
+;
+
+choice_option_list:
+         /* empty */
+       | choice_option_list choice_option
+       | choice_option_list depends
+       | choice_option_list help
+       | choice_option_list T_EOL
+       | choice_option_list option_error
+;
+
+choice_option: T_PROMPT prompt if_expr T_EOL
+{
+       menu_add_prompt(P_PROMPT, $2, $3);
+       printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_TYPE prompt_stmt_opt T_EOL
+{
+       if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) {
+               menu_set_type($1->stype);
+               printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+                       zconf_curname(), zconf_lineno(),
+                       $1->stype);
+       } else
+               YYERROR;
+};
+
+choice_option: T_OPTIONAL T_EOL
+{
+       current_entry->sym->flags |= SYMBOL_OPTIONAL;
+       printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_DEFAULT T_WORD if_expr T_EOL
+{
+       if ($1->stype == S_UNKNOWN) {
+               menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
+               printd(DEBUG_PARSE, "%s:%d:default\n",
+                       zconf_curname(), zconf_lineno());
+       } else
+               YYERROR;
+};
+
+choice_block:
+         /* empty */
+       | choice_block common_stmt
+;
+
+/* if entry */
+
+if_entry: T_IF expr nl
+{
+       printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+       menu_add_entry(NULL);
+       menu_add_dep($2);
+       $$ = menu_add_menu();
+};
+
+if_end: end
+{
+       if (zconf_endtoken($1, T_IF, T_ENDIF)) {
+               menu_end_menu();
+               printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+       }
+};
+
+if_stmt: if_entry if_block if_end
+;
+
+if_block:
+         /* empty */
+       | if_block common_stmt
+       | if_block menu_stmt
+       | if_block choice_stmt
+;
+
+/* menu entry */
+
+menu: T_MENU prompt T_EOL
+{
+       menu_add_entry(NULL);
+       menu_add_prompt(P_MENU, $2, NULL);
+       printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+};
+
+menu_entry: menu depends_list
+{
+       $$ = menu_add_menu();
+};
+
+menu_end: end
+{
+       if (zconf_endtoken($1, T_MENU, T_ENDMENU)) {
+               menu_end_menu();
+               printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+       }
+};
+
+menu_stmt: menu_entry menu_block menu_end
+;
+
+menu_block:
+         /* empty */
+       | menu_block common_stmt
+       | menu_block menu_stmt
+       | menu_block choice_stmt
+;
+
+source_stmt: T_SOURCE prompt T_EOL
+{
+       printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
+       zconf_nextfile($2);
+};
+
+/* comment entry */
+
+comment: T_COMMENT prompt T_EOL
+{
+       menu_add_entry(NULL);
+       menu_add_prompt(P_COMMENT, $2, NULL);
+       printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+};
+
+comment_stmt: comment depends_list
+{
+       menu_end_entry();
+};
+
+/* help option */
+
+help_start: T_HELP T_EOL
+{
+       printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+       zconf_starthelp();
+};
+
+help: help_start T_HELPTEXT
+{
+       current_entry->help = $2;
+};
+
+/* depends option */
+
+depends_list:
+         /* empty */
+       | depends_list depends
+       | depends_list T_EOL
+       | depends_list option_error
+;
+
+depends: T_DEPENDS T_ON expr T_EOL
+{
+       menu_add_dep($3);
+       printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+};
+
+/* prompt statement */
+
+prompt_stmt_opt:
+         /* empty */
+       | prompt if_expr
+{
+       menu_add_prompt(P_PROMPT, $1, $2);
+};
+
+prompt:          T_WORD
+       | T_WORD_QUOTE
+;
+
+end:     T_ENDMENU T_EOL       { $$ = $1; }
+       | T_ENDCHOICE T_EOL     { $$ = $1; }
+       | T_ENDIF T_EOL         { $$ = $1; }
+;
+
+nl:
+         T_EOL
+       | nl T_EOL
+;
+
+if_expr:  /* empty */                  { $$ = NULL; }
+       | T_IF expr                     { $$ = $2; }
+;
+
+expr:    symbol                                { $$ = expr_alloc_symbol($1); }
+       | symbol T_EQUAL symbol                 { $$ = expr_alloc_comp(E_EQUAL, $1, $3); }
+       | symbol T_UNEQUAL symbol               { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); }
+       | T_OPEN_PAREN expr T_CLOSE_PAREN       { $$ = $2; }
+       | T_NOT expr                            { $$ = expr_alloc_one(E_NOT, $2); }
+       | expr T_OR expr                        { $$ = expr_alloc_two(E_OR, $1, $3); }
+       | expr T_AND expr                       { $$ = expr_alloc_two(E_AND, $1, $3); }
+;
+
+symbol:          T_WORD        { $$ = sym_lookup($1, 0); free($1); }
+       | T_WORD_QUOTE  { $$ = sym_lookup($1, SYMBOL_CONST); free($1); }
+;
+
+word_opt: /* empty */                  { $$ = NULL; }
+       | T_WORD
+
+%%
+
+void conf_parse(const char *name)
+{
+       struct symbol *sym;
+       int i;
+
+       zconf_initscan(name);
+
+       sym_init();
+       menu_init();
+       modules_sym = sym_lookup(NULL, 0);
+       modules_sym->type = S_BOOLEAN;
+       modules_sym->flags |= SYMBOL_AUTO;
+       rootmenu.prompt = menu_add_prompt(P_MENU, "firmly.0cpm Configuration", NULL);
+
+#if YYDEBUG
+       if (getenv("ZCONF_DEBUG"))
+               zconfdebug = 1;
+#endif
+       zconfparse();
+       if (zconfnerrs)
+               exit(1);
+       if (!modules_sym->prop) {
+               struct property *prop;
+
+               prop = prop_alloc(P_DEFAULT, modules_sym);
+               prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
+       }
+       menu_finalize(&rootmenu);
+       for_all_symbols(i, sym) {
+               if (sym_check_deps(sym))
+                       zconfnerrs++;
+        }
+       if (zconfnerrs)
+               exit(1);
+       sym_set_change_count(1);
+}
+
+const char *zconf_tokenname(int token)
+{
+       switch (token) {
+       case T_MENU:            return "menu";
+       case T_ENDMENU:         return "endmenu";
+       case T_CHOICE:          return "choice";
+       case T_ENDCHOICE:       return "endchoice";
+       case T_IF:              return "if";
+       case T_ENDIF:           return "endif";
+       case T_DEPENDS:         return "depends";
+       }
+       return "<token>";
+}
+
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
+{
+       if (id->token != endtoken) {
+               zconf_error("unexpected '%s' within %s block",
+                       kconf_id_strings + id->name, zconf_tokenname(starttoken));
+               zconfnerrs++;
+               return false;
+       }
+       if (current_menu->file != current_file) {
+               zconf_error("'%s' in different file than '%s'",
+                       kconf_id_strings + id->name, zconf_tokenname(starttoken));
+               fprintf(stderr, "%s:%d: location of the '%s'\n",
+                       current_menu->file->name, current_menu->lineno,
+                       zconf_tokenname(starttoken));
+               zconfnerrs++;
+               return false;
+       }
+       return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+       va_list ap;
+
+       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+       va_start(ap, err);
+       vfprintf(stderr, err, ap);
+       va_end(ap);
+       fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+       va_list ap;
+
+       zconfnerrs++;
+       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+       va_start(ap, err);
+       vfprintf(stderr, err, ap);
+       va_end(ap);
+       fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+#if YYDEBUG
+       fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
+}
+
+void print_quoted_string(FILE *out, const char *str)
+{
+       const char *p;
+       int len;
+
+       putc('"', out);
+       while ((p = strchr(str, '"'))) {
+               len = p - str;
+               if (len)
+                       fprintf(out, "%.*s", len, str);
+               fputs("\\\"", out);
+               str = p + 1;
+       }
+       fputs(str, out);
+       putc('"', out);
+}
+
+void print_symbol(FILE *out, struct menu *menu)
+{
+       struct symbol *sym = menu->sym;
+       struct property *prop;
+
+       if (sym_is_choice(sym))
+               fprintf(out, "choice\n");
+       else
+               fprintf(out, "config %s\n", sym->name);
+       switch (sym->type) {
+       case S_BOOLEAN:
+               fputs("  boolean\n", out);
+               break;
+       case S_TRISTATE:
+               fputs("  tristate\n", out);
+               break;
+       case S_STRING:
+               fputs("  string\n", out);
+               break;
+       case S_INT:
+               fputs("  integer\n", out);
+               break;
+       case S_HEX:
+               fputs("  hex\n", out);
+               break;
+       default:
+               fputs("  ???\n", out);
+               break;
+       }
+       for (prop = sym->prop; prop; prop = prop->next) {
+               if (prop->menu != menu)
+                       continue;
+               switch (prop->type) {
+               case P_PROMPT:
+                       fputs("  prompt ", out);
+                       print_quoted_string(out, prop->text);
+                       if (!expr_is_yes(prop->visible.expr)) {
+                               fputs(" if ", out);
+                               expr_fprint(prop->visible.expr, out);
+                       }
+                       fputc('\n', out);
+                       break;
+               case P_DEFAULT:
+                       fputs( "  default ", out);
+                       expr_fprint(prop->expr, out);
+                       if (!expr_is_yes(prop->visible.expr)) {
+                               fputs(" if ", out);
+                               expr_fprint(prop->visible.expr, out);
+                       }
+                       fputc('\n', out);
+                       break;
+               case P_CHOICE:
+                       fputs("  #choice value\n", out);
+                       break;
+               default:
+                       fprintf(out, "  unknown prop %d!\n", prop->type);
+                       break;
+               }
+       }
+       if (menu->help) {
+               int len = strlen(menu->help);
+               while (menu->help[--len] == '\n')
+                       menu->help[len] = 0;
+               fprintf(out, "  help\n%s\n", menu->help);
+       }
+       fputc('\n', out);
+}
+
+void zconfdump(FILE *out)
+{
+       struct property *prop;
+       struct symbol *sym;
+       struct menu *menu;
+
+       menu = rootmenu.list;
+       while (menu) {
+               if ((sym = menu->sym))
+                       print_symbol(out, menu);
+               else if ((prop = menu->prompt)) {
+                       switch (prop->type) {
+                       case P_COMMENT:
+                               fputs("\ncomment ", out);
+                               print_quoted_string(out, prop->text);
+                               fputs("\n", out);
+                               break;
+                       case P_MENU:
+                               fputs("\nmenu ", out);
+                               print_quoted_string(out, prop->text);
+                               fputs("\n", out);
+                               break;
+                       default:
+                               ;
+                       }
+                       if (!expr_is_yes(prop->visible.expr)) {
+                               fputs("  depends ", out);
+                               expr_fprint(prop->visible.expr, out);
+                               fputc('\n', out);
+                       }
+                       fputs("\n", out);
+               }
+
+               if (menu->list)
+                       menu = menu->list;
+               else if (menu->next)
+                       menu = menu->next;
+               else while ((menu = menu->parent)) {
+                       if (menu->prompt && menu->prompt->type == P_MENU)
+                               fputs("\nendmenu\n", out);
+                       if (menu->next) {
+                               menu = menu->next;
+                               break;
+                       }
+               }
+       }
+}
+
+#include "lex.zconf.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
diff --git a/bin/lex.zconf.c b/bin/lex.zconf.c
new file mode 100644 (file)
index 0000000..112f0a0
--- /dev/null
@@ -0,0 +1,2459 @@
+#line 2 "bin/lex.zconf.c"
+
+#line 4 "bin/lex.zconf.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)
+
+/* 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 (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 (((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 yyrestart(yyin  )
+
+#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
+
+extern int yyleng;
+
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* 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 = (yy_hold_char); \
+               YY_RESTORE_YY_MORE_OFFSET \
+               (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, (yytext_ptr)  )
+
+#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 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 */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* 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 ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(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 (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+static int yy_n_chars;         /* number of characters read into yy_ch_buf */
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0;                /* whether we need to initialize */
+static int yy_start = 0;       /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart (FILE *input_file  );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size  );
+void yy_delete_buffer (YY_BUFFER_STATE b  );
+void yy_flush_buffer (YY_BUFFER_STATE b  );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer  );
+void yypop_buffer_state (void );
+
+static void yyensure_buffer_stack (void );
+static void yy_load_buffer_state (void );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len  );
+
+void *yyalloc (yy_size_t  );
+void *yyrealloc (void *,yy_size_t  );
+void yyfree (void *  );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+       { \
+       if ( ! YY_CURRENT_BUFFER ){ \
+        yyensure_buffer_stack (); \
+               YY_CURRENT_BUFFER_LVALUE =    \
+            yy_create_buffer(yyin,YY_BUF_SIZE ); \
+       } \
+       YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+       }
+
+#define yy_set_bol(at_bol) \
+       { \
+       if ( ! YY_CURRENT_BUFFER ){\
+        yyensure_buffer_stack (); \
+               YY_CURRENT_BUFFER_LVALUE =    \
+            yy_create_buffer(yyin,YY_BUF_SIZE ); \
+       } \
+       YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+       }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int yylineno;
+
+int yylineno = 1;
+
+extern char *yytext;
+#define yytext_ptr yytext
+static yyconst flex_int16_t yy_nxt[][17] =
+    {
+    {
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0
+    },
+
+    {
+       11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12
+    },
+
+    {
+       11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12
+    },
+
+    {
+       11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   18,   16,   16,   16
+    },
+
+    {
+       11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   18,   16,   16,   16
+
+    },
+
+    {
+       11,   19,   20,   21,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19
+    },
+
+    {
+       11,   19,   20,   21,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19
+    },
+
+    {
+       11,   22,   22,   23,   22,   24,   22,   22,   24,   22,
+       22,   22,   22,   22,   22,   25,   22
+    },
+
+    {
+       11,   22,   22,   23,   22,   24,   22,   22,   24,   22,
+       22,   22,   22,   22,   22,   25,   22
+    },
+
+    {
+       11,   26,   26,   27,   28,   29,   30,   31,   29,   32,
+       33,   34,   35,   35,   36,   37,   38
+
+    },
+
+    {
+       11,   26,   26,   27,   28,   29,   30,   31,   29,   32,
+       33,   34,   35,   35,   36,   37,   38
+    },
+
+    {
+      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,
+      -11,  -11,  -11,  -11,  -11,  -11,  -11
+    },
+
+    {
+       11,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,
+      -12,  -12,  -12,  -12,  -12,  -12,  -12
+    },
+
+    {
+       11,  -13,   39,   40,  -13,  -13,   41,  -13,  -13,  -13,
+      -13,  -13,  -13,  -13,  -13,  -13,  -13
+    },
+
+    {
+       11,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,
+      -14,  -14,  -14,  -14,  -14,  -14,  -14
+
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,
+      -16,  -16,  -16,  -16,  -16,  -16,  -16
+    },
+
+    {
+       11,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,
+      -17,  -17,  -17,  -17,  -17,  -17,  -17
+    },
+
+    {
+       11,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,
+      -18,  -18,  -18,   44,  -18,  -18,  -18
+    },
+
+    {
+       11,   45,   45,  -19,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45
+
+    },
+
+    {
+       11,  -20,   46,   47,  -20,  -20,  -20,  -20,  -20,  -20,
+      -20,  -20,  -20,  -20,  -20,  -20,  -20
+    },
+
+    {
+       11,   48,  -21,  -21,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48
+    },
+
+    {
+       11,   49,   49,   50,   49,  -22,   49,   49,  -22,   49,
+       49,   49,   49,   49,   49,  -22,   49
+    },
+
+    {
+       11,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,
+      -23,  -23,  -23,  -23,  -23,  -23,  -23
+    },
+
+    {
+       11,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,
+      -24,  -24,  -24,  -24,  -24,  -24,  -24
+
+    },
+
+    {
+       11,   51,   51,   52,   51,   51,   51,   51,   51,   51,
+       51,   51,   51,   51,   51,   51,   51
+    },
+
+    {
+       11,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,
+      -26,  -26,  -26,  -26,  -26,  -26,  -26
+    },
+
+    {
+       11,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,
+      -27,  -27,  -27,  -27,  -27,  -27,  -27
+    },
+
+    {
+       11,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,
+      -28,  -28,  -28,  -28,   53,  -28,  -28
+    },
+
+    {
+       11,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,
+      -29,  -29,  -29,  -29,  -29,  -29,  -29
+
+    },
+
+    {
+       11,   54,   54,  -30,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54
+    },
+
+    {
+       11,  -31,  -31,  -31,  -31,  -31,  -31,   55,  -31,  -31,
+      -31,  -31,  -31,  -31,  -31,  -31,  -31
+    },
+
+    {
+       11,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,
+      -32,  -32,  -32,  -32,  -32,  -32,  -32
+    },
+
+    {
+       11,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,
+      -33,  -33,  -33,  -33,  -33,  -33,  -33
+    },
+
+    {
+       11,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,
+      -34,   56,   57,   57,  -34,  -34,  -34
+
+    },
+
+    {
+       11,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,
+      -35,   57,   57,   57,  -35,  -35,  -35
+    },
+
+    {
+       11,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,
+      -36,  -36,  -36,  -36,  -36,  -36,  -36
+    },
+
+    {
+       11,  -37,  -37,   58,  -37,  -37,  -37,  -37,  -37,  -37,
+      -37,  -37,  -37,  -37,  -37,  -37,  -37
+    },
+
+    {
+       11,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,
+      -38,  -38,  -38,  -38,  -38,  -38,   59
+    },
+
+    {
+       11,  -39,   39,   40,  -39,  -39,   41,  -39,  -39,  -39,
+      -39,  -39,  -39,  -39,  -39,  -39,  -39
+
+    },
+
+    {
+       11,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,
+      -40,  -40,  -40,  -40,  -40,  -40,  -40
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,
+      -43,  -43,  -43,  -43,  -43,  -43,  -43
+    },
+
+    {
+       11,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,
+      -44,  -44,  -44,   44,  -44,  -44,  -44
+
+    },
+
+    {
+       11,   45,   45,  -45,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45
+    },
+
+    {
+       11,  -46,   46,   47,  -46,  -46,  -46,  -46,  -46,  -46,
+      -46,  -46,  -46,  -46,  -46,  -46,  -46
+    },
+
+    {
+       11,   48,  -47,  -47,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48
+    },
+
+    {
+       11,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,
+      -48,  -48,  -48,  -48,  -48,  -48,  -48
+    },
+
+    {
+       11,   49,   49,   50,   49,  -49,   49,   49,  -49,   49,
+       49,   49,   49,   49,   49,  -49,   49
+
+    },
+
+    {
+       11,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,
+      -50,  -50,  -50,  -50,  -50,  -50,  -50
+    },
+
+    {
+       11,  -51,  -51,   52,  -51,  -51,  -51,  -51,  -51,  -51,
+      -51,  -51,  -51,  -51,  -51,  -51,  -51
+    },
+
+    {
+       11,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,
+      -52,  -52,  -52,  -52,  -52,  -52,  -52
+    },
+
+    {
+       11,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,
+      -53,  -53,  -53,  -53,  -53,  -53,  -53
+    },
+
+    {
+       11,   54,   54,  -54,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54
+
+    },
+
+    {
+       11,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,
+      -55,  -55,  -55,  -55,  -55,  -55,  -55
+    },
+
+    {
+       11,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,
+      -56,   60,   57,   57,  -56,  -56,  -56
+    },
+
+    {
+       11,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,
+      -57,   57,   57,   57,  -57,  -57,  -57
+    },
+
+    {
+       11,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,
+      -58,  -58,  -58,  -58,  -58,  -58,  -58
+    },
+
+    {
+       11,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,
+      -59,  -59,  -59,  -59,  -59,  -59,  -59
+
+    },
+
+    {
+       11,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,
+      -60,   57,   57,   57,  -60,  -60,  -60
+    },
+
+    } ;
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+       (yytext_ptr) = yy_bp; \
+       yyleng = (size_t) (yy_cp - yy_bp); \
+       (yy_hold_char) = *yy_cp; \
+       *yy_cp = '\0'; \
+       (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 33
+#define YY_END_OF_BUFFER 34
+/* 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[61] =
+    {   0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+       34,    5,    4,    2,    3,    7,    8,    6,   32,   29,
+       31,   24,   28,   27,   26,   22,   17,   13,   16,   20,
+       22,   11,   12,   19,   19,   14,   22,   22,    4,    2,
+        3,    3,    1,    6,   32,   29,   31,   30,   24,   23,
+       26,   25,   15,   20,    9,   19,   19,   21,   10,   18
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    4,    5,    6,    1,    1,    7,    8,    9,
+       10,    1,    1,    1,   11,   12,   12,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,    1,    1,    1,
+       14,    1,    1,    1,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+        1,   15,    1,    1,   13,    1,   13,   13,   13,   13,
+
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,    1,   16,    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,    1
+    } ;
+
+extern int yy_flex_debug;
+int yy_flex_debug = 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
+char *yytext;
+#line 1 "bin/kconfig/zconf.l"
+
+#line 5 "bin/kconfig/zconf.l"
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define START_STRSIZE  16
+
+static struct {
+       struct file *file;
+       int lineno;
+} current_pos;
+
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+        struct buffer *parent;
+        YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+void new_string(void)
+{
+       text = malloc(START_STRSIZE);
+       text_asize = START_STRSIZE;
+       text_size = 0;
+       *text = 0;
+}
+
+void append_string(const char *str, int size)
+{
+       int new_size = text_size + size + 1;
+       if (new_size > text_asize) {
+               new_size += START_STRSIZE - 1;
+               new_size &= -START_STRSIZE;
+               text = realloc(text, new_size);
+               text_asize = new_size;
+       }
+       memcpy(text + text_size, str, size);
+       text_size += size;
+       text[text_size] = 0;
+}
+
+void alloc_string(const char *str, int size)
+{
+       text = malloc(size + 1);
+       memcpy(text, str, size);
+       text[size] = 0;
+}
+#line 825 "bin/lex.zconf.c"
+
+#define INITIAL 0
+#define COMMAND 1
+#define HELP 2
+#define STRING 3
+#define PARAM 4
+
+#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
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy (void );
+
+int yyget_debug (void );
+
+void yyset_debug (int debug_flag  );
+
+YY_EXTRA_TYPE yyget_extra (void );
+
+void yyset_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *yyget_in (void );
+
+void yyset_in  (FILE * in_str  );
+
+FILE *yyget_out (void );
+
+void yyset_out  (FILE * out_str  );
+
+int yyget_leng (void );
+
+char *yyget_text (void );
+
+int yyget_lineno (void );
+
+void yyset_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (void );
+#else
+extern int yywrap (void );
+#endif
+#endif
+
+    static void yyunput (int c,char *buf_ptr  );
+    
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#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) \
+       errno=0; \
+       while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \
+       { \
+               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 )
+#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 yylex (void);
+
+#define YY_DECL int yylex (void)
+#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 \
+       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;
+    
+#line 74 "bin/kconfig/zconf.l"
+
+       int str = 0;
+       int ts, i;
+
+#line 1005 "bin/lex.zconf.c"
+
+       if ( !(yy_init) )
+               {
+               (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+               YY_USER_INIT;
+#endif
+
+               if ( ! (yy_start) )
+                       (yy_start) = 1; /* first start state */
+
+               if ( ! yyin )
+                       yyin = stdin;
+
+               if ( ! yyout )
+                       yyout = stdout;
+
+               if ( ! YY_CURRENT_BUFFER ) {
+                       yyensure_buffer_stack ();
+                       YY_CURRENT_BUFFER_LVALUE =
+                               yy_create_buffer(yyin,YY_BUF_SIZE );
+               }
+
+               yy_load_buffer_state( );
+               }
+
+       while ( 1 )             /* loops until end-of-file is reached */
+               {
+               yy_cp = (yy_c_buf_p);
+
+               /* Support of yytext. */
+               *yy_cp = (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 = (yy_start);
+yy_match:
+               while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)]  ]) > 0 )
+                       ++yy_cp;
+
+               yy_current_state = -yy_current_state;
+
+yy_find_action:
+               yy_act = yy_accept[yy_current_state];
+
+               YY_DO_BEFORE_ACTION;
+
+do_action:     /* This label is used only to access EOF actions. */
+
+               switch ( yy_act )
+       { /* beginning of action switch */
+case 1:
+/* rule 1 can match eol */
+#line 79 "bin/kconfig/zconf.l"
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+#line 79 "bin/kconfig/zconf.l"
+{
+       current_file->lineno++;
+       return T_EOL;
+}
+       YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 83 "bin/kconfig/zconf.l"
+
+       YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 86 "bin/kconfig/zconf.l"
+{
+       BEGIN(COMMAND);
+}
+       YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 90 "bin/kconfig/zconf.l"
+{
+       unput(yytext[0]);
+       BEGIN(COMMAND);
+}
+       YY_BREAK
+
+case 6:
+YY_RULE_SETUP
+#line 97 "bin/kconfig/zconf.l"
+{
+               struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+               BEGIN(PARAM);
+               current_pos.file = current_file;
+               current_pos.lineno = current_file->lineno;
+               if (id && id->flags & TF_COMMAND) {
+                       zconflval.id = id;
+                       return id->token;
+               }
+               alloc_string(yytext, yyleng);
+               zconflval.string = text;
+               return T_WORD;
+       }
+       YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 110 "bin/kconfig/zconf.l"
+
+       YY_BREAK
+case 8:
+/* rule 8 can match eol */
+YY_RULE_SETUP
+#line 111 "bin/kconfig/zconf.l"
+{
+               BEGIN(INITIAL);
+               current_file->lineno++;
+               return T_EOL;
+       }
+       YY_BREAK
+
+
+case 9:
+YY_RULE_SETUP
+#line 119 "bin/kconfig/zconf.l"
+return T_AND;
+       YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 120 "bin/kconfig/zconf.l"
+return T_OR;
+       YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 121 "bin/kconfig/zconf.l"
+return T_OPEN_PAREN;
+       YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 122 "bin/kconfig/zconf.l"
+return T_CLOSE_PAREN;
+       YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 123 "bin/kconfig/zconf.l"
+return T_NOT;
+       YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 124 "bin/kconfig/zconf.l"
+return T_EQUAL;
+       YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 125 "bin/kconfig/zconf.l"
+return T_UNEQUAL;
+       YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 126 "bin/kconfig/zconf.l"
+{
+               str = yytext[0];
+               new_string();
+               BEGIN(STRING);
+       }
+       YY_BREAK
+case 17:
+/* rule 17 can match eol */
+YY_RULE_SETUP
+#line 131 "bin/kconfig/zconf.l"
+BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+       YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 132 "bin/kconfig/zconf.l"
+/* ignore */
+       YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 133 "bin/kconfig/zconf.l"
+{
+               struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+               if (id && id->flags & TF_PARAM) {
+                       zconflval.id = id;
+                       return id->token;
+               }
+               alloc_string(yytext, yyleng);
+               zconflval.string = text;
+               return T_WORD;
+       }
+       YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 143 "bin/kconfig/zconf.l"
+/* comment */
+       YY_BREAK
+case 21:
+/* rule 21 can match eol */
+YY_RULE_SETUP
+#line 144 "bin/kconfig/zconf.l"
+current_file->lineno++;
+       YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 145 "bin/kconfig/zconf.l"
+
+       YY_BREAK
+case YY_STATE_EOF(PARAM):
+#line 146 "bin/kconfig/zconf.l"
+{
+               BEGIN(INITIAL);
+       }
+       YY_BREAK
+
+
+case 23:
+/* rule 23 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 152 "bin/kconfig/zconf.l"
+{
+               append_string(yytext, yyleng);
+               zconflval.string = text;
+               return T_WORD_QUOTE;
+       }
+       YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 157 "bin/kconfig/zconf.l"
+{
+               append_string(yytext, yyleng);
+       }
+       YY_BREAK
+case 25:
+/* rule 25 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 160 "bin/kconfig/zconf.l"
+{
+               append_string(yytext + 1, yyleng - 1);
+               zconflval.string = text;
+               return T_WORD_QUOTE;
+       }
+       YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 165 "bin/kconfig/zconf.l"
+{
+               append_string(yytext + 1, yyleng - 1);
+       }
+       YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 168 "bin/kconfig/zconf.l"
+{
+               if (str == yytext[0]) {
+                       BEGIN(PARAM);
+                       zconflval.string = text;
+                       return T_WORD_QUOTE;
+               } else
+                       append_string(yytext, 1);
+       }
+       YY_BREAK
+case 28:
+/* rule 28 can match eol */
+YY_RULE_SETUP
+#line 176 "bin/kconfig/zconf.l"
+{
+               printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+               current_file->lineno++;
+               BEGIN(INITIAL);
+               return T_EOL;
+       }
+       YY_BREAK
+case YY_STATE_EOF(STRING):
+#line 182 "bin/kconfig/zconf.l"
+{
+               BEGIN(INITIAL);
+       }
+       YY_BREAK
+
+
+case 29:
+YY_RULE_SETUP
+#line 188 "bin/kconfig/zconf.l"
+{
+               ts = 0;
+               for (i = 0; i < yyleng; i++) {
+                       if (yytext[i] == '\t')
+                               ts = (ts & ~7) + 8;
+                       else
+                               ts++;
+               }
+               last_ts = ts;
+               if (first_ts) {
+                       if (ts < first_ts) {
+                               zconf_endhelp();
+                               return T_HELPTEXT;
+                       }
+                       ts -= first_ts;
+                       while (ts > 8) {
+                               append_string("        ", 8);
+                               ts -= 8;
+                       }
+                       append_string("        ", ts);
+               }
+       }
+       YY_BREAK
+case 30:
+/* rule 30 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 210 "bin/kconfig/zconf.l"
+{
+               current_file->lineno++;
+               zconf_endhelp();
+               return T_HELPTEXT;
+       }
+       YY_BREAK
+case 31:
+/* rule 31 can match eol */
+YY_RULE_SETUP
+#line 215 "bin/kconfig/zconf.l"
+{
+               current_file->lineno++;
+               append_string("\n", 1);
+       }
+       YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 219 "bin/kconfig/zconf.l"
+{
+               while (yyleng) {
+                       if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
+                               break;
+                       yyleng--;
+               }
+               append_string(yytext, yyleng);
+               if (!first_ts)
+                       first_ts = last_ts;
+       }
+       YY_BREAK
+case YY_STATE_EOF(HELP):
+#line 229 "bin/kconfig/zconf.l"
+{
+               zconf_endhelp();
+               return T_HELPTEXT;
+       }
+       YY_BREAK
+
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(COMMAND):
+#line 235 "bin/kconfig/zconf.l"
+{
+       if (current_file) {
+               zconf_endfile();
+               return T_EOL;
+       }
+       fclose(yyin);
+       yyterminate();
+}
+       YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 244 "bin/kconfig/zconf.l"
+YY_FATAL_ERROR( "flex scanner jammed" );
+       YY_BREAK
+#line 1379 "bin/lex.zconf.c"
+
+       case YY_END_OF_BUFFER:
+               {
+               /* Amount of text matched not including the EOB char. */
+               int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+               /* Undo the effects of YY_DO_BEFORE_ACTION. */
+               *yy_cp = (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
+                        * 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.
+                        */
+                       (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 ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+                       { /* This was really a NUL. */
+                       yy_state_type yy_next_state;
+
+                       (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+                       yy_current_state = yy_get_previous_state(  );
+
+                       /* 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 );
+
+                       yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+                       if ( yy_next_state )
+                               {
+                               /* Consume the NUL. */
+                               yy_cp = ++(yy_c_buf_p);
+                               yy_current_state = yy_next_state;
+                               goto yy_match;
+                               }
+
+                       else
+                               {
+                               yy_cp = (yy_c_buf_p);
+                               goto yy_find_action;
+                               }
+                       }
+
+               else switch ( yy_get_next_buffer(  ) )
+                       {
+                       case EOB_ACT_END_OF_FILE:
+                               {
+                               (yy_did_buffer_switch_on_eof) = 0;
+
+                               if ( yywrap( ) )
+                                       {
+                                       /* 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.
+                                        */
+                                       (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+                                       yy_act = YY_STATE_EOF(YY_START);
+                                       goto do_action;
+                                       }
+
+                               else
+                                       {
+                                       if ( ! (yy_did_buffer_switch_on_eof) )
+                                               YY_NEW_FILE;
+                                       }
+                               break;
+                               }
+
+                       case EOB_ACT_CONTINUE_SCAN:
+                               (yy_c_buf_p) =
+                                       (yytext_ptr) + yy_amount_of_matched_text;
+
+                               yy_current_state = yy_get_previous_state(  );
+
+                               yy_cp = (yy_c_buf_p);
+                               yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+                               goto yy_match;
+
+                       case EOB_ACT_LAST_MATCH:
+                               (yy_c_buf_p) =
+                               &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+                               yy_current_state = yy_get_previous_state(  );
+
+                               yy_cp = (yy_c_buf_p);
+                               yy_bp = (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 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 (void)
+{
+       register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+       register char *source = (yytext_ptr);
+       register int number_to_move, i;
+       int ret_val;
+
+       if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(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 ( (yy_c_buf_p) - (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) ((yy_c_buf_p) - (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 = (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) ((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. */
+                                       yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );
+                               }
+                       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" );
+
+                       (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]),
+                       (yy_n_chars), (size_t) num_to_read );
+
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+               }
+
+       if ( (yy_n_chars) == 0 )
+               {
+               if ( number_to_move == YY_MORE_ADJ )
+                       {
+                       ret_val = EOB_ACT_END_OF_FILE;
+                       yyrestart(yyin  );
+                       }
+
+               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) ((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 = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+               YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
+               if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+                       YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+       }
+
+       (yy_n_chars) += number_to_move;
+       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+       (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 (void)
+{
+       register yy_state_type yy_current_state;
+       register char *yy_cp;
+    
+       yy_current_state = (yy_start);
+
+       for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+               {
+               yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)];
+               }
+
+       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 )
+{
+       register int yy_is_jam;
+    
+       yy_current_state = yy_nxt[yy_current_state][1];
+       yy_is_jam = (yy_current_state <= 0);
+
+       return yy_is_jam ? 0 : yy_current_state;
+}
+
+    static void yyunput (int c, register char * yy_bp )
+{
+       register char *yy_cp;
+    
+    yy_cp = (yy_c_buf_p);
+
+       /* undo effects of setting up yytext */
+       *yy_cp = (yy_hold_char);
+
+       if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+               { /* need to shift things up to make room */
+               /* +2 for EOB chars. */
+               register int number_to_move = (yy_n_chars) + 2;
+               register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+                                       YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+               register char *source =
+                               &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+               while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+                       *--dest = *--source;
+
+               yy_cp += (int) (dest - source);
+               yy_bp += (int) (dest - source);
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+                       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+               if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+                       YY_FATAL_ERROR( "flex scanner push-back overflow" );
+               }
+
+       *--yy_cp = (char) c;
+
+       (yytext_ptr) = yy_bp;
+       (yy_hold_char) = *yy_cp;
+       (yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+       int c;
+    
+       *(yy_c_buf_p) = (yy_hold_char);
+
+       if ( *(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 ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+                       /* This was really a NUL. */
+                       *(yy_c_buf_p) = '\0';
+
+               else
+                       { /* need more input */
+                       int offset = (yy_c_buf_p) - (yytext_ptr);
+                       ++(yy_c_buf_p);
+
+                       switch ( yy_get_next_buffer(  ) )
+                               {
+                               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. */
+                                       yyrestart(yyin );
+
+                                       /*FALLTHROUGH*/
+
+                               case EOB_ACT_END_OF_FILE:
+                                       {
+                                       if ( yywrap( ) )
+                                               return EOF;
+
+                                       if ( ! (yy_did_buffer_switch_on_eof) )
+                                               YY_NEW_FILE;
+#ifdef __cplusplus
+                                       return yyinput();
+#else
+                                       return input();
+#endif
+                                       }
+
+                               case EOB_ACT_CONTINUE_SCAN:
+                                       (yy_c_buf_p) = (yytext_ptr) + offset;
+                                       break;
+                               }
+                       }
+               }
+
+       c = *(unsigned char *) (yy_c_buf_p);    /* cast for 8-bit char's */
+       *(yy_c_buf_p) = '\0';   /* preserve yytext */
+       (yy_hold_char) = *++(yy_c_buf_p);
+
+       return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void yyrestart  (FILE * input_file )
+{
+    
+       if ( ! YY_CURRENT_BUFFER ){
+        yyensure_buffer_stack ();
+               YY_CURRENT_BUFFER_LVALUE =
+            yy_create_buffer(yyin,YY_BUF_SIZE );
+       }
+
+       yy_init_buffer(YY_CURRENT_BUFFER,input_file );
+       yy_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+       /* TODO. We should be able to replace this entire function body
+        * with
+        *              yypop_buffer_state();
+        *              yypush_buffer_state(new_buffer);
+     */
+       yyensure_buffer_stack ();
+       if ( YY_CURRENT_BUFFER == new_buffer )
+               return;
+
+       if ( YY_CURRENT_BUFFER )
+               {
+               /* Flush out information for old buffer. */
+               *(yy_c_buf_p) = (yy_hold_char);
+               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+               }
+
+       YY_CURRENT_BUFFER_LVALUE = new_buffer;
+       yy_load_buffer_state( );
+
+       /* We don't actually know whether we did this switch during
+        * EOF (yywrap()) processing, but the only time this flag
+        * is looked at is after yywrap() is called, so it's safe
+        * to go ahead and always set it.
+        */
+       (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void yy_load_buffer_state  (void)
+{
+       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+       (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+       yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+       (yy_hold_char) = *(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.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE yy_create_buffer  (FILE * file, int  size )
+{
+       YY_BUFFER_STATE b;
+    
+       b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in 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 *) yyalloc(b->yy_buf_size + 2  );
+       if ( ! b->yy_ch_buf )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+       b->yy_is_our_buffer = 1;
+
+       yy_init_buffer(b,file );
+
+       return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * 
+ */
+    void yy_delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+       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 )
+               yyfree((void *) b->yy_ch_buf  );
+
+       yyfree((void *) b  );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+    static void yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+       int oerrno = errno;
+    
+       yy_flush_buffer(b );
+
+       b->yy_input_file = file;
+       b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then yy_init_buffer was _probably_
+     * called from 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 = 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.
+ * 
+ */
+    void yy_flush_buffer (YY_BUFFER_STATE  b )
+{
+       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 )
+               yy_load_buffer_state( );
+}
+
+/** 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.
+ *  
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+       if (new_buffer == NULL)
+               return;
+
+       yyensure_buffer_stack();
+
+       /* This block is copied from yy_switch_to_buffer. */
+       if ( YY_CURRENT_BUFFER )
+               {
+               /* Flush out information for old buffer. */
+               *(yy_c_buf_p) = (yy_hold_char);
+               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+               }
+
+       /* Only push if top exists. Otherwise, replace top. */
+       if (YY_CURRENT_BUFFER)
+               (yy_buffer_stack_top)++;
+       YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+       /* copied from yy_switch_to_buffer. */
+       yy_load_buffer_state( );
+       (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void yypop_buffer_state (void)
+{
+       if (!YY_CURRENT_BUFFER)
+               return;
+
+       yy_delete_buffer(YY_CURRENT_BUFFER );
+       YY_CURRENT_BUFFER_LVALUE = NULL;
+       if ((yy_buffer_stack_top) > 0)
+               --(yy_buffer_stack_top);
+
+       if (YY_CURRENT_BUFFER) {
+               yy_load_buffer_state( );
+               (yy_did_buffer_switch_on_eof) = 1;
+       }
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (void)
+{
+       int num_to_alloc;
+    
+       if (!(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;
+               (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+                                                               (num_to_alloc * sizeof(struct yy_buffer_state*)
+                                                               );
+               if ( ! (yy_buffer_stack) )
+                       YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+                                                                 
+               memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+                               
+               (yy_buffer_stack_max) = num_to_alloc;
+               (yy_buffer_stack_top) = 0;
+               return;
+       }
+
+       if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+               /* Increase the buffer to prepare for a possible push. */
+               int grow_size = 8 /* arbitrary grow size */;
+
+               num_to_alloc = (yy_buffer_stack_max) + grow_size;
+               (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+                                                               ((yy_buffer_stack),
+                                                               num_to_alloc * sizeof(struct yy_buffer_state*)
+                                                               );
+               if ( ! (yy_buffer_stack) )
+                       YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+               /* zero only the new slots.*/
+               memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+               (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
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size )
+{
+       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) yyalloc(sizeof( struct yy_buffer_state )  );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in 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;
+
+       yy_switch_to_buffer(b  );
+
+       return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
+{
+    
+       return yy_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to 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.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
+{
+       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 *) yyalloc(n  );
+       if ( ! buf )
+               YY_FATAL_ERROR( "out of dynamic memory in 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 = yy_scan_buffer(buf,n );
+       if ( ! b )
+               YY_FATAL_ERROR( "bad buffer in 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 )
+{
+       (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] = (yy_hold_char); \
+               (yy_c_buf_p) = yytext + yyless_macro_arg; \
+               (yy_hold_char) = *(yy_c_buf_p); \
+               *(yy_c_buf_p) = '\0'; \
+               yyleng = yyless_macro_arg; \
+               } \
+       while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ * 
+ */
+int yyget_lineno  (void)
+{
+        
+    return yylineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *yyget_in  (void)
+{
+        return yyin;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *yyget_out  (void)
+{
+        return yyout;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+int yyget_leng  (void)
+{
+        return yyleng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *yyget_text  (void)
+{
+        return yytext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void yyset_lineno (int  line_number )
+{
+    
+    yylineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE *  in_str )
+{
+        yyin = in_str ;
+}
+
+void yyset_out (FILE *  out_str )
+{
+        yyout = out_str ;
+}
+
+int yyget_debug  (void)
+{
+        return yy_flex_debug;
+}
+
+void yyset_debug (int  bdebug )
+{
+        yy_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from yylex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+/* 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
+     * yylex_init()
+     */
+    return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+       while(YY_CURRENT_BUFFER){
+               yy_delete_buffer(YY_CURRENT_BUFFER  );
+               YY_CURRENT_BUFFER_LVALUE = NULL;
+               yypop_buffer_state();
+       }
+
+       /* Destroy the stack itself. */
+       yyfree((yy_buffer_stack) );
+       (yy_buffer_stack) = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * yylex() is called, initialization will occur. */
+    yy_init_globals( );
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+       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 )
+{
+       register int n;
+       for ( n = 0; s[n]; ++n )
+               ;
+
+       return n;
+}
+#endif
+
+void *yyalloc (yy_size_t  size )
+{
+       return (void *) malloc( size );
+}
+
+void *yyrealloc  (void * ptr, yy_size_t  size )
+{
+       /* 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 yyfree (void * ptr )
+{
+       free( (char *) ptr );   /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 244 "bin/kconfig/zconf.l"
+
+
+void zconf_starthelp(void)
+{
+       new_string();
+       last_ts = first_ts = 0;
+       BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+       zconflval.string = text;
+       BEGIN(INITIAL);
+}
+
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+       char *env, fullname[PATH_MAX+1];
+       FILE *f;
+
+       f = fopen(name, "r");
+       if (!f && name != NULL && name[0] != '/') {
+               env = getenv(SRCTREE);
+               if (env) {
+                       sprintf(fullname, "%s/%s", env, name);
+                       f = fopen(fullname, "r");
+               }
+       }
+       return f;
+}
+
+void zconf_initscan(const char *name)
+{
+       yyin = zconf_fopen(name);
+       if (!yyin) {
+               printf("can't find file %s\n", name);
+               exit(1);
+       }
+
+       current_buf = malloc(sizeof(*current_buf));
+       memset(current_buf, 0, sizeof(*current_buf));
+
+       current_file = file_lookup(name);
+       current_file->lineno = 1;
+       current_file->flags = FILE_BUSY;
+}
+
+void zconf_nextfile(const char *name)
+{
+       struct file *file = file_lookup(name);
+       struct buffer *buf = malloc(sizeof(*buf));
+       memset(buf, 0, sizeof(*buf));
+
+       current_buf->state = YY_CURRENT_BUFFER;
+       yyin = zconf_fopen(name);
+       if (!yyin) {
+               printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name);
+               exit(1);
+       }
+       yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE));
+       buf->parent = current_buf;
+       current_buf = buf;
+
+       if (file->flags & FILE_BUSY) {
+               printf("recursive scan (%s)?\n", name);
+               exit(1);
+       }
+       if (file->flags & FILE_SCANNED) {
+               printf("file %s already scanned?\n", name);
+               exit(1);
+       }
+       file->flags |= FILE_BUSY;
+       file->lineno = 1;
+       file->parent = current_file;
+       current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+       struct buffer *parent;
+
+       current_file->flags |= FILE_SCANNED;
+       current_file->flags &= ~FILE_BUSY;
+       current_file = current_file->parent;
+
+       parent = current_buf->parent;
+       if (parent) {
+               fclose(yyin);
+               yy_delete_buffer(YY_CURRENT_BUFFER);
+               yy_switch_to_buffer(parent->state);
+       }
+       free(current_buf);
+       current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+       return current_pos.lineno;
+}
+
+char *zconf_curname(void)
+{
+       return current_pos.file ? current_pos.file->name : "<none>";
+}
+
diff --git a/bin/mconf b/bin/mconf
new file mode 100755 (executable)
index 0000000..6232bac
Binary files /dev/null and b/bin/mconf differ
diff --git a/bin/zconf.hash.c b/bin/zconf.hash.c
new file mode 100644 (file)
index 0000000..5c73d51
--- /dev/null
@@ -0,0 +1,237 @@
+/* ANSI-C code produced by gperf version 3.0.3 */
+/* Command-line: gperf  */
+/* Computed positions: -k'1,3' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+struct kconf_id;
+/* maximum key range = 47, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+kconf_id_hash (register const char *str, register unsigned int len)
+{
+  static unsigned char asso_values[] =
+    {
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 11,  5,
+       0,  0,  5, 49,  5, 20, 49, 49,  5, 20,
+       5,  0, 30, 49,  0, 15,  0, 10,  0, 49,
+      25, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49
+    };
+  register int hval = len;
+
+  switch (hval)
+    {
+      default:
+        hval += asso_values[(unsigned char)str[2]];
+      /*FALLTHROUGH*/
+      case 2:
+      case 1:
+        hval += asso_values[(unsigned char)str[0]];
+        break;
+    }
+  return hval;
+}
+
+struct kconf_id_strings_t
+  {
+    char kconf_id_strings_str2[sizeof("on")];
+    char kconf_id_strings_str3[sizeof("env")];
+    char kconf_id_strings_str5[sizeof("endif")];
+    char kconf_id_strings_str6[sizeof("option")];
+    char kconf_id_strings_str7[sizeof("endmenu")];
+    char kconf_id_strings_str8[sizeof("optional")];
+    char kconf_id_strings_str9[sizeof("endchoice")];
+    char kconf_id_strings_str10[sizeof("range")];
+    char kconf_id_strings_str11[sizeof("choice")];
+    char kconf_id_strings_str12[sizeof("default")];
+    char kconf_id_strings_str13[sizeof("def_bool")];
+    char kconf_id_strings_str14[sizeof("help")];
+    char kconf_id_strings_str15[sizeof("bool")];
+    char kconf_id_strings_str16[sizeof("config")];
+    char kconf_id_strings_str17[sizeof("def_tristate")];
+    char kconf_id_strings_str18[sizeof("boolean")];
+    char kconf_id_strings_str19[sizeof("defconfig_list")];
+    char kconf_id_strings_str21[sizeof("string")];
+    char kconf_id_strings_str22[sizeof("if")];
+    char kconf_id_strings_str23[sizeof("int")];
+    char kconf_id_strings_str26[sizeof("select")];
+    char kconf_id_strings_str27[sizeof("modules")];
+    char kconf_id_strings_str28[sizeof("tristate")];
+    char kconf_id_strings_str29[sizeof("menu")];
+    char kconf_id_strings_str31[sizeof("source")];
+    char kconf_id_strings_str32[sizeof("comment")];
+    char kconf_id_strings_str33[sizeof("hex")];
+    char kconf_id_strings_str35[sizeof("menuconfig")];
+    char kconf_id_strings_str36[sizeof("prompt")];
+    char kconf_id_strings_str37[sizeof("depends")];
+    char kconf_id_strings_str48[sizeof("mainmenu")];
+  };
+static struct kconf_id_strings_t kconf_id_strings_contents =
+  {
+    "on",
+    "env",
+    "endif",
+    "option",
+    "endmenu",
+    "optional",
+    "endchoice",
+    "range",
+    "choice",
+    "default",
+    "def_bool",
+    "help",
+    "bool",
+    "config",
+    "def_tristate",
+    "boolean",
+    "defconfig_list",
+    "string",
+    "if",
+    "int",
+    "select",
+    "modules",
+    "tristate",
+    "menu",
+    "source",
+    "comment",
+    "hex",
+    "menuconfig",
+    "prompt",
+    "depends",
+    "mainmenu"
+  };
+#define kconf_id_strings ((const char *) &kconf_id_strings_contents)
+#ifdef __GNUC__
+__inline
+#ifdef __GNUC_STDC_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
+#endif
+struct kconf_id *
+kconf_id_lookup (register const char *str, register unsigned int len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 31,
+      MIN_WORD_LENGTH = 2,
+      MAX_WORD_LENGTH = 14,
+      MIN_HASH_VALUE = 2,
+      MAX_HASH_VALUE = 48
+    };
+
+  static struct kconf_id wordlist[] =
+    {
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2,            T_ON,           TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3,            T_OPT_ENV,      TF_OPTION},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5,            T_ENDIF,        TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6,            T_OPTION,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7,    T_ENDMENU,      TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8,    T_OPTIONAL,     TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9,    T_ENDCHOICE,    TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10,           T_RANGE,        TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11,           T_CHOICE,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12,   T_DEFAULT,      TF_COMMAND, S_UNKNOWN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13,   T_DEFAULT,      TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14,           T_HELP,         TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str15,           T_TYPE,         TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16,           T_CONFIG,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17,   T_DEFAULT,      TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18,   T_TYPE,         TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str19,   T_OPT_DEFCONFIG_LIST,TF_OPTION},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21,           T_TYPE,         TF_COMMAND, S_STRING},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22,           T_IF,           TF_COMMAND|TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23,           T_TYPE,         TF_COMMAND, S_INT},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26,           T_SELECT,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27,   T_OPT_MODULES,  TF_OPTION},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28,   T_TYPE,         TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29,           T_MENU,         TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31,           T_SOURCE,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32,   T_COMMENT,      TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33,           T_TYPE,         TF_COMMAND, S_HEX},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35,   T_MENUCONFIG,   TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36,           T_PROMPT,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37,   T_DEPENDS,      TF_COMMAND},
+      {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str48,   T_MAINMENU,     TF_COMMAND}
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      register int key = kconf_id_hash (str, len);
+
+      if (key <= MAX_HASH_VALUE && key >= 0)
+        {
+          register int o = wordlist[key].name;
+          if (o >= 0)
+            {
+              register const char *s = o + kconf_id_strings;
+
+              if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
+                return &wordlist[key];
+            }
+        }
+    }
+  return 0;
+}
+
diff --git a/bin/zconf.tab.c b/bin/zconf.tab.c
new file mode 100644 (file)
index 0000000..e77ed67
--- /dev/null
@@ -0,0 +1,2490 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* 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 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+/* 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.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names.  */
+#define yyparse zconfparse
+#define yylex   zconflex
+#define yyerror zconferror
+#define yylval  zconflval
+#define yychar  zconfchar
+#define yydebug zconfdebug
+#define yynerrs zconfnerrs
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     T_MAINMENU = 258,
+     T_MENU = 259,
+     T_ENDMENU = 260,
+     T_SOURCE = 261,
+     T_CHOICE = 262,
+     T_ENDCHOICE = 263,
+     T_COMMENT = 264,
+     T_CONFIG = 265,
+     T_MENUCONFIG = 266,
+     T_HELP = 267,
+     T_HELPTEXT = 268,
+     T_IF = 269,
+     T_ENDIF = 270,
+     T_DEPENDS = 271,
+     T_OPTIONAL = 272,
+     T_PROMPT = 273,
+     T_TYPE = 274,
+     T_DEFAULT = 275,
+     T_SELECT = 276,
+     T_RANGE = 277,
+     T_OPTION = 278,
+     T_ON = 279,
+     T_WORD = 280,
+     T_WORD_QUOTE = 281,
+     T_UNEQUAL = 282,
+     T_CLOSE_PAREN = 283,
+     T_OPEN_PAREN = 284,
+     T_EOL = 285,
+     T_OR = 286,
+     T_AND = 287,
+     T_EQUAL = 288,
+     T_NOT = 289
+   };
+#endif
+/* Tokens.  */
+#define T_MAINMENU 258
+#define T_MENU 259
+#define T_ENDMENU 260
+#define T_SOURCE 261
+#define T_CHOICE 262
+#define T_ENDCHOICE 263
+#define T_COMMENT 264
+#define T_CONFIG 265
+#define T_MENUCONFIG 266
+#define T_HELP 267
+#define T_HELPTEXT 268
+#define T_IF 269
+#define T_ENDIF 270
+#define T_DEPENDS 271
+#define T_OPTIONAL 272
+#define T_PROMPT 273
+#define T_TYPE 274
+#define T_DEFAULT 275
+#define T_SELECT 276
+#define T_RANGE 277
+#define T_OPTION 278
+#define T_ON 279
+#define T_WORD 280
+#define T_WORD_QUOTE 281
+#define T_UNEQUAL 282
+#define T_CLOSE_PAREN 283
+#define T_OPEN_PAREN 284
+#define T_EOL 285
+#define T_OR 286
+#define T_AND 287
+#define T_EQUAL 288
+#define T_NOT 289
+
+
+
+
+/* Copy the first part of user declarations.  */
+
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#include "zconf.hash.c"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD         0x0001
+#define DEBUG_PARSE    0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[257];
+
+static struct menu *current_menu, *current_entry;
+
+#define YYDEBUG 0
+#if YYDEBUG
+#define YYERROR_VERBOSE
+#endif
+
+
+/* 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
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+
+{
+       char *string;
+       struct file *file;
+       struct symbol *symbol;
+       struct expr *expr;
+       struct menu *menu;
+       struct kconf_id *id;
+}
+/* Line 187 of yacc.c.  */
+
+       YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 216 of yacc.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 i)
+#else
+static int
+YYID (i)
+    int i;
+#endif
+{
+  return i;
+}
+#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;
+  YYSTYPE yyvs;
+  };
+
+/* 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)                                       \
+    do                                                                 \
+      {                                                                        \
+       YYSIZE_T yynewbytes;                                            \
+       YYCOPY (&yyptr->Stack, Stack, yysize);                          \
+       Stack = &yyptr->Stack;                                          \
+       yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+       yyptr += yynewbytes / sizeof (*yyptr);                          \
+      }                                                                        \
+    while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  3
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   259
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  35
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  46
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  110
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  180
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   289
+
+#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,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint16 yyprhs[] =
+{
+       0,     0,     3,     5,     6,     9,    12,    15,    20,    23,
+      28,    33,    37,    39,    41,    43,    45,    47,    49,    51,
+      53,    55,    57,    59,    61,    63,    67,    70,    74,    77,
+      81,    84,    85,    88,    91,    94,    97,   100,   103,   107,
+     112,   117,   122,   128,   132,   133,   137,   138,   141,   145,
+     148,   150,   154,   155,   158,   161,   164,   167,   170,   175,
+     179,   182,   187,   188,   191,   195,   197,   201,   202,   205,
+     208,   211,   215,   218,   220,   224,   225,   228,   231,   234,
+     238,   242,   245,   248,   251,   252,   255,   258,   261,   266,
+     267,   270,   272,   274,   277,   280,   283,   285,   288,   289,
+     292,   294,   298,   302,   306,   309,   313,   317,   319,   321,
+     322
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      36,     0,    -1,    37,    -1,    -1,    37,    39,    -1,    37,
+      53,    -1,    37,    64,    -1,    37,     3,    74,    76,    -1,
+      37,    75,    -1,    37,    25,     1,    30,    -1,    37,    38,
+       1,    30,    -1,    37,     1,    30,    -1,    16,    -1,    18,
+      -1,    19,    -1,    21,    -1,    17,    -1,    22,    -1,    20,
+      -1,    30,    -1,    59,    -1,    68,    -1,    42,    -1,    44,
+      -1,    66,    -1,    25,     1,    30,    -1,     1,    30,    -1,
+      10,    25,    30,    -1,    41,    45,    -1,    11,    25,    30,
+      -1,    43,    45,    -1,    -1,    45,    46,    -1,    45,    47,
+      -1,    45,    72,    -1,    45,    70,    -1,    45,    40,    -1,
+      45,    30,    -1,    19,    73,    30,    -1,    18,    74,    77,
+      30,    -1,    20,    78,    77,    30,    -1,    21,    25,    77,
+      30,    -1,    22,    79,    79,    77,    30,    -1,    23,    48,
+      30,    -1,    -1,    48,    25,    49,    -1,    -1,    33,    74,
+      -1,     7,    80,    30,    -1,    50,    54,    -1,    75,    -1,
+      51,    56,    52,    -1,    -1,    54,    55,    -1,    54,    72,
+      -1,    54,    70,    -1,    54,    30,    -1,    54,    40,    -1,
+      18,    74,    77,    30,    -1,    19,    73,    30,    -1,    17,
+      30,    -1,    20,    25,    77,    30,    -1,    -1,    56,    39,
+      -1,    14,    78,    76,    -1,    75,    -1,    57,    60,    58,
+      -1,    -1,    60,    39,    -1,    60,    64,    -1,    60,    53,
+      -1,     4,    74,    30,    -1,    61,    71,    -1,    75,    -1,
+      62,    65,    63,    -1,    -1,    65,    39,    -1,    65,    64,
+      -1,    65,    53,    -1,     6,    74,    30,    -1,     9,    74,
+      30,    -1,    67,    71,    -1,    12,    30,    -1,    69,    13,
+      -1,    -1,    71,    72,    -1,    71,    30,    -1,    71,    40,
+      -1,    16,    24,    78,    30,    -1,    -1,    74,    77,    -1,
+      25,    -1,    26,    -1,     5,    30,    -1,     8,    30,    -1,
+      15,    30,    -1,    30,    -1,    76,    30,    -1,    -1,    14,
+      78,    -1,    79,    -1,    79,    33,    79,    -1,    79,    27,
+      79,    -1,    29,    78,    28,    -1,    34,    78,    -1,    78,
+      31,    78,    -1,    78,    32,    78,    -1,    25,    -1,    26,
+      -1,    -1,    25,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,   104,   104,   106,   108,   109,   110,   111,   112,   113,
+     114,   118,   122,   122,   122,   122,   122,   122,   122,   126,
+     127,   128,   129,   130,   131,   135,   136,   142,   150,   156,
+     164,   174,   176,   177,   178,   179,   180,   181,   184,   192,
+     198,   208,   214,   220,   223,   225,   236,   237,   242,   251,
+     256,   264,   267,   269,   270,   271,   272,   273,   276,   282,
+     293,   299,   309,   311,   316,   324,   332,   335,   337,   338,
+     339,   344,   351,   356,   364,   367,   369,   370,   371,   374,
+     382,   389,   396,   402,   409,   411,   412,   413,   416,   424,
+     426,   431,   432,   435,   436,   437,   441,   442,   445,   446,
+     449,   450,   451,   452,   453,   454,   455,   458,   459,   462,
+     463
+};
+#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", "T_MAINMENU", "T_MENU", "T_ENDMENU",
+  "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG",
+  "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS",
+  "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_RANGE",
+  "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL",
+  "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL",
+  "T_NOT", "$accept", "input", "stmt_list", "option_name", "common_stmt",
+  "option_error", "config_entry_start", "config_stmt",
+  "menuconfig_entry_start", "menuconfig_stmt", "config_option_list",
+  "config_option", "symbol_option", "symbol_option_list",
+  "symbol_option_arg", "choice", "choice_entry", "choice_end",
+  "choice_stmt", "choice_option_list", "choice_option", "choice_block",
+  "if_entry", "if_end", "if_stmt", "if_block", "menu", "menu_entry",
+  "menu_end", "menu_stmt", "menu_block", "source_stmt", "comment",
+  "comment_stmt", "help_start", "help", "depends_list", "depends",
+  "prompt_stmt_opt", "prompt", "end", "nl", "if_expr", "expr", "symbol",
+  "word_opt", 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,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287,   288,   289
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    35,    36,    37,    37,    37,    37,    37,    37,    37,
+      37,    37,    38,    38,    38,    38,    38,    38,    38,    39,
+      39,    39,    39,    39,    39,    40,    40,    41,    42,    43,
+      44,    45,    45,    45,    45,    45,    45,    45,    46,    46,
+      46,    46,    46,    47,    48,    48,    49,    49,    50,    51,
+      52,    53,    54,    54,    54,    54,    54,    54,    55,    55,
+      55,    55,    56,    56,    57,    58,    59,    60,    60,    60,
+      60,    61,    62,    63,    64,    65,    65,    65,    65,    66,
+      67,    68,    69,    70,    71,    71,    71,    71,    72,    73,
+      73,    74,    74,    75,    75,    75,    76,    76,    77,    77,
+      78,    78,    78,    78,    78,    78,    78,    79,    79,    80,
+      80
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     1,     0,     2,     2,     2,     4,     2,     4,
+       4,     3,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     3,     2,     3,     2,     3,
+       2,     0,     2,     2,     2,     2,     2,     2,     3,     4,
+       4,     4,     5,     3,     0,     3,     0,     2,     3,     2,
+       1,     3,     0,     2,     2,     2,     2,     2,     4,     3,
+       2,     4,     0,     2,     3,     1,     3,     0,     2,     2,
+       2,     3,     2,     1,     3,     0,     2,     2,     2,     3,
+       3,     2,     2,     2,     0,     2,     2,     2,     4,     0,
+       2,     1,     1,     2,     2,     2,     1,     2,     0,     2,
+       1,     3,     3,     3,     2,     3,     3,     1,     1,     0,
+       1
+};
+
+/* 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[] =
+{
+       3,     0,     0,     1,     0,     0,     0,     0,     0,   109,
+       0,     0,     0,     0,     0,     0,    12,    16,    13,    14,
+      18,    15,    17,     0,    19,     0,     4,    31,    22,    31,
+      23,    52,    62,     5,    67,    20,    84,    75,     6,    24,
+      84,    21,     8,    11,    91,    92,     0,     0,    93,     0,
+     110,     0,    94,     0,     0,     0,   107,   108,     0,     0,
+       0,   100,    95,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,    96,     7,    71,    79,    48,    80,    27,
+      29,     0,   104,     0,     0,    64,     0,     0,     9,    10,
+       0,     0,     0,     0,    89,     0,     0,     0,    44,     0,
+      37,    36,    32,    33,     0,    35,    34,     0,     0,    89,
+       0,    56,    57,    53,    55,    54,    63,    51,    50,    68,
+      70,    66,    69,    65,    86,    87,    85,    76,    78,    74,
+      77,    73,    97,   103,   105,   106,   102,   101,    26,    82,
+       0,    98,     0,    98,    98,    98,     0,     0,     0,    83,
+      60,    98,     0,    98,     0,     0,     0,    38,    90,     0,
+       0,    98,    46,    43,    25,     0,    59,     0,    88,    99,
+      39,    40,    41,     0,     0,    45,    58,    61,    42,    47
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int16 yydefgoto[] =
+{
+      -1,     1,     2,    25,    26,   101,    27,    28,    29,    30,
+      65,   102,   103,   147,   175,    31,    32,   117,    33,    67,
+     113,    68,    34,   121,    35,    69,    36,    37,   129,    38,
+      71,    39,    40,    41,   104,   105,    70,   106,   142,   143,
+      42,    74,   156,    60,    61,    51
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -80
+static const yytype_int16 yypact[] =
+{
+     -80,     2,   132,   -80,   -13,    -1,    -1,    -2,    -1,     9,
+      33,    -1,    27,    40,    -3,    38,   -80,   -80,   -80,   -80,
+     -80,   -80,   -80,    71,   -80,    77,   -80,   -80,   -80,   -80,
+     -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,
+     -80,   -80,   -80,   -80,   -80,   -80,    57,    61,   -80,    63,
+     -80,    76,   -80,    87,   101,   133,   -80,   -80,    -3,    -3,
+     195,    -6,   -80,   136,   149,    39,   104,    65,   150,     5,
+     194,     5,   167,   -80,   176,   -80,   -80,   -80,   -80,   -80,
+     -80,    68,   -80,    -3,    -3,   176,    72,    72,   -80,   -80,
+     177,   187,    78,    -1,    -1,    -3,   196,    72,   -80,   222,
+     -80,   -80,   -80,   -80,   221,   -80,   -80,   205,    -1,    -1,
+     211,   -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,
+     -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,
+     -80,   -80,   -80,   -80,   206,   -80,   -80,   -80,   -80,   -80,
+      -3,   223,   209,   223,   197,   223,    72,     7,   210,   -80,
+     -80,   223,   212,   223,   201,    -3,   213,   -80,   -80,   214,
+     215,   223,   208,   -80,   -80,   216,   -80,   217,   -80,   113,
+     -80,   -80,   -80,   218,    -1,   -80,   -80,   -80,   -80,   -80
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int16 yypgoto[] =
+{
+     -80,   -80,   -80,   -80,   122,   -34,   -80,   -80,   -80,   -80,
+     220,   -80,   -80,   -80,   -80,   -80,   -80,   -80,    59,   -80,
+     -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,   -80,   125,
+     -80,   -80,   -80,   -80,   -80,   183,   219,    22,   142,    -5,
+     147,   192,    69,   -54,   -79,   -80
+};
+
+/* 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 -82
+static const yytype_int16 yytable[] =
+{
+      46,    47,     3,    49,    81,    82,    53,   136,   137,     6,
+       7,     8,     9,    10,    11,    12,    13,    43,   146,    14,
+      15,    86,    56,    57,    44,    45,    58,    87,    48,   134,
+     135,    59,   162,   112,    50,    24,   125,   163,   125,   -28,
+      90,   144,   -28,   -28,   -28,   -28,   -28,   -28,   -28,   -28,
+     -28,    91,    54,   -28,   -28,    92,   -28,    93,    94,    95,
+      96,    97,    98,    52,    99,    55,    90,   161,    62,   100,
+     -49,   -49,    63,   -49,   -49,   -49,   -49,    91,    64,   -49,
+     -49,    92,   107,   108,   109,   110,   154,    73,   141,   115,
+      99,    75,   126,    76,   126,   111,   133,    56,    57,    83,
+      84,   169,   140,   151,   -30,    90,    77,   -30,   -30,   -30,
+     -30,   -30,   -30,   -30,   -30,   -30,    91,    78,   -30,   -30,
+      92,   -30,    93,    94,    95,    96,    97,    98,   120,    99,
+     128,    79,    -2,     4,   100,     5,     6,     7,     8,     9,
+      10,    11,    12,    13,    83,    84,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,     7,     8,    23,    10,    11,
+      12,    13,    24,    80,    14,    15,    88,   -81,    90,   179,
+     -81,   -81,   -81,   -81,   -81,   -81,   -81,   -81,   -81,    89,
+      24,   -81,   -81,    92,   -81,   -81,   -81,   -81,   -81,   -81,
+     116,   119,    99,   127,   122,    90,   130,   124,   -72,   -72,
+     -72,   -72,   -72,   -72,   -72,   -72,   132,   138,   -72,   -72,
+      92,   155,   158,   159,   160,   118,   123,   139,   131,    99,
+     165,   145,   167,   148,   124,    73,    83,    84,    83,    84,
+     173,   168,    83,    84,   149,   150,   153,   155,    84,   157,
+     164,   174,   166,   170,   171,   172,   176,   177,   178,    66,
+     114,   152,    85,     0,     0,     0,     0,     0,     0,    72
+};
+
+static const yytype_int16 yycheck[] =
+{
+       5,     6,     0,     8,    58,    59,    11,    86,    87,     4,
+       5,     6,     7,     8,     9,    10,    11,    30,    97,    14,
+      15,    27,    25,    26,    25,    26,    29,    33,    30,    83,
+      84,    34,    25,    67,    25,    30,    70,    30,    72,     0,
+       1,    95,     3,     4,     5,     6,     7,     8,     9,    10,
+      11,    12,    25,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,    23,    30,    25,    25,     1,   146,    30,    30,
+       5,     6,     1,     8,     9,    10,    11,    12,     1,    14,
+      15,    16,    17,    18,    19,    20,   140,    30,    93,    67,
+      25,    30,    70,    30,    72,    30,    28,    25,    26,    31,
+      32,   155,    24,   108,     0,     1,    30,     3,     4,     5,
+       6,     7,     8,     9,    10,    11,    12,    30,    14,    15,
+      16,    17,    18,    19,    20,    21,    22,    23,    69,    25,
+      71,    30,     0,     1,    30,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    31,    32,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,     5,     6,    25,     8,     9,
+      10,    11,    30,    30,    14,    15,    30,     0,     1,   174,
+       3,     4,     5,     6,     7,     8,     9,    10,    11,    30,
+      30,    14,    15,    16,    17,    18,    19,    20,    21,    22,
+      68,    69,    25,    71,    69,     1,    71,    30,     4,     5,
+       6,     7,     8,     9,    10,    11,    30,    30,    14,    15,
+      16,    14,   143,   144,   145,    68,    69,    30,    71,    25,
+     151,    25,   153,     1,    30,    30,    31,    32,    31,    32,
+     161,    30,    31,    32,    13,    30,    25,    14,    32,    30,
+      30,    33,    30,    30,    30,    30,    30,    30,    30,    29,
+      67,   109,    60,    -1,    -1,    -1,    -1,    -1,    -1,    40
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,    36,    37,     0,     1,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    14,    15,    16,    17,    18,    19,
+      20,    21,    22,    25,    30,    38,    39,    41,    42,    43,
+      44,    50,    51,    53,    57,    59,    61,    62,    64,    66,
+      67,    68,    75,    30,    25,    26,    74,    74,    30,    74,
+      25,    80,    30,    74,    25,    25,    25,    26,    29,    34,
+      78,    79,    30,     1,     1,    45,    45,    54,    56,    60,
+      71,    65,    71,    30,    76,    30,    30,    30,    30,    30,
+      30,    78,    78,    31,    32,    76,    27,    33,    30,    30,
+       1,    12,    16,    18,    19,    20,    21,    22,    23,    25,
+      30,    40,    46,    47,    69,    70,    72,    17,    18,    19,
+      20,    30,    40,    55,    70,    72,    39,    52,    75,    39,
+      53,    58,    64,    75,    30,    40,    72,    39,    53,    63,
+      64,    75,    30,    28,    78,    78,    79,    79,    30,    30,
+      24,    74,    73,    74,    78,    25,    79,    48,     1,    13,
+      30,    74,    73,    25,    78,    14,    77,    30,    77,    77,
+      77,    79,    25,    30,    30,    77,    30,    77,    30,    78,
+      30,    30,    30,    77,    33,    49,    30,    30,    30,    74
+};
+
+#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 (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 (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#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); \
+      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)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (!yyvaluep)
+    return;
+# 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)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+  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 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    yytype_int16 *bottom;
+    yytype_int16 *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  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)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+    YYSTYPE *yyvsp;
+    int yyrule;
+#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++)
+    {
+      fprintf (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+                      &(yyvsp[(yyi + 1) - (yynrhs)])
+                                      );
+      fprintf (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)         \
+do {                                   \
+  if (yydebug)                         \
+    yy_reduce_print (yyvsp, Rule); \
+} 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
+
+\f
+
+#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 */
+\f
+
+/*-----------------------------------------------.
+| 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)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  YYUSE (yyvaluep);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+      case 51: /* "choice_entry" */
+
+       {
+       fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+               (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+       if (current_menu == (yyvaluep->menu))
+               menu_end_menu();
+};
+
+       break;
+      case 57: /* "if_entry" */
+
+       {
+       fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+               (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+       if (current_menu == (yyvaluep->menu))
+               menu_end_menu();
+};
+
+       break;
+      case 62: /* "menu_entry" */
+
+       {
+       fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+               (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+       if (current_menu == (yyvaluep->menu))
+               menu_end_menu();
+};
+
+       break;
+
+      default:
+       break;
+    }
+}
+\f
+
+/* 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);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol.  */
+int yychar;
+
+/* The semantic value of the look-ahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#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)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+  
+  int yystate;
+  int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Look-ahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack.  */
+  yytype_int16 yyssa[YYINITDEPTH];
+  yytype_int16 *yyss = yyssa;
+  yytype_int16 *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  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);
+       YYSTACK_RELOCATE (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));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     look-ahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to look-ahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a look-ahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead 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;
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token unless it is eof.  */
+  if (yychar != YYEOF)
+    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 8:
+
+    { zconf_error("unexpected end statement"); ;}
+    break;
+
+  case 9:
+
+    { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); ;}
+    break;
+
+  case 10:
+
+    {
+       zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[(2) - (4)].id)->name);
+;}
+    break;
+
+  case 11:
+
+    { zconf_error("invalid statement"); ;}
+    break;
+
+  case 25:
+
+    { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); ;}
+    break;
+
+  case 26:
+
+    { zconf_error("invalid option"); ;}
+    break;
+
+  case 27:
+
+    {
+       struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0);
+       sym->flags |= SYMBOL_OPTIONAL;
+       menu_add_entry(sym);
+       printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+;}
+    break;
+
+  case 28:
+
+    {
+       menu_end_entry();
+       printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 29:
+
+    {
+       struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0);
+       sym->flags |= SYMBOL_OPTIONAL;
+       menu_add_entry(sym);
+       printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+;}
+    break;
+
+  case 30:
+
+    {
+       if (current_entry->prompt)
+               current_entry->prompt->type = P_MENU;
+       else
+               zconfprint("warning: menuconfig statement without prompt");
+       menu_end_entry();
+       printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 38:
+
+    {
+       menu_set_type((yyvsp[(1) - (3)].id)->stype);
+       printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+               zconf_curname(), zconf_lineno(),
+               (yyvsp[(1) - (3)].id)->stype);
+;}
+    break;
+
+  case 39:
+
+    {
+       menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
+       printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 40:
+
+    {
+       menu_add_expr(P_DEFAULT, (yyvsp[(2) - (4)].expr), (yyvsp[(3) - (4)].expr));
+       if ((yyvsp[(1) - (4)].id)->stype != S_UNKNOWN)
+               menu_set_type((yyvsp[(1) - (4)].id)->stype);
+       printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+               zconf_curname(), zconf_lineno(),
+               (yyvsp[(1) - (4)].id)->stype);
+;}
+    break;
+
+  case 41:
+
+    {
+       menu_add_symbol(P_SELECT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr));
+       printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 42:
+
+    {
+       menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr));
+       printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 45:
+
+    {
+       struct kconf_id *id = kconf_id_lookup((yyvsp[(2) - (3)].string), strlen((yyvsp[(2) - (3)].string)));
+       if (id && id->flags & TF_OPTION)
+               menu_add_option(id->token, (yyvsp[(3) - (3)].string));
+       else
+               zconfprint("warning: ignoring unknown option %s", (yyvsp[(2) - (3)].string));
+       free((yyvsp[(2) - (3)].string));
+;}
+    break;
+
+  case 46:
+
+    { (yyval.string) = NULL; ;}
+    break;
+
+  case 47:
+
+    { (yyval.string) = (yyvsp[(2) - (2)].string); ;}
+    break;
+
+  case 48:
+
+    {
+       struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), SYMBOL_CHOICE);
+       sym->flags |= SYMBOL_AUTO;
+       menu_add_entry(sym);
+       menu_add_expr(P_CHOICE, NULL, NULL);
+       printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 49:
+
+    {
+       (yyval.menu) = menu_add_menu();
+;}
+    break;
+
+  case 50:
+
+    {
+       if (zconf_endtoken((yyvsp[(1) - (1)].id), T_CHOICE, T_ENDCHOICE)) {
+               menu_end_menu();
+               printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+       }
+;}
+    break;
+
+  case 58:
+
+    {
+       menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
+       printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 59:
+
+    {
+       if ((yyvsp[(1) - (3)].id)->stype == S_BOOLEAN || (yyvsp[(1) - (3)].id)->stype == S_TRISTATE) {
+               menu_set_type((yyvsp[(1) - (3)].id)->stype);
+               printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+                       zconf_curname(), zconf_lineno(),
+                       (yyvsp[(1) - (3)].id)->stype);
+       } else
+               YYERROR;
+;}
+    break;
+
+  case 60:
+
+    {
+       current_entry->sym->flags |= SYMBOL_OPTIONAL;
+       printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 61:
+
+    {
+       if ((yyvsp[(1) - (4)].id)->stype == S_UNKNOWN) {
+               menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr));
+               printd(DEBUG_PARSE, "%s:%d:default\n",
+                       zconf_curname(), zconf_lineno());
+       } else
+               YYERROR;
+;}
+    break;
+
+  case 64:
+
+    {
+       printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+       menu_add_entry(NULL);
+       menu_add_dep((yyvsp[(2) - (3)].expr));
+       (yyval.menu) = menu_add_menu();
+;}
+    break;
+
+  case 65:
+
+    {
+       if (zconf_endtoken((yyvsp[(1) - (1)].id), T_IF, T_ENDIF)) {
+               menu_end_menu();
+               printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+       }
+;}
+    break;
+
+  case 71:
+
+    {
+       menu_add_entry(NULL);
+       menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL);
+       printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 72:
+
+    {
+       (yyval.menu) = menu_add_menu();
+;}
+    break;
+
+  case 73:
+
+    {
+       if (zconf_endtoken((yyvsp[(1) - (1)].id), T_MENU, T_ENDMENU)) {
+               menu_end_menu();
+               printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+       }
+;}
+    break;
+
+  case 79:
+
+    {
+       printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+       zconf_nextfile((yyvsp[(2) - (3)].string));
+;}
+    break;
+
+  case 80:
+
+    {
+       menu_add_entry(NULL);
+       menu_add_prompt(P_COMMENT, (yyvsp[(2) - (3)].string), NULL);
+       printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 81:
+
+    {
+       menu_end_entry();
+;}
+    break;
+
+  case 82:
+
+    {
+       printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+       zconf_starthelp();
+;}
+    break;
+
+  case 83:
+
+    {
+       current_entry->help = (yyvsp[(2) - (2)].string);
+;}
+    break;
+
+  case 88:
+
+    {
+       menu_add_dep((yyvsp[(3) - (4)].expr));
+       printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 90:
+
+    {
+       menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr));
+;}
+    break;
+
+  case 93:
+
+    { (yyval.id) = (yyvsp[(1) - (2)].id); ;}
+    break;
+
+  case 94:
+
+    { (yyval.id) = (yyvsp[(1) - (2)].id); ;}
+    break;
+
+  case 95:
+
+    { (yyval.id) = (yyvsp[(1) - (2)].id); ;}
+    break;
+
+  case 98:
+
+    { (yyval.expr) = NULL; ;}
+    break;
+
+  case 99:
+
+    { (yyval.expr) = (yyvsp[(2) - (2)].expr); ;}
+    break;
+
+  case 100:
+
+    { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); ;}
+    break;
+
+  case 101:
+
+    { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
+    break;
+
+  case 102:
+
+    { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
+    break;
+
+  case 103:
+
+    { (yyval.expr) = (yyvsp[(2) - (3)].expr); ;}
+    break;
+
+  case 104:
+
+    { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); ;}
+    break;
+
+  case 105:
+
+    { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
+    break;
+
+  case 106:
+
+    { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
+    break;
+
+  case 107:
+
+    { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); ;}
+    break;
+
+  case 108:
+
+    { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); ;}
+    break;
+
+  case 109:
+
+    { (yyval.string) = NULL; ;}
+    break;
+
+
+/* Line 1267 of yacc.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 (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 (yymsg);
+         }
+       else
+         {
+           yyerror (YY_("syntax error"));
+           if (yysize != 0)
+             goto yyexhaustedlab;
+         }
+      }
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse look-ahead 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);
+         yychar = YYEMPTY;
+       }
+    }
+
+  /* Else will try to reuse look-ahead 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);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  *++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;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEOF && yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+                yytoken, &yylval);
+  /* 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);
+      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);
+}
+
+
+
+
+
+void conf_parse(const char *name)
+{
+       struct symbol *sym;
+       int i;
+
+       zconf_initscan(name);
+
+       sym_init();
+       menu_init();
+       modules_sym = sym_lookup(NULL, 0);
+       modules_sym->type = S_BOOLEAN;
+       modules_sym->flags |= SYMBOL_AUTO;
+       rootmenu.prompt = menu_add_prompt(P_MENU, "firmly.0cpm Configuration", NULL);
+
+#if YYDEBUG
+       if (getenv("ZCONF_DEBUG"))
+               zconfdebug = 1;
+#endif
+       zconfparse();
+       if (zconfnerrs)
+               exit(1);
+       if (!modules_sym->prop) {
+               struct property *prop;
+
+               prop = prop_alloc(P_DEFAULT, modules_sym);
+               prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
+       }
+       menu_finalize(&rootmenu);
+       for_all_symbols(i, sym) {
+               if (sym_check_deps(sym))
+                       zconfnerrs++;
+        }
+       if (zconfnerrs)
+               exit(1);
+       sym_set_change_count(1);
+}
+
+const char *zconf_tokenname(int token)
+{
+       switch (token) {
+       case T_MENU:            return "menu";
+       case T_ENDMENU:         return "endmenu";
+       case T_CHOICE:          return "choice";
+       case T_ENDCHOICE:       return "endchoice";
+       case T_IF:              return "if";
+       case T_ENDIF:           return "endif";
+       case T_DEPENDS:         return "depends";
+       }
+       return "<token>";
+}
+
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
+{
+       if (id->token != endtoken) {
+               zconf_error("unexpected '%s' within %s block",
+                       kconf_id_strings + id->name, zconf_tokenname(starttoken));
+               zconfnerrs++;
+               return false;
+       }
+       if (current_menu->file != current_file) {
+               zconf_error("'%s' in different file than '%s'",
+                       kconf_id_strings + id->name, zconf_tokenname(starttoken));
+               fprintf(stderr, "%s:%d: location of the '%s'\n",
+                       current_menu->file->name, current_menu->lineno,
+                       zconf_tokenname(starttoken));
+               zconfnerrs++;
+               return false;
+       }
+       return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+       va_list ap;
+
+       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+       va_start(ap, err);
+       vfprintf(stderr, err, ap);
+       va_end(ap);
+       fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+       va_list ap;
+
+       zconfnerrs++;
+       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+       va_start(ap, err);
+       vfprintf(stderr, err, ap);
+       va_end(ap);
+       fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+#if YYDEBUG
+       fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
+}
+
+void print_quoted_string(FILE *out, const char *str)
+{
+       const char *p;
+       int len;
+
+       putc('"', out);
+       while ((p = strchr(str, '"'))) {
+               len = p - str;
+               if (len)
+                       fprintf(out, "%.*s", len, str);
+               fputs("\\\"", out);
+               str = p + 1;
+       }
+       fputs(str, out);
+       putc('"', out);
+}
+
+void print_symbol(FILE *out, struct menu *menu)
+{
+       struct symbol *sym = menu->sym;
+       struct property *prop;
+
+       if (sym_is_choice(sym))
+               fprintf(out, "choice\n");
+       else
+               fprintf(out, "config %s\n", sym->name);
+       switch (sym->type) {
+       case S_BOOLEAN:
+               fputs("  boolean\n", out);
+               break;
+       case S_TRISTATE:
+               fputs("  tristate\n", out);
+               break;
+       case S_STRING:
+               fputs("  string\n", out);
+               break;
+       case S_INT:
+               fputs("  integer\n", out);
+               break;
+       case S_HEX:
+               fputs("  hex\n", out);
+               break;
+       default:
+               fputs("  ???\n", out);
+               break;
+       }
+       for (prop = sym->prop; prop; prop = prop->next) {
+               if (prop->menu != menu)
+                       continue;
+               switch (prop->type) {
+               case P_PROMPT:
+                       fputs("  prompt ", out);
+                       print_quoted_string(out, prop->text);
+                       if (!expr_is_yes(prop->visible.expr)) {
+                               fputs(" if ", out);
+                               expr_fprint(prop->visible.expr, out);
+                       }
+                       fputc('\n', out);
+                       break;
+               case P_DEFAULT:
+                       fputs( "  default ", out);
+                       expr_fprint(prop->expr, out);
+                       if (!expr_is_yes(prop->visible.expr)) {
+                               fputs(" if ", out);
+                               expr_fprint(prop->visible.expr, out);
+                       }
+                       fputc('\n', out);
+                       break;
+               case P_CHOICE:
+                       fputs("  #choice value\n", out);
+                       break;
+               default:
+                       fprintf(out, "  unknown prop %d!\n", prop->type);
+                       break;
+               }
+       }
+       if (menu->help) {
+               int len = strlen(menu->help);
+               while (menu->help[--len] == '\n')
+                       menu->help[len] = 0;
+               fprintf(out, "  help\n%s\n", menu->help);
+       }
+       fputc('\n', out);
+}
+
+void zconfdump(FILE *out)
+{
+       struct property *prop;
+       struct symbol *sym;
+       struct menu *menu;
+
+       menu = rootmenu.list;
+       while (menu) {
+               if ((sym = menu->sym))
+                       print_symbol(out, menu);
+               else if ((prop = menu->prompt)) {
+                       switch (prop->type) {
+                       case P_COMMENT:
+                               fputs("\ncomment ", out);
+                               print_quoted_string(out, prop->text);
+                               fputs("\n", out);
+                               break;
+                       case P_MENU:
+                               fputs("\nmenu ", out);
+                               print_quoted_string(out, prop->text);
+                               fputs("\n", out);
+                               break;
+                       default:
+                               ;
+                       }
+                       if (!expr_is_yes(prop->visible.expr)) {
+                               fputs("  depends ", out);
+                               expr_fprint(prop->visible.expr, out);
+                               fputc('\n', out);
+                       }
+                       fputs("\n", out);
+               }
+
+               if (menu->list)
+                       menu = menu->list;
+               else if (menu->next)
+                       menu = menu->next;
+               else while ((menu = menu->parent)) {
+                       if (menu->prompt && menu->prompt->type == P_MENU)
+                               fputs("\nendmenu\n", out);
+                       if (menu->next) {
+                               menu = menu->next;
+                               break;
+                       }
+               }
+       }
+}
+
+#include "lex.zconf.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
+
diff --git a/doc/top2bottom.rst b/doc/top2bottom.rst
new file mode 100644 (file)
index 0000000..4a58405
--- /dev/null
@@ -0,0 +1,755 @@
+----------------------------------------------
+Kernel API between Phone Bottom and Top Halves
+----------------------------------------------
+
+This is the porting guide that explains what parts
+of 0cpm should be changed in order to make it run on
+new kinds of hardware.
+
+The 0cpm open source firmware for SIP phones is split
+into a device-dependent part (the bottom half) and a
+device-independent part (the top half).  These parts
+interact in the manner described below.
+
+       +----------------+----------------+
+        |                |  Applications  |
+        |  Top           +----------------+
+        |                |  Kernel        |
+       +----------------+----------------+
+        |  Bottom                         |
+       +---------------------------------+
+        |  Hardware                       |
+       +---------------------------------+
+
+
+
+Making changes to this phone firmware
+=====================================
+
+Here are a few guidelines to help you on your way with this code.
+
+
+Never mix top and bottom half code
+----------------------------------
+
+When porting this phone firmware to new hardware,
+you should never have to change code in the top half
+of the software.  If you feel a need to do so, please
+contact the developers, because you will either have
+misunderstood something about the structure, or you
+will have run into a situation that needs general
+treatment in this interface definition.
+
+If you additionally feel the need to extend the top half
+application for your own purposes, please be sure to
+keep the patches completely separate.  This helps to
+maintain a clear structure at all times.  We actively
+maintain this interface definition in a way to support
+this separation of concerns.  Note that even though we
+try to maintain clarity with separate patches to top
+and bottom halves, it still forms one program that
+cannot be separated.
+
+
+Source tree structure
+---------------------
+
+The source tree contains a few dedicated directories
+into which bottom half code should go.  Each original
+manufacturer of hardware has its own directory, so as
+to avoid clashing code.  This allows you to write code
+that is highly optimised for your use of the hardware.
+Even when the same processor architecture is used, it is
+still possible to embed knowledge about the rest of the
+hardware in your code.
+
+The following directories are designed for bottom half
+code, where MANUF should be replaced with your company
+name, or if it is not globally known or unique, your
+domain name.  Within the company, choose ``DEVICE``
+as a shorthand name to name a device or line of devices
+that can share the same binary firmware.
+
+* ``src/bottom/MANUF/`` contains the C and/or Assembly
+  code for your bottom half.  It is probably a good idea
+  to setup a subdirectory per line of device, and one or
+  more with common code.
+
+* ``src/bottom/MANUF/DEVICE/`` must contain a ``Makefile``
+  for use with GNU Make.
+  TODO: Or rules?
+
+* ``src/bottom/MANUF/include/`` contains the C headers
+  that describe how the C compiler from your toolchain
+  displays the data types exchanged with the bottom half.
+  At the very least, the directory contains a header file
+  for each product (or line of products) that share the
+  same bottom half code.
+
+* ``src/bottom/MANUF/DEVICE/include/`` must contain a
+  single file ``config.h`` that defines the configuration
+  of that type of device in terms of general compile-time
+  parameters for the top half.  This includes bottom-compatible
+  data type definitions used on the interface between the
+  bottom and top halves.
+
+You can just create and fill these directories when you start
+porting.  Your porting patch should only contain changes in
+these directories.  Please submit the toolchain as a separate
+package; you should not incllude it in the source tree.
+
+In additon, there are a few include files that define the
+upcall and downcall interface:
+
+* ``src/include/downcall.h`` contains the functions that must
+  be implemented in all bottom halves.
+
+* ``src/include/upcall.h`` contains the only functions that a
+  bottom half may invoke on the top half.
+
+The data types exchanged between bottom and top halves should be
+declared as part of the configuration file for the bottom half.
+This ensures compatibility of these data types with the bottom half
+code, also when it is written in Assembly language.
+
+TODO: Configuration information for ``make menuconfig``.
+
+
+Open source licensing
+---------------------
+
+You are welcome to sell your ported or otherwise changed
+phone firmware as part of a phone or as a separate piece
+of software, but do note that the GNU Public License on
+this code imposes a legal obligation to publish all
+changes at no cost, along with a free toolchain to build
+the code for your platform.  You should also make it
+possible for your users to migrate to versions of the
+firmware that were not created by you.
+
+The idea behind the use of the GPL is that you
+will gain much more from others than you will need to
+share with them; that is the central idea that makes
+open source such a powerful tool in commerce.  The legal
+obligation exists to ensure that nobody can profit from
+your work without sharing their improvements with you,
+and that works both ways.
+
+Needless to say, you are under
+no obligation to support firmware versions that you did
+not create as part of your production, sales or support.
+
+
+Upcalls and Downcalls
+=====================
+
+A function invocation from bottom half to top half is
+called an upcall; the functions supporting this are
+named ``top_XXX`` where ``XXX`` varies with the function
+being called.
+
+A function invocation from top half to bottom half is
+called a downcall; the functions supporting this are
+named ``bottom`` where ``XXX`` varies with the function
+being called.
+
+Upcalls are usually the result of some hardware-initiated
+event, such as an interrupt.  The idea of an upcall is
+to enable the top half to process newly arrived information,
+or a timeout, or whatever caused the upcall.
+
+Downcalls are usually made to access drivers, that is
+to achieve some generic effect in a device-dependent
+way.
+
+Upcall handler code may never invoke downcalls, and
+similarly, downcall handler code may never invoke
+upcalls.  If there is a need to trigger an effect in
+the layer that called you, you should set it up in some
+queue for later processing.
+
+
+Initialisation
+--------------
+
+When the phone is started, the bottom half starts up in
+a way that is determined by the hardware alone.  It will
+do minimal setup of the hardware, but only enough to make
+all future downcalls possible.
+
+The top half supports a function that will be started by
+the bottom half after initialisation::
+
+       void top_main (void);
+
+Although it follows the same naming convention, this
+is not really an upcall, in that it may actually spend time,
+block waiting and make downcalls.
+
+The top half ensures that this function never ends, so
+the bottom half can jump to it, rather than call it as
+a subroutine.  It is assumed that a sufficiently large
+stack has been setup by the bottom before this is done.
+To ensure that the stack cannot run out, the top will
+refrain from recursive calls.
+
+
+Asynchronous upcalls
+--------------------
+
+Upcalls occur due to external events such as when network packets
+arrive, when timers expire, or when a user operates a button.  It
+is generally good to process any such situations as soon as possible,
+and not to have to poll them.
+
+Since the bottom half usually receives asynchronous events
+as interrupts, it gains temporary control over the processor
+in an asynchronous manner.  It is possible to format the
+information to be communicated in a standard format and
+make an upcall with it, but the upcall must be setup to
+touch as little of the data structures as possible, that is,
+to be as supportive as possible towards asynchronous calls.
+Also, the upcall service function ``top_XXX`` is supposed
+to return very, very quickly and never to block on any
+condition.
+
+TODO: Allow parallel upcalls?  (a) same type, (b) diff type?
+
+The top half may block asynchronous upcalls for short
+periods.  This implements a so-called critical region,
+where the top half manipulates data that is also handled
+during an upcall.  The top half should never block in a
+critical region, nor should it do complex things.  The
+functions supporting asynchronous upcall blocking are::
+
+       void bottom_critical_begin (void);
+       void bottom_critical_end   (void);
+
+The definition of these functions may well be an
+assembler inline function to disable and enable interrupts.
+Being bottom calls, these functions may not be invoked
+in an upcall.
+
+The code structure for a critical region is::
+
+       #include <bottom.h>
+
+       // non-critical code
+       bottom_criticital_begin ();
+       // critical region
+       bottom_criticital_end ();
+       // non-critical code
+
+When the bottom invokes ``top_main()``, it has not yet
+enabled asynchronous upcalls, so after some setup this
+function must start by releasing the critical region::
+
+       #include <bottom.h>
+
+       void top_main (void) {
+               // top-half setup code
+               bottom_critical_region_end ();
+               while (1) {
+                       // main loop, normal operation
+               }
+       }
+
+
+Synchronous downcalls
+---------------------
+
+Downcalls are always synchronous in nature.  The top half is
+a single task, and as upcalls may never make downcalls, it
+is safe to assume that the downcall code need not be
+re-entrant.  This leads to a simplification of complexity in
+the bottom half.  As a result, porting the application to
+other platforms should be limited in complexity to the
+idiosynchracies of the target platform.
+
+
+Kernel scheduling
+=================
+
+The kernel implements a scheduling discipline that fulfills
+the following constraingts:
+
+* soft realtime scheduling
+* tickless scheduling inasfar as possible on the hardware
+* event scheduling instead of process switching
+* priority-levels separate expedited events from background work
+* applications support their own precedence order for user interaction
+
+
+Sleeping top-half
+-----------------
+
+If the top half has no work to do, it can rest by asking
+the bottom half to sleep until the next need for an upcall.
+It does this in two stages, to make sure that no race
+conditions occur due to upcalls between the check for no
+more work in the top half and asking the bottom half to
+yield until the next upcall::
+
+       #include <bottom.h>
+       
+       bottom_sleep_prepare ();
+       if ( /* nothing to do in the top half? */ ) {
+               bottom_sleep_commit (SLEEP_SNOOZE);
+       }
+
+If it turns out that there is work to be done after calling
+``bottom_sleep_prepare()``, then there is no need to cancel
+anything.  The next invocation will simply prepare once
+again.  The most likely implementation is a flag that is set
+during ``bottom_sleep_prepare()`` and cleared by any invocation
+of an upcall.  The ``bottom_sleep_commit()`` will atomically
+check the flag and only sleep while the flag is set.
+So, if an upcall occurred between ``bottom_sleep_prepare()`` and
+``bottom_sleep_commit()`` then the latter will return immediately.
+This way, the top half program acts as if it was just woken up
+on account of a newly processed upcall.
+
+There are two levels of sleep that the top half can request
+from the bottom half.  Snoozing is requested while calls are in
+progress, and a quick wakeup is anticipated.  Hibernation is
+requested when there are no active calls, and a long waited is
+anticipated until a major event such as a key press or an incoming
+network packet is needed before the phone should wakeup again.
+The two forms use ``SLEEP_SNOOZE`` and ``SLEEP_HIBERNATE`` as
+flags to ``bottom_sleep_commit()``.
+
+The idea is that the bottom half opts for a sleep mode with high
+responsiveness to interrupts when ``SLEEP_SNOOZE`` is requested,
+whereas the choice for ``SLEEP_HIBERNATE`` may take some recovery
+time.  For example, hibernation could involve stopping the clock
+for the processor, while hibernation may not do anything but stop
+the intake of instructions.
+
+
+Sleeping bottom-half
+--------------------
+
+It is possible to keep a top half sleeping even if there is
+a lot of activity in the bottom half.  For example, the
+bottom half can continuously scan the keyboard but not
+report anything through an upcall if nothing was pressed
+or released.
+
+In general, it is a principe of good design to look for
+ways to conserve energy; a phone is always switched
+on, and scanning buttons continously is basically a sign
+of bad design.  If the buttons are laid out in a matrix with
+input columns and output rows, it is probably good to only
+trigger on changes; when no button is pressed, a design may
+support selection of all columns at the same time, and
+wait until either row changes state.  Then it may wait a
+small time to enable debouncing.  When a key is pressed,
+it is usually sufficient to select only its column and wait
+until its row changes state back to the unpressed state.
+The only thing left then is to await a debouncing interval.
+
+Polling, in general, is a bad idea for a phone that spends
+most of its time doing nothing.  In short, it is a good idea
+to design the bottom-half for tickless operation.  The
+top-half will actively request timing, the network will
+raise an interrupt for incoming traffic, and nothing further
+is needed to keep the processor running.  A sleeping phone
+is a low-power phone, and it is usually straightforward to
+embed that desire into a piece of hardware.
+
+
+Top-half structure
+------------------
+
+Most data processed in the top half will be allocated statically.
+Instead of dynamic allocation routines for an unknown number of
+calls, is it safe to assume that no more calls can be processed
+than the number of lines on a phone, or perhaps two if the phone
+has a flash button instead of line buttons.  It is just an example,
+but it is generally expected that structures can be allocated at
+compile-time.
+
+The top-half software is single-tasking.  This is possible by
+making it event-driven, and have a scheduler to handle queues
+of events, each of which are delivered when it is their time.
+Examples of events range from time expiration to incoming
+phone calls, and their targets range from LED-flashing routines
+to connection-establishing SIP routines.  In all cases, the
+communication is through events.
+
+The software recognises a number of applications, each of which
+process their own events, and run in parallel on top of a
+simple kernel.  The task of the kernel is to provide the core
+mechanisms used in support of all applications, and it ranges
+over event handling, deliver and scheduling, as well as
+resource allocation and application dynamicity.  Outside the
+kernel, there are no support routines for upcalls, nor is it
+permitted to make downcalls such as interrupt blocking.
+
+The scheduler for the top-half handles events at priority
+levels.  This ensures that the most important events are
+handled immediately, 
+
+
+Top/Bottom API primitives
+=========================
+
+The bottom half implements generic drivers, and must therefore
+deliver preprocessed information to the top half when making
+an upcall, as well as processing generic information when it
+receives a bottom call.  The adaption should be trivial, but
+it is nonetheless good to understand their design motivations.
+
+
+LEDs
+----
+
+Most phone support LEDs in a variaty of shapes and locations.
+The phone's configration provides details, and assigns each
+phone a unique code in a gap-less range of index numbers.
+These indexes should be used to identify a LED on all
+communication between top and bottom halves.  More to the
+point, since LEDs do not generate upcalls, the numbering
+should always be used during downcalls.
+
+LEDs can display a number of colours, ranging from 0 for the
+least intrusive colour to a higher number for the most
+intrusive one.  The configuration specifies the highest
+number available.  Colour 0 is always the off state for a
+LED, and examples of other colours could be 1 for green
+and 2 for red, or on another LED it could be 1 for green,
+2 for amber and 3 for red.
+
+The function ``bottom_led_set (led, col)`` is defined to set
+a LED with index number ``led`` to colour number ``col``.
+
+The top half will arrange for LEDs to flash at a regular
+pace with a 50% duty cycle.  The top half has functions
+to construct a flashing pattern, but the bottom half is not
+expected to support flashing LEDs.
+
+If a display with backlight is configured, then the backlight
+LED will be defined as any other LED, with its own symbol and
+index number.  If the light intensity can be arranged in a
+number of steps, then the colouring scheme will show the
+number of grades, ranging from off at 0 to the brightest at
+the highest colour value specified for the backlight LED.
+
+
+Buttons
+-------
+
+Buttons only make upcalls.  If a LED is attached to a button,
+then the phone configuration describes that fact and the
+application logic in the top half will work accordingly.
+
+Buttons are grouped for practical purposes, as follows:
+
+* DTMF keys: ``0`` to ``9``, ``*``, ``#`` and ``A`` to ``D``
+* Function-bound keys like Hold, Transfer, Flash, Menu or Up/Down.
+* Line buttons, positioned to manage lines/accounts/calls.
+* Soft function buttons, usually positioned under a display.
+* Generic buttons, which can be programmed for speed dial and so on.
+
+The configuration files specify which are available, and
+how many of the various classes.  The bottom half is
+expected to setup translation tables from hardware inputs
+to the button class, and with the class the instance,
+conforming to the configuration.  The upcalls that report
+button actions are::
+
+       void top_button_press (buttonclass_t bcl, buttoncode_t cde);
+       void top_button_release (void);
+
+Debouncing the hardware is part of the bottom-half code, but
+timer-based repeats and even the processing of overlapping
+button presses are part of the top-half logic.  The upcall
+that reports a button being pressed implies that any other
+ones are released, even if this may not reflect what the
+hardware detects.  The ability to decode multiple buttons
+pressed at the same time is so dependent on hardware that
+the top half should refrain from interpreting such situations.
+This is also why the ``top_button_release()`` function has
+no arguments -- everything that may still be thought of as
+being pressed should be released after this call.
+
+
+Timers
+------
+
+General frameworks for timing tend to facilitate two kinds of
+timers; oneshot timers for a single delay, and interval timers
+that cause a timeout event at fixed intervals.  We combine
+both these kinds of timer in one concept.
+
+Timers are used to enable tickless realtime operation; in other
+words, there is no need for a regular timer interrupt in the
+top-half code, but if the application needs to wait a specific
+time it will simply create a timer that satisfies the
+application-desired waiting period.  The top half operates a
+queue of timer requests, and will send the shortest wait time
+down for implementation in a hardware timer.
+
+The bottom half is also expected to support a clock, from which
+a unix timestamp can be read, so the number of seconds since the
+epoch.  This is expected from the following downcalls to get and
+set the clock time::
+
+       uint32_t unixtime bottom_clock_get (void);
+       void bottom_clock_set (uint32_t unixtime);
+
+The top half will usually employ a protocol like SNTP to obtain
+the current time, and set the device clock accordingly.  The
+reason that the bottom half is involved is that it usually has
+the facilities to include realtime timers and thereby avoid
+code in the top half that would need to tick away once a second.
+This is especially useful for mobile devices that want to track
+time with the least possible power expenditure.
+
+Timeouts cannot be defined at a second granularity.  It is
+advised to use a millisecond granularity, as that captures the
+most detailed time measurements that a phone could handle.  It
+will usually be possible for hardware to accommodate such timing,
+but just in case this is not true there is a possibility in the
+configuration files to specify multiplication factors for timing.
+
+The current unixtime should be taken into account when setting
+a timer, even if that means that the range of an ``uint32_t``
+will be exhausted.  The overlapping part will be taken to
+apply, however.  At millisecond precisions, that means that
+time stretches of up to 24 days in the past and future can be
+represented.  That easily suffices for a phone.  The bottom half
+should select such a precision that times of up to a day in the
+past or future can be represented.  The function definition for
+setting the next timer interval is::
+
+       uint32_t bottom_timer_set (uint32_t timeout);
+
+The value returned is the previous value in the timer.  The special
+value ``TIMER_NULL`` is used to represent no timer setting.  By
+setting the timer to that value, it will stop running.  If the
+timer returns that time, then the timer was not using before.  When
+the bottom half invokes ``top_main()`` the timer is not running
+yet, so the first invocation of ``bottom_timer_set()`` will return
+``TIMER_NULL``.  If the time returned is a valid time, the top
+half may assume that the timer has not expired on that time.  In
+other words, the top half must either have the value as a later
+entry in its queue, or it must process the timeout returned.
+
+When the timer expires, it will make an upcall.  One of the tasks
+of this upcall is to return the next timer setting, usually taken
+from the next element in the timer queue maintained in the top
+half.  The bottom half will immediately check if the new timer
+expiration has already passed, and if so, it will make another
+upcall on that time, asking for yet another timeout.  The upcall
+is made as follows::
+
+       uint32_t top_timer_expiration (uint32_t timeout);
+
+The value sent up is the current timer expiration setting, and the
+value expected in return is the new expiration setting.  The
+function argument will never be ``TIMER_NULL``, but the value
+returned may be, to indicate that no more timeouts are currently
+requested.
+
+The normal course of action in ``top_timer_expiration`` is to do
+two things: First, schedule an event for top-half handling, and
+second, return the timer expiration value for the next timeout
+in the timer's queue.
+
+
+Network
+-------
+
+Network events relate to a few events:
+
+* Network connectivity going offline and coming online
+* The arrival of a network packet
+
+When booted, the network connectivity is assumed to be
+down.  Upon activation of upcalls, a check is made to
+see if network connectivity is live, and if so, the
+corresponding upcall is made to inform the top half.
+
+When the network goes online, the upcall made is
+``top_network_online (void)``.  Conversely, when it
+goes offline, the call made is
+``top_network_offline (void)``.  Where a difference
+between uplink and downlink can be detected, these
+calls apply to the uplink, and the downlink is
+ignored.  Switching between downlink and uplink
+is part of the bottom half responsibilities.
+
+The bottom half is also responsible for selecting
+packets destined for the phone.  It will make this
+distinction at the ethernet level, so based on the
+MAC address of incoming packets.  Unicast messages
+as well as broadcast packets are welcomed.  For each
+of those, an upcall exists::
+
+       top_network_unicast   (uint8_t *pkt, uint16_t pktlen, uint16_t ether_t);
+       top_network_broadcast (uint8_t *pkt, uint16_t pktlen, uint16_t ether_t);
+
+The ``pkt`` in both functions points to the part of the
+network packet after ethernet headers; only the
+ethernet type field is added as a 16-bit integer (after
+changing from network to host-local byte order) to guide
+further demultiplexing.
+
+At the ethernet level, there is no separate addressing
+mode for multicast traffic, so any multicast traffic
+results in a broadcasting upcall.
+
+
+
+Display
+-------
+
+TODO -- probably a generic format for the capabilities of a device,
+so that the kernel can make choices.  It is possible that a display
+represents multiple partial display resources; on a LCD-display there
+may be a part for number display, another for times, and a few dedicated
+symbols to represent state information; on a graphical display, parts of
+the screen may be reserved for softbuttons and/or line buttons.
+
+
+Sound
+-----
+
+A phone can have a number of sound channels, and the configuration
+of the platform defines which are available.  The possible channels
+are:
+
+* Handset.  This is the only obliged channel for sound I/O.
+* Speaker.  This usually combines with a microphone, although it
+  is possible that the handset microphone doubles with this function.
+  The bottom half should present this as a bidirectional channel and
+  hide any such choices.
+* Headset.
+
+In all cases, it is a good idea if the bottom half implements echo
+cancellation, because it has more insight in the construction of the
+sound channels than the top half.
+
+The top half can make the following downcall to instruct the bottom
+half about the current sound channel to use.  This implies dropping
+any channel currently in use::
+
+       bottom_soundchannel (SOUND_NONE);
+       bottom_soundchannel (SOUND_HANDSET);
+       bottom_soundchannel (SOUND_SPEAKER);
+       bottom_soundchannel (SOUND_HEADSET);
+
+Naturally, the bottom half will never be asked to support a sound
+channel that it has not made available in the phone's configuration.
+
+Note that handling any buttons for speakerphone access and such are
+usually done by the top half.
+
+
+Special hardware
+================
+
+We all recognise a phone when we see one, but not all devices have
+the same structure, and some need a special treatment.  A discussion
+on how these are handled follows.
+
+
+Analog Telephone Adapters
+-------------------------
+
+An ATA is not a complete phone, but it talks to a phone.  Even if
+there is just a metre of analog wire between these devices, it still
+constrains what can be done to/with the user.  If an ATA can also
+connect to a phone line, we suggest passing on the signals to the
+analog phone and not to pass it on to the top half.
+
+A bottom half implementing access to an ATA should act as if the
+attached phone is the phone that is being programmed:
+
+* The bottom half should detect a Flash button or, equivalently, a
+  brief press on the hook contact.
+
+* The bottom half should detect DTMF tones and deliver them as if
+  local keys had been pressed.  If the ATA supports rotary phones,
+  it should deliver rotary-dialed digits upstream as well; if so,
+  when the flash button or the hook contact is used within 4 seconds
+  of the end of dialing a digit, it should be delivered as ``*``.
+  (This is in support of ITAD dialing schemes.)
+
+* If a LED is present on the ATA, it should be reported by the bottom
+  half as a voicemail LED.  This will usually be why it was put there,
+  and its second function will be to hint the user about ZRTP status.
+
+* Lacking a display and LEDs, the ATA should make an effort to send
+  sound signals downstream.  Minimum signals to support are tones to
+  indicate insecure calls, to tell the user about the possibility to
+  setup a ZRTP secret, and reading out ZRTP digits to the user in
+  small chunks when Flash is used while they are available.
+
+
+Base stations
+-------------
+
+A base station is used for wireless calling, usually over DECT.
+Unlike a WiFi base station, these units actually handle SIP and
+RTP traffic and format it as user interface material.
+
+Base stations are special in that they can represent multiple
+handsets which each behave as an independent phone.  What this means
+is that the firmware in a base station must not act as a phone, but
+as an array of phones.
+
+If this array of phones was treated as completely independent phones
+there would be more overhead than strictly needed; it is quite likely
+that the handsets want to share numbers, and this is reflected in the
+interface by supporting shared lines among handsets.
+
+Additional features are possible, but not yet implemented in this
+software.  These features are all specific to the existence of an
+array of handsets:
+
+* Calls between handsets, as well as transferring calls to them or
+  pulling them into conference calls.  Until this is implemented, a
+  normal SIP call will have to be setup to a number recognised on
+  the destination handset.
+
+Note that base stations may be sufficiently complex to run Linux.
+If this is the case, then this phone application is best setup as
+an application on top of Linux.  That way, existing interface drivers
+for DECT, networking and so on can be taken from the Linux kernel.
+
+
+USB and Bluetooth phones
+------------------------
+
+These are usually simple sound I/O devices with limited additional
+facilities.  A USB phone may have keys, a bluetooth phone will not.
+In both cases, the simple phone and its base station must be treated
+as one whole, and that whole should implement the bottom half of this
+code.
+
+
+WiFi phones
+-----------
+
+WiFi phones are usually pretty clever; they tend to run Linux and
+have one process dedicated to telephony on top of that.  The negotiation
+of a WiFi connection (finding a base station, setting up encryption
+and so on) should all be dealt with in the bottom half, but other
+than that this phone application could be built as an application
+that runs on top of Linux.
+
+Remember to use a Linux kernel capable of IPv6 for this application.
+
+
+VoIP Routers
+------------
+
+VoIP routers are not as special as they may seem; inasfar as they
+connect to analog FXO and FXS lines they are basically the same as
+an ATA, and inasfar as they proxy SIP calls they are just routers.
+
+Having said that, a bottom implementation as a process on the
+existing infrastructure (like OpenWRT) is a good idea.
+
diff --git a/doc/usrman.rst b/doc/usrman.rst
new file mode 100644 (file)
index 0000000..fad5da7
--- /dev/null
@@ -0,0 +1,479 @@
+======================================
+0cpm Open Source Firmware: User Manual
+======================================
+
+
+Thank you for using the 0cpm Open Source Firmware on your device.
+The firmware brings you lots of possibilities to not just conduct
+normal phone calls, but also to do many, many other things.
+
+
+-------------------
+Operating the Phone
+-------------------
+
+This chapter explains how intuitive it is to operate your phone,
+in spite of its potential power.
+
+
+Concepts
+========
+
+Your phone is capable of handling multiple calls, forwarding them,
+setting them up in conferences, and so on.  Please take the time
+to read these instructions to learn how that works.
+
+
+Lines and Accounts
+------------------
+
+You can configure as many as 6 **accounts** or, if you like the
+old term, 6 **phone numbers**.  By default the phone will accept
+all incoming calls, but you can set it up to be more restrictive.
+
+Somewhat related are the 6 **lines** on your phone.  The idea of
+a line is that it connects you to a remote party, regardless of
+whether they called you or you called them.
+
+Every line is loosely related to an account.  If a call comes in
+for an account that is setup on a line, then usually that line
+will be used for the call.  But if the line is in use, an
+incoming call can just as easily spill over to another line.
+
+Outgoing calls work likewise.  If you press a line button, you
+initiate an outgoing call using the account for that line.  If you
+press the same line button again however, you start to cycle through
+the other accounts.  That way, you can dial out on an account even
+if its line button is in use.
+
+
+Soft buttons
+------------
+
+Your phone is equiped with 4 **soft buttons**, arranged under the
+display.  These buttons change their function depending on the
+state the phone is in.  The display prints the function assigned
+to each button at every moment in the display, just over the
+buttons.
+
+
+Speed-dial and Presence monitoring
+----------------------------------
+
+Your phone has no general-purpose buttons of its own, but extension
+units with many such buttons are available for it.  These add
+powerful facilities that can really help receptionists overview
+their company.
+
+The phone uses general-purpose buttons to configure speed-dial
+to a preset remote party, and to reveal presence information of
+that remote party.
+
+
+Step by step
+============
+
+These are a few actions, or steps, to get comfortable with the
+phone's operation.
+
+
+Outward dialing
+---------------
+
+While your phone has no accounts configured, you cannot dial any
+number anywhere, but there are still some calls you can make.  It
+works very much like you are used to.
+
+If you like to hear a dial tone, you will pickup the horn
+before dialing the number; if you prefer to start dialing right
+away you can do so and pickup the horn when done.  Count on
+your intuition to operate the phone's buttons for
+lines, speakerphone, headset and you will probably get the
+behaviour that makes sense to you.
+
+Even without any account setup, you can already make digital calls:
+
+**ISN**, Internet Subscriber Numbers
+
+       These are numbers like ``77*880`` with a local number before,
+       and a telephony domain number after an asterisk.  This is a
+       free telephony approach, much like the way domain names are
+       able to freely arrange email.
+
+**ENUM** for backward compatibility
+
+       This is a normal (officially e.164) phone number, which has
+       been registered with a digital alternative.  You will only
+       be able to contact digital phones over ENUM if they have
+       been registered; but inasfar as you can, there is no
+       difference from normal phone calls -- except that it is
+       done over the internet.
+
+       ENUM is an international structure, and the official version
+       will charge a small annual fee for the registration service.
+       There are also informal registers at no cost.  You can
+       register your normal phone number and have it translate to,
+       say, your ISN.
+
+Even if you are engaged in a call, you can setup a new call.
+Just press a free line button and dial as usual.
+
+
+Getting your own ISN assigned
+-----------------------------
+
+Your phone has no phone number configured.  If you would like
+to have one for free from 0cpm.org you should dial the following
+number::
+
+       77*880
+
+You will be assigned a number or, if you prefer, you can request
+sharing a previously assigned number (after jumping through a few
+hoops for reasons of security).  This number is also your service
+number for future settings related to 0cpm.
+
+If you plan to use multiple accounts, usually because you want to
+display several identities: you, your husband, your first company
+and your second, and so on.  If you want this you can just dial
+the same number from each line that you wish to setup with an ISN.
+
+While setting this up, you will also be offered the option of
+setting up ENUM.  Note that a few verification steps will make sure
+that you are only registering phone numbers that are actually
+yours.
+
+
+Receiving calls
+---------------
+
+Incoming calls will make the phone ring, and when you pickup the
+horn, or press a speaker button or similar, you will start to
+answer the call.  When you are already on the phone it will
+respond differently; instead of ringing out loud, it will ask
+for your attention by way of flashing lights and/or tones.
+
+If you are in a call and pickup another one, you are automatically
+placing the previous call on hold.  The phone will never connect
+parties unless you ask it to.  Likewise, it will not disconnect
+a call until you tell the phone to do that, by operating a
+button or putting down the horn, and so on.
+
+
+Calls, Conferences, Forwarding
+------------------------------
+
+A **call** is basically any number of parties talking to each
+other.  As a phone operator, you may or may not be involved, and
+the number of remote parties may be any number.
+
+A **conference call** is in that respect nothing special, it is
+merely an informal term to cover talking with more multiple parties
+at once.
+
+Similarly, **call forwarding** is just an application of the
+general idea of a call in which you as the phone operator are
+not involved anymore.
+
+The management of these principles is always the same.  
+
+If you are engaged in a call and want to step out, you can press
+the hold button.
+
+When you press a line button, you switch to the call, or conference,
+that is running under that button.  If you were in a call before you
+did, you will step out of that call.
+
+While you are engaged in a call, you can press the conference
+button followed by a remote party's line button to pull him in.
+If the remote party was engaged in a conference, then he will
+be pulled out of that conference.
+
+Call forwarding is nothing more than setting up a conference and
+then forgetting about it.  Depending on whether you set it up with
+the conference button or the transfer button, you will or will not
+see the lines still active.  As with old phone switches, you can
+choose between letting your original party hear the ringtone or
+not.
+
+
+Parking Calls
+-------------
+
+Another advanced facility of this firmware is call parking.  This means
+that a call is put on hold in such a way that it can be picked up
+elsewhere.  This is implemented by forwarding the call to the same
+number as it originally called; all phones answering to that number
+will then start to ring, including the one that parked the call.  You
+will then usually walk to another phone and complete the call there.
+
+Call parking can be arranged with a call transfer, but it can also be
+done in a simple way.  First you put the line you wish to park on hold,
+and then you put down the horn.  Since this terminates all calls on the
+phone, it is vital that you handle them first.  If not, you might park
+them all at the same time -- and release chaos!
+
+
+Using Speed-dial and Presence monitoring
+----------------------------------------
+
+Any general-purpose buttons on your phone can get a remote party
+assigned.  By default, only the last button is programmed with
+the 0cpm service number, ``77*880``.
+
+If you press a speed-dial button, it will simply dial its preset
+remote party.  Doing so after pressing the transfer button during
+a call will forward that call to the remote party.  Doing so after
+pressing the conference button in a call will invite the remote
+party into a conference call.
+
+The buttons contain a light to show presence information.  Not all
+accounts publish such information, but if they do it helps to see
+if a remote party is currently willing to answer calls.
+
+A phone can set its own presence with the do-not-disturb function.
+The usual setting is to be available, and the most extreme is to
+not answer any calls at all, but in between it is also possible
+to politely suggest through presentation information that calls
+are not preferred right now.  This principle is also widely used
+in chat.
+
+
+Call Security
+=============
+
+Your phone goes through lengths to protect you from eavesdropping,
+as well as sidepassing you to a wrong party.
+
+
+Secure information gathering
+----------------------------
+
+The phone needs to collect information on the internet about
+parties you intend to call; such parties may or may not have
+setup their information securely.  The 0cpm firmware will
+check it if they have, and reject false information.
+
+The default security setup for this is somewhat mild; it is
+possible to tighten security more, as detailed in the
+configuration settings chapter.
+
+
+Protection from eavesdropping
+-----------------------------
+
+Old telephony connected dumb phones over a clever network; with
+digital telephony, clever phones are connected over a simple,
+transport-only network.  This makes it possible to scramble all
+calls in protection against eavesdropping.
+
+Interestingly, it
+is in the most developed countries of the world that governments
+eavesdrop on citizens as though they had anything to do with
+their business; these same governments usually have a reputation
+of loosing private information on street corners and so on.
+Even if you have nothing to hide, you should wonder if you want
+to support governments wasting time on your calls instead of
+catching crooks (who already scrambled their calls anyway).
+We believe that it is useful to reposess the privacy of calls.
+
+The phone actively tries to scramble calls, but it also depends
+on the remoty party's support of the ZRTP mechanism used.  The
+phone uses the voicemail indicator to show if it scrambles.  If it
+burns solidly, then it failed.  If it is off, the call is
+secure.  If it flashes, which it will usually do with a new
+remote party, you will be presented with a small code to
+exchange with the remote party to ensure that no intermediate
+listener is following the call.  As soon as you verified the
+code and confirmed that it matched, you can have fully
+private conversations with that party.  Future calls will
+continue to profit from the one-time code check.
+
+
+---------------------
+Configuring the Phone
+---------------------
+
+Although several things can already be done with a phone without
+configuring it, it will usually be preferred to configure a phone
+until it behaves in a more personalised manner.
+
+
+The Configuration Menu
+======================
+
+The phone has a menu button, and pressing it brings up a menu.
+The arrow buttons can be used to select an option, and pressing
+OK will activate an option, making it confurable.
+
+
+Setting up Accounts
+===================
+
+The most important thing to do is setting up accounts, or as we used
+to call them, phone numbers.  As explained before, it suffices to
+dial ``77*880`` to receive a free ISN account that can be dialed
+from any phone compliant to this standard, anywhere on the IPv6
+internet.  And as explained, a phone number can be requested for
+every individual line on the phone, if so desired.
+
+By configuring the phone with the account for outgoing calls, the
+phone number will be shown on outgoing traffic, thus enabling
+others to see it, and call you back if they want to.  The default
+setup is to use anonymous calling, which is not very practical in
+online calling, especially because they also accept any incoming
+call.
+
+Phone numbers (or accounts) are configured under a line key.
+Therefore, you can have as many phone numbers as you have line
+keys.  To configure a line, press the line key, pull up the
+menu and select the account details.
+
+The number provided, which will look a bit like ``77*880``, should
+be setup as the username.  The password is used to login to the
+account in all sorts of circumstances.  The provider can be
+anything, but in case of an ISN it would be ``0cpm.org``.
+
+Further settings are not required, but they may be for other types
+of accounts; the outgoing proxy may be a local PBX, for instance,
+or a translation service that supports connectivity to the IPv4
+network of SIP telephony.
+
+
+Setting up Security through DNSSEC
+==================================
+
+TODO -- default look at AD, prefer TSIG
+
+
+Setting up Privacy through ZRTP
+===============================
+
+TODO -- default drop sessions, prefer storage
+
+
+Including Additional Services on the LAN
+========================================
+
+TODO -- how to add their address/port pairs
+
+
+
+----------------------------
+Configuring the 0cpm Service
+----------------------------
+
+The previous chapter discussed how to setup the phone; this chapter
+explains how the 0cpm service can be tweaked.  Of course this only
+applies to accounts setup as 0cpm accounts.
+
+
+Personalised phone "numbers"
+============================
+
+To get even more value out of the phone service, you can create
+fancy names like ``sip:your.name@0cpm.org`` that your friends
+and family can use from their computer.  The software they should
+use for this is a standard SIP-client that is IPv6-ready.
+
+TODO -- setup alias
+
+
+Advertised freedom
+==================
+
+The free service at 0cpm is paid for by small advertisements that
+are played while the phone is ringing.  For people calling you
+from outside 0cpm, an advertisement about 0cpm is played.  If you
+make a call through 0cpm, you can hear any kind of advertisement.
+
+You are never under any obligation to purchase anything from 0cpm
+or anyone else, but you should accept that the advertisements are
+what makes the free service possible.
+
+You should be aware that the advertisements will never make you
+wait longer.  As soon as the remote party picks up their phone,
+the advertisement will be terminated.
+
+Some people dislike advertisements, and would rather pay for the
+service.  This is certainly possible; we will than charge a small
+fee of a few cents for call setup, but there never be a charge
+per minute.  One payment will buy as many ad-free incoming calls
+as outgoing.
+
+Individuals using 0cpm can prepay for this benefit; companies will
+present us with more contact information and in return they will
+be billed after the calls are made.  Commercial service at 0cpm
+always includes ad-free operation, but at the same price level as
+private calls: a few cents for call setup, no per-minute charges.
+
+We always welcome new advertisers; their task is to create a
+message that quickly comes to the point, in order to pass on a
+message before the remote party picks up the call.  Ads must
+meet a certain level of professionality to qualify.  The price
+of an ad is the same few cents that are otherwise charged to
+the customer for call setup.
+
+
+Webphone
+========
+
+If you want your contacts to call you by pressing a button on your
+website, you should login to https://cockpit.0cpm.org/ and follow
+the instructions for including a webphone button on your site.
+
+The instructions can be used on any straightforward website, and
+consists of the following parts:
+
+* A bit of HTML code, to be pasted into your webpage(s)
+* A Java applet that must be installed on the same website
+* A button image that invites your visitors
+
+You can customise or replace the button if you like, it is just
+there as a starting point.  The reason that you need to install
+the applet on your own website is that security requirements for
+Java dictate it.
+
+When installed, your visitors see a button, they press it and
+their browser will open a webphone that calls you directly.
+The webphone is clever enough to create a temporary link to
+the IPv6 network if your visitor is not setup with IPv6 yet.
+
+
+----------------
+Business Options
+----------------
+
+Businesses usually require more advanced options, and understand
+that some services cost a bit of money.  Just like we have a
+collection of free consumer options under ``0cpm.org``, we also
+have a more extended collection of paid options under ``0cpm.ocm``.
+
+Any business can choose between the ``0cpm.org`` and ``0cpm.com``
+variety as they please -- it is certainly permitted to use the
+consumer-version for businesses, but the service has not really
+been designed for it.  Anyway, the things that are free under
+``0cpm.org`` are also for free under ``0cpm.com``.
+
+
+Internal number ranges
+======================
+
+It is common for businesses to require their own number range
+for internal use.  This is possible by acquiring an Internet
+Telephony Adminsitrative Domain, or ITAD for short.  This is
+used in an ISN as the part behind the asterisk; 0cpm uses
+``*880`` numbers so its ITAD is ``880``, and businesses can
+request their own and choose what numbers to place before the
+asterisk.
+
+The 0cpm switches are clever enough to understand that ranges
+of 3, 4 or 5 digits are aimed at the ITAD of the dialing party.
+So dialing such short numbers would automatically become a
+local call.
+
+Having an ITAD is only useful if the underlying technical
+setups are hosted.  This can be done by 0cpm or any other
+party.  Look on ``0cpm.com`` for options and pricing.
+
+
diff --git a/include/0cpm/netcmd.h b/include/0cpm/netcmd.h
new file mode 100644 (file)
index 0000000..9705ac7
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * bpfcmd.h -- Berkeley Packet Filter (ish) command set.
+ *
+ * This defines a virtual machine which is based on the BPF
+ * machine, as that is very suitable for taking apart packets,
+ * storing juicy parts on a scratchpad, and finally deciding
+ * what to do with it.
+ *
+ * The implementation, although inspired on the original
+ * BPF code, is a full reimplementation, mainly because the
+ * purpose is different: We want to generate code that is
+ * as efficient as possible, and that can be overridden
+ * locally by code that generates real assembler instructions
+ * optimised for a particular target platform.
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+
+/* Enable overriding per target, if so desired.  This supports
+ * direct translation of these instructions into real assembler,
+ * fit for very fast execution of these vital bits of network
+ * code.  The utility of this code is that it is simple and is
+ * a delay in the actual handling of the network packet.  The
+ * BPF setup is geared towards efficiency, although the added
+ * value of this implementation is even better -- compile-time
+ * translation into real machine instructions at the expense of
+ * the flexibility that BPF needs but that we can live without.
+ *
+ * All data is stored in network byte order.  For some machines,
+ * that implies conversions.  The commands below do as much of
+ * these conversions on constants, counting on a clever compiler
+ * to precalculate it before it turns into code.
+ */
+
+#ifdef HAVE_BPF_ASM_INLINES
+#include <asm/bpfcmd.h>
+#else
+
+
+/* The following functions mark the structure of a program:
+ *
+ * BPF_BEGIN(selhdr)
+ *     ...insn...
+ * BPF_LABEL(skip)
+ *     ...insn...
+ * BPF_END()
+ *
+ * main () {
+ *     uint32_t memspace [20];
+ *     uint8_t *pkt = ...;
+ *     uint32_t pktlen = ...;
+ *     uint32_t outcome = selhdr (pkt, pktlen, memspace);
+ *     ...
+ * }
+ */
+
+#define BPF_BEGIN(fname) uint32_t fname (uint8_t *P, uint32_t L, uint32_t *M) { register uint32_t A, X=htonl ((uint32_t) P), S; register int k;
+#define BPF_LABEL(l) l:
+#define BPF_END() }
+#define BPF_TAIL(fname) return (fname) (P, L, M);
+
+
+/* Opcodes and their meaning:
+ *
+ * LDB_        load byte and expand into accu A, unsigned
+ * LDH_        load halfword and expand into accu A, unsigned
+ * LDW_ load word into accu A
+ * LDX_ load word into indexreg X
+ * STB_        store byte from accu A
+ * STH_        store halfword from accu A
+ * STW_        store accu A
+ * STX_        store indexreg X
+ * JMP_        jump always
+ * JEQ_        jump on equal
+ * JNE_        jump on not equal
+ * JGT_        jump on greater
+ * JGE_        jump on greater or equal
+ * JLT_        jump on less
+ * JLE_        jump on less or equal
+ * JMN_        jump on nonzero after masking
+ * JMZ_        jump on zero after masking
+ * ADD_ add to accu A
+ * SUB_ subtract from accu A
+ * MUL_ multiply into accu A
+ * DIV_ divide accu A by
+ * AND_ bitwise and with accu A
+ * IOR_ bitwise inclusive or with accu A
+ * LSH_ left shift accu A
+ * RSH_ right shift accu A
+ * RET_ return value (finish program)
+ * 
+ * Note: TAX is renamed to LDX_ACC, TXA is renamed to LDW_REX
+ *
+ * Addressing modes
+ *
+ * _PKT k      [k]
+ * _IDX k      [X+k]   (X not shown as an operand)
+ * _LIT k      #k
+ * _LEN                #len    (not shown as an operand)
+ * _MEM k      M[k]    (M not shown as an operand)
+ * _ACC                A       (not shown as an operand)
+ * _TOP                A       (not shown, top half is used)
+ * _REX                X       (not shown as an operand)
+ * _ALW                        (no operand)
+ * _IP4                4*([k]&0x0f)    (not used in this phone)
+ * _SUM                S       (not shown as an operand)
+ *
+ * Local extensions:
+ * Commands    XOR_ STH_ STB_ SUM_ CLR_
+ * Modes       _TOP _SUM
+ * Combinations        ST*_PKT ST*_IDX 
+ */
+
+
+
+/* A few utility macros */
+
+#define BPF_GET32(a,o) htonl ( (((uint8_t *)a)[o+0] << 24) | (((uint8_t *)a)[o+1] << 16) | (((uint8_t *)a)[o+2] << 8) | ((uint8_t *)a)[o+3] )
+#define BPF_GET16(a,o) htonl (                                   (((uint8_t *)a)[o+0] << 8) | ((uint8_t *)a)[o+1] )
+#define BPF_GET08(a,o) htonl (                                                   ((uint8_t *)a)[o+0] )
+
+#define BPF_PUT32(a,o,v) ((uint8_t *)a)[o+0] = ((v) >> 24) & 0xff; \
+                         ((uint8_t *)a)[o+1] = ((v) >> 16) & 0xff; \
+                         ((uint8_t *)a)[o+2] = ((v) >>  8) & 0xff; \
+                         ((uint8_t *)a)[o+3] = ((v)      ) & 0xff;
+#define BPF_PUT16(a,o,v) ((uint8_t *)a)[o+0] = ((v) >>  8) & 0xff; \
+                         ((uint8_t *)a)[o+1] = ((v)      ) & 0xff;
+#define BPF_PUT08(a,o,v) ((uint8_t *)a)[o+0] = ((v)      ) & 0xff;
+
+
+/* Instruction macros.  These can be overridden by
+ * real assembly instructions for a particular target
+ * platform if HAVE_BPF_ASM_INLINES is defined for it.
+ *
+ * TODO: Handle _PKT mode boundaries?  How about _IDX?
+ */
+
+#ifdef DEBUG
+#  include <stdio.h>
+#  define DEBUG_REGS printf ("%d: A=%08X X=%08X\n", __LINE__, htonl (A), htonl (X))
+#  define DEBUG_REGS_PLUS printf ("%d: A=%08X X=%08X, S=%08X\n", __LINE__, htonl (A), htonl (X), S)
+#else
+#  define DEBUG_REGS
+#  define DEBUG_REGS_PLUS
+#endif
+
+#define RET_LIT(k)     return (uint32_t) (k);                  DEBUG_REGS;
+#define RET_ACC()      return A;                               DEBUG_REGS;
+#define LDW_PKT(k)     A = BPF_GET32 (P, (k));                 DEBUG_REGS;
+#define LDH_PKT(k)     A = BPF_GET16 (P, (k));                 DEBUG_REGS;
+#define LDB_PKT(k)     A = BPF_GET08 (P, (k));                 DEBUG_REGS;
+#define LDW_LEN()      A = htonl (L);                          DEBUG_REGS;
+#define LDX_LIT(k)     X = htonl (k);                          DEBUG_REGS;
+#define LDX_LEN()      X = htonl (L);                          DEBUG_REGS;
+#define LDW_IDX(k)     A = BPF_GET32 (ntohl(X), (k));          DEBUG_REGS;
+#define STW_IDX(k)     BPF_PUT32 (ntohl(X), (k), ntohl (A));   DEBUG_REGS;
+#define LDH_IDX(k)     A = BPF_GET16 (ntohl(X), (k));          DEBUG_REGS;
+#define STH_IDX(k)     BPF_PUT16 (ntohl(X), (k), ntohl (A));   DEBUG_REGS;
+#define LDB_IDX(k)     A = BPF_GET08 (ntohl(X), (k));          DEBUG_REGS;
+#define STB_IDX(k)     BPF_PUT08 (ntohl(X), (k), ntohl (A));   DEBUG_REGS;
+#define LDX_IP4(k)     A = (P [k] & 0x0f) << 2;                DEBUG_REGS;
+#define LDW_LIT(k)     A = htonl ((k) & 0xffffffff);           DEBUG_REGS;
+#define LDH_LIT(k)     A = htonl ((k) & 0x0000ffff);           DEBUG_REGS;
+#define LDB_LIT(k)     A = htonl ((k) & 0x000000ff);           DEBUG_REGS;
+#define LDW_MEM(k)     A = htonl (M[k]);                       DEBUG_REGS;
+#define LDX_MEM(k)     X = htonl (M[k]);                       DEBUG_REGS;
+#define STW_MEM(k)     M[k] = ntohl (A);                       DEBUG_REGS;
+#define STX_MEM(k)     M[k] = ntohl (X);                       DEBUG_REGS;
+#define JMP_ALW(t)     goto t;         DEBUG_REGS;
+#define JGT_LIT(k,t)   if (ntohl(A) >  (k)) goto t;            DEBUG_REGS;
+#define JGE_LIT(k,t)   if (ntohl(A) >= (k)) goto t;            DEBUG_REGS;
+#define JLT_LIT(k,t)   if (ntohl(A) <  (k)) goto t;            DEBUG_REGS;
+#define JLE_LIT(k,t)   if (ntohl(A) <= (k)) goto t;            DEBUG_REGS;
+#define JEQ_LIT(k,t)   if (ntohl(A) == (k)) goto t;            DEBUG_REGS;
+#define JNE_LIT(k,t)   if (ntohl(A) != (k)) goto t;            DEBUG_REGS;
+#define JMN_LIT(k,t)   if ((ntohl(A) &  (k)) != 0) goto t;     DEBUG_REGS;
+#define JMZ_LIT(k,t)   if ((ntohl(A) &  (k)) == 0) goto t;     DEBUG_REGS;
+#define ADD_REX()      A = htonl (ntohl (A) + ntohl (X));      DEBUG_REGS;
+#define SUB_REX()      A = htonl (ntohl (A) - ntohl (X));      DEBUG_REGS;
+#define MUL_REX()      A = htonl (ntohl (A) * ntohl (X));      DEBUG_REGS;
+#define DIV_REX()      if (X == 0) return 0; A = htonl (ntohl (A) / ntohl (X)); \
+                                                               DEBUG_REGS;
+#define AND_REX()      A = A & X;                              DEBUG_REGS;
+#define IOR_REX()      A = A | X;                              DEBUG_REGS;
+#define XOR_REX()      A = A ^ X;                              DEBUG_REGS;
+#define LSH_REX()      A = htonl (ntohl (A) << ntohl (X));     DEBUG_REGS;
+#define RSH_REX()      A = htonl (ntohl (A) >> ntohl (X));     DEBUG_REGS;
+#define ADD_LIT(k)     A = htonl (ntohl (A) + (k));            DEBUG_REGS;
+#define SUB_LIT(k)     A = htonl (ntohl (A) - (k));            DEBUG_REGS;
+#define MUL_LIT(k)     A = htonl (ntohl (A) * (k));            DEBUG_REGS;
+#define DIV_LIT(k)     if ((k) == 0) return 0; A = htonl (ntohl (A) / (k)); \
+                                                               DEBUG_REGS;
+#define AND_LIT(k)     A = A & htonl ((k));                    DEBUG_REGS;
+#define IOR_LIT(k)     A = A | htonl ((k));                    DEBUG_REGS;
+#define XOR_LIT(k)     A = A ^ htonl ((k));                    DEBUG_REGS;
+#define LSH_LIT(k)     A = htonl (ntohl (A) << (k))            DEBUG_REGS;
+#define RSH_LIT(k)     A = htonl (ntohl (A) >> (k))            DEBUG_REGS;
+#define NEG_ACC()      A = htonl (-ntohl (A))                  DEBUG_REGS;
+#define LDX_ACC()      X = A;                                  DEBUG_REGS;
+#define LDW_REX()      A = A;                                  DEBUG_REGS;
+#define SUM_PKT(k)     S += ntohl (BPF_GET16 (P, (k)));        DEBUG_REGS_PLUS;
+#define SUM_IDX(k)     S += ntohl (BPF_GET16 (ntohl(X), (k))); DEBUG_REGS_PLUS;
+#define SUM_ACC()      S += ntohl (A) & 0xffff;                DEBUG_REGS_PLUS;
+#define SUM_TOP()      S += ntohl (A) >> 16;                   DEBUG_REGS_PLUS;
+#define LDH_SUM()      printf ("S_pre = %08x\n", S); S = ((S & 0xffff) + (S >> 16)) & 0xffff; A = htonl (S) ^ 0xffff; printf ("S_post= %08x\n", S); \
+                                                               DEBUG_REGS_PLUS;
+#define CLR_SUM()      S = 0;                                  DEBUG_REGS_PLUS;
+
+
+#endif // HAVE_BPF_ASM_INLINES
+
diff --git a/include/0cpm/netdb.h b/include/0cpm/netdb.h
new file mode 100644 (file)
index 0000000..81e1fa4
--- /dev/null
@@ -0,0 +1,83 @@
+/* netdb.h -- Network database structures
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+/* IPv4  routing and addressing information.
+ *
+ * This structure is used to store local IPv4 information.
+ * Even if the application in IPv6-only, it may still need IPv4 as a
+ * "local" transport to a nearby 6bed4 tunnel server.
+ *
+ * Some other protocols may use IPv4 for the time being: DNS, NTP.
+ */
+
+struct ip4binding {
+       struct ip4binding *next;        // Linked-list -- TODO:ARRAY?
+       uint32_t ip4addr;               // My IPv4 address -- network order
+       uint32_t ip4mask;               // My IPv4 mask -- network order
+       uint32_t ip4gateway;            // My IPv4 gateway
+       uint32_t ip4timeout;            // The timeout for ip4addr / ip4gateway
+       uint32_t ip4dns [2];            // DNS servers available on this route
+       //TODO:NONE?// uint16_t flags;                  // See I4B_xxx below
+};
+
+
+/* IPv6 routing and addressing information.
+ * 
+ * This structure is used to find the routing information from a particular
+ * IPv6 address.  It also includes timeout values to aid in refreshing or
+ * expiring the allocation.
+ * 
+ * All data is stored in network byte order.
+ * 
+ * The ip6 variables represent the global IPv6 addressing information,
+ * including an ip6uplink if IPv6 routes locally.
+ *
+ * The ip4 parts represent local communication parameters for IPv4, if
+ * 6bed4 is used as a routing layer.
+ *
+ * Multiple ip6binding structures can be in use at any time.  The first
+ * suitable one from the list is selected, but given an assigned address
+ * the route is of course set in stone.
+ */
+struct ip6binding {
+       struct ip6binding *next;        // Linked-list -- TODO:ARRAY?
+       uint8_t ip6addr [16];           // My IPv6 address
+       uint8_t ip6uplink [16];         // The router's link-local address
+       uint32_t ip6timeout;            // The timeout for ip6uplink / ip6addr
+       struct ip4binding *ip4binding;  // For 6bed4, underlying IPv4 binding
+       uint16_t flags;                 // See I6B_xxx below
+};
+
+/* An autoconfig ip6binding has a preference; tunnels are always lower */
+#define I6B_PREFERENCE_MASK            0x000f
+// #define I6B_PREFERENCE_TUNNEL               TODO
+
+/* An ip6binding can be obtained from one of a few sources */
+#define I6B_ROUTE_SOURCE_MASK          0x00f0
+#define I6B_ROUTE_SOURCE_6BED4_FLAG    0x0080  /* Native if not 6bed4 */
+#define I6B_ROUTE_SOURCE_AUTOCONF      0x0000  /* AUTO6 + NATIVE */
+#define I6B_ROUTE_SOURCE_DHCP          0x0010  /* DHCP6 + NATIVE */
+#define I6B_ROUTE_SOURCE_STATIC                0x0020  /* STAT6 + NATIVE */
+#define I6B_ROUTE_SOURCE_6BED4_AUTOCONF        0x0080  /* IP4LL + 6BED4 */
+#define I6B_ROUTE_SOURCE_6BED4_DHCP    0x0090  /* DHCP4 + 6BED4 */
+#define I6B_ROUTE_SOURCE_6BED4_STATIC  0x00a0  /* STAT4 + 6BED4 */
+
+/* An ip6binding can be tentative, if it is undergoing peer review */
+#define I6B_TENTATIVE                  0x0100
+
+/* An ip6binding can be in active use; expiry then only sets a flag */
+#define I6B_ACTIVE                     0x0200
+#define I6B_EXPIRED                    0x0400
+
+
+/* The netdb structure with the binding structures */
+
+#define IP4BINDING_COUNT 16
+extern struct ip4binding ip4binding [IP4BINDING_COUNT];
+
+#define IP6BINDING_COUNT 16
+extern struct ip6binding ip6binding [IP6BINDING_COUNT];
+
diff --git a/include/0cpm/netfun.h b/include/0cpm/netfun.h
new file mode 100644 (file)
index 0000000..cd1f4a9
--- /dev/null
@@ -0,0 +1,86 @@
+
+enum mem_netinput {
+       //
+       // Pointers to recognised structures
+       MEM_ETHER_HEAD,
+       MEM_ETHER_PLOAD,
+       MEM_ARP_HEAD,
+       MEM_IP4_HEAD,
+       MEM_IP4_PLOAD,
+       MEM_ICMP4_HEAD,
+       MEM_DHCP4_HEAD,
+       MEM_UDP4_HEAD,
+       MEM_UDP4_PLOAD,
+       MEM_6BED4_PLOAD,
+       MEM_IP6_HEAD,
+       MEM_IP6_PLOAD,
+       MEM_ICMP6_HEAD,
+       MEM_UDP6_HEAD,
+       MEM_UDP6_PLOAD,
+       MEM_RTP_HEAD,
+       MEM_RTCP_HEAD,
+       MEM_DHCP6_HEAD,
+       MEM_DNS_HEAD,
+       MEM_DNSSD_HEAD,
+       MEM_SIP_HEAD,
+       //
+       // Pointer to the first bit outside the packet
+       MEM_ALL_DONE,
+       //
+       // Miscellaneous data from the parsed packets
+       MEM_IP4_SRC,
+       MEM_IP4_DST,
+       MEM_ETHER_SRC,
+       MEM_ETHER_DST,
+       MEM_UDP4_PORTS,
+       MEM_UDP6_PORTS,
+       MEM_VLAN_ID,
+       MEM_BINDING6,
+       MEM_IP6_DST,
+       //
+       // The number of entries in this enum
+       MEM_NETVAR_COUNT
+};
+
+#include <linux/if_tun.h>
+struct tunbuf {
+       struct tun_pi prefix;
+       uint8_t data [1500 + 18];
+};
+
+
+
+uint16_t netcore_checksum_areas (void *area0, ...);
+int netcore_send_buffer (int tunsox, uint32_t *mem, struct tunbuf *wbuf);
+
+uint8_t *net_arp_reply (uint8_t *pkt, uint32_t pktlen, uint32_t *mem);
+uint8_t *net_dhcp4 (uint8_t *pkt, uint32_t pktlen, uint32_t *mem);
+uint8_t *net_rtp (uint8_t *pkt, uint32_t pktlen, uint32_t *mem);
+uint8_t *net_rtcp (uint8_t *pkt, uint32_t pktlen, uint32_t *mem);
+uint8_t *net_sip (uint8_t *pkt, uint32_t pktlen, uint32_t *mem);
+uint8_t *net_mdns_resp_error (uint8_t *pkt, uint32_t pktlen, uint32_t *mem);
+uint8_t *net_mdns_resp_dyn (uint8_t *pkt, uint32_t pktlen, uint32_t *mem);
+uint8_t *net_mdns_resp_std (uint8_t *pkt, uint32_t pktlen, uint32_t *mem);
+uint8_t *net_mdns_query_error (uint8_t *pkt, uint32_t pktlen, uint32_t *mem);
+uint8_t *net_mdns_query_ok (uint8_t *pkt, uint32_t pktlen, uint32_t *mem);
+
+uint8_t *netreply_arp_query (uint8_t *pkt, uint32_t *mem);
+uint8_t *netreply_icmp4_echo_req (uint8_t *pkt, uint32_t *mem);
+uint8_t *netreply_icmp6_ngb_disc (uint8_t *pkt, uint32_t *mem);
+uint8_t *netreply_icmp6_echo_req (uint8_t *pkt, uint32_t *mem);
+uint8_t *netreply_dhcp4_offer (uint8_t *pkt, uint32_t *mem);
+uint8_t *netreply_dhcp6_advertise (uint8_t *pout, uint32_t *mem);
+
+uint8_t *netsend_icmp6_router_solicit (uint8_t *pout, uint32_t *mem);
+uint8_t *netsend_icmp6_ngb_sol (uint8_t *pout, uint32_t *mem);
+uint8_t *netsend_dhcp4_discover (uint8_t *pout, uint32_t *mem);
+uint8_t *netsend_dhcp6_solicit (uint8_t *pout, uint32_t *mem);
+
+uint8_t *netdb_router_advertised (uint8_t *pout, uint32_t *mem);
+uint8_t *netdb_neighbour_advertised (uint8_t *pout, uint32_t *mem);
+uint8_t *netdb_dhcp4_ack (uint8_t *pout, uint32_t *mem);
+uint8_t *netdb_dhcp4_nak (uint8_t *pout, uint32_t *mem);
+uint8_t *netdb_dhcp6_reply (uint8_t *pout, uint32_t *mem);
+uint8_t *netdb_dhcp6_reconfigure (uint8_t *pout, uint32_t *mem);
+
+uint8_t *netout (uint8_t *pkt, uint32_t pktlen, uint32_t *mem);
diff --git a/src/driver/tunnel/tuntest.c b/src/driver/tunnel/tuntest.c
new file mode 100644 (file)
index 0000000..d0170d3
--- /dev/null
@@ -0,0 +1,215 @@
+/* tuntest.c -- Tunnel-based testing of the network code.
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
+
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <linux/if_ether.h>
+
+#include <0cpm/netfun.h>
+#include <0cpm/netdb.h>
+
+
+
+int tunsox = -1;
+
+struct tunbuf rbuf, wbuf;
+
+
+
+/*
+ * TEST OUTPUT FUNCTIONS
+ */
+
+uint8_t *net_arp_reply (uint8_t *pkt, uint32_t pktlen, uint32_t *mem) {
+       printf ("Received: ARP Reply\n");
+       return NULL;
+}
+
+uint8_t *net_rtp (uint8_t *pkt, uint32_t pktlen, uint32_t *mem) {
+       printf ("Received: RTP\n");
+       return NULL;
+}
+
+uint8_t *net_rtcp (uint8_t *pkt, uint32_t pktlen, uint32_t *mem) {
+       printf ("Received: RTCP\n");
+       return NULL;
+}
+
+uint8_t *net_sip (uint8_t *pkt, uint32_t pktlen, uint32_t *mem) {
+       printf ("Received: SIP\n");
+       return NULL;
+}
+
+uint8_t *net_mdns_resp_error (uint8_t *pkt, uint32_t pktlen, uint32_t *mem) {
+       //TODO// printf ("Received: mDNS error response\n");
+       return NULL;
+}
+
+uint8_t *net_mdns_resp_dyn (uint8_t *pkt, uint32_t pktlen, uint32_t *mem) {
+       //TODO// printf ("Received: mDNS dynamic response\n");
+       return NULL;
+}
+
+uint8_t *net_mdns_resp_std (uint8_t *pkt, uint32_t pktlen, uint32_t *mem) {
+       //TODO// printf ("Received: mDNS standard response\n");
+       return NULL;
+}
+
+uint8_t *net_mdns_query_error (uint8_t *pkt, uint32_t pktlen, uint32_t *mem) {
+       //TODO// printf ("Received: mDNS error query\n");
+       return NULL;
+}
+
+uint8_t *net_mdns_query_ok (uint8_t *pkt, uint32_t pktlen, uint32_t *mem) {
+       //TODO// printf ("Received: mDNS ok query\n");
+       return NULL;
+}
+
+
+
+/* A collection of initialisation steps.
+ */
+void init (void) {
+       int i;
+       for (i=0; i<IP6BINDING_COUNT; i++) {
+               ip6binding [i].flags = I6B_EXPIRED;
+       }
+}
+
+/*
+ * TEST SETUP FUNCTIONS
+ */
+
+typedef void *retfn (uint8_t *pout, uint32_t *mem);
+
+int process_packets (int sox, int secs) {
+       int ok = 1;
+       time_t maxtm = secs + time (NULL);
+       while (ok) {
+               fd_set seln;
+               FD_ZERO (&seln);
+               FD_SET (sox, &seln);
+               struct timeval tout;
+               tout.tv_sec = maxtm - time (NULL);
+               tout.tv_usec = 500000;
+               if ((tout.tv_sec < 0) || (select (sox+1, &seln, NULL, NULL, &tout) <= 0)) {
+                       return 1;
+               }
+               size_t len = read (sox, &rbuf, sizeof (struct tun_pi) + sizeof (rbuf.data));
+               uint8_t *pkt = rbuf.data;
+               uint32_t pktlen = len - sizeof (struct tun_pi);
+               if (pktlen > 18) {
+                       uint32_t mem [28];
+                       bzero (mem, sizeof (mem));
+                       retfn *rf = (retfn *) netinput (rbuf.data, len - sizeof (struct tun_pi), mem);
+#if 0
+                       int i;
+                       for (i=0; i<28; i++) {
+                               printf ("  M[%d]=0x%08x%s", i, mem [i],
+                                               ((i+1)%4 == 0)? "\n": "");
+                       }
+#endif
+                       if (rf != NULL) {
+                               uint8_t *start = wbuf.data;
+                               uint8_t *stop = (*rf) (start, mem);
+                               if (stop) {
+                                       mem [MEM_ALL_DONE] = (uint32_t) stop;
+                                       uint32_t len = mem [MEM_ALL_DONE] - mem [MEM_ETHER_HEAD];
+                                       if (netcore_send_buffer (tunsox, mem, &wbuf) < 0) {
+                                               printf ("Failed while sending reply data\n");
+                                       }
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
+
+int setup_tunnel (void) {
+       tunsox = -1;
+       int ok = 1;
+       //
+       // Open the tunnel
+       tunsox = open ("/dev/net/tun", O_RDWR);
+       if (tunsox < 0) {
+               ok = 0;
+       }
+       //
+       // Set the tunnel name to "test0cpm"
+       struct ifreq ifreq;
+       bzero (&ifreq, sizeof (ifreq));
+       strncpy (ifreq.ifr_name, "test0cpm", IFNAMSIZ);
+       ifreq.ifr_flags = IFF_TAP;
+       if (ok)
+       if (ioctl (tunsox, TUNSETIFF, &ifreq) == -1) {
+               ok = 0;
+       }
+       //
+       // Set to promiscuous mode (meaningless for a tunnel)
+#if 0
+       if (ok)
+       if (ioctl(tunsox, SIOCGIFFLAGS, &ifreq) == -1) {
+               ok = 0;
+       }
+       ifreq.ifr_flags |= IFF_PROMISC | IFF_UP;
+       if (ok)
+       if (ioctl(tunsox, SIOCSIFFLAGS, &ifreq) == -1) {
+               ok = 0;
+       }
+#endif
+       //
+       // Cleanup and report success or failure
+       if (!ok) {
+               if (tunsox >= 0) {
+                       close (tunsox);
+                       tunsox = -1;
+               }
+               return -1;
+       }
+       return tunsox;
+}
+
+
+
+int main (int argc, char *argv []) {
+       init ();
+       int tunsox = setup_tunnel ();
+       if (tunsox == -1) {
+               fprintf (stderr, "Failed to setup tunnel\n");
+               exit (1);
+       }
+       system ("/sbin/ifconfig test0cpm up");
+       system ("/sbin/ifconfig test0cpm");
+       sleep (10);
+       if (!netcore_bootstrap ()) {
+               fprintf (stderr, "Failed to bootstrap the network\n");
+               exit (1);
+       }
+       process_packets (tunsox, 60);
+       printf ("Done.\n");
+       close (tunsox);
+       return 0;
+}
+
diff --git a/src/net/Kconfig b/src/net/Kconfig
new file mode 100644 (file)
index 0000000..e1cbcdd
--- /dev/null
@@ -0,0 +1,5 @@
+
+menu "Network Configuration"
+
+config NET_6BED4_V4ADDR
+       
diff --git a/src/net/Makefile b/src/net/Makefile
new file mode 100644 (file)
index 0000000..ca3afce
--- /dev/null
@@ -0,0 +1,2 @@
+src/net/net.o: src/net/core.o src/net/input.o src/net/reply.o src/net/send.o src/net/db.o
+       ld -r -o $@ $^
diff --git a/src/net/core.c b/src/net/core.c
new file mode 100644 (file)
index 0000000..100d5e0
--- /dev/null
@@ -0,0 +1,285 @@
+/* netcore.c -- Networking core routines.
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
+#include <net/ethernet.h>
+
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <linux/if_ether.h>
+
+#include <0cpm/netfun.h>
+#include <0cpm/netdb.h>
+
+
+/* Global variables
+ */
+
+extern struct tunbuf rbuf, wbuf;       // TODO: Testing setup
+extern int tunsox;                     // TODO: Testing setup
+
+extern uint8_t ether_mine [ETHER_ADDR_LEN];
+
+/* netcore_checksum_areas (void *area0, uint16_t len0, ..., NULL)
+ * Calculate the Internet checksum over the given areas
+ */
+uint16_t netcore_checksum_areas (void *area0, ...) {
+       uint32_t csum = 0;
+       uint16_t *area;
+       va_list pairs;
+       va_start (pairs, area0);
+       area = (uint16_t *) area0;
+       while (area) {
+               uint16_t len = (int16_t) va_arg (pairs, int);
+               while (len > 1) {
+                       csum = csum + ntohs (*area++);
+                       len -= 2;
+               }
+               if (len > 0) {
+                       csum = csum + * (uint8_t *) area;
+               }
+               area = va_arg (pairs, uint16_t *);
+       }
+       va_end (pairs);
+       csum = (csum & 0xffff) + (csum >> 16);
+       csum = (csum & 0xffff) + (csum >> 16);
+       return htons ((uint16_t) ~csum);
+}
+
+
+/* Send a buffer with a given MEM[] array of internal pointers.
+ * This calculates length and checksum fields, then sends the
+ * message into the world.
+ */
+int netcore_send_buffer (int tunsox, uint32_t *mem, struct tunbuf *wbuf) {
+       struct icmp6_hdr *icmp6 = (void *) mem [MEM_ICMP6_HEAD];
+       struct icmp      *icmp4 = (void *) mem [MEM_ICMP4_HEAD];
+       struct udphdr *udp4 = (void *) mem [MEM_UDP4_HEAD];
+       struct udphdr *udp6 = (void *) mem [MEM_UDP6_HEAD];
+       struct iphdr   *ip4 = (void *) mem [MEM_IP4_HEAD];
+       struct ip6_hdr *ip6 = (void *) mem [MEM_IP6_HEAD];
+       struct arphdr  *arp = (void *) mem [MEM_ARP_HEAD];
+       struct ethhdr  *eth = (void *) mem [MEM_ETHER_HEAD];
+       //
+       // Checksum UDPv6 on IPv6
+       if (ip6 && udp6) {
+               uint16_t pload6 = htons (IPPROTO_UDP);
+               udp6->len = htons (mem [MEM_ALL_DONE] - mem [MEM_UDP6_HEAD]);
+               ip6->ip6_plen = udp6->len;
+               ip6->ip6_nxt = IPPROTO_UDP;
+               udp6->check = netcore_checksum_areas (
+                               &ip6->ip6_src, 32,
+                               &ip6->ip6_plen, 2,
+                               &pload6, 2,
+                               udp6, 6,
+                               udp6 + 1, (int) htons (udp6->len) - 8,
+                               NULL);
+       }
+       //
+       // Checksum ICMPv6 on IPv6
+       if (ip6 && icmp6) {
+               ip6->ip6_nxt = IPPROTO_ICMPV6;
+               uint16_t pload6 = htons (IPPROTO_ICMPV6);
+               ip6->ip6_plen = htons (mem [MEM_ALL_DONE] - mem [MEM_ICMP6_HEAD]);
+               icmp6->icmp6_cksum = 0;
+               icmp6->icmp6_cksum = netcore_checksum_areas (
+                               &ip6->ip6_src, 32,
+                               &ip6->ip6_plen, 2,
+                               &pload6, 2,
+                               icmp6, (int) mem [MEM_ALL_DONE] - (int) mem [MEM_ICMP6_HEAD],
+                               NULL);
+       }
+       //
+       // Checksum UDPv4 under IPv6 (6bed4 tunnel)
+       if (udp4) {
+               udp4->len = htons (mem [MEM_ALL_DONE] - mem [MEM_UDP4_HEAD]);
+       }
+       //
+       // Checksum UDPv4 on IPv4
+       if (ip4 && udp4) {
+               ip4->protocol = IPPROTO_UDP;
+               uint16_t pload4 = htons (IPPROTO_UDP);
+               ip4->tot_len = htons (20 + ntohs (udp4->len));
+               udp4->check = netcore_checksum_areas (
+                               &ip4->saddr, 8,
+                               &pload4, 2,
+                               &udp4->len, 2,
+                               udp4, 6,
+                               udp4 + 1, (int) ntohs (udp4->len) - 8,
+                               NULL);
+       }
+       //
+       // Checksum ICMPv4
+       if (icmp4) {
+               ip4->tot_len = htons (mem [MEM_ALL_DONE] - mem [MEM_IP4_HEAD]);
+               ip4->protocol = IPPROTO_ICMP;
+               icmp4->icmp_cksum = 0;
+               icmp4->icmp_cksum = netcore_checksum_areas (
+                               icmp4, (int) mem [MEM_ALL_DONE] - (int) mem [MEM_ICMP4_HEAD],
+                               NULL);
+       }
+       //
+       // Checksum IPv4
+       if (ip4) {
+               ip4->check = netcore_checksum_areas (
+                               ip4, 10,
+                               &ip4->saddr, 8,
+                               NULL);
+       }
+       //
+       // Determine the tunnel prefix info and ethernet protocol
+       if (ip4) {
+               wbuf->prefix.proto = htons (ETH_P_IP);
+       } else if (ip6) {
+               wbuf->prefix.proto = htons (ETH_P_IPV6);
+       } else if (arp) {
+               wbuf->prefix.proto = htons (ETH_P_ARP);
+       } else {
+               return -1;
+       }
+       eth->h_proto = wbuf->prefix.proto;
+       wbuf->prefix.flags = 0;
+       //
+       // Actually send the packet
+       int alen = mem [MEM_ALL_DONE] - mem [MEM_ETHER_HEAD] + sizeof (struct tun_pi);
+       if ((alen > 0) && (alen < 1500+12)) {
+               int wlen = write (tunsox, wbuf, alen);
+printf ("Written %d out of %d:\n", wlen, alen); int i; for (i=0; i<alen; i++) { printf ("%02x%s", ((uint8_t *) wbuf) [i], (i%16 == 0? "\n": " ")); }; printf ("\n");
+               if (wlen != alen) {
+                       if (wlen < 0) {
+                               return -1;
+                       } else {
+                               // No guaranteed delivery -- swallow problem
+                               return 0;
+                       }
+               }
+       }
+       return 0;
+}
+
+
+/* Send a router solicitation.
+ */
+static void solicit_router (void) {
+       uint8_t *start = wbuf.data;
+       uint32_t mem [MEM_NETVAR_COUNT];
+       bzero (mem, sizeof (mem));
+       mem [MEM_BINDING6] = (uint32_t) &ip6binding [0];
+       uint8_t *stop = netsend_icmp6_router_solicit (start, mem);
+       mem [MEM_ALL_DONE] = (uint32_t) stop;
+       uint32_t len = mem [MEM_ALL_DONE] - mem [MEM_ETHER_HEAD];
+       if ((len > 0) && (len < 1500 + 18)) {
+               netcore_send_buffer (tunsox, mem, &wbuf);
+       }
+}
+
+
+/* Start to obtain an IPv4 address.
+ */
+static void get_dhcp4_lease (void) {
+       uint8_t *start = wbuf.data;
+       uint32_t mem [MEM_NETVAR_COUNT];
+       bzero (mem, sizeof (mem));
+       uint8_t *stop = netsend_dhcp4_discover (start, mem);
+       mem [MEM_ALL_DONE] = (uint32_t) stop;
+       uint32_t len = mem [MEM_ALL_DONE] - mem [MEM_ETHER_HEAD];
+       if ((len > 0) && (len < 1500 + 18)) {
+               netcore_send_buffer (tunsox, mem, &wbuf);
+       }
+}
+
+/* Start to obtain an IPv6 address.
+ */
+static void get_dhcp6_lease (void) {
+       uint8_t *start = wbuf.data;
+       uint32_t mem [MEM_NETVAR_COUNT];
+       bzero (mem, sizeof (mem));
+       uint8_t *stop = netsend_dhcp6_solicit (start, mem);
+       mem [MEM_ALL_DONE] = (uint32_t) stop;
+       uint32_t len = mem [MEM_ALL_DONE] - mem [MEM_ETHER_HEAD];
+       if ((len > 0) && (len < 1500 + 18)) {
+               netcore_send_buffer (tunsox, mem, &wbuf);
+       }
+}
+
+
+/* Boot the network: Obtain an IPv6 address, possibly based on an IPv4
+ * and a 6bed4 tunnel.  The routine returns success as nonzero.
+ *
+ * The booting procedure works through the following 1-second steps:
+ *  - ensure that the interface is connected to a network
+ *  - try IPv6 autoconfiguration a few times (random number)
+ *     - first try to reuse an older IPv6 address, even if it was DHCPv6
+ *  - try DHCPv6 a few times
+ *     - first try to reuse an older IPv6 address, even if it was autoconfig
+ *  - try DHCPv4 a few times
+ *     - first try to reuse an older IPv4 address
+ *     - when an IPv4 address is acquired, autoconfigure 6bed4 over it
+ */
+int netcore_bootstrap (void) {
+       int process_packets (int sox, int secs); //TODO:NOTHERE
+       int i;
+       int rnd1 = 2 + ((ether_mine [5] & 0x1c) >> 2);
+       int rnd2 =       ether_mine [5] & 0x03;
+       //
+       // TODO: better wipe bindings at physical boot
+       bzero (ip4binding, sizeof (ip4binding));
+       bzero (ip6binding, sizeof (ip6binding));
+       //
+       // TODO: ensure physical network connectivity
+       //
+       // Obtain an IPv6 address through stateless autoconfiguration
+       i = rnd1;
+       while (i-- > 0) {
+               solicit_router ();
+               process_packets (tunsox, 2);
+               // TODO: return 1 if bound
+       }
+       //
+       // Obtain an IPv6 address through DHCPv6
+       i = 3;
+       while (i-- > 0) {
+               get_dhcp6_lease ();
+               process_packets (tunsox, 3);
+               // TODO: return 1 if bound
+       }
+       //
+       // Obtain an IPv4 address through DHCPv4
+       i = 3;
+       while (i-- > 0) {
+               get_dhcp4_lease ();
+               process_packets (tunsox, rnd2);
+               // TODO: break if bound
+       }
+       // TODO: fail (return 0) if no IPv4 connection
+       //
+       // Obtain an IPv6 address through 6bed4 over IPv4
+       i = rnd1;
+       while (i-- > 0) {
+               ip6binding [0].ip4binding = &ip4binding [0];
+               ip6binding [0].flags |= I6B_ROUTE_SOURCE_6BED4_FLAG;
+               solicit_router ();      //TODO: Over 6bed4
+               sleep (1);
+               // TODO:return 1 if bound
+       }
+       return 0;
+}
+
diff --git a/src/net/db.c b/src/net/db.c
new file mode 100644 (file)
index 0000000..6e2c491
--- /dev/null
@@ -0,0 +1,274 @@
+/* netdb.c -- Network Database -- Storage for network bindings and addresses.
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+#include <stdint.h>
+#include <time.h>
+
+#include <0cpm/netfun.h>
+#include <0cpm/netdb.h>
+
+#include <netinet/icmp6.h>
+
+
+/* A few useful global variables
+ */
+
+extern uint8_t ether_mine [];
+
+uint32_t localtime_ofs = 0;
+
+/* The binding table shows all available bindings and their routing */
+// TODO: Initialise all binding entries as expired
+struct ip4binding ip4binding [IP4BINDING_COUNT];
+struct ip6binding ip6binding [IP6BINDING_COUNT];
+
+
+/* Distortion value, stored in flash, distorting local addresses
+ * from the very first attempt.  This is used for /112 allocations
+ * over the LAN, in order to avoid clashes.  Once resolved, such
+ * clash avoidance should stick until a new clash occurs.  As long
+ * as new phones are only plugged in while others are operational,
+ * new phones should automatically adapt their /112 accordingly.
+ */
+uint8_t ifid_distort [8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+
+/* Use a MAC address build an EUI64 interface identifier in a IPv6 address.
+ */
+void util_mac2ifid (uint8_t *ip6address, const uint8_t *mac) {
+       ip6address [ 8] = mac [0] ^ 0x02;
+       ip6address [ 9] = mac [1];
+       ip6address [10] = mac [2];
+       ip6address [11] = 0xff;
+       ip6address [12] = 0xfe;
+       ip6address [13] = mac [3];
+       ip6address [14] = mac [4];
+       ip6address [15] = mac [5];
+}
+
+
+/* An IPv6 Router Advertisement was received.  Process it by storing
+ * the offered prefix.
+ */
+// TODO: Process retractions (life set to 0)
+// TODO: Generate ND packet for DAD and start timeout
+uint8_t *netdb_router_advertised (uint8_t *pout, uint32_t *mem) {
+       printf ("Received & Processing: Router Advertisement\n");
+       struct icmp6_hdr *icmp6 = (struct icmp6_hdr *) mem [MEM_ICMP6_HEAD];
+       uint32_t routerlife = (uint32_t) icmp6->icmp6_data16 [1];
+       uint32_t preferlife = (uint32_t) 0xffffffff;
+       uint8_t *options = icmp6->icmp6_data8 + 12;
+       uint8_t *ip6uplink_mac = NULL;
+       uint8_t *ip6prefix = NULL;
+       int ip6prefixlen = -1;
+       int best_pref = -1, cur_pref = -1;
+       int ok = 1;
+       int needDHCP = 0;
+       while (ok && (mem [MEM_ALL_DONE] > (uint32_t) options)) {
+               if (((uint32_t) options) + 8 * options [1] > mem [MEM_ALL_DONE]) {
+                       ok = 0;
+                       break;
+               }
+               switch (options [0] + 256 * options [1]) {
+               case ND_OPT_SOURCE_LINKADDR + 256:
+                       ip6uplink_mac = options + 2;
+                       break;
+               case ND_OPT_MTU + 256:
+                       if (ntohl (*(uint32_t *)(options + 4)) < 1280) {
+                               // MTU under 1280 is illegal, higher ignored
+                               ok = 0;
+                               break;
+                       }
+                       break;
+               case ND_OPT_PREFIX_INFORMATION + 4*256:
+                       // How much do we appreciate the offer?  Only the
+                       // best one continues.
+                       // Autoconfiguration: 8 + 2 * prefix_pref_if_any
+                       // DHCPv6: 0
+                       if (options [3] & 0x40) {
+                               cur_pref = 8;
+                               needDHCP = 0;
+                       } else {
+                               cur_pref = 0;
+                               if (best_pref == -1) {
+                                       needDHCP = 1;
+                               }
+                       }
+                       // Accept only /64 or /112 prefixes, prefer /64
+                       if (options [2] == 64) {
+                               cur_pref++;
+                       } else if (options [2] != 112) {
+                               break;
+                       }
+                       // Choose the best available prefix
+                       if (cur_pref < best_pref) {
+                               break;
+                       }
+                       // Copy settings for this prefix, as it is the best
+                       preferlife = ntohl (*(uint32_t *)(options+8));
+                       ip6prefix = options + 16;
+                       ip6prefixlen = options [2];
+                       best_pref = cur_pref;
+                       break;
+               default:
+                       ok = 0;
+                       break;
+               }
+               options = options + 8 * options [1];
+       }
+       ok = ok && (mem [MEM_ALL_DONE] == (uint32_t) options);
+       ok = ok && (best_pref >= 0);
+       if (!ok) {
+               return NULL;
+       }
+       // Now setup the prefix according one of three cases:
+       // 0. The only option is to use DHCP6
+       // 1. /112 prefix on 6bed4 -> interface-id = 0x0001
+       // 2. /64  prefix on LAN   -> interface-id = EIU64(MAC)
+       // 3. /112 prefix on LAN   -> interface-id = MAC-based, >= 0x0002
+       uint8_t ip6address [16];
+       uint16_t bindflags = I6B_ROUTE_SOURCE_AUTOCONF | best_pref;
+       memcpy (ip6address, ip6prefix, 16);
+       if (needDHCP) {
+               // Case 0. Must use DHCP6
+               // Do not memorise, as DHCP6 is a fallback anyway
+               return NULL;
+       } else if (mem [MEM_6BED4_PLOAD] != 0) {
+               // Case 1. /112 over 6bed4, interface-id 0x0001
+               if (ip6prefixlen != 112) {
+                       return NULL;    // Oops -- funny prefix, ignore it
+               }
+               ip6address [14] = 0x00;
+               ip6address [15] = 0x01;
+               bindflags |= I6B_ROUTE_SOURCE_6BED4_FLAG;
+       } else if (ip6prefixlen == 112) {
+               // Case 2. /112 over LAN, interface-id constructed:
+               //         Addresses are random-ish, but replayable
+               // Note: Addresses 0x0000 and 0x0001 are usually reserved
+               //       for the tunnel server and proxy/client; duplicate
+               //       address detection will then handle & randomise
+               //       by changing the lan_distort values until okay.
+               ip6address [14] = ether_mine [0] ^ ether_mine [1]
+                               ^ ether_mine [2] ^ ifid_distort [6];
+               ip6address [15] = ether_mine [3] ^ ether_mine [4]
+                               ^ ether_mine [5] ^ ifid_distort [7];
+               bindflags |= I6B_TENTATIVE;
+       } else {
+               // Case 3. /64 over LAN, interface-id is EUI64
+               util_mac2ifid (ip6address, ether_mine);
+               bindflags |= I6B_TENTATIVE;
+       }
+       // Now find an entry in the routing table for this tentative
+       // address and start up duplicate address detection if needed
+       int bindidx = 0; // TODO: Actually find a suitable entry to update
+       ip6binding [bindidx].next = NULL;
+       bzero (&ip6binding [bindidx], sizeof (ip6binding [bindidx]));
+       memcpy (ip6binding [bindidx].ip6addr, ip6address, 16);
+       if (ip6uplink_mac != NULL) {
+               ip6binding [bindidx].ip6uplink [0] = 0xfe;
+               ip6binding [bindidx].ip6uplink [1] = 0x80;
+               util_mac2ifid (ip6binding [bindidx].ip6uplink, ip6uplink_mac);
+       }
+       ip6binding [bindidx].ip6timeout = 0xffffffff;           //TODO
+       if (bindflags & I6B_ROUTE_SOURCE_6BED4_FLAG) {
+               //TODO:OLD// ip6binding [bindidx].ip4timeout = 0xffffffff;      //TODO
+               //TODO:OLD// ip6binding [bindidx].ip4uplink = ip4gateway;
+               //TODO:OLD// ip6binding [bindidx].ip4addr = htonl (mem [MEM_IP4_DST]);
+               //TODO:OLD// ip6binding [bindidx].ip4port = htons (mem [MEM_UDP4_PORTS] & 0xffff);
+               ip6binding [bindidx].ip4binding = &ip4binding[0]; //TODO:mk_dyn
+       }
+       ip6binding [bindidx].flags = bindflags;
+       // Finally, if needed, send a packet for duplicate address detection
+       if (ip6binding [bindidx].flags & I6B_TENTATIVE) {
+               mem [MEM_BINDING6] = (uint32_t) &ip6binding [bindidx];
+               return netsend_icmp6_ngb_sol (pout, mem);
+       } else {
+               return NULL;
+       }
+}
+
+/* A neighbour advertisement was received.  Store it for future reference.
+ */
+uint8_t *netdb_neighbour_advertised (uint8_t *pout, uint32_t *mem) {
+       printf ("Received: Neighbour Advertisement\n");
+       //TODO -- embodyment of this function//
+       return NULL;
+}
+
+/* DHCPv4 sends an acknowledgement.  Create a ip6binding for that.
+ */
+uint8_t *netdb_dhcp4_ack (uint8_t *pout, uint32_t *mem) {
+       printf ("Received: DHCP4 ACK\n");
+       uint8_t *opt = (uint8_t *) (mem [MEM_DHCP4_HEAD] + 240);
+       static const uint8_t cookie [4] = { 99, 130, 83, 99 };
+       if (memcmp (opt - 4, cookie, 4) != 0) {
+               return NULL;    /* No options? */
+       }
+       //TODO -- select an ip4binding dynamically?
+       int bndidx = 0;
+       bzero (&ip4binding [bndidx], sizeof (struct ip4binding));
+       ip4binding [bndidx].ip4addr = htonl (* (uint32_t *) (mem [MEM_DHCP4_HEAD] + 16));
+       // Security note: The following settings assume that the DHCP4 ACK
+       // contains proper lengths.  If not, the only problem is that bad
+       // network addresses are copied, which is not a severe problem.
+       while (*opt != 255) {
+               switch (*opt) {
+               case 1:         /* subnet mask */
+                       ip4binding [bndidx].ip4mask = * (uint32_t *) (opt + 2);
+                       break;
+               case 3:         /* router */
+                       ip4binding [bndidx].ip4gateway = * (uint32_t *) (opt + 2);
+                       break;
+               case 6:         /* DNS server(s) */
+                       ip4binding [bndidx].ip4dns [0] = * (uint32_t *) (opt + 2);
+                       ip4binding [bndidx].ip4dns [1] = * (uint32_t *) (opt + 2 + opt [1] - 4);
+                       break;
+               case 2:         /* Local time offset */
+                       localtime_ofs = ntohl (* (uint32_t *) (opt + 2));
+                       break;
+               case 58:        /* Renewal time */
+                       ip4binding [bndidx].ip4timeout = time (NULL) + ntohl (* (uint32_t *) (opt + 2));
+                       break;
+               case 0:         /* Padding, single byte */
+                       opt++;
+                       continue;       // Do not increment the usual way
+               case 15:        /* Domain name */
+               case 59:        /* Rebinding time */
+               case 54:        /* DHCP server identifier */
+               case 51:        /* IP address lease time */
+               default:
+                       break;
+               }
+       
+               opt = opt + 2 + opt [1];
+       }
+       return NULL;
+}
+
+/* DHCPv4 sends a negative acknowledgement.  Whatever :)
+ */
+uint8_t *netdb_dhcp4_nak (uint8_t *pout, uint32_t *mem) {
+       printf ("Received: DHCP4 NAK\n");
+       // Drop this, it is non-information to us
+       return NULL;
+}
+
+/* DHCPv6 sends a reply to confirm allocation of an IPv6 address
+ */
+uint8_t *netdb_dhcp6_reply (uint8_t *pout, uint32_t *mem) {
+       // TODO: Validate offer to be mine + store configuration data
+       printf ("Received: DHCP6 REPLY\n");
+       return NULL;
+}
+
+/* DHCPv6 wants to reconfigure our settings
+ */
+uint8_t *netdb_dhcp6_reconfigure (uint8_t *pout, uint32_t *mem) {
+       // TODO: Validate offer to be mine + update configuration data
+       printf ("Received: DHCP6 RECONFIGURE\n");
+       return NULL;
+}
+
diff --git a/src/net/input.c b/src/net/input.c
new file mode 100644 (file)
index 0000000..1ef6e4c
--- /dev/null
@@ -0,0 +1,502 @@
+/* netinput.c
+ *
+ * Process networked input and select actions to take.
+ *
+ * The "assembly language" used below is the BPF pseudo-language,
+ * documented in
+ *
+ *                     The BSD Packet Filter:
+ *     A New Architecture for User-Level Packet Capture
+ *             by Steven McCanne and Van Jacobson
+ *
+ *      ftp://ftp.ee.lbl.gov/papers/bpf-usenix93.ps.Z
+ *
+ * It serves to analyse frames, set aside the juicy details and
+ * return a value which in this case is either the address of a
+ * function to invoke, or NULL if the frame should be dropped.
+ *
+ * It should not be difficult to interpret the consistent assembly
+ * instructions (stored in a fixed structure format) from native
+ * code, thus leading to extremely efficient network packet handling
+ * with a very high level of flexibility for future extensions.
+ *
+ * This language is designed for speed, and is used in tcpdump et al.
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+#include <stdint.h>
+
+#include <0cpm/netcmd.h>
+#include <0cpm/netfun.h>
+
+#include <netinet/icmp6.h>
+
+
+
+
+/*
+ * The following is written in BPF assembler, because that is a proper
+ * form for handling this kind of problem.  The language lends itself
+ * for optimal translation.  In spite of that, it is very flexible.
+ *
+ * The labels ending in _sel indicate that a definite selection has been
+ * made of the kind of frame, but some validation may still be in order.
+ *
+ * The code below does not calculate checksums yet.  It also does not
+ * take packet length into account.
+ *
+ * The code collects various bits of data in the M[] scratchpad array:
+ * TODO:OLD:USING MEM_INPUT ENUM NOW
+ * M[0] is the ethernet payload
+ * M[1] is the IP4.src address                 (or 0 for native IP6)
+ * M[2] is the IP4.dst address                 (or 0 for native IP6)
+ * M[3] is the IP4 payload                     (or 0 for native IP6)
+ * M[4] is the UDP4 src.PORT|dst.PORT          (or 0 for native IP6)
+ * M[5] is the UDP4 payload                    (or 0 for native IP6)
+ * M[6] is the IP6 frame address (+40 is payload)
+ * M[7] is the UDP6 src.PORT|dst.PORT
+ * M[8] is the UDP6 payload
+ * M[9] is the ethernet header
+ *
+ * These addresses and values can be used in further analyses, based
+ * on the functions returned from the analysis.  Note that the first
+ * things these functions do is (1) check lengths and (2) check sums.
+ *
+ * If all that is okay, it can start processing the frame contents.
+ */
+
+
+/* Declare an efficient network packet analysis function:
+ *
+ * uint32_t netinput (uint8_t *pkt, uint32_t pktlen, uint32_t *mem) {
+ *     ...possibly assembly...
+ * }
+ *
+ * TODO: Check lengths
+ * TODO: Verify checksums
+ */
+BPF_BEGIN(netinput)
+
+       STX_MEM (MEM_ETHER_HEAD)                // Store the ethernet header
+       LDW_LEN ()
+       ADD_REX ()
+       STW_MEM (MEM_ALL_DONE)
+
+// IN: ETHER frame at X
+// OUT: ARP, IP4, IP6 frame at X=M[0]
+//
+// netin_ETHER         ldw     #14
+//                     add     x
+//                     tax
+//                     ldh     [x-2]
+//                     jeq     #8100h, .1, .2  ; 802.1Q tag? => step 4 bytes
+// .1                  ldw     #4
+//                     add     x
+//                     tax
+//                     ldh     [x-2]
+// .2                  stx     M[0]
+//                     jeq     #86DDh, netin_IP6_sel, .3
+// .3                  jeq     #0800h, netin_IP4_sel, .4
+// .4                  jeq     #0806h, netin_ARP_sel, netin_DROP
+
+       LDW_LIT (14)
+       ADD_REX ()
+       LDX_ACC ()
+       LDH_IDX (-2)
+       JNE_LIT (0x8100, _ether_1)
+       LDW_LIT (4)
+       ADD_REX ()
+       LDX_ACC ()
+       LDH_IDX (-2)
+BPF_LABEL (_ether_1)
+       STX_MEM (MEM_ETHER_PLOAD)
+       JEQ_LIT (0x86dd, netin_IP6_sel)
+       JEQ_LIT (0x0800, netin_IP4_sel)
+       JEQ_LIT (0x0806, netin_ARP_sel)
+       JMP_ALW (netin_DROP)
+
+
+// IN: ARP frame at X=M[0]
+// RET: ARP fn with frame in M[0], IPv4 src addr in M[1], IPv4 dst addr in M[2]
+//
+// netin_ARP_sel       ldh     [x+2]                   ; protocol type
+//                     jeq     #0800h, .1, netin_DROP  ; check IPv4
+// .1                  ld      [x+4]                   ; hwalen, protalen, cmd
+//                     stx     M[0]
+//                     jeq     #06040001, netin_ARPREQ, .2
+// .2                  jeq     #06040002, netin_ARPREPLY, netin_DROP
+// netin_ARPREQ                return  #net_arp_request
+// netin_ARPREPLY      return  #net_arp_reply
+
+BPF_LABEL(netin_ARP_sel)
+       STX_MEM (MEM_ARP_HEAD)
+       LDH_IDX (2)
+       JNE_LIT (0x0800, netin_DROP)
+       LDW_IDX (4)
+       JEQ_LIT (0x06040001, netin_ARPREQ)
+       JEQ_LIT (0x06040002, netin_ARPREPLY)
+       JMP_ALW (netin_DROP)
+BPF_LABEL(netin_ARPREPLY)
+       LDW_IDX (14)
+       STW_MEM (MEM_IP4_SRC)
+       LDW_IDX (24)
+       STW_MEM (MEM_IP4_DST)
+       RET_LIT (net_arp_reply)
+BPF_LABEL(netin_ARPREQ)
+       LDW_IDX (14)
+       STW_MEM (MEM_IP4_SRC)
+       LDW_IDX (24)
+       STW_MEM (MEM_IP4_DST)
+       RET_LIT (netreply_arp_query)
+
+
+// IN: IP4 frame at X=M[0]
+// OUT: UDP4, ICMP4 at X+20=M[3]; M[1]=src.IP4, M[2]=dst.IP4
+// Assumption: No IPv4 option headers
+//
+// netin_IP4_sel       ldb     [x]                     ; version/headerlen
+//                     jeq     #45h, .1, netin_DROP
+// .1                  ld      [x+12]                  ; src.IP4
+//                     st      M[1]
+//                     ld      [x+16]                  ; dst.IP4
+//                     st      M[2]
+//                     ldx     #20
+//                     add     x
+//                     st      M[3]                    ; IP4 payload address
+//                     tax
+//                     ldb     [x-20+9]                ; payload protocol
+//                     jeq     #17, netin_UDP4_sel, .2
+// .2                  jeq     #1, netin_ICMP4_sel, netin_DROP
+
+BPF_LABEL(netin_IP4_sel)
+       STX_MEM (MEM_IP4_HEAD)
+       LDB_IDX (0)
+       JNE_LIT (0x0045, netin_DROP)
+       LDW_IDX (12)
+       STW_MEM (MEM_IP4_SRC)
+       LDW_IDX (16)
+       STW_MEM (MEM_IP4_DST)
+       LDW_LIT (20)
+       ADD_REX ()
+       STW_MEM (MEM_IP4_PLOAD)
+       LDX_ACC ()
+       LDB_IDX (-20+9)
+       JEQ_LIT (17, netin_UDP4_sel)
+       JEQ_LIT (1, netin_ICMP4_sel)
+       JMP_ALW (netin_DROP)
+
+
+// IN: ICMP4 frame at X=M[3]
+// OUT: TODO
+//
+// netin_ICMP4_sel     TODO
+
+BPF_LABEL(netin_ICMP4_sel)
+       STX_MEM (MEM_ICMP4_HEAD)
+       LDH_IDX (0)     // type/code
+       JEQ_LIT (8 << 8, netin_ICMP4_ping)
+       RET_LIT (0)
+
+BPF_LABEL(netin_ICMP4_ping)
+       RET_LIT (netreply_icmp4_echo_req)
+
+
+// IN: UDP4 frame at X=M[3]
+// OUT: 6BED4, DHCP4 at X+20+8=M[5]; M[4]=src.PORT|dst.PORT
+//
+// netin_UDP4_sel      ld      #8
+//                     add     x
+//                     st      M[5]
+//                     ld      [x]             ; src.PORT|dst.PORT
+//                     st      M[4]
+//                     jeq     #0e450e45h, netin_6BED4_sel, .1
+// .1                  jeq     #4344h, netin_DHCP4_sel, .2
+// .2                  and     #ffff0000h
+//                     jeq     #00350000h, netin_DNS_sel, netin_DROP
+
+BPF_LABEL(netin_UDP4_sel)
+       STX_MEM (MEM_UDP4_HEAD)
+       LDW_LIT (8)
+       ADD_REX ()
+       LDX_ACC ()
+       STX_MEM (MEM_UDP4_PLOAD)
+       LDW_IDX (-8)
+       STW_MEM (MEM_UDP4_PORTS)
+       JEQ_LIT (0x0e450e45, netin_6BED4_sel)
+       JEQ_LIT (0x00430044, netin_DHCP4_sel)
+       AND_LIT (0xffff0000)
+       JEQ_LIT (0x00350000, netin_DNS_sel)
+       JMP_ALW (netin_DROP)
+
+
+// IN: DHCP4 frame at X=M[5]
+// OUT: Returns one of netreply_dhcp4_offer, netdb_dhcp4_ack, netdb_dhcp4_nak
+
+BPF_LABEL(netin_DHCP4_sel)
+       STX_MEM (MEM_DHCP4_HEAD)
+       LDW_LIT (236 + 4)
+       ADD_REX ()
+       LDX_ACC ()
+       LDW_IDX (-4)    // Magic cookie check
+       JNE_LIT (0x63825363, netin_DROP)
+BPF_LABEL(netin_DHCP4_optparse)
+       LDB_IDX (0)
+       JEQ_LIT (255, netin_DROP)
+       JEQ_LIT (0, netin_DHCP4_padding)
+       JNE_LIT (53, netin_DHCP4_optskip)
+       LDB_IDX (2)
+       JEQ_LIT (2, netin_DHCP4_offer)
+       JEQ_LIT (5, netin_DHCP4_ack)
+       JEQ_LIT (6, netin_DHCP4_nak)
+       JMP_ALW (netin_DROP)    // Including for my b'casted DHCP4 discover
+BPF_LABEL(netin_DHCP4_padding)
+       LDW_LIT (1)
+       ADD_REX ()
+       LDX_ACC ()
+       JMP_ALW (netin_DHCP4_optparse)
+BPF_LABEL(netin_DHCP4_optskip)
+       AND_LIT (0xff)
+       ADD_LIT (2)
+       ADD_REX ()
+       LDX_ACC ()
+       JMP_ALW (netin_DHCP4_optparse)
+BPF_LABEL(netin_DHCP4_offer)
+       RET_LIT (netreply_dhcp4_offer)
+BPF_LABEL(netin_DHCP4_ack)
+       RET_LIT (netdb_dhcp4_ack)
+BPF_LABEL(netin_DHCP4_nak)
+       RET_LIT (netdb_dhcp4_nak)
+
+
+// IN: 6BED4 frame at X=M[5]
+// OUT: IP6 at X=M[6]
+// Note: M[1]=src.IP, M[2]=dst.IP, M[3]=IP4, M[4]=src.PORT|dst.PORT all nonzero
+//
+// netin_6BED4_sel     ldx     M[5]            ; decapsulate IP6 package
+//                     jmp     netin_IP6_sel_anysrc
+
+BPF_LABEL(netin_6BED4_sel)
+       STX_MEM (MEM_UDP4_PLOAD)
+       STX_MEM (MEM_6BED4_PLOAD)
+       JMP_ALW (netin_IP6_sel_anysrc)
+
+
+// IN: IP6 frame at X
+// OUT: IP6 frame at X=M[6], UDP6 or ICMP6 at X+40
+//
+// netin_IP6_sel       ld      #0
+//                     st      M[1]            ; no src.IP4
+//                     st      M[2]            ; no dst.IP4
+//                     st      M[3]            ; no IP4 payload
+//                     st      M[4]            ; no UDP4 src.PORT|dst.PORT
+// netin_IP6sel__anysrc        stx     M[6]            ; IP6 frame
+//                     ldb     [x+0]           ; version/trafficclass
+//                     and     #f0h            ; version/0
+//                     jeq     #60h, .1, netin_DROP
+// .1                  ldb     [x+6]           ; next header
+//                     jeq     #17, netin_UDP6_sel, .2
+// .2                  jeq     #58, netin_ICMP6_sel, netin_DROP
+
+BPF_LABEL(netin_IP6_sel)
+#if 0
+       LDW_LIT (0)
+       STW_MEM (MEM_IP4_SRC)
+       STW_MEM (MEM_IP4_DST)
+       STW_MEM (MEM_IP4_PLOAD)
+       STW_MEM (MEM_UDP4_PLOAD)
+#endif
+BPF_LABEL(netin_IP6_sel_anysrc)
+       STX_MEM (MEM_IP6_HEAD)
+       LDB_LIT (40)
+       ADD_REX ()
+       LDX_ACC ()
+       STX_MEM (MEM_IP6_PLOAD)
+       LDB_IDX (-40)
+       AND_LIT (0xf0)
+       JNE_LIT (0x60, netin_DROP)
+       LDB_IDX (-40+6)
+       JEQ_LIT (17, netin_UDP6_sel)
+       JEQ_LIT (58, netin_ICMP6_sel)
+       JMP_ALW (netin_DROP)
+
+
+// IN: ICMP6 at X
+// OUT: TODO
+//
+// netin_ICMP6_sel: switch between alternative message types
+
+BPF_LABEL(netin_ICMP6_sel)
+       STX_MEM (MEM_ICMP6_HEAD)
+       LDH_IDX (0)     // Fetch type, code
+       // Ignore ND_ROUTER_SOLICIT  << 8, netin_ICMP6_ROUTER_SOLICIT
+       JEQ_LIT (ND_ROUTER_ADVERT    << 8, netin_ICMP6_ROUTER_ADVERT)
+       JEQ_LIT (ND_NEIGHBOR_SOLICIT << 8, netin_ICMP6_NEIGHBOUR_SOLICIT)
+       JEQ_LIT (ND_NEIGHBOR_ADVERT  << 8, netin_ICMP6_NEIGHBOUR_ADVERT)
+       //TODO//JEQ_LIT (ND_REDIRECT << 8, netin_ICMP6_REDIRECT)
+       JEQ_LIT (ICMP6_ECHO_REQUEST  << 8, netin_ICMP6_ECHO_REQUEST)
+       JEQ_LIT (ICMP6_ECHO_REPLY    << 8, netin_ICMP6_ECHO_REPLY)
+       JMP_ALW (netin_DROP)
+
+BPF_LABEL(netin_ICMP6_ROUTER_ADVERT)
+       RET_LIT (netdb_router_advertised)
+
+// ND Neighbour Solicitation:
+// If aimed at me, respond automatically with Neigbour Advertisement
+BPF_LABEL(netin_ICMP6_NEIGHBOUR_SOLICIT)
+       RET_LIT (netreply_icmp6_ngb_disc)
+
+BPF_LABEL(netin_ICMP6_NEIGHBOUR_ADVERT)
+       RET_LIT (netdb_neighbour_advertised)
+
+BPF_LABEL(netin_ICMP6_ECHO_REQUEST)
+       RET_LIT (netreply_icmp6_echo_req)
+
+BPF_LABEL(netin_ICMP6_ECHO_REPLY)
+       JMP_ALW (netin_DROP)    // TODO: Process if it is used for tests?
+
+
+// IN: UDP6 at X
+// OUT: RTP, RTCP, SIP, DHCP6, DNS, DNS_SD at X=M[8]; M[7]=src.PORT|dst.PORT
+// Note: RTP/RTCP is located at ports 8192..65535
+//
+// netin_UDP6_sel      ld      #48
+//                     add     x
+//                     st      M[8]
+//                     tax
+//                     ld      [x-8+0]                 ; src.PORT|dst.PORT
+//                     jset    #0000e000h, .1, .3      ; RTP/RTCP or other?
+// .1                  jset    #00000001h, netin_RTCP_sel, netin_RTP_sel
+// .2                  jeq     #02230222h, netin_DHCP6_sel, .3
+// .3                  and     #0000ffffh              ; dst.PORT
+//                     jeq     #5060, netin_SIP_sel, .4
+// .4                  jeq     #5353, netin_DNS_SD_sel, .5
+// .5                  jeq     #53, netin_DNS_sel, netin_DROP
+
+BPF_LABEL(netin_UDP6_sel)
+       STX_MEM (MEM_UDP6_HEAD)
+       LDW_LIT (8)
+       ADD_REX ()
+       STW_MEM (MEM_UDP6_PLOAD)
+       LDX_ACC ()
+       LDW_IDX (-8+0)
+       STW_MEM (MEM_UDP6_PORTS)
+       JMZ_LIT (0x0000e000, _UDP6_2)
+       JMZ_LIT (0x00000001, netin_RTCP_sel)
+       JMP_ALW (netin_RTP_sel)
+BPF_LABEL(_UDP6_2)
+       AND_LIT (0x0000ffff)
+       JEQ_LIT (546, netin_DHCP6_sel)
+       JEQ_LIT (5060, netin_SIP_sel)
+       JEQ_LIT (5353, netin_DNS_SD_sel)
+       JEQ_LIT (53, netin_DNS_sel)
+       JMP_ALW (netin_DROP)
+
+
+// IN: RTP at M[8]=X
+// OUT: net_rtp
+//
+// netin_RTP_sel       return  #net_rtp
+
+BPF_LABEL(netin_RTP_sel)
+       STX_MEM (MEM_RTP_HEAD)
+       RET_LIT (net_rtp)
+
+
+// IN: RTCP at M[8]=X
+// OUT: net_rtcp
+//
+// netin_RTCP_sel      return  #net_rtcp
+
+BPF_LABEL(netin_RTCP_sel)
+       STX_MEM (MEM_RTCP_HEAD)
+       RET_LIT (net_rtcp)
+
+
+// IN: SIP at M[8]=X
+// OUT: net_sip
+//
+// netin_SIP_sel       return  #net_sip
+
+BPF_LABEL(netin_SIP_sel)
+       STX_MEM (MEM_SIP_HEAD)
+       RET_LIT (net_sip)
+
+
+// IN: DHCP6 at M[8]=X
+// OUT: TODO
+
+BPF_LABEL(netin_DHCP6_sel)
+       STX_MEM (MEM_DHCP6_HEAD)
+       LDB_IDX (0)
+       JEQ_LIT (2, netin_DHCP6_advertise)
+       JEQ_LIT (7, netin_DHCP6_reply)
+       JNE_LIT (10, netin_DROP)
+BPF_LABEL(netin_DHCP6_reconfigure)
+       RET_LIT (netdb_dhcp6_reconfigure)
+BPF_LABEL(netin_DHCP6_reply)
+       RET_LIT (netdb_dhcp6_reply)
+BPF_LABEL(netin_DHCP6_advertise)
+       RET_LIT (netreply_dhcp6_advertise)
+
+
+// IN: DNS at M[8]=X
+// OUT: TODO
+
+BPF_LABEL(netin_DNS_sel)
+       STX_MEM (MEM_DNS_HEAD)
+       RET_LIT (0)
+
+
+// IN: DNS_SD at M[8]=X
+// OUT: TODO: Nogal wat gegokt over hoe MDNS/DNS_SD werkt
+//
+// netin_DNS_SD_sel    ldh     [x+2]
+//                     jset    #8000h, .resp, .query
+//
+// .resp               jset    #0203h, .resp.ko, .resp.ok   ; TC or RC!=OK
+// .resp.ko            return  #net_mdns_resp_error
+// .resp.ok            jset    #0400h, .resp.dyn, .resp.std
+// .resp.dyn           return  #net_mdns_resp_dyn
+// .resp.std           return  #net_mdns_resp_std
+//
+// .query              xor     #2000h  ; std query flag
+//                     jset    #3c00h, .query.ko, .query.ok
+// .query.ko           return  #net_mdns_query_error
+// .query.ok           return  #net_mdns_query_ok
+
+BPF_LABEL(netin_DNS_SD_sel)
+       STX_MEM (MEM_DNSSD_HEAD)
+       LDH_IDX (2)
+       JMZ_LIT (0x8000, _DNS_query)
+       JMZ_LIT (0x0203, _DNS_resp_ok)
+       RET_LIT (net_mdns_resp_error)
+BPF_LABEL(_DNS_resp_ok)
+       JMZ_LIT (0x0400, _DNS_resp_std)
+       RET_LIT (net_mdns_resp_dyn)
+BPF_LABEL(_DNS_resp_std)
+       RET_LIT (net_mdns_resp_std)
+
+BPF_LABEL(_DNS_query)
+       XOR_LIT (0x2000)
+       JMZ_LIT (0x3c00, _DNS_query_ok)
+       RET_LIT (net_mdns_query_error)
+BPF_LABEL(_DNS_query_ok)
+       RET_LIT (net_mdns_query_ok)
+
+
+// Note: Return a panic result, intending to cause a silent frame drop.
+//       No explicitly communicated error message should jump here, only
+//       frames that match no known pattern should end up here.
+//
+// netin_DROP          return  #0                      ; request frame drop
+
+BPF_LABEL(netin_DROP)
+       RET_LIT (0)
+
+
+// End of the BPF-styled assembly code
+//
+BPF_END()
+
diff --git a/src/net/reply.c b/src/net/reply.c
new file mode 100644 (file)
index 0000000..19e9016
--- /dev/null
@@ -0,0 +1,305 @@
+/* netreply.c -- Directly responding to parsed packets
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+#include <stdint.h>
+
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/ip6.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
+#include <netinet/if_ether.h>
+
+#include <0cpm/netfun.h>
+#include <0cpm/netdb.h>
+
+
+/* A few well-known addresses to look for
+ */
+extern uint8_t ether_broadcast [ETHER_ADDR_LEN];
+uint8_t ether_zero [ETHER_ADDR_LEN] = { 0, 0, 0, 0, 0, 0 };
+uint8_t prefix_6bed4 [8] = {
+                       0x20, 0x01, 0xab, 0xba, 0x6b, 0xed, 0x00, 0x04 };
+uint32_t ip4_6bed4 = ( 123 << 24 | 45 << 16 | 67 << 8 | 89 );
+uint8_t ip4_mine [4] = { 192, 168, 3, 13 };
+
+extern uint8_t linklocal_mine [];
+
+uint8_t ether_mine [ETHER_ADDR_LEN] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }; 
+
+uint16_t bootsecs = 0;
+
+
+/******************* HEADERVEL CREATION UTILITIES *******************/
+
+
+/* Create an Ethernet header.
+ * Some fields are filled later: h_proto
+ */
+uint8_t *netreply_ether (uint8_t *pout, uint32_t *mem) {
+       struct ethhdr *ethin  = (struct ethhdr *) mem [MEM_ETHER_HEAD];
+       struct ethhdr *ethout = (struct ethhdr *) pout;
+       if (mem [MEM_ETHER_DST] != 0) {
+               memcpy (ethout->h_dest, (void *) mem [MEM_ETHER_DST], ETHER_ADDR_LEN);
+       } else if (memcmp (ethin->h_source, ether_zero, ETHER_ADDR_LEN) != 0) {
+               memcpy (ethout->h_dest, ethin->h_source, ETHER_ADDR_LEN);
+       } else {
+               memset (ethout->h_dest, 0xff, ETHER_ADDR_LEN);  // Broadcast
+       }
+       memcpy (ethout->h_source, ether_mine, ETHER_ADDR_LEN);
+       mem [MEM_ETHER_HEAD] = (uint32_t) ethout;
+       return &pout [sizeof (struct ethhdr)];
+}
+
+/* Create an IPv4 header.
+ * Some IPv4 fields are filled later: protocol, tot_len, check.
+ */
+uint8_t *netreply_ip4 (uint8_t *pout, uint32_t *mem) {
+       pout = netreply_ether (pout, mem);
+       struct iphdr *ip4in  = (struct iphdr *) mem [MEM_IP4_HEAD];
+       struct iphdr *ip4out = (struct iphdr *) pout;
+       bzero (ip4out, sizeof (struct iphdr));
+       ip4out->version = 4;
+       ip4out->ihl = 5;
+       ip4out->ttl = 64;
+       ip4out->frag_off = htons (0x4000);      // Don't fragment
+       ip4out->saddr = ip4in->daddr;
+       ip4out->daddr = ip4in->saddr;
+       mem [MEM_IP4_HEAD] = (uint32_t) ip4out;
+       return &pout [sizeof (struct iphdr)];
+}
+
+/* Create an UDPv4 header.
+ * Some fields are filled later: len, check.
+ */
+uint8_t *netreply_udp4 (uint8_t *pout, uint32_t *mem) {
+       pout = netreply_ip4 (pout, mem);
+       struct udphdr *udp = (struct udphdr *) pout;
+       udp->source = htons (mem [MEM_UDP4_PORTS] & 0xffff);
+       udp->dest   = htons (mem [MEM_UDP4_PORTS] >> 16);
+       mem [MEM_UDP4_HEAD] = (uint32_t) udp;
+       return &pout [sizeof (struct udphdr)];
+}
+
+/* Create an UDPv4 header for 6bed4.
+ * Some fields are filled later: len, check.
+ */
+uint8_t *netreply_udp4_6bed4 (uint8_t *pout, uint32_t *mem) {
+       mem [MEM_IP4_SRC] = htonl (ip4_6bed4);
+       pout = netreply_ip4 (pout, mem);
+       struct udphdr *udp = (struct udphdr *) pout;
+       udp->source = htons (mem [MEM_UDP4_PORTS] & 0xffff);
+       udp->dest   = htons (3653);
+       mem [MEM_6BED4_PLOAD] =
+       mem [MEM_UDP4_HEAD] = (uint32_t) udp;
+       return &pout [sizeof (struct udphdr)];
+}
+
+/* Create an IPv6 header.
+ * Some fields are filled later: plen, nxt.
+ */
+uint8_t *netreply_ip6 (uint8_t *pout, uint32_t *mem) {
+       struct ip6_hdr *in6 = (struct ip6_hdr *) mem [MEM_IP6_HEAD];
+       if (mem [MEM_6BED4_PLOAD] != 0) {
+               // Use 6bed4 for destination address
+               pout = netreply_udp4_6bed4 (pout, mem);
+       } else {
+               // Use LAN for destination address
+               pout = netreply_ether (pout, mem);
+       }
+       struct ip6_hdr *ip6 = (struct ip6_hdr *) pout;
+       ip6->ip6_vfc = htonl (0x60000000);
+       ip6->ip6_hlim = 64;
+       memcpy (&ip6->ip6_src, &in6->ip6_dst, 16);
+       memcpy (&ip6->ip6_dst, &in6->ip6_src, 16);
+       mem [MEM_IP6_HEAD] = (uint32_t) ip6;
+       return &pout [sizeof (struct ip6_hdr)];
+}
+
+/* Create an UDPv6 header.
+ * Some fields are filled later: len, check.
+ */
+uint8_t *netreply_udp6 (uint8_t *pout, uint32_t *mem) {
+       pout = netreply_ip6 (pout, mem);
+       struct udphdr *udp = (struct udphdr *) pout;
+       udp->source = htons (mem [MEM_UDP6_PORTS] & 0xffff);
+       udp->dest   = htons (mem [MEM_UDP6_PORTS] >> 16);
+       mem [MEM_UDP6_HEAD] = (uint32_t) udp;
+       return &pout [sizeof (struct udphdr)];
+}
+
+
+/******************* APPLICATION LEVEL ROUTINES *******************/
+
+
+/* Create an ARP Reply packet to respond to an ARP Query
+ * There are no checksum or length fields in ARP.
+ */
+uint8_t *netreply_arp_query (uint8_t *pout, uint32_t *mem) {
+       printf ("Received an ARP Request; replying\n");
+       pout = netreply_ether (pout, mem);
+       struct ether_arp *arpout  = (struct ether_arp *) pout;
+       struct ether_arp *arpin  = (struct ether_arp *) mem [MEM_ARP_HEAD];
+       if (memcmp (arpin->arp_tpa, ip4_mine, 4) == 0) {
+               // arpout->ea_hdr.ar_hrd = htons (ARPHRD_IEEE802);
+               arpout->ea_hdr.ar_hrd = htons (ARPHRD_ETHER);
+               arpout->ea_hdr.ar_pro = htons (ETHERTYPE_IP);
+               arpout->ea_hdr.ar_hln = ETHER_ADDR_LEN;
+               arpout->ea_hdr.ar_pln = 4;              // IPv4 len
+               arpout->ea_hdr.ar_op  = htons (2);      // ARP Reply
+               memcpy (arpout->arp_sha, ether_mine, ETHER_ADDR_LEN);
+               memcpy (arpout->arp_spa, ip4_mine, 4);
+               memcpy (arpout->arp_tha, arpin->arp_sha, ETHER_ADDR_LEN);
+               memcpy (arpout->arp_tpa, arpin->arp_spa, 4);
+               return pout + sizeof (struct ether_arp);
+       } else {
+               return NULL;
+       }
+}
+
+/* Create an ICMPv4 Echo Reply packet to respond to Echo Request
+ * Some fields are filled later: icmp_cksum.
+ */
+uint8_t *netreply_icmp4_echo_req (uint8_t *pout, uint32_t *mem) {
+       printf ("Received an ICMPv4 Echo Request; replying\n");
+       pout = netreply_ip4 (pout, mem);
+       struct icmphdr *icmp4out = (struct icmphdr *) pout;
+       struct icmphdr *icmp4in  = (struct icmphdr *) mem [MEM_ICMP4_HEAD];
+       icmp4out->type = ICMP_ECHOREPLY;
+       icmp4out->code = 0;
+       icmp4out->un.echo.id       = icmp4in->un.echo.id ;
+       icmp4out->un.echo.sequence = icmp4in->un.echo.sequence;
+       pout = pout + sizeof (struct icmphdr);
+       uint32_t alen = mem [MEM_ALL_DONE] - mem [MEM_ICMP4_HEAD] - sizeof (struct icmphdr);
+       if ((alen > 0) && (alen < 128)) {
+               memcpy (&icmp4out [1], &icmp4in [1], alen);
+               pout += alen;
+       }
+       mem [MEM_ICMP4_HEAD] = (uint32_t) icmp4out;
+       return pout;
+}
+
+/* Create an ICMPv6 Echo Reply packet to respond to Echo Request
+ * Some fields are filled later: icmp6_cksum.
+ */
+uint8_t *netreply_icmp6_echo_req (uint8_t *pout, uint32_t *mem) {
+       printf ("Received an ICMPv6 Echo Request; replying\n");
+       pout = netreply_ip6 (pout, mem);
+       struct icmp6_hdr *icmp6 = (struct icmp6_hdr *) pout;
+       icmp6->icmp6_type = ICMP6_ECHO_REPLY;
+       icmp6->icmp6_code = 0;
+       uint16_t len = mem [MEM_ALL_DONE] - mem [MEM_ICMP6_HEAD];
+       memcpy (&icmp6->icmp6_data8,
+                       (void *) (mem [MEM_ICMP6_HEAD] + 4),
+                       len - 4);
+       mem [MEM_ICMP6_HEAD] = (uint32_t) icmp6;
+       return pout + len;
+}
+
+/* Create a Neighbour Advertisement packet to respond to Neighbour Discovery.
+ * This will also respond to ff02::1:ffxx:xxxx packets that end in the last
+ * 3 bytes of the ethernet address.
+ *
+ * Some fields are filled later: icmp6_cksum.
+ */
+uint8_t *netreply_icmp6_ngb_disc (uint8_t *pout, uint32_t *mem) {
+       printf ("Received an ICMPv6 Neighbour Discovery; replying\n");
+       int bndidx = IP6BINDING_COUNT;
+       uint8_t *addr = linklocal_mine;
+       uint16_t flgs = 0;
+       do {
+               if ((flgs & (I6B_EXPIRED | I6B_TENTATIVE)) == 0) {
+                       if (memcmp ((void *) (mem [MEM_ICMP6_HEAD] + 8), addr, 16) == 0) {
+                               break;
+                       }
+               }
+               addr = ip6binding [bndidx].ip6addr;
+               flgs = ip6binding [bndidx].flags;
+       } while (bndidx-- >= 0);
+       if (bndidx < 0) {
+               return NULL;
+       }
+       pout = netreply_ip6 (pout, mem);
+       struct ip6_hdr *ip6 = (struct ip6_hdr *) mem [MEM_IP6_HEAD];
+       memcpy (&ip6->ip6_src, addr, 16);
+       ip6->ip6_hlim = 255;
+       struct icmp6_hdr *icmp6 = (struct icmp6_hdr *) pout;
+       icmp6->icmp6_type = ND_NEIGHBOR_ADVERT;
+       icmp6->icmp6_code = 0;
+       icmp6->icmp6_data32 [0] = htonl (0x60000000);
+       memcpy (&icmp6->icmp6_data32 [1], addr, 16);
+       icmp6->icmp6_data8 [20] = ND_OPT_TARGET_LINKADDR;
+       icmp6->icmp6_data8 [21] = 1;    // 1x 8 bytes
+       memcpy (icmp6->icmp6_data8 + 22, ether_mine, ETHER_ADDR_LEN);
+       mem [MEM_ICMP6_HEAD] = (uint32_t) icmp6;
+       return pout + 8 + 16 + 8;
+}
+
+/* Respond to a DHCPv4 OFFER with a REQUEST.  An address is being
+ * offered in the yiaddr field (offset 16) of the DHCP packet, but
+ * that will also be repeated in the future DHCP ACK.
+ */
+uint8_t *netreply_dhcp4_offer (uint8_t *pout, uint32_t *mem) {
+       uint8_t *yiaddrptr = (uint8_t *) (mem [MEM_DHCP4_HEAD] + 16);
+       printf ("DHCPv4 offer for %d.%d.%d.%d received -- requesting its activation\n", (int) yiaddrptr [0], (int) yiaddrptr [1], (int) yiaddrptr [2], (int) yiaddrptr [3]);
+       // TODO: Validate offer to be mine
+       mem [MEM_ETHER_DST] = (uint32_t) ether_broadcast;
+       pout = netreply_udp4 (pout, mem);
+       ((struct iphdr *) mem [MEM_IP4_HEAD])->daddr = 0xffffffff;
+       bzero (pout, 576);      // erase the acceptable package size
+       pout [0] = 1;           // bootrequest
+       pout [1] = 1;           // ARP hardware address type
+       pout [2] = 6;           // ARP hardware address length
+       pout [3] = 0;           // hops
+       memcpy (pout + 4, ether_mine + 2, 4);           // client-randomiser
+       *(uint16_t *) (pout +  8) = htons (bootsecs++); // 0 or seconds trying
+       // flags=0, no broadcast reply needed
+       // ciaddr [4] is 0.0.0.0, the initial client address
+       // yiaddr [4] is 0.0.0.0, the "your" address
+       // siaddr [4] is 0.0.0.0, the server address is returned
+       // giaddr [4] is 0.0.0.0, gateway address is not set by client
+       memcpy (pout + 28, ether_mine, 6);      // client hw addr
+       // sname [64], the server hostname is empty
+       // file [128], the boot filename, is empty
+       // options
+       uint8_t *popt = pout + 236;
+       static const uint8_t dhcp4_options [] = {
+               99, 130, 83, 99,        // Magic cookie, RFC 1497
+               53, 1, 3,               // DHCP message type REQUEST
+               50, 4, 0, 0, 0, 0,      // Requested IP @ 4 + 3 + 2
+               // 55, 4, 1, 3, 42, 2,  // Param Request List:
+                                       // mask, router, ntp?, time offset?.
+               255                     // End Option
+       };
+       memcpy (popt, dhcp4_options, sizeof (dhcp4_options));
+       memcpy (popt + 4 + 3 + 2, yiaddrptr, 4);
+       // return popt + sizeof (dhcp4_options);
+       return popt + sizeof (dhcp4_options);
+}
+
+
+/* Respond to a DHCPv6 advertisement with a request.
+ *
+ * Note that the phone is supportive of multi-homing, and wants to
+ * be reachable over as many IPv6 addresses as are available, so it
+ * will actually take hold of all the IPv6 space that it can get.
+ */
+uint8_t *netreply_dhcp6_advertise (uint8_t *pout, uint32_t *mem) {
+       printf ("DHCPv6 advertisement\n");
+       // TODO: Validate offer to be mine
+       uint32_t adlen = mem [MEM_ALL_DONE] - mem [MEM_DHCP6_HEAD];
+       if (adlen > 1024) {
+               return NULL;    // Suspicuously long options
+       }
+       pout = netreply_udp6 (pout, mem);
+       struct udphdr *udp = (struct udphdr *) mem [MEM_UDP6_HEAD];
+       udp->dest = htons (547);
+       memcpy (pout, (void *) mem [MEM_DHCP6_HEAD], adlen);
+       pout [0] = 3;
+       mem [MEM_DHCP6_HEAD] = (uint32_t) pout;
+       return pout + adlen;
+}
+
diff --git a/src/net/send.c b/src/net/send.c
new file mode 100644 (file)
index 0000000..c554ccb
--- /dev/null
@@ -0,0 +1,302 @@
+/* netsend.c -- Initiatiating interactions by composing new packets
+ *
+ * This set of routines is used to build network packets from scratch.
+ * Only really small actions will be handled by immediate netreply_
+ * routines, but many others will need some internal processing first.
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+#include <string.h>
+
+
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <netinet/if_ether.h>
+
+#include <0cpm/netfun.h>
+#include <0cpm/netdb.h>
+
+
+
+/* A few well-known addresses to look for
+ */
+
+extern uint16_t bootsecs;
+
+extern uint8_t ether_mine [];
+
+extern uint32_t ip4_6bed4;
+
+uint8_t ether_broadcast [ETHER_ADDR_LEN] = {
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+uint8_t ether_multicast_all_dhcp6_servers [ETHER_ADDR_LEN] = {
+                               0x33, 0x33, 0x00, 0x01, 0x00, 0x02 };
+
+uint8_t linklocal_mine [] = {
+       0xfe, 0x80, 0, 0, 0, 0, 0, 0,
+       0x13, 0x22, 0x33, 0xff, 0xfe, 0x44, 0x55, 0x66 };
+
+uint8_t allnodes_linklocal_address [] = {
+        0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x01 };
+
+uint8_t allrouters_linklocal_address [] = {
+        0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x02 };
+
+struct ip6binding binding_linklocal [1] = { {
+       NULL,
+       // 2 lines -- copy of linklocal_mine above:
+       { 0xfe, 0x80, 0, 0, 0, 0, 0, 0,
+         0x13, 0x22, 0x33, 0xff, 0xfe, 0x44, 0x55, 0x66 },
+       { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+       0xffffffff,
+       NULL,
+       I6B_ROUTE_SOURCE_STATIC },
+};
+
+uint8_t ip6_multicast_all_hosts [16] = {
+       0xff, 0x02, 0,0,0,0,0,0,0,0,0,0, 0x00,0x00, 0x00,0x01 };
+
+uint8_t ip6_multicast_all_dhcp6_servers [16] = {
+       0xff, 0x02, 0,0,0,0,0,0,0,0,0,0, 0x00,0x01, 0x00,0x02 };
+
+uint8_t ipv6_router_solicitation [] = {
+        // IPv6 header
+        0x60, 0x00, 0x00, 0x00,
+        16 / 256, 16 % 256, IPPROTO_ICMPV6, 255,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,          // unspecd src
+        0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02, // all-rtr tgt
+        // ICMPv6 header: router solicitation
+        ND_ROUTER_SOLICIT, 0, 0x7a, 0xae,       // Checksum from WireShark :)
+        // ICMPv6 body: reserved
+        0, 0, 0, 0,
+        // ICMPv6 option: source link layer address 0x0001 (end-aligned)
+        0x01, 0x01, 0, 0, 0, 0, 0x00, 0x01,
+};
+
+
+
+
+/******************* HEADERVEL CREATION UTILITIES *******************/
+
+
+/* Create an Ethernet header.
+ * Some fields are filled later: h_proto
+ * TODO: When to use the broadcast address?
+ */
+uint8_t *netsend_ether (uint8_t *pout, uint32_t *mem) {
+       struct ethhdr *eth = (struct ethhdr *) pout;
+       memcpy (eth->h_source, ether_mine, ETHER_ADDR_LEN);
+       memcpy (eth->h_dest, (void *) mem [MEM_ETHER_DST], ETHER_ADDR_LEN);
+       if (mem [MEM_VLAN_ID] != 0) {
+               // TODO: Setup VLAN with mem [MEM_VLAN] number
+       }
+       mem [MEM_ETHER_HEAD] = (uint32_t) eth;
+       return pout + sizeof (struct ethhdr);
+}
+
+/* Create an IPv4 header.
+ * This may be used for local protocols (DNS, DHCPv4) or as a 6bed4 carrier.
+ * Some IPv4 fields are filled later: protocol, tot_len, check.
+ */
+uint8_t *netsend_ip4 (uint8_t *pout, uint32_t *mem) {
+       pout = netsend_ether (pout, mem);
+       struct iphdr *ip4 = (struct iphdr *) pout;
+       bzero (ip4, sizeof (struct iphdr));
+       ip4->version = 4;
+       ip4->ihl = 5;
+       ip4->ttl = 64;
+       ip4->frag_off = htons (0x4000); // Don't fragment
+       ip4->saddr = htonl (mem [MEM_IP4_SRC]);
+       ip4->daddr = htonl (mem [MEM_IP4_DST]);
+       mem [MEM_IP4_HEAD] = (uint32_t) ip4;
+       return &pout [sizeof (struct iphdr)];
+}
+
+/* Send an UDPv4 header.
+ * Some fields are filled later: len, check.
+ */
+uint8_t *netsend_udp4 (uint8_t *pout, uint32_t *mem) {
+       // TODO: Setup MEM_ETHER_DST with router's address
+       pout = netsend_ip4 (pout, mem);
+       struct udphdr *udp = (struct udphdr *) pout;
+       udp->source = htons (mem [MEM_UDP4_PORTS] & 0xffff);
+       udp->dest   = htons (mem [MEM_UDP4_PORTS] >> 16);
+       mem [MEM_UDP4_HEAD] = (uint32_t) udp;
+       return &pout [sizeof (struct udphdr)];
+}
+
+/* Send an UDPv4 header for 6bed4.
+ * Some fields are filled later: len, check.
+ */
+uint8_t *netsend_udp4_6bed4 (uint8_t *pout, uint32_t *mem) {
+       struct ip6binding *bnd = (struct ip6binding *) mem [MEM_BINDING6];
+       mem [MEM_IP4_SRC] = bnd->ip4binding->ip4addr;
+       mem [MEM_IP4_DST] = ip4_6bed4;
+       // TODO: Setup MEM_ETHER_DST with router's address
+       pout = netsend_ip4 (pout, mem);
+       struct udphdr *udp = (struct udphdr *) pout;
+       //TODO:dyn.ports?// udp->source = htons (bnd->ip4binding->ip4port);
+       udp->source = htons (3653);
+       udp->dest   = htons (3653);
+       mem [MEM_UDP4_HEAD] = (uint32_t) udp;
+       mem [MEM_6BED4_PLOAD] = (uint32_t) (pout + sizeof (struct udphdr));
+       return (uint8_t *) mem [MEM_6BED4_PLOAD];
+}
+
+/* Send an IPv6 header, and wrap it in 6bed4 if needed.
+ * Some fields are filled later: plen, nxt.
+ */
+uint8_t *netsend_ip6 (uint8_t *pout, uint32_t *mem) {
+       struct ip6binding *bnd = (struct ip6binding *) mem [MEM_BINDING6];
+       if (bnd->flags & I6B_ROUTE_SOURCE_6BED4_FLAG) {
+               // Use 6bed4 for destination address
+               pout = netsend_udp4_6bed4 (pout, mem);
+       } else {
+               // Use LAN for destination address
+               // TODO: Setup MEM_ETHER_DST with router's address
+               pout = netsend_ether (pout, mem);
+       }
+       struct ip6_hdr *ip6 = (struct ip6_hdr *) pout;
+       ip6->ip6_vfc = htonl (0x60000000);
+       ip6->ip6_hlim = 64;
+       memcpy (&ip6->ip6_src, bnd->ip6addr, 16);
+       memcpy (&ip6->ip6_dst, (uint8_t *) mem [MEM_IP6_DST], 16);
+       mem [MEM_IP6_HEAD] = (uint32_t) ip6;
+       return &pout [sizeof (struct ip6_hdr)];
+}
+
+/* Send an UDP6 header over IPv6.
+ * Some fields are filled later: len, check.
+ */
+uint8_t *netsend_udp6 (uint8_t *pout, uint32_t *mem) {
+       // TODO: Setup MEM_ETHER_DST with router's address
+       pout = netsend_ip6 (pout, mem);
+       struct udphdr *udp = (struct udphdr *) pout;
+       udp->source = htons (mem [MEM_UDP6_PORTS] & 0xffff);
+       udp->dest   = htons (mem [MEM_UDP6_PORTS] >> 16);
+       mem [MEM_UDP6_HEAD] = (uint32_t) udp;
+       return &pout [sizeof (struct udphdr)];
+}
+
+
+
+/******************* APPLICATION LEVEL ROUTINES *******************/
+
+
+/* Create an ICMPv6 Router Solicitation.
+ */
+uint8_t *netsend_icmp6_router_solicit (uint8_t *pout, uint32_t *mem) {
+       mem [MEM_ETHER_DST] = (uint32_t) ether_broadcast;
+       struct ip6binding *bnd = (struct ip6binding *) mem [MEM_BINDING6];
+       if (bnd->flags & I6B_ROUTE_SOURCE_6BED4_FLAG) {
+               // Use 6bed4 for destination address
+               pout = netsend_udp4_6bed4 (pout, mem);
+       } else {
+               // Use LAN for destination address
+               pout = netsend_ether (pout, mem);
+       }
+       memcpy (pout, ipv6_router_solicitation, sizeof (ipv6_router_solicitation));
+       memcpy (pout + 40 + 8 + 2, ether_mine, ETHER_ADDR_LEN);
+       memcpy (pout + 8, linklocal_mine, 16);
+       //ADDS_NOTHING// memcpy (pout + 8, linklocal_mine, 16);
+       mem [MEM_IP6_HEAD] = (uint32_t) pout;
+       mem [MEM_ICMP6_HEAD] = (uint32_t) pout + 40;
+       return pout + sizeof (ipv6_router_solicitation);
+}
+
+/* Send a Neighbour Solicitation, possibly as part of autoconfiguration.
+ * Some fields are filled later: icmp6_cksum
+ * TODO: Set multicast target address for IPv6
+ */
+uint8_t *netsend_icmp6_ngb_sol (uint8_t *pout, uint32_t *mem) {
+       mem [MEM_ETHER_DST] = (uint32_t) ether_broadcast;
+       mem [MEM_IP6_DST] = (uint32_t) ip6_multicast_all_hosts;
+       pout = netsend_ip6 (pout, mem);
+       struct icmp6_hdr *icmp6 = (struct icmp6_hdr *) pout;
+       struct ip6binding *bnd = (struct ip6binding *) mem [MEM_BINDING6];
+       mem [MEM_ICMP6_HEAD] = (uint32_t) pout;
+       icmp6->icmp6_type = ND_NEIGHBOR_SOLICIT;
+       icmp6->icmp6_code = 0;
+       icmp6->icmp6_data32 [0] = 0;
+       memcpy (icmp6->icmp6_data8 + 4, bnd->ip6addr, 16);
+       icmp6->icmp6_data8 [4+16+0] = 1;
+       icmp6->icmp6_data8 [4+16+1] = 1;
+       memcpy (icmp6->icmp6_data8 + 4+16+2, ether_mine, 6);
+       return pout + 24 + 8;
+}
+
+/* Send a DHCPv4 DISCOVER packet to initiatie IPv4 LAN configuration.
+ */
+uint8_t *netsend_dhcp4_discover (uint8_t *pout, uint32_t *mem) {
+       mem [MEM_UDP4_PORTS] = 0x00430044;
+       mem [MEM_IP4_DST] = 0xffffffff;
+       mem [MEM_ETHER_DST] = (uint32_t) ether_broadcast;
+       pout = netsend_udp4 (pout, mem);
+       bzero (pout, 576);      // erase the acceptable package size
+       pout [0] = 1;           // bootrequest
+       pout [1] = 1;           // ARP hardware address type
+       pout [2] = 6;           // ARP hardware address length
+       pout [3] = 0;           // hops
+       memcpy (pout + 4, ether_mine + 2, 4);           // client-randomiser
+       *(uint16_t *) (pout +  8) = htons (bootsecs++); // 0 or seconds trying
+       // flags=0, no broadcast reply needed
+       // ciaddr [4] is 0.0.0.0, the initial client address
+       // yiaddr [4] is 0.0.0.0, the "your" address
+       // siaddr [4] is 0.0.0.0, the server address is returned
+       // giaddr [4] is 0.0.0.0, gateway address is not set by client
+       memcpy (pout + 28, ether_mine, 6);      // client hw addr
+       // sname [64], the server hostname is empty
+       // file [128], the boot filename, is empty
+       // options
+       uint8_t *popt = pout + 236;
+       static const uint8_t dhcp4_options [] = {
+               99, 130, 83, 99,        // Magic cookie, RFC 1497
+               53, 1, 1,               // DHCP message type DISCOVER
+               55, 4, 1, 3, 42, 2,     // Param Request List:
+                                       // mask, router, ntp?, time offset?.
+               255                     // End Option
+       };
+       memcpy (popt, dhcp4_options, sizeof (dhcp4_options));
+       return popt + sizeof (dhcp4_options);
+}
+
+/* Send a DHCPv6 SOLICIT packet to initiatie native IPv6 configuration.
+ */
+uint8_t *netsend_dhcp6_solicit (uint8_t *pout, uint32_t *mem) {
+       mem [MEM_UDP6_PORTS] = 0x02230222;
+       mem [MEM_BINDING6] = (uint32_t) binding_linklocal;
+       mem [MEM_IP6_DST] = (uint32_t) ip6_multicast_all_dhcp6_servers;
+       mem [MEM_ETHER_DST] = (uint32_t) ether_multicast_all_dhcp6_servers;
+       pout = netsend_udp6 (pout, mem);
+       pout [0] = 1;
+       memcpy (pout + 1, ether_mine + 3, 3);
+       static const uint8_t dhcp6_options [] = {
+               0,1, 0,4+6,     // Client ID, ether @ 4+4 (below), etherlen 6
+                       0, 3, 0, 1, 0,0,0,0,0,0,
+               0,18, 0,6,      // Interface ID, ether @4+4+6+4 below, len 6
+                       0,0,0,0,0,0,
+               0,6, 0,8,       // Option Request
+                       0,23, 0,22, 0,56, 0,141,
+                               // DNS resolver, SIP proxy, NTP, SIP UAcfg
+               0,3, 0,40,      // Identity Association, non-temporary
+                       0,0,0,0,                // IAID = 0x00000000
+                       0x00,0x09,0x3a,0x80,    // Refresh: 7d
+                       0x00,0x28,0xde,0x80,    // Extend:  31d
+                       0,5, 0,24,              // IdAssoc Address
+                       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                       0x00,0x28,0xde,0x80,    // Preferred: 31d
+                       0x00,0x28,0xde,0x80,    // Valid: 31d
+               // 0,14, 0,0,   // Rapid Commit -- IMPOSSIBLE with IP assignmt
+       };
+       memcpy (pout + 4          , dhcp6_options, sizeof (dhcp6_options));
+       memcpy (pout + 4 + 4+4    , ether_mine, ETHER_ADDR_LEN);
+       memcpy (pout + 4 + 4+4+6+4, ether_mine, ETHER_ADDR_LEN);
+       mem [MEM_DHCP6_HEAD] = (uint32_t) pout;
+       return pout + 4 + sizeof (dhcp6_options);
+}
+
diff --git a/src/target/Kconfig b/src/target/Kconfig
new file mode 100644 (file)
index 0000000..7e4dcc3
--- /dev/null
@@ -0,0 +1,102 @@
+#
+# Target configuration
+#
+# Targets are platforms on which one or more drivers can be
+# configured to support various chips.  Order alphabetically
+# by the manufacturer's name, then the model.
+#
+# Targets are selected by make and model.  Detailed selection
+# of specific models (and, possibly, chips to drive) are made
+# in submenus loaded from the target's own directory.
+#
+
+
+mainmenu "Configuration for firmly.0cpm SIP telephony"
+
+
+choice
+       prompt "Target platform"
+       default TARGET_LINUX_RAWSOCK
+
+config TARGET_AVM_FRITZBOX
+       depends on TODO_IMPLEMENT_FIRST
+       bool "AVM Fritz!Box"
+       help
+         Depending on the model, AVM Fritz!Box can use any of a variety
+         of telephony chips.  The firmware will build a program that
+         can be incorporated into Freetz (see http://freetz.org/ for
+         details).
+
+# config TARGET_GRANDSTREAM_HANDYTONE
+# config TARGET_GRANDSTREAM_BUDGETONE
+# config TARGET_GRANDSTREAM_GXP
+
+# config TARGET_LINKSYS_SPA3000
+# config TARGET_LINKSYS_SPA9xx
+
+config TARGET_LINUX_RAWSOCK
+       depends on TODO_IMPLEMENT_FIRST
+       bool "Linux desktop"
+       select TARGET_POSIX_RAWSOCK
+       help
+         This is a platform intended to run on the same platform as
+         used for building.  It is built on a raw socket, so it does
+         not require IPv6 support in the kernel.  It will obtain its
+         own network leases, so it should be tested for non-interference
+         if any other software is run on the same platform.
+
+         Once built, run the command src/target/rawsock/firmly0cpm.bin
+         on your current platform.  It will configure itself automatically.
+
+         TODO: sound devices?  keyboard?  display?
+
+         TODO: Demo entry. Not implemented yet.
+
+config TARGET_LINUX_TUNTEST
+       bool "Linux tunnel device"
+       help
+         Test and demonstration target intended for development.
+
+         This creates a tunnel interface behind which the firmly.0cpm
+         firmware is working.  You can route/bridge/filter/simulate
+         the surrounding network in any way you like.
+
+         Once built, run the command src/target/tuntest/firmly0cpm.bin
+         on your current platform.  It will configure itself automatically.
+
+         TODO: sound devices?  keyboard?  display?
+
+config TARGET_SIEMENS_GIGASET
+       depends on TODO_IMPLEMENT_FIRST
+       bool "Siemens Gigaset xnnnIP"
+       help
+         The Siemens Gigaset platform has DECT/SIP phones with numbers
+         like C470IP or A580IP.  Important in this is the "IP" postfix.
+         There has been a short-lived clone from Target, the DIP450.
+
+         The platforms contain LGPL-licensed software so they permit
+         uploading new firmware from their web interface.
+
+         Once built, upload src/target/gigaset/firmly0cpm.bin to a
+         webserver and set the firmware location in your phone to the
+         proper URL to migrate to the new platform.
+
+         TODO: Demo entry. Not implemented yet.
+
+config TARGET_SMC_WSP100_DSP200
+       depends on TODO_IMPLEMENT_FIRST
+       bool "SMC WSP100, WSKP100, DSP200"
+       help
+         This covers the wireless models WSP100 and WSKP100, as well
+         as the table model DSP200.  The WSKP100 is a special version
+         that runs Skype, not SIP.  The space in these devices varies.
+
+         This DSP200 seems to resist configuration with any common SIP
+         telephony service.  You can revive the phone by compiling the
+         firmly.0cpm platform for it.
+
+         Once built, install by ...TODO...
+
+         TODO: Demo entry. Not implemented yet.
+
+endchoice
diff --git a/src/target/tuntest/Makefile b/src/target/tuntest/Makefile
new file mode 100644 (file)
index 0000000..307bfb3
--- /dev/null
@@ -0,0 +1,2 @@
+src/target/tuntest/firmly0cpm.bin: src/driver/tunnel/tuntest.o src/net/net.o
+       gcc -ggdb3 -o $@ $^